Skip to content

Commit f8e6144

Browse files
committed
fix(review): bound agent metric labels
1 parent 29fc796 commit f8e6144

3 files changed

Lines changed: 63 additions & 25 deletions

File tree

apps/sim/lib/copilot/request/metrics.test.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @vitest-environment node
33
*/
44

5-
import { describe, expect, it, vi } from 'vitest'
5+
import { beforeEach, describe, expect, it, vi } from 'vitest'
66

77
const { toolCallsAdd, toolDurationRecord } = vi.hoisted(() => ({
88
toolCallsAdd: vi.fn(),
@@ -24,8 +24,30 @@ import { TraceAttr } from '@/lib/copilot/generated/trace-attributes-v1'
2424
import { recordSimToolMetric } from '@/lib/copilot/request/metrics'
2525

2626
describe('recordSimToolMetric', () => {
27-
it('attributes call counts to the agent without adding it to duration', () => {
28-
recordSimToolMetric('read', 'workflow', 'success', 125)
27+
beforeEach(() => {
28+
vi.clearAllMocks()
29+
})
30+
31+
it.each(['main', 'workflow'])(
32+
'attributes call counts to the registered %s agent without adding it to duration',
33+
(agentId) => {
34+
recordSimToolMetric('read', agentId, 'success', 125)
35+
36+
const baseAttributes = {
37+
[TraceAttr.ToolName]: 'read',
38+
[TraceAttr.ToolExecutor]: 'sim',
39+
[TraceAttr.ToolOutcome]: 'success',
40+
}
41+
expect(toolCallsAdd).toHaveBeenCalledWith(1, {
42+
...baseAttributes,
43+
[TraceAttr.GenAiAgentName]: agentId,
44+
})
45+
expect(toolDurationRecord).toHaveBeenCalledWith(125, baseAttributes)
46+
}
47+
)
48+
49+
it('collapses unknown agent IDs to the bounded fallback', () => {
50+
recordSimToolMetric('read', 'tenant-defined-agent', 'success', 125)
2951

3052
const baseAttributes = {
3153
[TraceAttr.ToolName]: 'read',
@@ -34,7 +56,7 @@ describe('recordSimToolMetric', () => {
3456
}
3557
expect(toolCallsAdd).toHaveBeenCalledWith(1, {
3658
...baseAttributes,
37-
[TraceAttr.GenAiAgentName]: 'workflow',
59+
[TraceAttr.GenAiAgentName]: 'other',
3860
})
3961
expect(toolDurationRecord).toHaveBeenCalledWith(125, baseAttributes)
4062
})

apps/sim/lib/copilot/request/metrics.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,15 @@ function cappedToolName(name: string): string {
6868
return TOOL_CATALOG[name] ? name : 'other'
6969
}
7070

71+
const REGISTERED_AGENT_IDS = new Set([
72+
'main',
73+
...Object.values(TOOL_CATALOG).flatMap(({ subagentId }) => (subagentId ? [subagentId] : [])),
74+
])
75+
76+
function cappedAgentId(agentId: string): string {
77+
return REGISTERED_AGENT_IDS.has(agentId) ? agentId : 'other'
78+
}
79+
7180
// recordSimToolMetric emits copilot.tool.calls (+1) and copilot.tool.duration
7281
// for one server-side Sim tool dispatch (executor=sim). outcome is the bounded
7382
// tool outcome (success/error/…). Pure telemetry.
@@ -85,7 +94,7 @@ export function recordSimToolMetric(
8594
}
8695
toolCalls.add(1, {
8796
...baseAttrs,
88-
[TraceAttr.GenAiAgentName]: agentId,
97+
[TraceAttr.GenAiAgentName]: cappedAgentId(agentId),
8998
})
9099
if (durationMs >= 0) toolDuration.record(durationMs, baseAttrs)
91100
}

apps/sim/lib/copilot/request/tools/executor.test.ts

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -112,25 +112,32 @@ describe('executeToolAndReport metrics', () => {
112112
)
113113
})
114114

115-
it('falls back to main when forwarding an unexpected throw', async () => {
116-
const toolCall: ToolCallState = {
117-
id: 'call-2',
118-
name: 'read',
119-
status: MothershipStreamV1ToolOutcome.error,
120-
endTime: Date.now(),
115+
it.each([
116+
{ agentId: 'workflow', expectedAgentId: 'workflow' },
117+
{ agentId: undefined, expectedAgentId: 'main' },
118+
])(
119+
'forwards $expectedAgentId when an unexpected error occurs',
120+
async ({ agentId, expectedAgentId }) => {
121+
const toolCall: ToolCallState = {
122+
id: 'call-2',
123+
name: 'read',
124+
status: MothershipStreamV1ToolOutcome.error,
125+
agentId,
126+
endTime: Date.now(),
127+
}
128+
const context = createStreamingContext({
129+
toolCalls: new Map([[toolCall.id, toolCall]]),
130+
})
131+
132+
await expect(executeToolAndReport(toolCall.id, context, executionContext)).rejects.toThrow(
133+
'missing a canonical error'
134+
)
135+
expect(recordSimToolMetric).toHaveBeenCalledWith(
136+
'read',
137+
expectedAgentId,
138+
MothershipStreamV1ToolOutcome.error,
139+
expect.any(Number)
140+
)
121141
}
122-
const context = createStreamingContext({
123-
toolCalls: new Map([[toolCall.id, toolCall]]),
124-
})
125-
126-
await expect(executeToolAndReport(toolCall.id, context, executionContext)).rejects.toThrow(
127-
'missing a canonical error'
128-
)
129-
expect(recordSimToolMetric).toHaveBeenCalledWith(
130-
'read',
131-
'main',
132-
MothershipStreamV1ToolOutcome.error,
133-
expect.any(Number)
134-
)
135-
})
142+
)
136143
})

0 commit comments

Comments
 (0)