From d155816b22df7455917fa2a9723aded9ddbb2353 Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Mon, 27 Jul 2026 15:14:57 +0200 Subject: [PATCH 1/7] feat(core)!: Flip `genAI` defaults to collect it by default --- packages/astro/test/server/middleware.test.ts | 2 +- packages/core/src/integrations/mcp-server/index.ts | 4 ++-- packages/core/src/tracing/ai/utils.ts | 6 +++--- .../data-collection/defaultPiiToCollectionOptions.ts | 2 +- .../mcp-server/transportInstrumentation.test.ts | 5 +++-- packages/core/test/lib/tracing/ai/utils.test.ts | 11 ++++++----- .../defaultPiiToCollectionOptions.test.ts | 6 +++--- .../resolveDataCollectionOptions.test.ts | 4 ++-- .../integrations/tracing/langgraph/instrumentation.ts | 4 ++-- .../test/runtime/hooks/wrapMiddlewareHandler.test.ts | 2 +- 10 files changed, 24 insertions(+), 22 deletions(-) diff --git a/packages/astro/test/server/middleware.test.ts b/packages/astro/test/server/middleware.test.ts index 9f051ebd703e..b6f262e69acf 100644 --- a/packages/astro/test/server/middleware.test.ts +++ b/packages/astro/test/server/middleware.test.ts @@ -66,7 +66,7 @@ describe('sentryMiddleware', () => { httpBodies: [], urlQueryParams: true, graphQL: { document: true, variables: true }, - genAI: { inputs: false, outputs: false }, + genAI: { inputs: true, outputs: true }, databaseQueryData: true, stackFrameVariables: true, frameContextLines: 5, diff --git a/packages/core/src/integrations/mcp-server/index.ts b/packages/core/src/integrations/mcp-server/index.ts index df09714e404f..fd4c5168551a 100644 --- a/packages/core/src/integrations/mcp-server/index.ts +++ b/packages/core/src/integrations/mcp-server/index.ts @@ -64,8 +64,8 @@ export function wrapMcpServerWithSentry(mcpServerInstance: S, const genAI = client?.getDataCollectionOptions().genAI; const resolvedOptions: ResolvedMcpOptions = { - recordInputs: options?.recordInputs ?? genAI?.inputs ?? false, - recordOutputs: options?.recordOutputs ?? genAI?.outputs ?? false, + recordInputs: options?.recordInputs ?? genAI?.inputs ?? true, + recordOutputs: options?.recordOutputs ?? genAI?.outputs ?? true, }; fill(serverInstance, 'connect', originalConnect => { diff --git a/packages/core/src/tracing/ai/utils.ts b/packages/core/src/tracing/ai/utils.ts index 9a7dabced2d6..9f39c62cd4dd 100644 --- a/packages/core/src/tracing/ai/utils.ts +++ b/packages/core/src/tracing/ai/utils.ts @@ -47,14 +47,14 @@ export type InstrumentedMethodRegistry = Record /** * Resolves AI recording options by falling back to the client's `dataCollection.genAI` settings. - * Precedence: explicit option > dataCollection.genAI > sendDefaultPii > false + * Precedence: explicit option > dataCollection.genAI > true (genAI data collected by default) */ export function resolveAIRecordingOptions(options?: T): T & Required { const genAI = getClient()?.getDataCollectionOptions().genAI; return { ...options, - recordInputs: options?.recordInputs ?? genAI?.inputs ?? false, - recordOutputs: options?.recordOutputs ?? genAI?.outputs ?? false, + recordInputs: options?.recordInputs ?? genAI?.inputs ?? true, + recordOutputs: options?.recordOutputs ?? genAI?.outputs ?? true, } as T & Required; } diff --git a/packages/core/src/utils/data-collection/defaultPiiToCollectionOptions.ts b/packages/core/src/utils/data-collection/defaultPiiToCollectionOptions.ts index b70cddc267f4..a5bc57cb410a 100644 --- a/packages/core/src/utils/data-collection/defaultPiiToCollectionOptions.ts +++ b/packages/core/src/utils/data-collection/defaultPiiToCollectionOptions.ts @@ -31,7 +31,7 @@ export function defaultPiiToCollectionOptions(sendDefaultPii?: boolean): Resolve // The GraphQL document has literal values redacted at collection time, so it was historically // always attached regardless of `sendDefaultPii`; keep it on to preserve that behavior. graphQL: { document: true, variables: true }, - genAI: { inputs: false, outputs: false }, + genAI: { inputs: true, outputs: true }, // Database query values were only sent with `sendDefaultPii: true` (e.g. Supabase gated on it), // so map the legacy "off" state to `false`. databaseQueryData: false, diff --git a/packages/core/test/lib/integrations/mcp-server/transportInstrumentation.test.ts b/packages/core/test/lib/integrations/mcp-server/transportInstrumentation.test.ts index ef764b86f213..a7b00bb3b1c6 100644 --- a/packages/core/test/lib/integrations/mcp-server/transportInstrumentation.test.ts +++ b/packages/core/test/lib/integrations/mcp-server/transportInstrumentation.test.ts @@ -808,7 +808,8 @@ describe('MCP Server Transport Instrumentation', () => { ); }); - it('should NOT capture inputs/outputs when sendDefaultPii is false (legacy bridge)', async () => { + // todo: delete the following test once we remove sendDefaultPii + it('should capture inputs/outputs when sendDefaultPii is false (genAI collected by default)', async () => { getClientSpy.mockReturnValue(createTestClientWithSendDefaultPii(false)); const mockMcpServer = createMockMcpServer(); @@ -829,7 +830,7 @@ describe('MCP Server Transport Instrumentation', () => { expect(startInactiveSpanSpy).toHaveBeenCalledWith( expect.objectContaining({ - attributes: expect.not.objectContaining({ + attributes: expect.objectContaining({ 'mcp.request.argument.location': expect.anything(), }), }), diff --git a/packages/core/test/lib/tracing/ai/utils.test.ts b/packages/core/test/lib/tracing/ai/utils.test.ts index b761d3019e5b..701deaa85d54 100644 --- a/packages/core/test/lib/tracing/ai/utils.test.ts +++ b/packages/core/test/lib/tracing/ai/utils.test.ts @@ -34,21 +34,22 @@ describe('resolveAIRecordingOptions', () => { client.init(); } - it('defaults to false when no client is set', () => { - expect(resolveAIRecordingOptions()).toEqual({ recordInputs: false, recordOutputs: false }); + it('defaults to true when no client is set', () => { + expect(resolveAIRecordingOptions()).toEqual({ recordInputs: true, recordOutputs: true }); }); - it('defaults to false when sendDefaultPii is false (bridge)', () => { + // todo: delete the following tests once we remove sendDefaultPii + it.skip('defaults to false when sendDefaultPii is false (bridge)', () => { setupWithSendDefaultPii(false); expect(resolveAIRecordingOptions()).toEqual({ recordInputs: false, recordOutputs: false }); }); - it('defaults to true when sendDefaultPii is true (bridge)', () => { + it.skip('defaults to true when sendDefaultPii is true (bridge)', () => { setupWithSendDefaultPii(true); expect(resolveAIRecordingOptions()).toEqual({ recordInputs: true, recordOutputs: true }); }); - it('explicit options override sendDefaultPii bridge', () => { + it.skip('explicit options override sendDefaultPii bridge', () => { setupWithSendDefaultPii(true); expect(resolveAIRecordingOptions({ recordInputs: false })).toEqual({ recordInputs: false, recordOutputs: true }); }); diff --git a/packages/core/test/lib/utils/data-collection/defaultPiiToCollectionOptions.test.ts b/packages/core/test/lib/utils/data-collection/defaultPiiToCollectionOptions.test.ts index c76dc1dccb4b..23a5f38baeef 100644 --- a/packages/core/test/lib/utils/data-collection/defaultPiiToCollectionOptions.test.ts +++ b/packages/core/test/lib/utils/data-collection/defaultPiiToCollectionOptions.test.ts @@ -28,7 +28,7 @@ describe('defaultPiiToCollectionOptions', () => { httpBodies: [], urlQueryParams: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, graphQL: { document: true, variables: true }, - genAI: { inputs: false, outputs: false }, + genAI: { inputs: true, outputs: true }, databaseQueryData: false, stackFrameVariables: true, frameContextLines: 7, @@ -46,7 +46,7 @@ describe('defaultPiiToCollectionOptions', () => { httpBodies: [], urlQueryParams: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, graphQL: { document: true, variables: true }, - genAI: { inputs: false, outputs: false }, + genAI: { inputs: true, outputs: true }, databaseQueryData: false, stackFrameVariables: true, frameContextLines: 7, @@ -64,7 +64,7 @@ describe('defaultPiiToCollectionOptions', () => { httpBodies: [], urlQueryParams: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, graphQL: { document: true, variables: true }, - genAI: { inputs: false, outputs: false }, + genAI: { inputs: true, outputs: true }, databaseQueryData: false, stackFrameVariables: true, frameContextLines: 7, diff --git a/packages/core/test/lib/utils/data-collection/resolveDataCollectionOptions.test.ts b/packages/core/test/lib/utils/data-collection/resolveDataCollectionOptions.test.ts index 8d6ec21a0ab6..ff0d569e3320 100644 --- a/packages/core/test/lib/utils/data-collection/resolveDataCollectionOptions.test.ts +++ b/packages/core/test/lib/utils/data-collection/resolveDataCollectionOptions.test.ts @@ -22,7 +22,7 @@ describe('resolveDataCollectionOptions', () => { // sendDefaultPii undefined → restrictive bridge (backward compat; userInfo defaults to true only when dataCollection is set) expect(result.userInfo).toBe(false); expect(result.httpBodies).toEqual([]); - expect(result.genAI).toEqual({ inputs: false, outputs: false }); + expect(result.genAI).toEqual({ inputs: true, outputs: true }); // GraphQL documents are redacted at collection time, so they stay on to preserve legacy behavior. expect(result.graphQL).toEqual({ document: true, variables: true }); expect(result.databaseQueryData).toBe(false); @@ -60,7 +60,7 @@ describe('resolveDataCollectionOptions', () => { expect(result.userInfo).toBe(false); expect(result.httpBodies).toEqual([]); - expect(result.genAI).toEqual({ inputs: false, outputs: false }); + expect(result.genAI).toEqual({ inputs: true, outputs: true }); expect(result.graphQL).toEqual({ document: true, variables: true }); expect(result.databaseQueryData).toBe(false); }); diff --git a/packages/node/src/integrations/tracing/langgraph/instrumentation.ts b/packages/node/src/integrations/tracing/langgraph/instrumentation.ts index b41bc4f16b65..329227a6a004 100644 --- a/packages/node/src/integrations/tracing/langgraph/instrumentation.ts +++ b/packages/node/src/integrations/tracing/langgraph/instrumentation.ts @@ -94,8 +94,8 @@ export class SentryLangGraphInstrumentation extends InstrumentationBase { httpBodies: [], urlQueryParams: true, graphQL: { document: true, variables: true }, - genAI: { inputs: false, outputs: false }, + genAI: { inputs: true, outputs: true }, databaseQueryData: true, stackFrameVariables: true, frameContextLines: 5, From ef7524868857c0c9441b797fb6f4833fd5142a5f Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Mon, 27 Jul 2026 18:07:24 +0200 Subject: [PATCH 2/7] fix tests --- .../suites/tracing/vercelai/instrument.mjs | 1 + .../suites/tracing/vercelai/span-streaming-v4/instrument.mjs | 1 + .../suites/tracing/vercelai/span-streaming-v6/instrument.mjs | 1 + .../suites/tracing/vercelai/v5/instrument.mjs | 1 + .../suites/tracing/vercelai/v6_v7/instrument.mjs | 1 + 5 files changed, 5 insertions(+) diff --git a/dev-packages/node-integration-tests/suites/tracing/vercelai/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/vercelai/instrument.mjs index 6e1234b5c975..22d1e17ce40e 100644 --- a/dev-packages/node-integration-tests/suites/tracing/vercelai/instrument.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/vercelai/instrument.mjs @@ -6,6 +6,7 @@ Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', release: '1.0', tracesSampleRate: 1.0, + dataCollection: { genAI: { inputs: false, outputs: false } }, transport: loggingTransport, streamGenAiSpans: true, }); diff --git a/dev-packages/node-integration-tests/suites/tracing/vercelai/span-streaming-v4/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/vercelai/span-streaming-v4/instrument.mjs index 53b9511a21f0..5e0b6fb5592f 100644 --- a/dev-packages/node-integration-tests/suites/tracing/vercelai/span-streaming-v4/instrument.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/vercelai/span-streaming-v4/instrument.mjs @@ -5,6 +5,7 @@ Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', release: '1.0', tracesSampleRate: 1.0, + dataCollection: { genAI: { inputs: false, outputs: false } }, transport: loggingTransport, traceLifecycle: 'stream', }); diff --git a/dev-packages/node-integration-tests/suites/tracing/vercelai/span-streaming-v6/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/vercelai/span-streaming-v6/instrument.mjs index 53b9511a21f0..5e0b6fb5592f 100644 --- a/dev-packages/node-integration-tests/suites/tracing/vercelai/span-streaming-v6/instrument.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/vercelai/span-streaming-v6/instrument.mjs @@ -5,6 +5,7 @@ Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', release: '1.0', tracesSampleRate: 1.0, + dataCollection: { genAI: { inputs: false, outputs: false } }, transport: loggingTransport, traceLifecycle: 'stream', }); diff --git a/dev-packages/node-integration-tests/suites/tracing/vercelai/v5/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/vercelai/v5/instrument.mjs index 6e1234b5c975..22d1e17ce40e 100644 --- a/dev-packages/node-integration-tests/suites/tracing/vercelai/v5/instrument.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/vercelai/v5/instrument.mjs @@ -6,6 +6,7 @@ Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', release: '1.0', tracesSampleRate: 1.0, + dataCollection: { genAI: { inputs: false, outputs: false } }, transport: loggingTransport, streamGenAiSpans: true, }); diff --git a/dev-packages/node-integration-tests/suites/tracing/vercelai/v6_v7/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/vercelai/v6_v7/instrument.mjs index 170ad6f6a702..42052d281304 100644 --- a/dev-packages/node-integration-tests/suites/tracing/vercelai/v6_v7/instrument.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/vercelai/v6_v7/instrument.mjs @@ -6,5 +6,6 @@ Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', release: '1.0', tracesSampleRate: 1.0, + dataCollection: { genAI: { inputs: false, outputs: false } }, transport: loggingTransport, }); From 9d99ff5f1557c57a2f4e27a751de40740389a914 Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Tue, 28 Jul 2026 10:44:16 +0200 Subject: [PATCH 3/7] fix tests (add genAI option) --- .../test-applications/cloudflare-vercelai-v7-als/src/index.ts | 1 + .../test-applications/cloudflare-vercelai-v7-compat/src/index.ts | 1 + .../suites/aws-serverless/bedrock/instrument.mjs | 1 + 3 files changed, 3 insertions(+) diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-vercelai-v7-als/src/index.ts b/dev-packages/e2e-tests/test-applications/cloudflare-vercelai-v7-als/src/index.ts index 0d18c070ec3d..494d02e7d92a 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-vercelai-v7-als/src/index.ts +++ b/dev-packages/e2e-tests/test-applications/cloudflare-vercelai-v7-als/src/index.ts @@ -10,6 +10,7 @@ export default Sentry.withSentry( tunnel: 'http://localhost:3031/', streamGenAiSpans: false, tracesSampleRate: 1.0, + dataCollection: { genAI: { inputs: false, outputs: false } }, integrations: [Sentry.vercelAIIntegration()], }), { diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-vercelai-v7-compat/src/index.ts b/dev-packages/e2e-tests/test-applications/cloudflare-vercelai-v7-compat/src/index.ts index 1cf5d617196f..f23b39611e43 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-vercelai-v7-compat/src/index.ts +++ b/dev-packages/e2e-tests/test-applications/cloudflare-vercelai-v7-compat/src/index.ts @@ -10,6 +10,7 @@ export default Sentry.withSentry( tunnel: 'http://localhost:3031/', tracesSampleRate: 1.0, streamGenAiSpans: false, + dataCollection: { genAI: { inputs: false, outputs: false } }, integrations: [Sentry.vercelAIIntegration()], }), { diff --git a/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/instrument.mjs b/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/instrument.mjs index d6a9efde7bae..14dbd52b3824 100644 --- a/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/instrument.mjs +++ b/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/instrument.mjs @@ -6,5 +6,6 @@ Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', release: '1.0', tracesSampleRate: 1.0, + dataCollection: { genAI: { inputs: false, outputs: false } }, transport: loggingTransport, }); From f4a1ad60baa013f4cbb3537c77f666915489ec0c Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Tue, 28 Jul 2026 16:54:01 +0200 Subject: [PATCH 4/7] add cloudflare integration tests --- .../suites/tracing/anthropic-ai/index.ts | 1 + .../suites/tracing/anthropic-ai/test.ts | 3 +++ .../suites/tracing/google-genai/index.ts | 1 + .../suites/tracing/google-genai/test.ts | 15 +++++++++++++ .../suites/tracing/openai/index.ts | 1 + .../suites/tracing/openai/test.ts | 13 +++++++++++ .../suites/tracing/workers-ai/index.ts | 1 + .../suites/tracing/workers-ai/test.ts | 22 ++++++++++++++++++- 8 files changed, 56 insertions(+), 1 deletion(-) diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/index.ts index 19107938d26d..69825e7d08bf 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/index.ts @@ -28,6 +28,7 @@ export default Sentry.withSentry( dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, + dataCollection: { genAI: { inputs: false, outputs: true } }, streamGenAiSpans: true, }), { diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/test.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/test.ts index 4ba21f73c6c0..0b9402ce3936 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/test.ts @@ -6,6 +6,7 @@ import { GEN_AI_REQUEST_TEMPERATURE, GEN_AI_RESPONSE_ID, GEN_AI_RESPONSE_MODEL, + GEN_AI_RESPONSE_TEXT, GEN_AI_SYSTEM, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, @@ -45,6 +46,8 @@ it('traces a basic message creation request with the anthropic SDK', async ({ si [GEN_AI_REQUEST_MODEL]: { value: 'claude-3-haiku-20240307', type: 'string' }, [GEN_AI_REQUEST_TEMPERATURE]: { value: 0.7, type: 'double' }, [GEN_AI_REQUEST_MAX_TOKENS]: { value: 100, type: 'integer' }, + // collect only LLM output + [GEN_AI_RESPONSE_TEXT]: { value: 'Hello from Anthropic!', type: 'string' }, [GEN_AI_RESPONSE_ID]: { value: 'msg_mock123', type: 'string' }, [GEN_AI_RESPONSE_MODEL]: { value: 'claude-3-haiku-20240307', type: 'string' }, [GEN_AI_USAGE_INPUT_TOKENS]: { value: 10, type: 'integer' }, diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/index.ts index 1e56569ff1ea..cb7660db506b 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/index.ts @@ -46,6 +46,7 @@ export default Sentry.withSentry( dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, + dataCollection: { genAI: { inputs: true } }, streamGenAiSpans: true, }), { diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/test.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/test.ts index 0115791c3c22..b44a962de465 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/test.ts @@ -1,16 +1,20 @@ import { expect, it } from 'vitest'; import type { SerializedStreamedSpan } from '@sentry/core'; import { + GEN_AI_EMBEDDINGS_INPUT, + GEN_AI_INPUT_MESSAGES, GEN_AI_OPERATION_NAME, GEN_AI_REQUEST_MAX_TOKENS, GEN_AI_REQUEST_MODEL, GEN_AI_REQUEST_TEMPERATURE, GEN_AI_REQUEST_TOP_P, + GEN_AI_RESPONSE_TEXT, GEN_AI_SYSTEM, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_TOTAL_TOKENS, } from '@sentry/conventions/attributes'; +import { GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE } from '../../../../../packages/core/src/tracing/ai/gen-ai-attributes'; import { createRunner } from '../../../runner'; // This test runs the `@google/genai` SDK on the Workers runtime (with a @@ -46,6 +50,10 @@ it('traces Google GenAI chat, generateContent, and embedContent calls', async ({ [GEN_AI_SYSTEM]: { value: 'google_genai', type: 'string' }, [GEN_AI_OPERATION_NAME]: { value: 'chat', type: 'string' }, [GEN_AI_REQUEST_MODEL]: { value: 'gemini-1.5-pro', type: 'string' }, + // collect LLM input and outputs (default true) + [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: { value: 1, type: 'integer' }, + [GEN_AI_INPUT_MESSAGES]: { value: '[{"role":"user","content":"Tell me a joke"}]', type: 'string' }, + [GEN_AI_RESPONSE_TEXT]: { value: 'Hello from Google GenAI!', type: 'string' }, [GEN_AI_USAGE_INPUT_TOKENS]: { value: 8, type: 'integer' }, [GEN_AI_USAGE_OUTPUT_TOKENS]: { value: 12, type: 'integer' }, [GEN_AI_USAGE_TOTAL_TOKENS]: { value: 20, type: 'integer' }, @@ -70,9 +78,15 @@ it('traces Google GenAI chat, generateContent, and embedContent calls', async ({ [GEN_AI_REQUEST_TEMPERATURE]: { value: 0.7, type: 'double' }, [GEN_AI_REQUEST_TOP_P]: { value: 0.9, type: 'double' }, [GEN_AI_REQUEST_MAX_TOKENS]: { value: 100, type: 'integer' }, + [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: { value: 1, type: 'integer' }, + [GEN_AI_INPUT_MESSAGES]: { + value: '[{"role":"user","parts":[{"text":"What is the capital of France?"}]}]', + type: 'string', + }, [GEN_AI_USAGE_INPUT_TOKENS]: { value: 8, type: 'integer' }, [GEN_AI_USAGE_OUTPUT_TOKENS]: { value: 12, type: 'integer' }, [GEN_AI_USAGE_TOTAL_TOKENS]: { value: 20, type: 'integer' }, + [GEN_AI_RESPONSE_TEXT]: { value: 'Hello from Google GenAI!', type: 'string' }, }, }); @@ -91,6 +105,7 @@ it('traces Google GenAI chat, generateContent, and embedContent calls', async ({ [GEN_AI_SYSTEM]: { value: 'google_genai', type: 'string' }, [GEN_AI_OPERATION_NAME]: { value: 'embeddings', type: 'string' }, [GEN_AI_REQUEST_MODEL]: { value: 'text-embedding-004', type: 'string' }, + [GEN_AI_EMBEDDINGS_INPUT]: { value: 'Hello world', type: 'string' }, }, }); }) diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/openai/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/openai/index.ts index 67ef4e868d71..e3541475b36a 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/openai/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/openai/index.ts @@ -33,6 +33,7 @@ export default Sentry.withSentry( dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, + dataCollection: { genAI: { inputs: true, outputs: false } }, streamGenAiSpans: true, }), { diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/openai/test.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/openai/test.ts index e0e55cf7ec79..027d11935b76 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/openai/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/openai/test.ts @@ -1,5 +1,6 @@ import { expect, it } from 'vitest'; import { + GEN_AI_INPUT_MESSAGES, GEN_AI_OPERATION_NAME, GEN_AI_REQUEST_MODEL, GEN_AI_REQUEST_TEMPERATURE, @@ -7,10 +8,12 @@ import { GEN_AI_RESPONSE_ID, GEN_AI_RESPONSE_MODEL, GEN_AI_SYSTEM, + GEN_AI_SYSTEM_INSTRUCTIONS, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_TOTAL_TOKENS, } from '@sentry/conventions/attributes'; +import { GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE } from '../../../../../packages/core/src/tracing/ai/gen-ai-attributes'; import { createRunner } from '../../../runner'; // This test runs the `openai` SDK on the Workers runtime (with a canned @@ -44,6 +47,16 @@ it('traces a basic chat completion request with the openai SDK', async ({ signal [GEN_AI_OPERATION_NAME]: { value: 'chat', type: 'string' }, [GEN_AI_REQUEST_MODEL]: { value: 'gpt-3.5-turbo', type: 'string' }, [GEN_AI_REQUEST_TEMPERATURE]: { value: 0.7, type: 'double' }, + // collect only LLM input + [GEN_AI_SYSTEM_INSTRUCTIONS]: { + value: '[{"type":"text","content":"You are a helpful assistant."}]', + type: 'string', + }, + [GEN_AI_INPUT_MESSAGES]: { + value: '[{"role":"user","content":"What is the capital of France?"}]', + type: 'string', + }, + [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: { value: 1, type: 'integer' }, [GEN_AI_RESPONSE_ID]: { value: 'chatcmpl-mock123', type: 'string' }, [GEN_AI_RESPONSE_MODEL]: { value: 'gpt-3.5-turbo', type: 'string' }, [GEN_AI_USAGE_INPUT_TOKENS]: { value: 10, type: 'integer' }, diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts index ade153d04c12..d4ac635a733b 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts @@ -13,6 +13,7 @@ export default Sentry.withSentry( dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, + dataCollection: { genAI: { inputs: true, outputs: true } }, // Keep gen_ai spans embedded in the transaction (instead of streamed as a // separate envelope container) so they can be asserted on `transaction.spans`. streamGenAiSpans: false, diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/test.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/test.ts index 915b0e06a90c..ec6a051fd859 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/test.ts @@ -1,16 +1,23 @@ import { + GEN_AI_INPUT_MESSAGES, GEN_AI_OPERATION_NAME, + GEN_AI_OUTPUT_MESSAGES, GEN_AI_PROVIDER_NAME, GEN_AI_REQUEST_MAX_TOKENS, GEN_AI_REQUEST_MODEL, GEN_AI_REQUEST_TEMPERATURE, GEN_AI_RESPONSE_STREAMING, + GEN_AI_RESPONSE_TEXT, + GEN_AI_SYSTEM_INSTRUCTIONS, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_TOTAL_TOKENS, } from '@sentry/conventions/attributes'; import { expect, it } from 'vitest'; -import { GEN_AI_REQUEST_STREAM_ATTRIBUTE } from '../../../../../packages/core/src/tracing/ai/gen-ai-attributes'; +import { + GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, + GEN_AI_REQUEST_STREAM_ATTRIBUTE, +} from '../../../../../packages/core/src/tracing/ai/gen-ai-attributes'; import { createRunner } from '../../../runner'; // These tests are not exhaustive because the instrumentation is @@ -53,6 +60,13 @@ it('traces a basic Workers AI text generation request', async ({ signal }) => { [GEN_AI_USAGE_INPUT_TOKENS]: 12, [GEN_AI_USAGE_OUTPUT_TOKENS]: 7, [GEN_AI_USAGE_TOTAL_TOKENS]: 19, + // collect input and output messages + [GEN_AI_SYSTEM_INSTRUCTIONS]: '[{"type":"text","content":"You are a helpful assistant."}]', + [GEN_AI_INPUT_MESSAGES]: '[{"role":"user","content":"What is the capital of France?"}]', + [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: 1, + [GEN_AI_OUTPUT_MESSAGES]: + '[{"role":"assistant","parts":[{"type":"text","content":"The capital of France is Paris."}]}]', + [GEN_AI_RESPONSE_TEXT]: 'The capital of France is Paris.', }, }), ], @@ -98,6 +112,12 @@ it('traces a streaming Workers AI text generation request', async ({ signal }) = [GEN_AI_USAGE_INPUT_TOKENS]: 12, [GEN_AI_USAGE_OUTPUT_TOKENS]: 7, [GEN_AI_USAGE_TOTAL_TOKENS]: 19, + [GEN_AI_INPUT_MESSAGES]: '[{"role":"user","content":"What is the capital of France?"}]', + [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: 1, + // Accumulated from the streamed chunks rather than read off a single response body. + [GEN_AI_OUTPUT_MESSAGES]: + '[{"role":"assistant","parts":[{"type":"text","content":"The capital of France is Paris."}]}]', + [GEN_AI_RESPONSE_TEXT]: 'The capital of France is Paris.', }, }), ], From bf8bd79d0a6364da0f1e15ecf6d3be479017d988 Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Wed, 29 Jul 2026 11:32:06 +0200 Subject: [PATCH 5/7] fix cloudflare tests --- .../suites/tracing/anthropic-ai/index.ts | 8 +- .../suites/tracing/anthropic-ai/test.ts | 9 +- .../suites/tracing/google-genai/index.ts | 6 +- .../suites/tracing/openai/index.ts | 6 +- .../suites/tracing/workers-ai/index.ts | 13 +- .../suites/tracing/workers-ai/test.ts | 16 +- .../core/test/lib/tracing/workers-ai.test.ts | 166 ++++++++++++++++-- 7 files changed, 187 insertions(+), 37 deletions(-) diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/index.ts index 69825e7d08bf..ca09e5d54c0a 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/index.ts @@ -21,18 +21,20 @@ const mockFetch: typeof fetch = async () => { status: 200, headers: { 'content-type': 'application/json' } }, ); -const client = Sentry.instrumentAnthropicAiClient(new Anthropic({ apiKey: 'mock-api-key', fetch: mockFetch })); - export default Sentry.withSentry( (env: Env) => ({ dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, - dataCollection: { genAI: { inputs: false, outputs: true } }, + dataCollection: { genAI: { inputs: true, outputs: true } }, streamGenAiSpans: true, }), { async fetch(_request, _env, _ctx) { + // Wrapped in-request so the SDK is initialized when recording options are resolved, which is + // also the only place a real Worker can read its API key from `env`. + const client = Sentry.instrumentAnthropicAiClient(new Anthropic({ apiKey: 'mock-api-key', fetch: mockFetch })); + const response = await client.messages.create({ model: 'claude-3-haiku-20240307', messages: [{ role: 'user', content: 'What is the capital of France?' }], diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/test.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/test.ts index 0b9402ce3936..7c97b1709782 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/test.ts @@ -1,5 +1,6 @@ import { expect, it } from 'vitest'; import { + GEN_AI_INPUT_MESSAGES, GEN_AI_OPERATION_NAME, GEN_AI_REQUEST_MAX_TOKENS, GEN_AI_REQUEST_MODEL, @@ -12,6 +13,7 @@ import { GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_TOTAL_TOKENS, } from '@sentry/conventions/attributes'; +import { GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE } from '../../../../../packages/core/src/tracing/ai/gen-ai-attributes'; import { createRunner } from '../../../runner'; // This test runs the `@anthropic-ai/sdk` on the Workers runtime (with a @@ -46,7 +48,12 @@ it('traces a basic message creation request with the anthropic SDK', async ({ si [GEN_AI_REQUEST_MODEL]: { value: 'claude-3-haiku-20240307', type: 'string' }, [GEN_AI_REQUEST_TEMPERATURE]: { value: 0.7, type: 'double' }, [GEN_AI_REQUEST_MAX_TOKENS]: { value: 100, type: 'integer' }, - // collect only LLM output + // collect only LLM input + [GEN_AI_INPUT_MESSAGES]: { + value: '[{"role":"user","content":"What is the capital of France?"}]', + type: 'string', + }, + [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: { value: 1, type: 'integer' }, [GEN_AI_RESPONSE_TEXT]: { value: 'Hello from Anthropic!', type: 'string' }, [GEN_AI_RESPONSE_ID]: { value: 'msg_mock123', type: 'string' }, [GEN_AI_RESPONSE_MODEL]: { value: 'claude-3-haiku-20240307', type: 'string' }, diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/index.ts index cb7660db506b..3cfa9b9ac157 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/index.ts @@ -39,8 +39,6 @@ globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => { ); }) as typeof fetch; -const client = Sentry.instrumentGoogleGenAIClient(new GoogleGenAI({ apiKey: 'mock-api-key' })); - export default Sentry.withSentry( (env: Env) => ({ dsn: env.SENTRY_DSN, @@ -51,6 +49,10 @@ export default Sentry.withSentry( }), { async fetch(_request, _env, _ctx) { + // Wrapped in-request so the SDK is initialized when recording options are resolved, which is + // also the only place a real Worker can read its API key from `env`. + const client = Sentry.instrumentGoogleGenAIClient(new GoogleGenAI({ apiKey: 'mock-api-key' })); + // Test 1: chats.create and sendMessage flow const chat = client.chats.create({ model: 'gemini-1.5-pro', diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/openai/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/openai/index.ts index e3541475b36a..209497909346 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/openai/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/openai/index.ts @@ -26,8 +26,6 @@ const mockFetch: typeof fetch = async () => { status: 200, headers: { 'content-type': 'application/json' } }, ); -const client = Sentry.instrumentOpenAiClient(new OpenAI({ apiKey: 'mock-api-key', fetch: mockFetch })); - export default Sentry.withSentry( (env: Env) => ({ dsn: env.SENTRY_DSN, @@ -38,6 +36,10 @@ export default Sentry.withSentry( }), { async fetch(_request, _env, _ctx) { + // Wrapped in-request so the SDK is initialized when recording options are resolved, which is + // also the only place a real Worker can read its API key from `env`. + const client = Sentry.instrumentOpenAiClient(new OpenAI({ apiKey: 'mock-api-key', fetch: mockFetch })); + const response = await client.chat.completions.create({ model: 'gpt-3.5-turbo', messages: [ diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts index 2da6e49e5cd7..b657edeb1fc0 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts @@ -6,20 +6,29 @@ interface Env { SENTRY_DSN: string; } -const ai = instrumentWorkersAiClient(new MockAi(), { recordInputs: false, recordOutputs: false }); +// Stands in for the `env.AI` binding: the binding object exists before the request, but is only +// reachable through `env` inside the handler. +const aiBinding = new MockAi(); export default Sentry.withSentry( (env: Env) => ({ dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, - dataCollection: { genAI: { inputs: true, outputs: true } }, + // Responses only. Asserting that prompts are *absent* is what makes this suite fail if the + // binding is ever wrapped before the SDK is initialized again, since the fallback collects both. + dataCollection: { genAI: { inputs: false, outputs: true } }, // Keep gen_ai spans embedded in the transaction (instead of streamed as a // separate envelope container) so they can be asserted on `transaction.spans`. streamGenAiSpans: false, }), { async fetch(request) { + // Wrapped in-request, mirroring how `@sentry/cloudflare` instruments `env.AI` on first + // property access: after `withSentry` has initialized the SDK, so `dataCollection.genAI` + // is visible when recording options are resolved. + const ai = instrumentWorkersAiClient(aiBinding); + const url = new URL(request.url); if (url.pathname === '/error') { diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/test.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/test.ts index ec6a051fd859..54710edcb67b 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/test.ts @@ -1,5 +1,4 @@ import { - GEN_AI_INPUT_MESSAGES, GEN_AI_OPERATION_NAME, GEN_AI_OUTPUT_MESSAGES, GEN_AI_PROVIDER_NAME, @@ -8,16 +7,12 @@ import { GEN_AI_REQUEST_TEMPERATURE, GEN_AI_RESPONSE_STREAMING, GEN_AI_RESPONSE_TEXT, - GEN_AI_SYSTEM_INSTRUCTIONS, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_TOTAL_TOKENS, } from '@sentry/conventions/attributes'; import { expect, it } from 'vitest'; -import { - GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, - GEN_AI_REQUEST_STREAM_ATTRIBUTE, -} from '../../../../../packages/core/src/tracing/ai/gen-ai-attributes'; +import { GEN_AI_REQUEST_STREAM_ATTRIBUTE } from '../../../../../packages/core/src/tracing/ai/gen-ai-attributes'; import { createRunner } from '../../../runner'; // These tests are not exhaustive because the instrumentation is @@ -60,10 +55,7 @@ it('traces a basic Workers AI text generation request', async ({ signal }) => { [GEN_AI_USAGE_INPUT_TOKENS]: 12, [GEN_AI_USAGE_OUTPUT_TOKENS]: 7, [GEN_AI_USAGE_TOTAL_TOKENS]: 19, - // collect input and output messages - [GEN_AI_SYSTEM_INSTRUCTIONS]: '[{"type":"text","content":"You are a helpful assistant."}]', - [GEN_AI_INPUT_MESSAGES]: '[{"role":"user","content":"What is the capital of France?"}]', - [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: 1, + // collect only output messages [GEN_AI_OUTPUT_MESSAGES]: '[{"role":"assistant","parts":[{"type":"text","content":"The capital of France is Paris."}]}]', [GEN_AI_RESPONSE_TEXT]: 'The capital of France is Paris.', @@ -112,9 +104,7 @@ it('traces a streaming Workers AI text generation request', async ({ signal }) = [GEN_AI_USAGE_INPUT_TOKENS]: 12, [GEN_AI_USAGE_OUTPUT_TOKENS]: 7, [GEN_AI_USAGE_TOTAL_TOKENS]: 19, - [GEN_AI_INPUT_MESSAGES]: '[{"role":"user","content":"What is the capital of France?"}]', - [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: 1, - // Accumulated from the streamed chunks rather than read off a single response body. + // collect only output [GEN_AI_OUTPUT_MESSAGES]: '[{"role":"assistant","parts":[{"type":"text","content":"The capital of France is Paris."}]}]', [GEN_AI_RESPONSE_TEXT]: 'The capital of France is Paris.', diff --git a/packages/core/test/lib/tracing/workers-ai.test.ts b/packages/core/test/lib/tracing/workers-ai.test.ts index 78e5dc79fe2f..a044fb6ac1d9 100644 --- a/packages/core/test/lib/tracing/workers-ai.test.ts +++ b/packages/core/test/lib/tracing/workers-ai.test.ts @@ -1,13 +1,49 @@ +import { + GEN_AI_INPUT_MESSAGES, + GEN_AI_OPERATION_NAME, + GEN_AI_OUTPUT_MESSAGES, + GEN_AI_PROVIDER_NAME, + GEN_AI_REQUEST_MODEL, + GEN_AI_RESPONSE_TEXT, + GEN_AI_SYSTEM_INSTRUCTIONS, +} from '@sentry/conventions/attributes'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { getCurrentScope, getGlobalScope, getIsolationScope, setCurrentClient, startSpan } from '../../../src'; +import type { Span } from '../../../src'; +import { + getCurrentScope, + getGlobalScope, + getIsolationScope, + SEMANTIC_ATTRIBUTE_SENTRY_OP, + SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, + SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, + SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, + setCurrentClient, + startSpan, +} from '../../../src'; +import { GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE } from '../../../src/tracing/ai/gen-ai-attributes'; import { addVercelAiProcessors } from '../../../src/tracing/vercel-ai'; import { AI_OPERATION_ID_ATTRIBUTE } from '../../../src/tracing/vercel-ai/vercel-ai-attributes'; import { instrumentWorkersAiClient } from '../../../src/tracing/workers-ai'; +import type { DataCollection } from '../../../src/types/datacollection'; import { _INTERNAL_clearAiProviderSkips } from '../../../src/utils/ai/providerSkip'; import { spanToJSON } from '../../../src/utils/spanUtils'; import { getDefaultTestClientOptions, TestClient } from '../../mocks/client'; +const MODEL = '@cf/meta/llama-3.1-8b-instruct'; + describe('instrumentWorkersAiClient', () => { + beforeEach(() => { + getCurrentScope().clear(); + getIsolationScope().clear(); + getGlobalScope().clear(); + }); + + afterEach(() => { + getCurrentScope().clear(); + getIsolationScope().clear(); + getGlobalScope().clear(); + }); + it('passes through non-run methods bound to the original client', () => { class FakeAi { #internal = 'secret'; @@ -29,17 +65,119 @@ describe('instrumentWorkersAiClient', () => { const client = { run: vi.fn().mockResolvedValue({ response: 'Paris' }) }; const instrumented = instrumentWorkersAiClient(client); - const result = await instrumented.run('@cf/meta/llama-3.1-8b-instruct', { prompt: 'Hello' }); + const result = await instrumented.run(MODEL, { prompt: 'Hello' }); - expect(client.run).toHaveBeenCalledWith('@cf/meta/llama-3.1-8b-instruct', { prompt: 'Hello' }); + expect(client.run).toHaveBeenCalledWith(MODEL, { prompt: 'Hello' }); expect(result).toEqual({ response: 'Paris' }); }); + describe('message recording', () => { + /** + * Attributes recorded regardless of the `genAI` data collection settings. Sample rate and source + * are on here because the `run` call is the root span in these tests, with no active parent. + */ + const ALWAYS_RECORDED = { + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ai.cloudflare.workers_ai', + [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'gen_ai.chat', + [SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1, + [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'custom', + [GEN_AI_PROVIDER_NAME]: 'cloudflare.workers_ai', + [GEN_AI_OPERATION_NAME]: 'chat', + [GEN_AI_REQUEST_MODEL]: MODEL, + }; + + /** Everything gated behind `recordInputs`. The system message is split into its own attribute. */ + const PROMPT_ATTRIBUTES = { + [GEN_AI_SYSTEM_INSTRUCTIONS]: '[{"type":"text","content":"Answer in one word."}]', + [GEN_AI_INPUT_MESSAGES]: '[{"role":"user","content":"Capital of France?"}]', + [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: 1, + }; + + /** Everything gated behind `recordOutputs`. */ + const RESPONSE_ATTRIBUTES = { + [GEN_AI_OUTPUT_MESSAGES]: '[{"role":"assistant","parts":[{"type":"text","content":"Paris"}]}]', + [GEN_AI_RESPONSE_TEXT]: 'Paris', + }; + + function setupClient(dataCollection?: DataCollection): Span[] { + const client = new TestClient( + getDefaultTestClientOptions({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + tracesSampleRate: 1, + dataCollection, + }), + ); + setCurrentClient(client); + client.init(); + + const endedSpans: Span[] = []; + client.on('spanEnd', span => endedSpans.push(span)); + return endedSpans; + } + + // `@sentry/cloudflare` instruments the `env.AI` binding on first property access, which happens + // inside the request — after `withSentry` has initialized the SDK. These cases wrap in that same + // order so `dataCollection.genAI` is readable when recording options are resolved. + it.each([ + { + name: 'collects prompts and responses when dataCollection is unset', + dataCollection: undefined, + options: undefined, + expected: { ...ALWAYS_RECORDED, ...PROMPT_ATTRIBUTES, ...RESPONSE_ATTRIBUTES }, + }, + { + name: 'omits prompts and responses when dataCollection.genAI disables both', + dataCollection: { genAI: { inputs: false, outputs: false } }, + options: undefined, + expected: ALWAYS_RECORDED, + }, + { + name: 'records prompts only when dataCollection.genAI enables inputs alone', + dataCollection: { genAI: { inputs: true, outputs: false } }, + options: undefined, + expected: { ...ALWAYS_RECORDED, ...PROMPT_ATTRIBUTES }, + }, + { + name: 'records responses only when dataCollection.genAI enables outputs alone', + dataCollection: { genAI: { inputs: false, outputs: true } }, + options: undefined, + expected: { ...ALWAYS_RECORDED, ...RESPONSE_ATTRIBUTES }, + }, + { + name: 'defaults the unspecified half of dataCollection.genAI to collecting', + dataCollection: { genAI: { inputs: false } }, + options: undefined, + expected: { ...ALWAYS_RECORDED, ...RESPONSE_ATTRIBUTES }, + }, + { + name: 'prefers explicit recording options over dataCollection.genAI', + dataCollection: { genAI: { inputs: true, outputs: true } }, + options: { recordInputs: false, recordOutputs: false }, + expected: ALWAYS_RECORDED, + }, + ])('$name', async ({ dataCollection, options, expected }) => { + const endedSpans = setupClient(dataCollection); + + const client = { run: vi.fn().mockResolvedValue({ response: 'Paris' }) }; + const instrumented = instrumentWorkersAiClient(client, options); + + await instrumented.run(MODEL, { + messages: [ + { role: 'system', content: 'Answer in one word.' }, + { role: 'user', content: 'Capital of France?' }, + ], + }); + + expect(endedSpans).toHaveLength(1); + expect(spanToJSON(endedSpans[0]!).data).toEqual(expected); + }); + }); + describe('when the Vercel AI SDK drives the binding', () => { let spans: string[]; /** Set up a client with the Vercel AI processors registered, recording every ended span. */ - function setupClient(): void { + function setupVercelAiClient(): void { getCurrentScope().clear(); getIsolationScope().clear(); getGlobalScope().clear(); @@ -55,7 +193,7 @@ describe('instrumentWorkersAiClient', () => { beforeEach(() => { _INTERNAL_clearAiProviderSkips(); - setupClient(); + setupVercelAiClient(); }); afterEach(() => { @@ -79,11 +217,11 @@ describe('instrumentWorkersAiClient', () => { const client = { run: vi.fn().mockResolvedValue({ response: 'Paris' }) }; const instrumented = instrumentWorkersAiClient(client); - await withVercelAiModelCall(() => instrumented.run('@cf/meta/llama-3.1-8b-instruct', { prompt: 'Hello' })); + await withVercelAiModelCall(() => instrumented.run(MODEL, { prompt: 'Hello' })); // The call is forwarded, but no duplicate `gen_ai.chat` span is emitted — only the // Vercel AI model-call span remains. - expect(client.run).toHaveBeenCalledWith('@cf/meta/llama-3.1-8b-instruct', { prompt: 'Hello' }); + expect(client.run).toHaveBeenCalledWith(MODEL, { prompt: 'Hello' }); expect(spans).not.toContain('chat @cf/meta/llama-3.1-8b-instruct'); expect(spans).toEqual(['streamText.doStream']); }); @@ -92,9 +230,9 @@ describe('instrumentWorkersAiClient', () => { const client = { run: vi.fn().mockResolvedValue({ response: 'Paris' }) }; const instrumented = instrumentWorkersAiClient(client); - await startSpan({ name: 'root' }, () => instrumented.run('@cf/meta/llama-3.1-8b-instruct', { prompt: 'Hello' })); + await startSpan({ name: 'root' }, () => instrumented.run(MODEL, { prompt: 'Hello' })); - expect(spans).toContain('chat @cf/meta/llama-3.1-8b-instruct'); + expect(spans).toEqual([`chat ${MODEL}`, 'root']); }); it('clears the skip between clients so a later isolate reuse is unaffected', async () => { @@ -102,17 +240,17 @@ describe('instrumentWorkersAiClient', () => { const instrumented = instrumentWorkersAiClient(client); // First request: the `ai` SDK runs and marks Workers AI as skipped. - await withVercelAiModelCall(() => instrumented.run('@cf/meta/llama-3.1-8b-instruct', { prompt: 'Hello' })); - expect(spans).not.toContain('chat @cf/meta/llama-3.1-8b-instruct'); + await withVercelAiModelCall(() => instrumented.run(MODEL, { prompt: 'Hello' })); + expect(spans).toEqual(['streamText.doStream']); // Second request on the same isolate: `_setupIntegrations` resets the registry, so a direct // `env.AI.run` call must get its span back. Without the reset this would stay suppressed. _INTERNAL_clearAiProviderSkips(); - setupClient(); + setupVercelAiClient(); - await startSpan({ name: 'root' }, () => instrumented.run('@cf/meta/llama-3.1-8b-instruct', { prompt: 'Hello' })); + await startSpan({ name: 'root' }, () => instrumented.run(MODEL, { prompt: 'Hello' })); - expect(spans).toContain('chat @cf/meta/llama-3.1-8b-instruct'); + expect(spans).toEqual([`chat ${MODEL}`, 'root']); }); }); }); From ffad96de9c943955f3c5f96a00d0c4785c2b3381 Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Wed, 29 Jul 2026 12:08:26 +0200 Subject: [PATCH 6/7] fix conflicts --- .../suites/tracing/anthropic-ai/index.ts | 1 - .../suites/tracing/google-genai/index.ts | 1 - .../suites/tracing/openai/index.ts | 1 - .../suites/tracing/workers-ai/index.ts | 3 - .../suites/tracing/workers-ai/test.ts | 114 ++++++++---------- .../src/index.ts | 1 - 6 files changed, 48 insertions(+), 73 deletions(-) diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/index.ts index ca09e5d54c0a..4bec21ba206b 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/index.ts @@ -27,7 +27,6 @@ export default Sentry.withSentry( traceLifecycle: 'static', tracesSampleRate: 1.0, dataCollection: { genAI: { inputs: true, outputs: true } }, - streamGenAiSpans: true, }), { async fetch(_request, _env, _ctx) { diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/index.ts index 3cfa9b9ac157..2b809fd9767a 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/index.ts @@ -45,7 +45,6 @@ export default Sentry.withSentry( traceLifecycle: 'static', tracesSampleRate: 1.0, dataCollection: { genAI: { inputs: true } }, - streamGenAiSpans: true, }), { async fetch(_request, _env, _ctx) { diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/openai/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/openai/index.ts index 209497909346..6b9cb7ee2bed 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/openai/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/openai/index.ts @@ -32,7 +32,6 @@ export default Sentry.withSentry( traceLifecycle: 'static', tracesSampleRate: 1.0, dataCollection: { genAI: { inputs: true, outputs: false } }, - streamGenAiSpans: true, }), { async fetch(_request, _env, _ctx) { diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts index b657edeb1fc0..60755738eccb 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts @@ -18,9 +18,6 @@ export default Sentry.withSentry( // Responses only. Asserting that prompts are *absent* is what makes this suite fail if the // binding is ever wrapped before the SDK is initialized again, since the fallback collects both. dataCollection: { genAI: { inputs: false, outputs: true } }, - // Keep gen_ai spans embedded in the transaction (instead of streamed as a - // separate envelope container) so they can be asserted on `transaction.spans`. - streamGenAiSpans: false, }), { async fetch(request) { diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/test.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/test.ts index 8ccfb65ea117..ec0b82cd69bc 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/test.ts @@ -32,39 +32,30 @@ it('traces a basic Workers AI text generation request', async ({ signal }) => { expect(container.items[0]).toEqual( expect.objectContaining({ - type: 'transaction', - transaction: 'GET /', - transaction_info: { source: 'route' }, - contexts: expect.objectContaining({ - trace: expect.objectContaining({ - op: 'http.server', - origin: 'auto.http.cloudflare', - status: 'ok', - }), - }), - spans: [ - expect.objectContaining({ - description: 'chat @cf/meta/llama-3.1-8b-instruct', - op: 'gen_ai.chat', - origin: 'auto.ai.cloudflare.workers_ai', - data: { - 'sentry.origin': 'auto.ai.cloudflare.workers_ai', - 'sentry.op': 'gen_ai.chat', - [GEN_AI_PROVIDER_NAME]: 'cloudflare.workers_ai', - [GEN_AI_OPERATION_NAME]: 'chat', - [GEN_AI_REQUEST_MODEL]: '@cf/meta/llama-3.1-8b-instruct', - [GEN_AI_REQUEST_TEMPERATURE]: 0.7, - [GEN_AI_REQUEST_MAX_TOKENS]: 100, - [GEN_AI_USAGE_INPUT_TOKENS]: 12, - [GEN_AI_USAGE_OUTPUT_TOKENS]: 7, - [GEN_AI_USAGE_TOTAL_TOKENS]: 19, - // collect only output messages - [GEN_AI_OUTPUT_MESSAGES]: - '[{"role":"assistant","parts":[{"type":"text","content":"The capital of France is Paris."}]}]', - [GEN_AI_RESPONSE_TEXT]: 'The capital of France is Paris.', - }, - }), - ], + name: 'chat @cf/meta/llama-3.1-8b-instruct', + status: 'ok', + is_segment: false, + attributes: { + 'sentry.origin': { value: 'auto.ai.cloudflare.workers_ai', type: 'string' }, + 'sentry.op': { value: 'gen_ai.chat', type: 'string' }, + [GEN_AI_PROVIDER_NAME]: { value: 'cloudflare.workers_ai', type: 'string' }, + [GEN_AI_OPERATION_NAME]: { value: 'chat', type: 'string' }, + [GEN_AI_REQUEST_MODEL]: { value: '@cf/meta/llama-3.1-8b-instruct', type: 'string' }, + [GEN_AI_REQUEST_TEMPERATURE]: { value: 0.7, type: 'double' }, + [GEN_AI_REQUEST_MAX_TOKENS]: { value: 100, type: 'integer' }, + [GEN_AI_USAGE_INPUT_TOKENS]: { value: 12, type: 'integer' }, + [GEN_AI_USAGE_OUTPUT_TOKENS]: { value: 7, type: 'integer' }, + [GEN_AI_USAGE_TOTAL_TOKENS]: { value: 19, type: 'integer' }, + // collect only output messages + [GEN_AI_OUTPUT_MESSAGES]: { + type: 'string', + value: '[{"role":"assistant","parts":[{"type":"text","content":"The capital of France is Paris."}]}]', + }, + [GEN_AI_RESPONSE_TEXT]: { + type: 'string', + value: 'The capital of France is Paris.', + }, + }, }), ); }) @@ -86,39 +77,30 @@ it('traces a streaming Workers AI text generation request', async ({ signal }) = expect(container.items[0]).toEqual( expect.objectContaining({ - type: 'transaction', - transaction: 'GET /stream', - transaction_info: { source: 'url' }, - contexts: expect.objectContaining({ - trace: expect.objectContaining({ - op: 'http.server', - origin: 'auto.http.cloudflare', - status: 'ok', - }), - }), - spans: [ - expect.objectContaining({ - description: 'chat @cf/meta/llama-3.1-8b-instruct', - op: 'gen_ai.chat', - origin: 'auto.ai.cloudflare.workers_ai', - data: { - 'sentry.origin': 'auto.ai.cloudflare.workers_ai', - 'sentry.op': 'gen_ai.chat', - [GEN_AI_PROVIDER_NAME]: 'cloudflare.workers_ai', - [GEN_AI_OPERATION_NAME]: 'chat', - [GEN_AI_REQUEST_MODEL]: '@cf/meta/llama-3.1-8b-instruct', - [GEN_AI_REQUEST_STREAM_ATTRIBUTE]: true, - [GEN_AI_RESPONSE_STREAMING]: true, - [GEN_AI_USAGE_INPUT_TOKENS]: 12, - [GEN_AI_USAGE_OUTPUT_TOKENS]: 7, - [GEN_AI_USAGE_TOTAL_TOKENS]: 19, - // collect only output - [GEN_AI_OUTPUT_MESSAGES]: - '[{"role":"assistant","parts":[{"type":"text","content":"The capital of France is Paris."}]}]', - [GEN_AI_RESPONSE_TEXT]: 'The capital of France is Paris.', - }, - }), - ], + name: 'chat @cf/meta/llama-3.1-8b-instruct', + status: 'ok', + is_segment: false, + attributes: { + 'sentry.origin': { value: 'auto.ai.cloudflare.workers_ai', type: 'string' }, + 'sentry.op': { value: 'gen_ai.chat', type: 'string' }, + [GEN_AI_PROVIDER_NAME]: { value: 'cloudflare.workers_ai', type: 'string' }, + [GEN_AI_OPERATION_NAME]: { value: 'chat', type: 'string' }, + [GEN_AI_REQUEST_MODEL]: { value: '@cf/meta/llama-3.1-8b-instruct', type: 'string' }, + [GEN_AI_REQUEST_STREAM_ATTRIBUTE]: { value: true, type: 'boolean' }, + [GEN_AI_RESPONSE_STREAMING]: { value: true, type: 'boolean' }, + [GEN_AI_USAGE_INPUT_TOKENS]: { value: 12, type: 'integer' }, + [GEN_AI_USAGE_OUTPUT_TOKENS]: { value: 7, type: 'integer' }, + [GEN_AI_USAGE_TOTAL_TOKENS]: { value: 19, type: 'integer' }, + // collect only output + [GEN_AI_OUTPUT_MESSAGES]: { + type: 'string', + value: '[{"role":"assistant","parts":[{"type":"text","content":"The capital of France is Paris."}]}]', + }, + [GEN_AI_RESPONSE_TEXT]: { + type: 'string', + value: 'The capital of France is Paris.', + }, + }, }), ); }) diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-vercelai-v7-compat/src/index.ts b/dev-packages/e2e-tests/test-applications/cloudflare-vercelai-v7-compat/src/index.ts index f23b39611e43..daae29d1dd53 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-vercelai-v7-compat/src/index.ts +++ b/dev-packages/e2e-tests/test-applications/cloudflare-vercelai-v7-compat/src/index.ts @@ -9,7 +9,6 @@ export default Sentry.withSentry( environment: 'qa', tunnel: 'http://localhost:3031/', tracesSampleRate: 1.0, - streamGenAiSpans: false, dataCollection: { genAI: { inputs: false, outputs: false } }, integrations: [Sentry.vercelAIIntegration()], }), From 473de0506c8b84595647fccaef5f5de7b7eb27cb Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Wed, 29 Jul 2026 12:23:56 +0200 Subject: [PATCH 7/7] remove undefined key --- .../suites/tracing/anthropic-ai/test.ts | 2 -- .../suites/tracing/google-genai/test.ts | 3 --- .../cloudflare-integration-tests/suites/tracing/openai/test.ts | 2 -- packages/core/test/lib/tracing/workers-ai.test.ts | 2 -- 4 files changed, 9 deletions(-) diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/test.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/test.ts index 7c97b1709782..77e4269e40b6 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/anthropic-ai/test.ts @@ -13,7 +13,6 @@ import { GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_TOTAL_TOKENS, } from '@sentry/conventions/attributes'; -import { GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE } from '../../../../../packages/core/src/tracing/ai/gen-ai-attributes'; import { createRunner } from '../../../runner'; // This test runs the `@anthropic-ai/sdk` on the Workers runtime (with a @@ -53,7 +52,6 @@ it('traces a basic message creation request with the anthropic SDK', async ({ si value: '[{"role":"user","content":"What is the capital of France?"}]', type: 'string', }, - [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: { value: 1, type: 'integer' }, [GEN_AI_RESPONSE_TEXT]: { value: 'Hello from Anthropic!', type: 'string' }, [GEN_AI_RESPONSE_ID]: { value: 'msg_mock123', type: 'string' }, [GEN_AI_RESPONSE_MODEL]: { value: 'claude-3-haiku-20240307', type: 'string' }, diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/test.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/test.ts index b44a962de465..e98f0a68bf0a 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/google-genai/test.ts @@ -14,7 +14,6 @@ import { GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_TOTAL_TOKENS, } from '@sentry/conventions/attributes'; -import { GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE } from '../../../../../packages/core/src/tracing/ai/gen-ai-attributes'; import { createRunner } from '../../../runner'; // This test runs the `@google/genai` SDK on the Workers runtime (with a @@ -51,7 +50,6 @@ it('traces Google GenAI chat, generateContent, and embedContent calls', async ({ [GEN_AI_OPERATION_NAME]: { value: 'chat', type: 'string' }, [GEN_AI_REQUEST_MODEL]: { value: 'gemini-1.5-pro', type: 'string' }, // collect LLM input and outputs (default true) - [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: { value: 1, type: 'integer' }, [GEN_AI_INPUT_MESSAGES]: { value: '[{"role":"user","content":"Tell me a joke"}]', type: 'string' }, [GEN_AI_RESPONSE_TEXT]: { value: 'Hello from Google GenAI!', type: 'string' }, [GEN_AI_USAGE_INPUT_TOKENS]: { value: 8, type: 'integer' }, @@ -78,7 +76,6 @@ it('traces Google GenAI chat, generateContent, and embedContent calls', async ({ [GEN_AI_REQUEST_TEMPERATURE]: { value: 0.7, type: 'double' }, [GEN_AI_REQUEST_TOP_P]: { value: 0.9, type: 'double' }, [GEN_AI_REQUEST_MAX_TOKENS]: { value: 100, type: 'integer' }, - [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: { value: 1, type: 'integer' }, [GEN_AI_INPUT_MESSAGES]: { value: '[{"role":"user","parts":[{"text":"What is the capital of France?"}]}]', type: 'string', diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/openai/test.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/openai/test.ts index 027d11935b76..5675bfa7a080 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/openai/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/openai/test.ts @@ -13,7 +13,6 @@ import { GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_TOTAL_TOKENS, } from '@sentry/conventions/attributes'; -import { GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE } from '../../../../../packages/core/src/tracing/ai/gen-ai-attributes'; import { createRunner } from '../../../runner'; // This test runs the `openai` SDK on the Workers runtime (with a canned @@ -56,7 +55,6 @@ it('traces a basic chat completion request with the openai SDK', async ({ signal value: '[{"role":"user","content":"What is the capital of France?"}]', type: 'string', }, - [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: { value: 1, type: 'integer' }, [GEN_AI_RESPONSE_ID]: { value: 'chatcmpl-mock123', type: 'string' }, [GEN_AI_RESPONSE_MODEL]: { value: 'gpt-3.5-turbo', type: 'string' }, [GEN_AI_USAGE_INPUT_TOKENS]: { value: 10, type: 'integer' }, diff --git a/packages/core/test/lib/tracing/workers-ai.test.ts b/packages/core/test/lib/tracing/workers-ai.test.ts index a044fb6ac1d9..e0fefb2ac2b4 100644 --- a/packages/core/test/lib/tracing/workers-ai.test.ts +++ b/packages/core/test/lib/tracing/workers-ai.test.ts @@ -20,7 +20,6 @@ import { setCurrentClient, startSpan, } from '../../../src'; -import { GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE } from '../../../src/tracing/ai/gen-ai-attributes'; import { addVercelAiProcessors } from '../../../src/tracing/vercel-ai'; import { AI_OPERATION_ID_ATTRIBUTE } from '../../../src/tracing/vercel-ai/vercel-ai-attributes'; import { instrumentWorkersAiClient } from '../../../src/tracing/workers-ai'; @@ -90,7 +89,6 @@ describe('instrumentWorkersAiClient', () => { const PROMPT_ATTRIBUTES = { [GEN_AI_SYSTEM_INSTRUCTIONS]: '[{"type":"text","content":"Answer in one word."}]', [GEN_AI_INPUT_MESSAGES]: '[{"role":"user","content":"Capital of France?"}]', - [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: 1, }; /** Everything gated behind `recordOutputs`. */