diff --git a/static/app/components/commandPalette/ui/commandPalette.spec.tsx b/static/app/components/commandPalette/ui/commandPalette.spec.tsx
index 0c964ed8cf57..0fd95dd263db 100644
--- a/static/app/components/commandPalette/ui/commandPalette.spec.tsx
+++ b/static/app/components/commandPalette/ui/commandPalette.spec.tsx
@@ -382,6 +382,54 @@ describe('CommandPalette', () => {
).toBeInTheDocument();
});
+ it('tells Seer a Tab handoff came from the command palette', async () => {
+ const openSeerExplorer = jest.fn();
+ render(
+
+
+
+
+ );
+
+ await userEvent.type(
+ screen.getByRole('searchbox', {name: 'Search commands'}),
+ 'dsn'
+ );
+ await userEvent.keyboard('{Tab}');
+
+ expect(openSeerExplorer).toHaveBeenCalledWith({
+ initialQuery: 'dsn',
+ initialQueryReferrer: 'command_palette.tab',
+ });
+ });
+
+ it('tells Seer a no-results handoff came from the command palette', async () => {
+ const openSeerExplorer = jest.fn();
+ render(
+
+
+
+
+ );
+
+ await userEvent.type(
+ screen.getByRole('searchbox', {name: 'Search commands'}),
+ 'xyzzy'
+ );
+ await userEvent.click(await screen.findByRole('option', {name: 'Ask Seer: xyzzy'}));
+
+ expect(openSeerExplorer).toHaveBeenCalledWith({
+ initialQuery: 'xyzzy',
+ initialQueryReferrer: 'command_palette.no_results',
+ });
+ });
+
it('clearing the query restores all top-level items', async () => {
render(
diff --git a/static/app/components/commandPalette/ui/commandPalette.tsx b/static/app/components/commandPalette/ui/commandPalette.tsx
index 0cd9136ca839..bbb138910c9d 100644
--- a/static/app/components/commandPalette/ui/commandPalette.tsx
+++ b/static/app/components/commandPalette/ui/commandPalette.tsx
@@ -40,6 +40,7 @@ import {fzf} from 'sentry/utils/search/fzf';
import {normalizeUrl} from 'sentry/utils/url/normalizeUrl';
import {useFeedbackForm} from 'sentry/utils/useFeedbackForm';
import {useNavigate} from 'sentry/utils/useNavigate';
+import type {SeerExplorerChatReferrer} from 'sentry/views/seerExplorer/types';
import type {CMDKActionData} from './cmdk';
import {CMDKCollection} from './cmdk';
@@ -91,7 +92,10 @@ interface CommandPaletteScore {
}
interface CommandPaletteProps extends ModalRenderProps {
- openSeerExplorer?: (options?: {initialQuery?: string}) => void;
+ openSeerExplorer?: (options?: {
+ initialQuery?: string;
+ initialQueryReferrer?: SeerExplorerChatReferrer;
+ }) => void;
}
export function CommandPalette({
@@ -201,7 +205,10 @@ export function CommandPalette({
listItemType: 'action',
display: {label: t('Ask Seer: %s', state.query), icon: },
onAction: () =>
- openSeerExplorer?.({initialQuery: state.query.trim() || undefined}),
+ openSeerExplorer?.({
+ initialQuery: state.query.trim() || undefined,
+ initialQueryReferrer: 'command_palette.no_results',
+ }),
},
...(openForm
? [
@@ -422,6 +429,7 @@ export function CommandPalette({
closeModal?.();
openSeerExplorer({
initialQuery: state.query.trim() || undefined,
+ initialQueryReferrer: 'command_palette.tab',
});
return;
}
diff --git a/static/app/components/events/autofix/v3/nextStep.spec.tsx b/static/app/components/events/autofix/v3/nextStep.spec.tsx
index 30ac0b3fd645..224b835ee03f 100644
--- a/static/app/components/events/autofix/v3/nextStep.spec.tsx
+++ b/static/app/components/events/autofix/v3/nextStep.spec.tsx
@@ -141,6 +141,7 @@ describe('SeerDrawerNextStep', () => {
setSidebarPosition: jest.fn(),
sidebarAppendInitialQuery: false,
sidebarInitialQuery: undefined,
+ sidebarInitialQueryReferrer: undefined,
sidebarKey: 0,
sidebarPosition: 'auto',
toggleSeerExplorer: jest.fn(),
diff --git a/static/app/utils/analytics/seerAnalyticsEvents.tsx b/static/app/utils/analytics/seerAnalyticsEvents.tsx
index b1b977f63daa..9c9a42b8cf6e 100644
--- a/static/app/utils/analytics/seerAnalyticsEvents.tsx
+++ b/static/app/utils/analytics/seerAnalyticsEvents.tsx
@@ -3,7 +3,10 @@ import type {
PullRequestReviewStatus,
} from 'sentry/types/integrations';
import type {Organization} from 'sentry/types/organization';
-import type {SeerExplorerRunId} from 'sentry/views/seerExplorer/types';
+import type {
+ SeerExplorerChatReferrer,
+ SeerExplorerRunId,
+} from 'sentry/views/seerExplorer/types';
type InvestigationActionRequestEvent = {
action_kind: string;
@@ -227,6 +230,8 @@ export type SeerAnalyticsEventsParameters = {
'seer.explorer.session_created': {
referrer: string;
surface: 'global_panel';
+ /** The UI entry point that started the chat, when it was recorded. */
+ entry_point?: SeerExplorerChatReferrer;
};
'seer.explorer.session_link_copied': Record;
'seer.explorer.sidebar.position_changed': {
diff --git a/static/app/views/navigation/topBar.spec.tsx b/static/app/views/navigation/topBar.spec.tsx
index e5ee49b7fa24..9aaa8c24ef9e 100644
--- a/static/app/views/navigation/topBar.spec.tsx
+++ b/static/app/views/navigation/topBar.spec.tsx
@@ -221,6 +221,7 @@ describe('TopBar', () => {
setSidebarPosition: jest.fn(),
sidebarAppendInitialQuery: false,
sidebarInitialQuery: undefined,
+ sidebarInitialQueryReferrer: undefined,
sidebarKey: 0,
sidebarPosition: 'auto',
toggleSeerExplorer: jest.fn(),
diff --git a/static/app/views/seerExplorer/components/drawer/explorerDrawerContent.tsx b/static/app/views/seerExplorer/components/drawer/explorerDrawerContent.tsx
index d62826ee13cb..a9a85cbc0304 100644
--- a/static/app/views/seerExplorer/components/drawer/explorerDrawerContent.tsx
+++ b/static/app/views/seerExplorer/components/drawer/explorerDrawerContent.tsx
@@ -1,6 +1,7 @@
import {DrawerHeader, useDrawerContentContext} from '@sentry/scraps/drawer';
import {SeerExplorerContent} from 'sentry/views/seerExplorer/components/seerExplorerContent';
+import type {SeerExplorerChatReferrer} from 'sentry/views/seerExplorer/types';
/**
* Drawer surface for Seer Explorer: renders the shared content with the drawer's
@@ -15,11 +16,13 @@ import {SeerExplorerContent} from 'sentry/views/seerExplorer/components/seerExpl
export function ExplorerDrawerContent({
getPageReferrer,
initialQuery,
+ initialQueryReferrer,
appendInitialQuery,
}: {
getPageReferrer: () => string;
appendInitialQuery?: boolean;
initialQuery?: string;
+ initialQueryReferrer?: SeerExplorerChatReferrer;
}) {
const {onClose = () => {}} = useDrawerContentContext();
@@ -27,6 +30,7 @@ export function ExplorerDrawerContent({
(
diff --git a/static/app/views/seerExplorer/components/drawer/useSeerExplorerDrawer.tsx b/static/app/views/seerExplorer/components/drawer/useSeerExplorerDrawer.tsx
index a1ca751603df..b4fc56eab7cb 100644
--- a/static/app/views/seerExplorer/components/drawer/useSeerExplorerDrawer.tsx
+++ b/static/app/views/seerExplorer/components/drawer/useSeerExplorerDrawer.tsx
@@ -8,7 +8,10 @@ import {isSeerExplorerEnabled} from 'sentry/utils/seer/isSeerExplorerEnabled';
import {useOrganization} from 'sentry/utils/useOrganization';
import type {ChatPrompt} from 'sentry/views/seerExplorer/chatPrompt';
import {useSeerExplorerChatDispatch} from 'sentry/views/seerExplorer/seerExplorerChatStateContext';
-import type {SeerExplorerRunId} from 'sentry/views/seerExplorer/types';
+import type {
+ SeerExplorerChatReferrer,
+ SeerExplorerRunId,
+} from 'sentry/views/seerExplorer/types';
import {usePageReferrer} from 'sentry/views/seerExplorer/utils';
import {ExplorerDrawerContent} from './explorerDrawerContent';
@@ -32,6 +35,8 @@ export type OpenSeerExplorerDrawerOptions = {
* an empty session, or the open one with `appendToOpenRun`.
*/
initialQuery?: string;
+ /** Where `initialQuery` came from, recorded on the run it starts. */
+ initialQueryReferrer?: SeerExplorerChatReferrer;
/**
* Optional run ID to open. If provided, opens an existing session.
*/
@@ -75,7 +80,12 @@ export const useSeerExplorerDrawer = (options?: {onClose?: () => void}) => {
const openSeerExplorerDrawer = useCallback(
(drawerOptions?: OpenSeerExplorerDrawerOptions) => {
- const {runId: openRunId, initialQuery, appendToOpenRun} = drawerOptions ?? {};
+ const {
+ runId: openRunId,
+ initialQuery,
+ initialQueryReferrer,
+ appendToOpenRun,
+ } = drawerOptions ?? {};
if (initialQuery) {
// A forwarded query starts a fresh session unless the caller asked to
@@ -94,6 +104,7 @@ export const useSeerExplorerDrawer = (options?: {onClose?: () => void}) => {
),
diff --git a/static/app/views/seerExplorer/components/seerExplorerContent.spec.tsx b/static/app/views/seerExplorer/components/seerExplorerContent.spec.tsx
index fee2aff7b96b..43e0188009dd 100644
--- a/static/app/views/seerExplorer/components/seerExplorerContent.spec.tsx
+++ b/static/app/views/seerExplorer/components/seerExplorerContent.spec.tsx
@@ -488,7 +488,13 @@ describe('SeerExplorerContent', () => {
// The explicit null run id is what forces a fresh run rather than a post
// into the run that just failed.
await waitFor(() => {
- expect(sendMessage).toHaveBeenCalledWith('why is this slow?', 0, null);
+ expect(sendMessage).toHaveBeenCalledWith(
+ 'why is this slow?',
+ 0,
+ null,
+ undefined,
+ undefined
+ );
});
});
});
@@ -2225,7 +2231,13 @@ describe('SeerExplorerContent', () => {
renderContent({initialQuery: 'why is this slow?'});
await waitFor(() => {
- expect(sendMessage).toHaveBeenCalledWith('why is this slow?', 0);
+ expect(sendMessage).toHaveBeenCalledWith(
+ 'why is this slow?',
+ 0,
+ undefined,
+ undefined,
+ undefined
+ );
});
expect(creditCheck).toHaveBeenCalledTimes(1);
expect(
@@ -2260,7 +2272,13 @@ describe('SeerExplorerContent', () => {
answerCreditCheck();
await waitFor(() => {
- expect(sendMessage).toHaveBeenCalledWith('why is this slow?', 0);
+ expect(sendMessage).toHaveBeenCalledWith(
+ 'why is this slow?',
+ 0,
+ undefined,
+ undefined,
+ undefined
+ );
});
expect(sendMessage).toHaveBeenCalledTimes(1);
expect(textarea).toHaveTextContent('my own question');
@@ -2316,7 +2334,13 @@ describe('SeerExplorerContent', () => {
answerCreditCheck();
await waitFor(() => {
- expect(sendMessage).toHaveBeenCalledWith('why is this slow?', 0);
+ expect(sendMessage).toHaveBeenCalledWith(
+ 'why is this slow?',
+ 0,
+ undefined,
+ undefined,
+ undefined
+ );
});
});
diff --git a/static/app/views/seerExplorer/components/seerExplorerContent.tsx b/static/app/views/seerExplorer/components/seerExplorerContent.tsx
index 729d2f576b83..9ef25e125f8b 100644
--- a/static/app/views/seerExplorer/components/seerExplorerContent.tsx
+++ b/static/app/views/seerExplorer/components/seerExplorerContent.tsx
@@ -66,6 +66,7 @@ import type {
Block,
ChatSuggestion,
PendingUserInput,
+ SeerExplorerChatReferrer,
SeerExplorerRunId,
SeerExplorerSidebarPosition,
} from 'sentry/views/seerExplorer/types';
@@ -141,6 +142,7 @@ function SidebarHeaderShell({
export function SeerExplorerContent({
getPageReferrer,
initialQuery,
+ initialQueryReferrer,
appendInitialQuery,
onClose,
renderHeader,
@@ -153,6 +155,8 @@ export function SeerExplorerContent({
/** Submit `initialQuery` into the open run rather than only an empty one. */
appendInitialQuery?: boolean;
initialQuery?: string;
+ /** Where `initialQuery` came from, recorded on the run it starts. */
+ initialQueryReferrer?: SeerExplorerChatReferrer;
onSidebarPositionChange?: (position: SeerExplorerSidebarPosition) => void;
/** Surface chrome for the header. Defaults to the sidebar shell. */
renderHeader?: RenderHeader;
@@ -502,12 +506,13 @@ export function SeerExplorerContent({
if (showLoadError) {
// The open run failed to load, so appending to it would post into a dead run.
// A forwarded query still deserves an answer: start it in a fresh one.
- sendMessage(query, 0, null);
+ sendMessage(query, 0, null, undefined, initialQueryReferrer);
return;
}
- sendMessage(query, blocks.length);
+ sendMessage(query, blocks.length, undefined, undefined, initialQueryReferrer);
}, [
initialQuery,
+ initialQueryReferrer,
appendInitialQuery,
isEmptyState,
isCheckingCredits,
diff --git a/static/app/views/seerExplorer/components/sidebar/seerExplorerPanel.tsx b/static/app/views/seerExplorer/components/sidebar/seerExplorerPanel.tsx
index e1561e4dea8d..e4de96550cde 100644
--- a/static/app/views/seerExplorer/components/sidebar/seerExplorerPanel.tsx
+++ b/static/app/views/seerExplorer/components/sidebar/seerExplorerPanel.tsx
@@ -15,6 +15,7 @@ export function SeerExplorerPanel() {
sidebarPosition,
setSidebarPosition,
sidebarInitialQuery,
+ sidebarInitialQueryReferrer,
sidebarAppendInitialQuery,
sidebarKey,
} = useSeerExplorerContext();
@@ -29,6 +30,7 @@ export function SeerExplorerPanel() {
key={sidebarKey}
getPageReferrer={getPageReferrer}
initialQuery={sidebarInitialQuery}
+ initialQueryReferrer={sidebarInitialQueryReferrer}
appendInitialQuery={sidebarAppendInitialQuery}
onClose={closeSeerExplorer}
sidebarPosition={sidebarPosition}
diff --git a/static/app/views/seerExplorer/components/sidebar/seerExplorerSidebarLayout.spec.tsx b/static/app/views/seerExplorer/components/sidebar/seerExplorerSidebarLayout.spec.tsx
index f5fe07d35de0..451ab88e178c 100644
--- a/static/app/views/seerExplorer/components/sidebar/seerExplorerSidebarLayout.spec.tsx
+++ b/static/app/views/seerExplorer/components/sidebar/seerExplorerSidebarLayout.spec.tsx
@@ -401,7 +401,10 @@ describe('SeerExplorerSidebarLayout', () => {
it('auto-submits an initialQuery when opened (command palette)', async () => {
mockWideScreen(true);
- renderSidebar(orgWithSidebar, {initialQuery: 'find the bug'});
+ renderSidebar(orgWithSidebar, {
+ initialQuery: 'find the bug',
+ initialQueryReferrer: 'command_palette.tab',
+ });
await userEvent.click(screen.getByText('open-seer'));
@@ -409,7 +412,10 @@ describe('SeerExplorerSidebarLayout', () => {
await waitFor(() =>
expect(defaultHookReturn.sendMessage).toHaveBeenCalledWith(
'find the bug',
- expect.any(Number)
+ expect.any(Number),
+ undefined,
+ undefined,
+ 'command_palette.tab'
)
);
});
diff --git a/static/app/views/seerExplorer/hooks/useSeerExplorer.spec.tsx b/static/app/views/seerExplorer/hooks/useSeerExplorer.spec.tsx
index 6c48c678a30d..4349e947ca51 100644
--- a/static/app/views/seerExplorer/hooks/useSeerExplorer.spec.tsx
+++ b/static/app/views/seerExplorer/hooks/useSeerExplorer.spec.tsx
@@ -130,6 +130,57 @@ describe('useSeerExplorer', () => {
});
});
+ it('records the referrer only on the message that starts a run', async () => {
+ MockApiClient.addMockResponse({
+ url: `/organizations/${organization.slug}/seer/explorer-chat/`,
+ method: 'GET',
+ body: {session: null},
+ });
+ const newRunMock = MockApiClient.addMockResponse({
+ url: `/organizations/${organization.slug}/seer/explorer-chat/`,
+ method: 'POST',
+ body: {run_id: 123},
+ });
+ MockApiClient.addMockResponse({
+ url: `/organizations/${organization.slug}/seer/explorer-chat/123/`,
+ method: 'GET',
+ body: {session: {blocks: [], run_id: 123, status: 'completed'}},
+ });
+ const continueMock = MockApiClient.addMockResponse({
+ url: `/organizations/${organization.slug}/seer/explorer-chat/123/`,
+ method: 'POST',
+ body: {run_id: 123},
+ });
+
+ const {result} = renderHookWithProviders(() => useSeerExplorer(), {
+ organization,
+ additionalWrapper: SeerExplorerChatStateProvider,
+ });
+
+ act(() => {
+ result.current.sendMessage('dsn', 0, null, undefined, 'command_palette.tab');
+ });
+ await waitFor(() => expect(result.current.runId).toBe(123));
+ expect(newRunMock).toHaveBeenCalledWith(
+ `/organizations/${organization.slug}/seer/explorer-chat/`,
+ expect.objectContaining({
+ data: expect.objectContaining({referrer: 'command_palette.tab'}),
+ })
+ );
+
+ act(() => {
+ result.current.sendMessage(
+ 'more',
+ undefined,
+ undefined,
+ undefined,
+ 'command_palette.tab'
+ );
+ });
+ await waitFor(() => expect(continueMock).toHaveBeenCalled());
+ expect(continueMock.mock.calls[0][1].data.referrer).toBeUndefined();
+ });
+
it('sends structured JSON on dashboard page with feature flag', async () => {
jest.spyOn(seerExplorerUtils, 'usePageReferrer').mockReturnValue({
getPageReferrer: () => '/dashboard/:dashboardId/',
diff --git a/static/app/views/seerExplorer/hooks/useSeerExplorer.tsx b/static/app/views/seerExplorer/hooks/useSeerExplorer.tsx
index 0be7985d2024..ba1a32323461 100644
--- a/static/app/views/seerExplorer/hooks/useSeerExplorer.tsx
+++ b/static/app/views/seerExplorer/hooks/useSeerExplorer.tsx
@@ -28,6 +28,7 @@ import type {
Block,
RepoPRState,
RespondToUserInputOptions,
+ SeerExplorerChatReferrer,
SeerExplorerResponse,
SeerExplorerRunId,
} from 'sentry/views/seerExplorer/types';
@@ -266,6 +267,7 @@ export const useSeerExplorer = () => {
/** The pending prompt this send took from chat state, put back if it fails. */
pendingChatPrompt: ChatPrompt | null;
query: string;
+ referrer: SeerExplorerChatReferrer | undefined;
requestId: string;
runId: SeerExplorerRunId | null;
screenshot: string | undefined;
@@ -294,6 +296,7 @@ export const useSeerExplorer = () => {
override_code_mode_enable: params.overrideCodeModeEnable,
chat_prompt: params.chatPrompt?.text,
chat_prompt_context: params.chatPrompt?.context,
+ referrer: params.referrer,
},
});
},
@@ -489,7 +492,8 @@ export const useSeerExplorer = () => {
query: string,
explicitInsertIndex?: number,
explicitRunId?: SeerExplorerRunId | null,
- explicitChatPrompt?: ChatPrompt | null
+ explicitChatPrompt?: ChatPrompt | null,
+ referrer?: SeerExplorerChatReferrer
) => {
if (!orgSlug) {
return;
@@ -528,6 +532,7 @@ export const useSeerExplorer = () => {
if (effectiveRunId === null) {
trackAnalytics('seer.explorer.session_created', {
referrer: pageName,
+ entry_point: referrer,
surface: 'global_panel',
organization,
});
@@ -559,6 +564,8 @@ export const useSeerExplorer = () => {
// Send POST request
sendMessageMutate({
query,
+ // Only a new run records where it started.
+ referrer: effectiveRunId === null ? referrer : undefined,
chatPrompt,
pendingChatPrompt: usesPendingChatPrompt ? pendingChatPrompt : null,
requestId,
diff --git a/static/app/views/seerExplorer/seerExplorerContextProvider.tsx b/static/app/views/seerExplorer/seerExplorerContextProvider.tsx
index a01897690d5d..deadae192ad2 100644
--- a/static/app/views/seerExplorer/seerExplorerContextProvider.tsx
+++ b/static/app/views/seerExplorer/seerExplorerContextProvider.tsx
@@ -31,7 +31,11 @@ import {
useSeerExplorerChatDispatch,
useSeerExplorerChatState,
} from './seerExplorerChatStateContext';
-import type {SeerExplorerRunId, SeerExplorerSidebarPosition} from './types';
+import type {
+ SeerExplorerChatReferrer,
+ SeerExplorerRunId,
+ SeerExplorerSidebarPosition,
+} from './types';
import {
SeerExplorerContext,
type SeerExplorerContextValue,
@@ -78,6 +82,9 @@ export function SeerExplorerContextProvider({children}: {children: ReactNode}) {
const [sidebarInitialQuery, setSidebarInitialQuery] = useState(
undefined
);
+ const [sidebarInitialQueryReferrer, setSidebarInitialQueryReferrer] = useState<
+ SeerExplorerChatReferrer | undefined
+ >(undefined);
const [sidebarKey, setSidebarKey] = useState(0);
const [sidebarPosition, setSidebarPositionState] =
useLocalStorageState(
@@ -198,7 +205,12 @@ export function SeerExplorerContextProvider({children}: {children: ReactNode}) {
// Mirror `useSeerExplorerDrawer`'s option handling so deep links
// (runId), the command palette (initialQuery), and session switching
// behave the same in sidebar mode as in the drawer.
- const {runId: openRunId, initialQuery, appendToOpenRun} = drawerOptions ?? {};
+ const {
+ runId: openRunId,
+ initialQuery,
+ initialQueryReferrer,
+ appendToOpenRun,
+ } = drawerOptions ?? {};
if (initialQuery) {
// A forwarded query starts a fresh session unless the caller asked to
// add to the open run. Bump the nonce either way so re-forwarding the
@@ -213,6 +225,7 @@ export function SeerExplorerContextProvider({children}: {children: ReactNode}) {
dispatch({type: 'set run id', payload: openRunId});
}
setSidebarInitialQuery(initialQuery);
+ setSidebarInitialQueryReferrer(initialQueryReferrer);
setSidebarAppendInitialQuery(!!appendToOpenRun);
openSidebar();
return;
@@ -407,6 +420,7 @@ export function SeerExplorerContextProvider({children}: {children: ReactNode}) {
sidebarContainerRef,
sidebarAppendInitialQuery,
sidebarInitialQuery,
+ sidebarInitialQueryReferrer,
sidebarKey,
sidebarPosition,
setSidebarPosition,
@@ -421,6 +435,7 @@ export function SeerExplorerContextProvider({children}: {children: ReactNode}) {
sessionState,
sidebarAppendInitialQuery,
sidebarInitialQuery,
+ sidebarInitialQueryReferrer,
sidebarKey,
sidebarPosition,
setSidebarPosition,
@@ -479,6 +494,7 @@ export function SeerExplorerContextProvider({children}: {children: ReactNode}) {
key={sidebarKey}
getPageReferrer={getPageReferrer}
initialQuery={sidebarInitialQuery}
+ initialQueryReferrer={sidebarInitialQueryReferrer}
appendInitialQuery={sidebarAppendInitialQuery}
onClose={closeSeerExplorer}
sidebarPosition={sidebarPosition}
diff --git a/static/app/views/seerExplorer/types.tsx b/static/app/views/seerExplorer/types.tsx
index 9732ab0db687..c4e4711fb588 100644
--- a/static/app/views/seerExplorer/types.tsx
+++ b/static/app/views/seerExplorer/types.tsx
@@ -9,6 +9,11 @@ import type {EmbedOutput} from 'sentry/components/seer/markdown/embeds/utils';
*/
export type SeerExplorerSidebarPosition = 'auto' | 'right' | 'bottom';
+/** The UI entry point that started a chat, recorded on the new run. */
+export type SeerExplorerChatReferrer =
+ | 'command_palette.tab'
+ | 'command_palette.no_results';
+
/**
* z.enum but forward-compatible: accepts any string at runtime while preserving
* autocomplete for the known values via the `(string & {})` trick.
diff --git a/static/app/views/seerExplorer/useSeerExplorerContext.tsx b/static/app/views/seerExplorer/useSeerExplorerContext.tsx
index a9c49a20a292..345479639286 100644
--- a/static/app/views/seerExplorer/useSeerExplorerContext.tsx
+++ b/static/app/views/seerExplorer/useSeerExplorerContext.tsx
@@ -1,7 +1,7 @@
import {createContext, useContext, type RefObject} from 'react';
import type {OpenSeerExplorerDrawerOptions} from './components/drawer/useSeerExplorerDrawer';
-import type {SeerExplorerSidebarPosition} from './types';
+import type {SeerExplorerChatReferrer, SeerExplorerSidebarPosition} from './types';
type SeerExplorerSessionState = 'inactive' | 'thinking' | 'done-thinking';
@@ -32,6 +32,8 @@ export type SeerExplorerContextValue = {
*/
sidebarContainerRef: RefObject;
sidebarInitialQuery: string | undefined;
+ /** Where `sidebarInitialQuery` came from. Sidebar mode only. */
+ sidebarInitialQueryReferrer: SeerExplorerChatReferrer | undefined;
/**
* Increments on each forwarded query so the (always-mounted) sidebar content
* resubmits a re-forwarded query. Only meaningful in sidebar mode.
@@ -52,6 +54,7 @@ export const SeerExplorerContext = createContext({
setSidebarPosition: () => {},
sidebarAppendInitialQuery: false,
sidebarInitialQuery: undefined,
+ sidebarInitialQueryReferrer: undefined,
sidebarKey: 0,
sidebarPosition: 'auto',
toggleSeerExplorer: () => {},