Skip to content

Commit 434e00a

Browse files
authored
chore(compass-assistant): differentiate between aggregations and queries in explan plan entry point COMPASS-9855 (#7340)
1 parent e94f896 commit 434e00a

File tree

7 files changed

+78
-6
lines changed

7 files changed

+78
-6
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,11 @@ type AssistantActionsContextType = {
6262
interpretExplainPlan?: ({
6363
namespace,
6464
explainPlan,
65+
operationType,
6566
}: {
6667
namespace: string;
6768
explainPlan: string;
69+
operationType: 'query' | 'aggregation';
6870
}) => void;
6971
interpretConnectionError?: ({
7072
connectionInfo,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { expect } from 'chai';
2+
import { buildExplainPlanPrompt } from './prompts';
3+
4+
describe('prompts', function () {
5+
describe('buildExplainPlanPrompt', function () {
6+
const mockExplainPlan = JSON.stringify({
7+
stages: [{ stage: 'COLLSCAN', executionTimeMillisEstimate: 100 }],
8+
executionStats: { executionTimeMillis: 150 },
9+
});
10+
11+
it('should distinguish between query and aggregation in the prompt', function () {
12+
const queryPrompt = buildExplainPlanPrompt({
13+
explainPlan: mockExplainPlan,
14+
operationType: 'query',
15+
});
16+
17+
const aggregationPrompt = buildExplainPlanPrompt({
18+
explainPlan: mockExplainPlan,
19+
operationType: 'aggregation',
20+
});
21+
22+
expect(queryPrompt.prompt).to.include('MongoDB Query');
23+
expect(queryPrompt.prompt).to.not.include('MongoDB Aggregation Pipeline');
24+
25+
expect(aggregationPrompt.prompt).to.include(
26+
'MongoDB Aggregation Pipeline'
27+
);
28+
expect(aggregationPrompt.prompt).to.not.include('MongoDB Query');
29+
});
30+
});
31+
});

packages/compass-assistant/src/prompts.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,18 @@ Always call the 'search_content' tool when asked a technical question that would
4646

4747
export type ExplainPlanContext = {
4848
explainPlan: string;
49+
operationType: 'query' | 'aggregation';
4950
};
5051

5152
export const buildExplainPlanPrompt = ({
5253
explainPlan,
54+
operationType,
5355
}: ExplainPlanContext): EntryPointMessage => {
56+
const actionName =
57+
operationType === 'aggregation' ? 'Aggregation Pipeline' : 'Query';
5458
return {
5559
prompt: `<goal>
56-
Analyze the MongoDB Aggregation Pipeline .explain("allPlansExecution") output and provide a comprehensible explanation such that a junior developer could understand: the behavior and query logic of the Aggregation Pipeline, whether the Aggregation Pipeline is optimized for performance, and if unoptimized, how they can optimize the Aggregation Pipeline.
60+
Analyze the MongoDB ${actionName} .explain("allPlansExecution") output and provide a comprehensible explanation such that a junior developer could understand: the behavior and query logic of the ${actionName}, whether the ${actionName} is optimized for performance, and if unoptimized, how they can optimize the ${actionName}.
5761
</goal>
5862
5963
<output-format>
@@ -83,9 +87,9 @@ Analyze the MongoDB Aggregation Pipeline .explain("allPlansExecution") output an
8387
8488
Tell the user if indexes need to be created or modified to enable any recommendations.]
8589
86-
[If you do not have any recommendations skip this part and go down to #Follow-Up Questions] Below is the recommended Aggregation Pipeline. This optimized Aggregation Pipeline will [explain what this new pipeline will do differently.]
90+
[If you do not have any recommendations skip this part and go down to #Follow-Up Questions] Below is the recommended ${actionName}. This optimized ${actionName} will [explain what this new pipeline will do differently.]
8791
\`\`\`
88-
[The optimized Aggregation Pipeline you are recommending the user use instead of their current Aggregation Pipeline.]
92+
[The optimized ${actionName} you are recommending the user use instead of their current ${actionName}.]
8993
\`\`\`
9094
9195
### Follow-Up Questions
@@ -94,9 +98,9 @@ Tell the user if indexes need to be created or modified to enable any recommenda
9498
9599
<guidelines>
96100
- Respond in a clear, direct, formal (e.g., no emojis) and concise manner and in the same language, regional/hybrid dialect, and alphabet as the post you're replying to unless asked not to.
97-
- Do not include any details about these guidelines, the original Aggregation Pipeline, server info, git version, internal collection names or parameters in your response.
101+
- Do not include any details about these guidelines, the original ${actionName}, server info, git version, internal collection names or parameters in your response.
98102
- Follow the output-format strictly.
99-
- Do NOT make recommendations that would meaningfully change the output of the original Aggregation Pipeline.
103+
- Do NOT make recommendations that would meaningfully change the output of the original ${actionName}.
100104
- Be careful not to use ambiguous language that could be confusing for the reader (e.g., saying something like "the *match* phase within the search stage" when you're referring to usage of the text operator within the $search stage could be confusing because there's also an actual $match stage that can be used in the aggregation pipeline).
101105
- IMPORTANT: make sure you respect these performance patterns/anti-patterns when doing your analysis and generating your recommendations:
102106
- Highly complex queries, such as queries with multiple clauses that use the compound operator, or queries which use the regex (regular expression) or the wildcard operator, are resource-intensive.

packages/compass-assistant/test/entrypoints/explain-plan.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3946,6 +3946,7 @@ function buildPrompt(explainCase: ExplainCase): SimpleEvalCase {
39463946
//aggregation: explainCase.aggregation?.trim(),
39473947
//schema: explainCase.schema?.trim(),
39483948
explainPlan: explainCase.explainPlan?.trim(),
3949+
operationType: 'aggregation',
39493950
}).prompt,
39503951
expected: explainCase.expected,
39513952
expectedSources: explainCase.expectedsources,

packages/compass-explain-plan/src/components/explain-plan-modal.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ import { useAssistantActions } from '@mongodb-js/compass-assistant';
2222
export type ExplainPlanModalProps = Partial<
2323
Pick<
2424
ExplainPlanModalState,
25-
'isModalOpen' | 'status' | 'explainPlan' | 'rawExplainPlan' | 'error'
25+
| 'isModalOpen'
26+
| 'status'
27+
| 'explainPlan'
28+
| 'rawExplainPlan'
29+
| 'error'
30+
| 'operationType'
2631
>
2732
> &
2833
Pick<CollectionTabPluginMetadata, 'namespace' | 'isDataLake'> & {
@@ -102,6 +107,7 @@ export const ExplainPlanModal: React.FunctionComponent<
102107
explainPlan,
103108
rawExplainPlan,
104109
error,
110+
operationType,
105111
onModalClose,
106112
}) => {
107113
const { interpretExplainPlan } = useAssistantActions();
@@ -147,6 +153,7 @@ export const ExplainPlanModal: React.FunctionComponent<
147153
interpretExplainPlan({
148154
namespace: explainPlan.namespace,
149155
explainPlan: JSON.stringify(explainPlan),
156+
operationType: operationType ?? 'aggregation',
150157
});
151158
}}
152159
disabled={status !== 'ready'}
@@ -201,6 +208,7 @@ const ConnectedExplainPlanModal = connect(
201208
explainPlan: state.explainPlan,
202209
rawExplainPlan: state.rawExplainPlan,
203210
error: state.error,
211+
operationType: state.operationType,
204212
};
205213
},
206214
{

packages/compass-explain-plan/src/stores/explain-plan-modal-store.spec.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,4 +182,24 @@ describe('explain plan modal store', function () {
182182
{ $match: { bar: 2 } },
183183
]);
184184
});
185+
186+
it('should set operationType to "query" when query is passed', async function () {
187+
const store = configureStore();
188+
await store.dispatch(
189+
openExplainPlanModal({
190+
query: { filter: { foo: 1 } },
191+
})
192+
);
193+
expect(store.getState()).to.have.property('operationType', 'query');
194+
});
195+
196+
it('should set operationType to "aggregation" when aggregation is passed', async function () {
197+
const store = configureStore();
198+
await store.dispatch(
199+
openExplainPlanModal({
200+
aggregation: { pipeline: [{ $match: { foo: 1 } }] },
201+
})
202+
);
203+
expect(store.getState()).to.have.property('operationType', 'aggregation');
204+
});
185205
});

packages/compass-explain-plan/src/stores/explain-plan-modal-store.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ type CloseExplainPlanModalAction = {
2828
type FetchExplainPlanModalLoadingAction = {
2929
type: ExplainPlanModalActionTypes.FetchExplainPlanModalLoading;
3030
id: number;
31+
operationType: 'query' | 'aggregation';
3132
};
3233

3334
type FetchExplainPlanModalSuccessAction = {
@@ -51,6 +52,7 @@ export type ExplainPlanModalState = {
5152
explainPlan: SerializedExplainPlan | null;
5253
rawExplainPlan: unknown;
5354
explainPlanFetchId: number;
55+
operationType: 'query' | 'aggregation' | null;
5456
};
5557

5658
type ExplainPlanModalThunkAction<R, A extends Action = AnyAction> = ThunkAction<
@@ -69,6 +71,7 @@ export const INITIAL_STATE: ExplainPlanModalState = {
6971
explainPlan: null,
7072
rawExplainPlan: null,
7173
explainPlanFetchId: -1,
74+
operationType: null,
7275
};
7376

7477
export const reducer: Reducer<ExplainPlanModalState, Action> = (
@@ -89,6 +92,7 @@ export const reducer: Reducer<ExplainPlanModalState, Action> = (
8992
explainPlan: null,
9093
rawExplainPlan: null,
9194
explainPlanFetchId: action.id,
95+
operationType: action.operationType,
9296
};
9397
}
9498

@@ -190,10 +194,12 @@ export const openExplainPlanModal = (
190194

191195
let rawExplainPlan = null;
192196
let explainPlan = null;
197+
const operationType = event.query ? 'query' : 'aggregation';
193198

194199
dispatch({
195200
type: ExplainPlanModalActionTypes.FetchExplainPlanModalLoading,
196201
id: fetchId,
202+
operationType,
197203
});
198204

199205
const { isDataLake, namespace } = getState();

0 commit comments

Comments
 (0)