Skip to content

Commit 83182d9

Browse files
authored
feat(compass-assistant): add global per-conversation instructions COMPASS-9766 (#7279)
* Add global per-conversation instructions * add Gagik's prompt tweak * extend stub for test * rather pass in a prop to the provider * also use the assistant prompt in the braintrust evals
1 parent 8a5b385 commit 83182d9

File tree

14 files changed

+4059
-135
lines changed

14 files changed

+4059
-135
lines changed

packages/compass-assistant/src/compass-assistant-provider.spec.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ const TestComponent: React.FunctionComponent<{
8383

8484
return (
8585
<DrawerContentProvider>
86-
<MockedProvider chat={chat}>
86+
<MockedProvider appNameForPrompt="MongoDB Compass" chat={chat}>
8787
<DrawerAnchor>
8888
<div data-testid="provider-children">Provider children</div>
8989
<CompassAssistantDrawer autoOpen={autoOpen} />
@@ -100,7 +100,9 @@ describe('useAssistantActions', function () {
100100

101101
return (
102102
<DrawerContentProvider>
103-
<MockedProvider chat={chat}>{children}</MockedProvider>
103+
<MockedProvider appNameForPrompt="MongoDB Compass" chat={chat}>
104+
{children}
105+
</MockedProvider>
104106
</DrawerContentProvider>
105107
);
106108
}
@@ -494,7 +496,7 @@ describe('CompassAssistantProvider', function () {
494496
render(
495497
<DrawerContentProvider>
496498
<DrawerAnchor />
497-
<MockedProvider />
499+
<MockedProvider appNameForPrompt="MongoDB Compass" />
498500
</DrawerContentProvider>,
499501
{
500502
preferences: {

packages/compass-assistant/src/compass-assistant-provider.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import type { ConnectionInfo } from '@mongodb-js/connection-info';
2828
import { useTelemetry } from '@mongodb-js/compass-telemetry/provider';
2929
import type { AtlasAiService } from '@mongodb-js/compass-generative-ai/provider';
3030
import { atlasAiServiceLocator } from '@mongodb-js/compass-generative-ai/provider';
31+
import { buildConversationInstructionsPrompt } from './prompts';
3132

3233
export const ASSISTANT_DRAWER_ID = 'compass-assistant-drawer';
3334

@@ -141,6 +142,7 @@ export type CompassAssistantService = {
141142

142143
export const AssistantProvider: React.FunctionComponent<
143144
PropsWithChildren<{
145+
appNameForPrompt: string;
144146
chat: Chat<AssistantMessage>;
145147
atlasAiService: AtlasAiService;
146148
}>
@@ -223,10 +225,12 @@ export const CompassAssistantProvider = registerCompassPlugin(
223225
{
224226
name: 'CompassAssistant',
225227
component: ({
228+
appNameForPrompt,
226229
chat,
227230
atlasAiService,
228231
children,
229232
}: PropsWithChildren<{
233+
appNameForPrompt: string;
230234
chat?: Chat<AssistantMessage>;
231235
atlasAiService?: AtlasAiService;
232236
}>) => {
@@ -237,7 +241,11 @@ export const CompassAssistantProvider = registerCompassPlugin(
237241
throw new Error('atlasAiService was not provided by the state');
238242
}
239243
return (
240-
<AssistantProvider chat={chat} atlasAiService={atlasAiService}>
244+
<AssistantProvider
245+
appNameForPrompt={appNameForPrompt}
246+
chat={chat}
247+
atlasAiService={atlasAiService}
248+
>
241249
{children}
242250
</AssistantProvider>
243251
);
@@ -248,6 +256,9 @@ export const CompassAssistantProvider = registerCompassPlugin(
248256
new Chat({
249257
transport: new DocsProviderTransport({
250258
baseUrl: atlasService.assistantApiEndpoint(),
259+
instructions: buildConversationInstructionsPrompt({
260+
target: initialProps.appNameForPrompt,
261+
}),
251262
}),
252263
onError: (err: Error) => {
253264
logger.log.error(

packages/compass-assistant/src/docs-provider-transport.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,20 @@ import { createOpenAI } from '@ai-sdk/openai';
99

1010
export class DocsProviderTransport implements ChatTransport<UIMessage> {
1111
private openai: ReturnType<typeof createOpenAI>;
12+
private instructions: string;
1213

13-
constructor({ baseUrl }: { baseUrl: string }) {
14+
constructor({
15+
baseUrl,
16+
instructions,
17+
}: {
18+
baseUrl: string;
19+
instructions: string;
20+
}) {
1421
this.openai = createOpenAI({
1522
baseURL: baseUrl,
1623
apiKey: '',
1724
});
25+
this.instructions = instructions;
1826
}
1927

2028
sendMessages({
@@ -25,6 +33,11 @@ export class DocsProviderTransport implements ChatTransport<UIMessage> {
2533
model: this.openai.responses('mongodb-chat-latest'),
2634
messages: convertToModelMessages(messages),
2735
abortSignal: abortSignal,
36+
providerOptions: {
37+
openai: {
38+
instructions: this.instructions,
39+
},
40+
},
2841
});
2942

3043
return Promise.resolve(result.toUIMessageStream());

packages/compass-assistant/src/prompts.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
import type { ConnectionInfo } from '@mongodb-js/connection-info';
22
import { redactConnectionString } from 'mongodb-connection-string-url';
33

4+
export const buildConversationInstructionsPrompt = ({
5+
target,
6+
}: {
7+
target: string;
8+
}) => {
9+
// TODO: we'll want to greatly expand on this, but at minimum this is where we
10+
// make the distinction between running inside Data Explorer vs Compass.
11+
return `You are an assistant running in a side-panel inside ${target}. Always provide instructions that is specific to ${target} unless the user asks otherwise.`;
12+
};
13+
414
export type EntryPointMessage = {
515
prompt: string;
616
displayText?: string;
@@ -78,7 +88,7 @@ Tell the user if indexes need to be created or modified to enable any recommenda
7888
</guidelines>
7989
<input>
8090
${explainPlan}
81-
</explain-plan>`,
91+
</input>`,
8292
displayText: 'Interpret this explain plan output for me.',
8393
};
8494
};

packages/compass-assistant/test/assistant.eval.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { evalCases } from './eval-cases';
99
import { fuzzyLinkMatch } from './fuzzylinkmatch';
1010
import { binaryNdcgAtK } from './binaryndcgatk';
1111
import { makeEntrypointCases } from './entrypoints';
12+
import { buildConversationInstructionsPrompt } from '../src/prompts';
1213

1314
const client = new OpenAI({
1415
baseURL: 'https://api.braintrust.dev/v1/proxy',
@@ -33,6 +34,7 @@ type ExpectedMessage = OutputMessage;
3334

3435
type ConversationEvalCaseInput = {
3536
messages: InputMessage[];
37+
instructions: Message;
3638
};
3739

3840
type ConversationEvalCaseExpected = {
@@ -79,13 +81,32 @@ function getScorerTemperature(): number | undefined {
7981
}
8082

8183
function makeEvalCases(): ConversationEvalCase[] {
82-
const entrypointCases: ConversationEvalCase[] = makeEntrypointCases();
84+
const instructions = buildConversationInstructionsPrompt({
85+
target: 'MongoDB Compass',
86+
});
87+
88+
const entrypointCases: ConversationEvalCase[] = makeEntrypointCases().map(
89+
(c) => {
90+
return {
91+
name: c.name ?? c.input,
92+
input: {
93+
messages: [{ text: c.input }],
94+
instructions: { text: instructions },
95+
},
96+
expected: {
97+
messages: [{ text: c.expected, sources: c.expectedSources || [] }],
98+
},
99+
metadata: {},
100+
};
101+
}
102+
);
83103

84104
const userCases: ConversationEvalCase[] = evalCases.map((c) => {
85105
return {
86106
name: c.name ?? c.input,
87107
input: {
88108
messages: [{ text: c.input }],
109+
instructions: { text: instructions },
89110
},
90111
expected: {
91112
messages: [{ text: c.expected, sources: c.expectedSources || [] }],
@@ -115,6 +136,11 @@ async function makeAssistantCall(
115136
model: openai.responses('mongodb-chat-latest'),
116137
temperature: getChatTemperature(),
117138
prompt,
139+
providerOptions: {
140+
openai: {
141+
instructions: input.instructions.text,
142+
},
143+
},
118144
});
119145

120146
const chunks: string[] = [];

0 commit comments

Comments
 (0)