diff --git a/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpOverview.ts b/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpOverview.ts index 4402cbdc225d2d..6a49ded4b840ed 100644 --- a/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpOverview.ts +++ b/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpOverview.ts @@ -6,7 +6,7 @@ import {WIDGET_COLUMN_LABELS} from 'sentry/views/dashboards/utils/prebuiltConfig import {spaceWidgetsEquallyOnRow} from 'sentry/views/dashboards/utils/prebuiltConfigs/utils/spaceWidgetsEquallyOnRow'; import {SpanFields, SpanFunction} from 'sentry/views/insights/types'; -const MCP_SERVER_FILTER = `${SpanFields.SPAN_OP}:mcp.server`; +const MCP_SERVER_FILTER = `${SpanFields.NAME}:mcp.server`; const MCP_TOOL_FILTER = `${MCP_SERVER_FILTER} has:${SpanFields.MCP_TOOL_NAME}`; const MCP_RESOURCE_FILTER = `${MCP_SERVER_FILTER} has:${SpanFields.MCP_RESOURCE_URI}`; const MCP_PROMPT_FILTER = `${MCP_SERVER_FILTER} has:${SpanFields.MCP_PROMPT_NAME}`; diff --git a/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpPrompts.ts b/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpPrompts.ts index 914f705a9440b1..e1deeae22e1453 100644 --- a/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpPrompts.ts +++ b/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpPrompts.ts @@ -7,7 +7,7 @@ import {WIDGET_COLUMN_LABELS} from 'sentry/views/dashboards/utils/prebuiltConfig import {spaceWidgetsEquallyOnRow} from 'sentry/views/dashboards/utils/prebuiltConfigs/utils/spaceWidgetsEquallyOnRow'; import {SpanFields, SpanFunction} from 'sentry/views/insights/types'; -const MCP_PROMPT_FILTER = `${SpanFields.SPAN_OP}:mcp.server has:${SpanFields.MCP_PROMPT_NAME}`; +const MCP_PROMPT_FILTER = `${SpanFields.NAME}:mcp.server has:${SpanFields.MCP_PROMPT_NAME}`; const FIRST_ROW_WIDGETS = spaceWidgetsEquallyOnRow( [ diff --git a/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpResources.ts b/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpResources.ts index 363a577582af87..3b744454513f4f 100644 --- a/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpResources.ts +++ b/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpResources.ts @@ -7,7 +7,7 @@ import {WIDGET_COLUMN_LABELS} from 'sentry/views/dashboards/utils/prebuiltConfig import {spaceWidgetsEquallyOnRow} from 'sentry/views/dashboards/utils/prebuiltConfigs/utils/spaceWidgetsEquallyOnRow'; import {SpanFields, SpanFunction} from 'sentry/views/insights/types'; -const MCP_RESOURCE_FILTER = `${SpanFields.SPAN_OP}:mcp.server has:${SpanFields.MCP_RESOURCE_URI}`; +const MCP_RESOURCE_FILTER = `${SpanFields.NAME}:mcp.server has:${SpanFields.MCP_RESOURCE_URI}`; const FIRST_ROW_WIDGETS = spaceWidgetsEquallyOnRow( [ diff --git a/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpTools.ts b/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpTools.ts index cf49305811d13d..567d9f1a172049 100644 --- a/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpTools.ts +++ b/static/app/views/dashboards/utils/prebuiltConfigs/ai/mcpTools.ts @@ -7,7 +7,7 @@ import {WIDGET_COLUMN_LABELS} from 'sentry/views/dashboards/utils/prebuiltConfig import {spaceWidgetsEquallyOnRow} from 'sentry/views/dashboards/utils/prebuiltConfigs/utils/spaceWidgetsEquallyOnRow'; import {SpanFields, SpanFunction} from 'sentry/views/insights/types'; -const MCP_TOOL_FILTER = `${SpanFields.SPAN_OP}:mcp.server has:${SpanFields.MCP_TOOL_NAME}`; +const MCP_TOOL_FILTER = `${SpanFields.NAME}:mcp.server has:${SpanFields.MCP_TOOL_NAME}`; const FIRST_ROW_WIDGETS = spaceWidgetsEquallyOnRow( [ diff --git a/static/app/views/insights/pages/agents/components/toolsTable.tsx b/static/app/views/insights/pages/agents/components/toolsTable.tsx index b45c9d16f5ee7a..d71e33c72ad917 100644 --- a/static/app/views/insights/pages/agents/components/toolsTable.tsx +++ b/static/app/views/insights/pages/agents/components/toolsTable.tsx @@ -189,7 +189,7 @@ const BodyCell = memo(function BodyCell({ }, ], query: `gen_ai.tool.name:"${dataRow.tool}"`, - field: ['span.description', 'gen_ai.tool.output', 'span.duration', 'timestamp'], + field: ['span.name', 'gen_ai.tool.output', 'span.duration', 'timestamp'], }); switch (column.key) { diff --git a/static/app/views/insights/pages/agents/hooks/useAgentSpanSearchProps.tsx b/static/app/views/insights/pages/agents/hooks/useAgentSpanSearchProps.tsx index 19781c3a5f4f86..3947ad16793ef1 100644 --- a/static/app/views/insights/pages/agents/hooks/useAgentSpanSearchProps.tsx +++ b/static/app/views/insights/pages/agents/hooks/useAgentSpanSearchProps.tsx @@ -34,9 +34,7 @@ export function useAgentSpanSearchProps() { }, searchSource: 'agent-monitoring', - replaceRawSearchKeys: hasRawSearchReplacement - ? ['span.description', 'span.name'] - : undefined, + replaceRawSearchKeys: hasRawSearchReplacement ? ['span.name'] : undefined, matchKeySuggestions: [ {key: 'trace', valuePattern: /^[0-9a-fA-F]{32}$/}, {key: 'id', valuePattern: /^[0-9a-fA-F]{16}$/}, diff --git a/static/app/views/insights/pages/agents/utils/aiTraceNodes.tsx b/static/app/views/insights/pages/agents/utils/aiTraceNodes.tsx index 952bb04671e8da..7053a04b1b98b9 100644 --- a/static/app/views/insights/pages/agents/utils/aiTraceNodes.tsx +++ b/static/app/views/insights/pages/agents/utils/aiTraceNodes.tsx @@ -2,7 +2,7 @@ import type {EventTransaction} from 'sentry/types/event'; import {prettifyAttributeName} from 'sentry/views/explore/components/traceItemAttributes/utils'; import type {TraceItemResponseAttribute} from 'sentry/views/explore/hooks/useTraceItemDetails'; import { - getGenAiOperationTypeFromSpanOp, + getGenAiOperationTypeFromSpanName, getIsAiAgentSpan, getIsAiGenerationSpan, getIsExecuteToolSpan, @@ -57,16 +57,18 @@ export function ensureAttributeObject( /** * Returns the `gen_ai.operation.type` for a given trace node. - * If the attribute is not present it will deduce it from the `span.op` + * If the attribute is not present it will deduce it from the `span.name` * - * **Note:** To keep the complexity manageable, this logic does not work for the edge case of transactions without `span.op` on the old data model. + * **Note:** To keep the complexity manageable, this logic does not work for the edge case of transactions without `span.name` on the old data model. */ export function getGenAiOpType(node: BaseNode): string | undefined { const attributeObject = node.attributes; return ( (attributeObject?.[SpanFields.GEN_AI_OPERATION_TYPE] as string | undefined) ?? - getGenAiOperationTypeFromSpanOp(node.op) + getGenAiOperationTypeFromSpanName( + node.value && 'name' in node.value ? (node.value.name as string) : undefined + ) ); } diff --git a/static/app/views/insights/pages/agents/utils/query.spec.ts b/static/app/views/insights/pages/agents/utils/query.spec.ts new file mode 100644 index 00000000000000..2cccbf64d34fe6 --- /dev/null +++ b/static/app/views/insights/pages/agents/utils/query.spec.ts @@ -0,0 +1,53 @@ +import {GenAiOperationType, getGenAiOperationTypeFromSpanName} from './query'; + +describe('getGenAiOperationTypeFromSpanName', () => { + it('returns undefined for undefined input', () => { + expect(getGenAiOperationTypeFromSpanName(undefined)).toBeUndefined(); + }); + + it('returns undefined for empty string', () => { + expect(getGenAiOperationTypeFromSpanName('')).toBeUndefined(); + }); + + it('returns undefined for non-gen_ai span names', () => { + expect(getGenAiOperationTypeFromSpanName('http.client')).toBeUndefined(); + expect(getGenAiOperationTypeFromSpanName('db.query')).toBeUndefined(); + expect(getGenAiOperationTypeFromSpanName('mcp.server')).toBeUndefined(); + }); + + it('returns AGENT for gen_ai.invoke_agent', () => { + expect(getGenAiOperationTypeFromSpanName('gen_ai.invoke_agent')).toBe( + GenAiOperationType.AGENT + ); + }); + + it('returns AGENT for gen_ai.create_agent', () => { + expect(getGenAiOperationTypeFromSpanName('gen_ai.create_agent')).toBe( + GenAiOperationType.AGENT + ); + }); + + it('returns TOOL for gen_ai.execute_tool', () => { + expect(getGenAiOperationTypeFromSpanName('gen_ai.execute_tool')).toBe( + GenAiOperationType.TOOL + ); + }); + + it('returns HANDOFF for gen_ai.handoff', () => { + expect(getGenAiOperationTypeFromSpanName('gen_ai.handoff')).toBe( + GenAiOperationType.HANDOFF + ); + }); + + it('returns AI_CLIENT for other gen_ai span names', () => { + expect(getGenAiOperationTypeFromSpanName('gen_ai.chat')).toBe( + GenAiOperationType.AI_CLIENT + ); + expect(getGenAiOperationTypeFromSpanName('gen_ai.completion')).toBe( + GenAiOperationType.AI_CLIENT + ); + expect(getGenAiOperationTypeFromSpanName('gen_ai.embeddings')).toBe( + GenAiOperationType.AI_CLIENT + ); + }); +}); diff --git a/static/app/views/insights/pages/agents/utils/query.tsx b/static/app/views/insights/pages/agents/utils/query.tsx index 7e9022ccfdfdc6..493721cde993f5 100644 --- a/static/app/views/insights/pages/agents/utils/query.tsx +++ b/static/app/views/insights/pages/agents/utils/query.tsx @@ -75,20 +75,20 @@ export enum GenAiOperationType { } // Should be used only when we don't have the gen_ai.operation.type attribute available -export const getGenAiOperationTypeFromSpanOp = ( - spanOp?: string +export const getGenAiOperationTypeFromSpanName = ( + spanName?: string ): GenAiOperationType | undefined => { - if (!spanOp?.startsWith('gen_ai.')) { + if (!spanName?.startsWith('gen_ai.')) { return undefined; } - if (['gen_ai.invoke_agent', 'gen_ai.create_agent'].includes(spanOp)) { + if (['gen_ai.invoke_agent', 'gen_ai.create_agent'].includes(spanName)) { return GenAiOperationType.AGENT; } - if (spanOp === 'gen_ai.execute_tool') { + if (spanName === 'gen_ai.execute_tool') { return GenAiOperationType.TOOL; } - if (spanOp === 'gen_ai.handoff') { + if (spanName === 'gen_ai.handoff') { return GenAiOperationType.HANDOFF; } return GenAiOperationType.AI_CLIENT; diff --git a/static/app/views/insights/pages/conversations/hooks/useConversation.spec.tsx b/static/app/views/insights/pages/conversations/hooks/useConversation.spec.tsx index 17933d91724fd2..629d04f16913ef 100644 --- a/static/app/views/insights/pages/conversations/hooks/useConversation.spec.tsx +++ b/static/app/views/insights/pages/conversations/hooks/useConversation.spec.tsx @@ -36,8 +36,7 @@ describe('useConversation', () => { 'precise.start_ts': 1000.0, project: 'test-project', 'project.id': 1, - 'span.description': 'AI generation', - 'span.op': 'gen_ai.generate', + 'span.name': 'gen_ai.generate', 'span.status': 'ok', span_id: 'span-1', trace: 'trace-1', @@ -81,8 +80,7 @@ describe('useConversation', () => { 'precise.start_ts': 1000.0, project: 'test-project', 'project.id': 1, - 'span.description': 'AI generation', - 'span.op': 'gen_ai.generate', + 'span.name': 'gen_ai.generate', 'span.status': 'ok', span_id: 'span-output', trace: 'trace-output', @@ -123,8 +121,7 @@ describe('useConversation', () => { 'precise.start_ts': 1000.0, project: 'test-project', 'project.id': 1, - 'span.description': 'AI generation', - 'span.op': 'gen_ai.generate', + 'span.name': 'gen_ai.generate', 'span.status': 'ok', span_id: 'span-2', trace: 'trace-2', @@ -161,8 +158,7 @@ describe('useConversation', () => { 'precise.start_ts': 1000.0, project: 'test-project', 'project.id': 1, - 'span.description': 'AI generation', - 'span.op': 'gen_ai.generate', + 'span.name': 'gen_ai.generate', 'span.status': 'ok', span_id: 'span-3', trace: 'trace-3', @@ -201,8 +197,7 @@ describe('useConversation', () => { 'precise.start_ts': 1000.0, project: 'test-project', 'project.id': 1, - 'span.description': 'AI generation', - 'span.op': 'gen_ai.generate', + 'span.name': 'gen_ai.generate', 'span.status': 'ok', span_id: 'span-ts', trace: 'trace-ts', @@ -247,20 +242,18 @@ describe('useConversation', () => { expect(queryArg).not.toHaveProperty('environment'); }); - it('falls back to span.name when span.description is empty', async () => { + it('uses span.name for description and name fields', async () => { MockApiClient.addMockResponse({ - url: `/organizations/${organization.slug}/ai-conversations/conv-name-fallback/`, + url: `/organizations/${organization.slug}/ai-conversations/conv-name/`, body: [ { - 'gen_ai.conversation.id': 'conv-name-fallback', + 'gen_ai.conversation.id': 'conv-name', parent_span: 'parent-1', 'precise.finish_ts': 1000.5, 'precise.start_ts': 1000.0, project: 'test-project', 'project.id': 1, - 'span.description': '', 'span.name': 'My AI Agent', - 'span.op': 'gen_ai.generate', 'span.status': 'ok', span_id: 'span-name', trace: 'trace-name', @@ -270,7 +263,7 @@ describe('useConversation', () => { }); const {result} = renderHookWithProviders( - () => useConversation({conversationId: 'conv-name-fallback'}), + () => useConversation({conversationId: 'conv-name'}), {organization} ); @@ -285,44 +278,6 @@ describe('useConversation', () => { expect(value?.name).toBe('My AI Agent'); }); - it('prefers span.description over span.name when both exist', async () => { - MockApiClient.addMockResponse({ - url: `/organizations/${organization.slug}/ai-conversations/conv-both/`, - body: [ - { - 'gen_ai.conversation.id': 'conv-both', - parent_span: 'parent-1', - 'precise.finish_ts': 1000.5, - 'precise.start_ts': 1000.0, - project: 'test-project', - 'project.id': 1, - 'span.description': 'AI generation', - 'span.name': 'My AI Agent', - 'span.op': 'gen_ai.generate', - 'span.status': 'ok', - span_id: 'span-both', - trace: 'trace-both', - 'gen_ai.operation.type': 'ai_client', - }, - ], - }); - - const {result} = renderHookWithProviders( - () => useConversation({conversationId: 'conv-both'}), - {organization} - ); - - await waitFor(() => { - expect(result.current.isLoading).toBe(false); - }); - - expect(result.current.nodes).toHaveLength(1); - const node = result.current.nodes[0]; - const value = node?.value as {description?: string; name?: string}; - expect(value?.description).toBe('AI generation'); - expect(value?.name).toBe('AI generation'); - }); - it('sorts nodes by start timestamp for AI spans list', async () => { MockApiClient.addMockResponse({ url: `/organizations/${organization.slug}/ai-conversations/conv-sort/`, @@ -334,8 +289,7 @@ describe('useConversation', () => { 'precise.start_ts': 1001.0, project: 'test-project', 'project.id': 1, - 'span.description': 'Second by start, first by end', - 'span.op': 'gen_ai.generate', + 'span.name': 'Second by start, first by end', 'span.status': 'ok', span_id: 'span-b', trace: 'trace-sort', @@ -348,8 +302,7 @@ describe('useConversation', () => { 'precise.start_ts': 1000.0, project: 'test-project', 'project.id': 1, - 'span.description': 'First by start, second by end', - 'span.op': 'gen_ai.generate', + 'span.name': 'First by start, second by end', 'span.status': 'ok', span_id: 'span-a', trace: 'trace-sort', @@ -384,8 +337,7 @@ describe('useConversation', () => { 'precise.start_ts': 1000.0, project: 'test-project', 'project.id': 1, - 'span.description': 'AI generation', - 'span.op': 'gen_ai.generate', + 'span.name': 'gen_ai.generate', 'span.status': 'ok', span_id: 'span-ai', trace: 'trace-1', @@ -398,8 +350,7 @@ describe('useConversation', () => { 'precise.start_ts': 1001.0, project: 'test-project', 'project.id': 1, - 'span.description': 'HTTP request', - 'span.op': 'http.client', + 'span.name': 'http.client', 'span.status': 'ok', span_id: 'span-http', trace: 'trace-1', diff --git a/static/app/views/insights/pages/conversations/hooks/useConversation.tsx b/static/app/views/insights/pages/conversations/hooks/useConversation.tsx index ab43380b1dfde5..97b8bd8fe3697c 100644 --- a/static/app/views/insights/pages/conversations/hooks/useConversation.tsx +++ b/static/app/views/insights/pages/conversations/hooks/useConversation.tsx @@ -6,7 +6,7 @@ import {usePageFilters} from 'sentry/components/pageFilters/usePageFilters'; import {getApiUrl} from 'sentry/utils/api/getApiUrl'; import {useInfiniteApiQuery} from 'sentry/utils/queryClient'; import {useOrganization} from 'sentry/utils/useOrganization'; -import {getGenAiOperationTypeFromSpanOp} from 'sentry/views/insights/pages/agents/utils/query'; +import {getGenAiOperationTypeFromSpanName} from 'sentry/views/insights/pages/agents/utils/query'; import type {AITraceSpanNode} from 'sentry/views/insights/pages/agents/utils/types'; import {SpanFields} from 'sentry/views/insights/types'; import {EAPSpanNodeDetails} from 'sentry/views/performance/newTraceDetails/traceDrawer/details/span'; @@ -30,8 +30,7 @@ interface ConversationApiSpan { 'precise.start_ts': number; project: string; 'project.id': number; - 'span.description': string; - 'span.op': string; + 'span.name': string; 'span.status': string; span_id: string; trace: string; @@ -49,7 +48,8 @@ interface ConversationApiSpan { 'gen_ai.tool.input'?: string; 'gen_ai.tool.name'?: string; 'gen_ai.usage.total_tokens'?: number; - 'span.name'?: string; + 'span.description'?: string; + 'span.op'?: string; 'user.email'?: string; 'user.id'?: string; 'user.ip'?: string; @@ -60,7 +60,7 @@ function isGenAiSpan(span: ConversationApiSpan): boolean { if (span['gen_ai.operation.type']) { return true; } - return span['span.op']?.startsWith('gen_ai.') ?? false; + return span['span.name']?.startsWith('gen_ai.') ?? false; } interface UseConversationResult { @@ -80,7 +80,7 @@ function createNodeFromApiSpan( ): AITraceSpanNode { const operationType = apiSpan['gen_ai.operation.type'] || - getGenAiOperationTypeFromSpanOp(apiSpan['span.op']); + getGenAiOperationTypeFromSpanName(apiSpan['span.name']); const duration = apiSpan['precise.finish_ts'] - apiSpan['precise.start_ts']; const value: TraceTree.EAPSpan = { @@ -89,8 +89,8 @@ function createNodeFromApiSpan( event_id: apiSpan.span_id, event_type: 'span', is_transaction: false, - op: apiSpan['span.op'], - description: apiSpan['span.description'] || apiSpan['span.name'], + op: apiSpan['span.name'], + description: apiSpan['span.name'], start_timestamp: apiSpan['precise.start_ts'], end_timestamp: apiSpan['precise.finish_ts'], project_id: apiSpan['project.id'], @@ -101,7 +101,7 @@ function createNodeFromApiSpan( sdk_name: '', transaction: '', transaction_id: '', - name: apiSpan['span.description'] || apiSpan['span.name'] || '', + name: apiSpan['span.name'] || '', errors: [], occurrences: [], additional_attributes: { diff --git a/static/app/views/insights/pages/conversations/overview.tsx b/static/app/views/insights/pages/conversations/overview.tsx index 27d83b4b9519c6..64a1ec9cd0390c 100644 --- a/static/app/views/insights/pages/conversations/overview.tsx +++ b/static/app/views/insights/pages/conversations/overview.tsx @@ -105,9 +105,7 @@ function ConversationsContent({datePageFilterProps}: ConversationsOverviewPagePr unsetCursor(); }, searchSource: 'conversations', - replaceRawSearchKeys: hasRawSearchReplacement - ? ['span.description', 'span.name'] - : undefined, + replaceRawSearchKeys: hasRawSearchReplacement ? ['span.name'] : undefined, matchKeySuggestions: [ {key: 'trace', valuePattern: /^[0-9a-fA-F]{32}$/}, {key: 'id', valuePattern: /^[0-9a-fA-F]{16}$/}, diff --git a/static/app/views/insights/pages/mcp/components/mcpOverviewTable.tsx b/static/app/views/insights/pages/mcp/components/mcpOverviewTable.tsx index bed2137d6daabb..edb53084af3b5a 100644 --- a/static/app/views/insights/pages/mcp/components/mcpOverviewTable.tsx +++ b/static/app/views/insights/pages/mcp/components/mcpOverviewTable.tsx @@ -53,7 +53,7 @@ const rightAlignColumns = new Set([ export function McpOverviewTable() { const organization = useOrganization(); const {selection} = usePageFilters(); - const query = useCombinedQuery('span.op:mcp.server'); + const query = useCombinedQuery('span.name:mcp.server'); const {tableSort} = useTableSort(); const tableDataRequest = useSpanTableData({ query, @@ -188,7 +188,7 @@ function SpanDescriptionCell({ fields.push('timestamp'); const search = new MutableSearch(''); - search.addFilterValue(SpanFields.SPAN_OP, 'mcp.server'); + search.addFilterValue(SpanFields.NAME, 'mcp.server'); search.addFilterValue(SpanFields.SPAN_DESCRIPTION, spanDescription); const link = getExploreUrl({ organization, diff --git a/static/app/views/insights/pages/mcp/components/mcpPromptDurationWidget.tsx b/static/app/views/insights/pages/mcp/components/mcpPromptDurationWidget.tsx index 6d47b35ba4c19c..c35d3c1c96ef99 100644 --- a/static/app/views/insights/pages/mcp/components/mcpPromptDurationWidget.tsx +++ b/static/app/views/insights/pages/mcp/components/mcpPromptDurationWidget.tsx @@ -8,7 +8,7 @@ export function McpPromptDurationWidget() { ); diff --git a/static/app/views/insights/pages/mcp/components/mcpPromptErrorRateWidget.tsx b/static/app/views/insights/pages/mcp/components/mcpPromptErrorRateWidget.tsx index bcbbafaf18006a..337557d2e1ed40 100644 --- a/static/app/views/insights/pages/mcp/components/mcpPromptErrorRateWidget.tsx +++ b/static/app/views/insights/pages/mcp/components/mcpPromptErrorRateWidget.tsx @@ -8,7 +8,7 @@ export function McpPromptErrorRateWidget() { ); diff --git a/static/app/views/insights/pages/mcp/components/mcpPromptTrafficWidget.tsx b/static/app/views/insights/pages/mcp/components/mcpPromptTrafficWidget.tsx index 384bc2d637f43a..1ea0a992182ff9 100644 --- a/static/app/views/insights/pages/mcp/components/mcpPromptTrafficWidget.tsx +++ b/static/app/views/insights/pages/mcp/components/mcpPromptTrafficWidget.tsx @@ -8,7 +8,7 @@ export function McpPromptTrafficWidget() { ); diff --git a/static/app/views/insights/pages/mcp/components/mcpPromptsTable.tsx b/static/app/views/insights/pages/mcp/components/mcpPromptsTable.tsx index 8095888965e3e7..7cbae00cff0706 100644 --- a/static/app/views/insights/pages/mcp/components/mcpPromptsTable.tsx +++ b/static/app/views/insights/pages/mcp/components/mcpPromptsTable.tsx @@ -49,7 +49,9 @@ const rightAlignColumns = new Set([ export function McpPromptsTable() { const organization = useOrganization(); const {selection} = usePageFilters(); - const query = useCombinedQuery(`span.op:mcp.server has:${SpanFields.MCP_PROMPT_NAME}`); + const query = useCombinedQuery( + `span.name:mcp.server has:${SpanFields.MCP_PROMPT_NAME}` + ); const {tableSort} = useTableSort(); const tableDataRequest = useSpanTableData({ query, @@ -155,7 +157,7 @@ function McpPromptCell({prompt}: {prompt: string}) { const {selection} = usePageFilters(); const search = new MutableSearch(''); - search.addFilterValue(SpanFields.SPAN_OP, 'mcp.server'); + search.addFilterValue(SpanFields.NAME, 'mcp.server'); search.addFilterValue(SpanFields.MCP_PROMPT_NAME, prompt); const link = getExploreUrl({ @@ -169,7 +171,7 @@ function McpPromptCell({prompt}: {prompt: string}) { }, ], field: [ - 'span.description', + 'span.name', 'span.status', 'mcp.prompt.result.message_content', 'span.duration', diff --git a/static/app/views/insights/pages/mcp/components/mcpResourceDurationWidget.tsx b/static/app/views/insights/pages/mcp/components/mcpResourceDurationWidget.tsx index f2e55e7e1b919e..21f70f0fb9b145 100644 --- a/static/app/views/insights/pages/mcp/components/mcpResourceDurationWidget.tsx +++ b/static/app/views/insights/pages/mcp/components/mcpResourceDurationWidget.tsx @@ -8,7 +8,7 @@ export function McpResourceDurationWidget() { ); diff --git a/static/app/views/insights/pages/mcp/components/mcpResourceErrorRateWidget.tsx b/static/app/views/insights/pages/mcp/components/mcpResourceErrorRateWidget.tsx index 403a668e9639f5..b08403858d4a0e 100644 --- a/static/app/views/insights/pages/mcp/components/mcpResourceErrorRateWidget.tsx +++ b/static/app/views/insights/pages/mcp/components/mcpResourceErrorRateWidget.tsx @@ -8,7 +8,7 @@ export function McpResourceErrorRateWidget() { ); diff --git a/static/app/views/insights/pages/mcp/components/mcpResourceTrafficWidget.tsx b/static/app/views/insights/pages/mcp/components/mcpResourceTrafficWidget.tsx index b48ce520ab8d76..094ce53f3791f6 100644 --- a/static/app/views/insights/pages/mcp/components/mcpResourceTrafficWidget.tsx +++ b/static/app/views/insights/pages/mcp/components/mcpResourceTrafficWidget.tsx @@ -8,7 +8,7 @@ export function McpResourceTrafficWidget() { ); diff --git a/static/app/views/insights/pages/mcp/components/mcpResourcesTable.tsx b/static/app/views/insights/pages/mcp/components/mcpResourcesTable.tsx index 2333e9be2c663e..3c54945a369464 100644 --- a/static/app/views/insights/pages/mcp/components/mcpResourcesTable.tsx +++ b/static/app/views/insights/pages/mcp/components/mcpResourcesTable.tsx @@ -49,7 +49,9 @@ const rightAlignColumns = new Set([ export function McpResourcesTable() { const organization = useOrganization(); const {selection} = usePageFilters(); - const query = useCombinedQuery(`span.op:mcp.server has:${SpanFields.MCP_RESOURCE_URI}`); + const query = useCombinedQuery( + `span.name:mcp.server has:${SpanFields.MCP_RESOURCE_URI}` + ); const {tableSort} = useTableSort(); const tableDataRequest = useSpanTableData({ query, @@ -155,7 +157,7 @@ function McpResourceCell({resource}: {resource: string}) { const {selection} = usePageFilters(); const search = new MutableSearch(''); - search.addFilterValue(SpanFields.SPAN_OP, 'mcp.server'); + search.addFilterValue(SpanFields.NAME, 'mcp.server'); search.addFilterValue(SpanFields.MCP_RESOURCE_URI, resource); const link = getExploreUrl({ @@ -168,7 +170,7 @@ function McpResourceCell({resource}: {resource: string}) { yAxes: ['count(span.duration)'], }, ], - field: ['span.description', 'span.status', 'span.duration', 'timestamp'], + field: ['span.name', 'span.status', 'span.duration', 'timestamp'], query: search.formatString(), sort: '-count(span.duration)', }); diff --git a/static/app/views/insights/pages/mcp/components/mcpToolDurationWidget.tsx b/static/app/views/insights/pages/mcp/components/mcpToolDurationWidget.tsx index d251bd0d543b69..75b7010cd252a0 100644 --- a/static/app/views/insights/pages/mcp/components/mcpToolDurationWidget.tsx +++ b/static/app/views/insights/pages/mcp/components/mcpToolDurationWidget.tsx @@ -8,7 +8,7 @@ export function McpToolDurationWidget() { ); diff --git a/static/app/views/insights/pages/mcp/components/mcpToolErrorRateWidget.tsx b/static/app/views/insights/pages/mcp/components/mcpToolErrorRateWidget.tsx index 7c43da59813a3a..5384a71f25737e 100644 --- a/static/app/views/insights/pages/mcp/components/mcpToolErrorRateWidget.tsx +++ b/static/app/views/insights/pages/mcp/components/mcpToolErrorRateWidget.tsx @@ -8,7 +8,7 @@ export function McpToolErrorRateWidget() { ); diff --git a/static/app/views/insights/pages/mcp/components/mcpToolTrafficWidget.tsx b/static/app/views/insights/pages/mcp/components/mcpToolTrafficWidget.tsx index 888f549b1f4673..6b190c30474647 100644 --- a/static/app/views/insights/pages/mcp/components/mcpToolTrafficWidget.tsx +++ b/static/app/views/insights/pages/mcp/components/mcpToolTrafficWidget.tsx @@ -8,7 +8,7 @@ export function McpToolTrafficWidget() { ); diff --git a/static/app/views/insights/pages/mcp/components/mcpToolsTable.tsx b/static/app/views/insights/pages/mcp/components/mcpToolsTable.tsx index ea354119626608..e37aea7b5f7809 100644 --- a/static/app/views/insights/pages/mcp/components/mcpToolsTable.tsx +++ b/static/app/views/insights/pages/mcp/components/mcpToolsTable.tsx @@ -49,7 +49,7 @@ const rightAlignColumns = new Set([ export function McpToolsTable() { const organization = useOrganization(); const {selection} = usePageFilters(); - const query = useCombinedQuery(`span.op:mcp.server has:${SpanFields.MCP_TOOL_NAME}`); + const query = useCombinedQuery(`span.name:mcp.server has:${SpanFields.MCP_TOOL_NAME}`); const {tableSort} = useTableSort(); const tableDataRequest = useSpanTableData({ query, @@ -155,7 +155,7 @@ function McpToolCell({tool}: {tool: string}) { const {selection} = usePageFilters(); const search = new MutableSearch(''); - search.addFilterValue(SpanFields.SPAN_OP, 'mcp.server'); + search.addFilterValue(SpanFields.NAME, 'mcp.server'); search.addFilterValue(SpanFields.MCP_TOOL_NAME, tool); const link = getExploreUrl({ @@ -170,7 +170,7 @@ function McpToolCell({tool}: {tool: string}) { ], query: search.formatString(), sort: '-count(span.duration)', - field: ['span.description', 'mcp.tool.result.content', 'span.duration', 'timestamp'], + field: ['span.name', 'mcp.tool.result.content', 'span.duration', 'timestamp'], }); return {tool}; } diff --git a/static/app/views/insights/pages/mcp/components/mcpTrafficByClientWidget.tsx b/static/app/views/insights/pages/mcp/components/mcpTrafficByClientWidget.tsx index e4888d910c04b1..80e1e4df050d5a 100644 --- a/static/app/views/insights/pages/mcp/components/mcpTrafficByClientWidget.tsx +++ b/static/app/views/insights/pages/mcp/components/mcpTrafficByClientWidget.tsx @@ -8,7 +8,7 @@ export function McpTrafficByClientWidget() { ); diff --git a/static/app/views/insights/pages/mcp/components/mcpTransportWidget.tsx b/static/app/views/insights/pages/mcp/components/mcpTransportWidget.tsx index 6d6e2780fb55da..ca9fa313d96c8c 100644 --- a/static/app/views/insights/pages/mcp/components/mcpTransportWidget.tsx +++ b/static/app/views/insights/pages/mcp/components/mcpTransportWidget.tsx @@ -8,7 +8,7 @@ export function McpTransportWidget() { ); diff --git a/static/app/views/insights/pages/mcp/hooks/useMcpSpanSearchProps.tsx b/static/app/views/insights/pages/mcp/hooks/useMcpSpanSearchProps.tsx index 667d8fac341346..8ebcda9629b3db 100644 --- a/static/app/views/insights/pages/mcp/hooks/useMcpSpanSearchProps.tsx +++ b/static/app/views/insights/pages/mcp/hooks/useMcpSpanSearchProps.tsx @@ -29,9 +29,7 @@ export function useMcpSpanSearchProps() { }, searchSource: 'mcp-monitoring', - replaceRawSearchKeys: hasRawSearchReplacement - ? ['span.description', 'span.name'] - : undefined, + replaceRawSearchKeys: hasRawSearchReplacement ? ['span.name'] : undefined, matchKeySuggestions: [ {key: 'trace', valuePattern: /^[0-9a-fA-F]{32}$/}, {key: 'id', valuePattern: /^[0-9a-fA-F]{16}$/}, diff --git a/static/app/views/insights/pages/mcp/onboarding.tsx b/static/app/views/insights/pages/mcp/onboarding.tsx index 439c72f06be484..4e5fbccb13cab7 100644 --- a/static/app/views/insights/pages/mcp/onboarding.tsx +++ b/static/app/views/insights/pages/mcp/onboarding.tsx @@ -70,7 +70,7 @@ function useAiSpanWaiter(project: Project) { const request = useSpans( { - search: 'span.op:"gen_ai.*"', + search: 'span.name:"gen_ai.*"', fields: ['id'], limit: 1, enabled: !!project, diff --git a/static/app/views/insights/pages/mcp/utils/mcpTraceNodes.tsx b/static/app/views/insights/pages/mcp/utils/mcpTraceNodes.tsx index fa1d0156ea758b..3adfa103665594 100644 --- a/static/app/views/insights/pages/mcp/utils/mcpTraceNodes.tsx +++ b/static/app/views/insights/pages/mcp/utils/mcpTraceNodes.tsx @@ -1,5 +1,7 @@ import type {BaseNode} from 'sentry/views/performance/newTraceDetails/traceModels/traceTreeNode/baseNode'; export function getIsMCPNode(node: BaseNode) { - return node.op?.startsWith('mcp.'); + const name = + node.value && 'name' in node.value ? (node.value.name as string) : undefined; + return name?.startsWith('mcp.') ?? false; } diff --git a/static/app/views/performance/newTraceDetails/traceRow/traceEAPSpanRow.tsx b/static/app/views/performance/newTraceDetails/traceRow/traceEAPSpanRow.tsx index 424899673a5d95..02f10fec8ba04e 100644 --- a/static/app/views/performance/newTraceDetails/traceRow/traceEAPSpanRow.tsx +++ b/static/app/views/performance/newTraceDetails/traceRow/traceEAPSpanRow.tsx @@ -8,7 +8,7 @@ import { } from 'sentry/views/insights/pages/agents/utils/aiTraceNodes'; import { GenAiOperationType, - getGenAiOperationTypeFromSpanOp, + getGenAiOperationTypeFromSpanName, } from 'sentry/views/insights/pages/agents/utils/query'; import {SpanFields} from 'sentry/views/insights/types'; import {TraceIcons} from 'sentry/views/performance/newTraceDetails/traceIcons'; @@ -36,7 +36,7 @@ function getAIEnhancedDescription(node: EapSpanNode): string | undefined { const opType = (attrs[SpanFields.GEN_AI_OPERATION_TYPE] as string | undefined) ?? - getGenAiOperationTypeFromSpanOp(node.op); + getGenAiOperationTypeFromSpanName(node.value.name); if (!opType) { return undefined;