Skip to content

Commit a3168f0

Browse files
fix(dashboards): Send current dashboard state on Seer follow-up messages
1 parent 39b1ebf commit a3168f0

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

static/app/views/dashboards/useSeerDashboardSession.spec.tsx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,68 @@ describe('useSeerDashboardSession', () => {
121121
);
122122
});
123123

124+
it('sends current dashboard state as on_page_context with follow-up messages', async () => {
125+
const dashboard = {
126+
title: 'My Dashboard',
127+
widgets: [
128+
{
129+
title: 'Count',
130+
displayType: DisplayType.LINE,
131+
interval: '1h',
132+
queries: [
133+
{
134+
name: '',
135+
conditions: '',
136+
fields: ['count()'],
137+
columns: [],
138+
aggregates: ['count()'],
139+
orderby: '',
140+
},
141+
],
142+
},
143+
],
144+
};
145+
146+
MockApiClient.addMockResponse({
147+
url: apiUrl,
148+
body: COMPLETED_SESSION,
149+
});
150+
151+
const postMock = MockApiClient.addMockResponse({
152+
url: apiUrl,
153+
method: 'POST',
154+
body: {},
155+
});
156+
157+
const onDashboardUpdate = jest.fn();
158+
159+
const {result} = renderHookWithProviders(
160+
() =>
161+
useSeerDashboardSession({
162+
seerRunId: SEER_RUN_ID,
163+
dashboard,
164+
onDashboardUpdate,
165+
}),
166+
{organization}
167+
);
168+
169+
await act(async () => {
170+
await result.current.sendFollowUpMessage('Add an error rate widget');
171+
});
172+
173+
expect(postMock).toHaveBeenCalledWith(
174+
apiUrl,
175+
expect.objectContaining({
176+
method: 'POST',
177+
data: expect.objectContaining({
178+
query: 'Add an error rate widget',
179+
on_page_context:
180+
'The user is editing an existing dashboard. The current dashboard state is:\n\n{"title":"My Dashboard","widgets":[{"title":"Count","displayType":"line","interval":"1h","queries":[{"name":"","conditions":"","fields":["count()"],"columns":[],"aggregates":["count()"],"orderby":""}]}]}\n\nThis session must ONLY modify the dashboard artifact. Produce a COMPLETE dashboard artifact that incorporates the requested changes while preserving widgets the user did not ask to change.',
181+
}),
182+
})
183+
);
184+
});
185+
124186
it('starts a new session via the generate endpoint when dashboard is provided without seerRunId', async () => {
125187
const dashboard = {
126188
title: 'My Dashboard',

static/app/views/dashboards/useSeerDashboardSession.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ import type {DashboardDetails, Widget} from './types';
1515
const POLL_INTERVAL_MS = 500;
1616
const POST_COMPLETE_POLL_MS = 5000;
1717

18+
function buildEditOnPageContext(
19+
dashboard: Pick<DashboardDetails, 'title' | 'widgets'>
20+
): string {
21+
return `The user is editing an existing dashboard. The current dashboard state is:\n\n${JSON.stringify({title: dashboard.title, widgets: dashboard.widgets})}\n\nThis session must ONLY modify the dashboard artifact. Produce a COMPLETE dashboard artifact that incorporates the requested changes while preserving widgets the user did not ask to change.`;
22+
}
23+
1824
async function startDashboardEditSession(
1925
orgSlug: string,
2026
message: string,
@@ -159,7 +165,10 @@ export function useSeerDashboardSession({
159165
await fetchMutation({
160166
url,
161167
method: 'POST',
162-
data: {query: message},
168+
data: {
169+
query: message,
170+
...(dashboard ? {on_page_context: buildEditOnPageContext(dashboard)} : {}),
171+
},
163172
});
164173
queryClient.invalidateQueries({queryKey});
165174
}

0 commit comments

Comments
 (0)