Skip to content

Commit 34db957

Browse files
RulaKhaledclaude
andcommitted
test(server-utils): Cover error capture for a failed Flue tool
Fails without the capture: the span is still errored, so only the error event distinguishes the two. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent f4c69c6 commit 34db957

1 file changed

Lines changed: 39 additions & 1 deletion

File tree

‎packages/server-utils/test/ai/lib/tracing/flue.test.ts‎

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,13 @@ function turn(overrides: Partial<FlueObservation> = {}): FlueObservation {
5656

5757
describe('createFlueInstrumentation', () => {
5858
let endedSpans: Span[];
59+
let client: TestClient;
5960
let instrumentation: FlueInstrumentation;
6061

6162
beforeEach(() => {
6263
_INTERNAL_clearAiProviderSkips();
6364
getMainCarrier().__SENTRY__ = undefined;
64-
const client = new TestClient(
65+
client = new TestClient(
6566
getDefaultTestClientOptions({
6667
dsn: 'https://public@dsn.ingest.sentry.io/1337',
6768
tracesSampleRate: 1,
@@ -499,6 +500,43 @@ describe('createFlueInstrumentation', () => {
499500
expect(json?.data['gen_ai.tool.name']).toBe('get_weather');
500501
});
501502

503+
// Flue catches whatever the tool threw and feeds it back to the model as a tool result, so
504+
// nothing reaches the SDK's global handlers. Without an explicit capture there is an errored span
505+
// and no error event at all.
506+
it('captures an error event for a failed tool, rebuilt from `errorInfo`', async () => {
507+
await withAgent(() => {
508+
instrumentation.observe({ type: 'tool_start', toolCallId: 'c1', toolName: 'boom', operationId: 'op_1' }, {});
509+
instrumentation.observe(
510+
{
511+
type: 'tool',
512+
toolCallId: 'c1',
513+
toolName: 'boom',
514+
operationId: 'op_1',
515+
isError: true,
516+
errorInfo: { type: 'Error', name: 'TypeError', message: 'kaboom', stack: 'TypeError: kaboom\n at run' },
517+
},
518+
{},
519+
);
520+
});
521+
522+
await client.flush();
523+
524+
const exception = client.event?.exception?.values?.[0];
525+
expect(exception?.type).toBe('TypeError');
526+
expect(exception?.value).toBe('kaboom');
527+
expect(exception?.mechanism?.type).toBe('auto.ai.flue.tool_error');
528+
});
529+
530+
it('does not capture an error event for a tool that succeeded', async () => {
531+
await withAgent(() => {
532+
instrumentation.observe({ type: 'tool_start', toolCallId: 'c1', toolName: 'ok', operationId: 'op_1' }, {});
533+
instrumentation.observe({ type: 'tool', toolCallId: 'c1', toolName: 'ok', operationId: 'op_1' }, {});
534+
});
535+
await client.flush();
536+
537+
expect(client.event).toBeUndefined();
538+
});
539+
502540
it('marks a failed tool call as errored', async () => {
503541
await withAgent(() => {
504542
instrumentation.observe({ type: 'tool_start', toolCallId: 'call_1', toolName: 'boom', operationId: 'op_1' }, {});

0 commit comments

Comments
 (0)