From 90e94beff44ac6a748c1ff207ee54b3b104cfb9a Mon Sep 17 00:00:00 2001 From: Nicolas Hrubec Date: Tue, 6 Oct 2026 11:11:43 +0200 Subject: [PATCH 1/4] test(node): Port Bedrock tests to span streaming Co-Authored-By: GPT-6 --- .../suites/aws-serverless/bedrock/instrument.mjs | 1 - .../suites/aws-serverless/bedrock/test.ts | 10 ++++------ 2 files changed, 4 insertions(+), 7 deletions(-) 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 14dbd52b3824..dcfc5fc614ed 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 @@ -2,7 +2,6 @@ import * as Sentry from '@sentry/aws-serverless'; import { loggingTransport } from '@sentry-internal/node-integration-tests'; Sentry.init({ - traceLifecycle: 'static', dsn: 'https://public@dsn.ingest.sentry.io/1337', release: '1.0', tracesSampleRate: 1.0, diff --git a/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts b/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts index af7e80bd10b2..25e5ac37103b 100644 --- a/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts +++ b/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts @@ -5,6 +5,9 @@ import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runn const MODEL_ID = 'anthropic.claude-3-5-sonnet-20240620-v1:0'; function assertBedrockSpans(container: SerializedStreamedSpanContainer): void { + const segment = container.items.find(span => span.is_segment && span.name === 'Test Transaction'); + expect(segment).toBeDefined(); + // Converse (non-streaming) const converseSpan = container.items.find(span => span.name === `chat ${MODEL_ID}`); expect(converseSpan).toBeDefined(); @@ -49,12 +52,7 @@ describe('awsIntegration - Bedrock', () => { 'instrument.mjs', (createTestRunner, test) => { test('auto-instruments Bedrock Converse and InvokeModel', { timeout: 90_000 }, async () => { - await createTestRunner() - .ignore('event') - .expect({ transaction: transaction => expect(transaction.transaction).toBe('Test Transaction') }) - .expect({ span: assertBedrockSpans }) - .start() - .completed(); + await createTestRunner().ignore('event').expect({ span: assertBedrockSpans }).start().completed(); }); }, { additionalDependencies: { '@aws-sdk/client-bedrock-runtime': '^3.1046.0' } }, From 023262159e1eae3518f354a64102cd5fad5c94cc Mon Sep 17 00:00:00 2001 From: Nicolas Hrubec Date: Tue, 6 Oct 2026 11:25:14 +0200 Subject: [PATCH 2/4] test(node): Remove redundant bedrock assertions Co-Authored-By: GPT-6 --- .../suites/aws-serverless/bedrock/test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts b/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts index 25e5ac37103b..f4cf97e8ee2d 100644 --- a/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts +++ b/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts @@ -10,7 +10,6 @@ function assertBedrockSpans(container: SerializedStreamedSpanContainer): void { // Converse (non-streaming) const converseSpan = container.items.find(span => span.name === `chat ${MODEL_ID}`); - expect(converseSpan).toBeDefined(); expect(converseSpan!.status).toBe('ok'); expect(converseSpan!.attributes['sentry.origin'].value).toBe('auto.aws.aws_sdk'); expect(converseSpan!.attributes['sentry.op'].value).toBe('gen_ai.chat'); @@ -26,7 +25,6 @@ function assertBedrockSpans(container: SerializedStreamedSpanContainer): void { // InvokeModel (non-streaming, anthropic.claude request/response body) const invokeModelSpan = container.items.find(span => span.name === `generate_content ${MODEL_ID}`); - expect(invokeModelSpan).toBeDefined(); expect(invokeModelSpan!.status).toBe('ok'); expect(invokeModelSpan!.attributes['sentry.origin'].value).toBe('auto.aws.aws_sdk'); expect(invokeModelSpan!.attributes['sentry.op'].value).toBe('gen_ai.generate_content'); From 89fa63811e53616956d8c34f34c09337171a94aa Mon Sep 17 00:00:00 2001 From: Nicolas Hrubec Date: Tue, 6 Oct 2026 12:06:55 +0200 Subject: [PATCH 3/4] test(node): Use the SENTRY_ORIGIN convention in bedrock tests Co-Authored-By: GPT-6 --- .../suites/aws-serverless/bedrock/test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts b/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts index f4cf97e8ee2d..aeffdd099721 100644 --- a/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts +++ b/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts @@ -1,3 +1,4 @@ +import { SENTRY_ORIGIN } from '@sentry/conventions/attributes'; import type { SerializedStreamedSpanContainer } from '@sentry/core'; import { afterAll, describe, expect } from 'vitest'; import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; @@ -11,7 +12,7 @@ function assertBedrockSpans(container: SerializedStreamedSpanContainer): void { // Converse (non-streaming) const converseSpan = container.items.find(span => span.name === `chat ${MODEL_ID}`); expect(converseSpan!.status).toBe('ok'); - expect(converseSpan!.attributes['sentry.origin'].value).toBe('auto.aws.aws_sdk'); + expect(converseSpan!.attributes[SENTRY_ORIGIN].value).toBe('auto.aws.aws_sdk'); expect(converseSpan!.attributes['sentry.op'].value).toBe('gen_ai.chat'); expect(converseSpan!.attributes['gen_ai.provider.name'].value).toBe('aws.bedrock'); expect(converseSpan!.attributes['gen_ai.operation.name'].value).toBe('chat'); @@ -26,7 +27,7 @@ function assertBedrockSpans(container: SerializedStreamedSpanContainer): void { // InvokeModel (non-streaming, anthropic.claude request/response body) const invokeModelSpan = container.items.find(span => span.name === `generate_content ${MODEL_ID}`); expect(invokeModelSpan!.status).toBe('ok'); - expect(invokeModelSpan!.attributes['sentry.origin'].value).toBe('auto.aws.aws_sdk'); + expect(invokeModelSpan!.attributes[SENTRY_ORIGIN].value).toBe('auto.aws.aws_sdk'); expect(invokeModelSpan!.attributes['sentry.op'].value).toBe('gen_ai.generate_content'); expect(invokeModelSpan!.attributes['gen_ai.provider.name'].value).toBe('aws.bedrock'); expect(invokeModelSpan!.attributes['gen_ai.operation.name'].value).toBe('generate_content'); From 19b55eede32441b31437db69c4e009a7634ccb04 Mon Sep 17 00:00:00 2001 From: Nicolas Hrubec Date: Tue, 6 Oct 2026 12:12:52 +0200 Subject: [PATCH 4/4] test(node): Use convention constants for bedrock span attributes Co-Authored-By: GPT-6 --- .../suites/aws-serverless/bedrock/test.ts | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts b/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts index aeffdd099721..a7bc374499b4 100644 --- a/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts +++ b/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts @@ -1,4 +1,16 @@ -import { SENTRY_ORIGIN } from '@sentry/conventions/attributes'; +import { + GEN_AI_OPERATION_NAME, + GEN_AI_PROVIDER_NAME, + GEN_AI_REQUEST_MAX_TOKENS, + GEN_AI_REQUEST_MODEL, + GEN_AI_REQUEST_TEMPERATURE, + GEN_AI_REQUEST_TOP_P, + GEN_AI_RESPONSE_FINISH_REASONS, + GEN_AI_USAGE_INPUT_TOKENS, + GEN_AI_USAGE_OUTPUT_TOKENS, + SENTRY_OP, + SENTRY_ORIGIN, +} from '@sentry/conventions/attributes'; import type { SerializedStreamedSpanContainer } from '@sentry/core'; import { afterAll, describe, expect } from 'vitest'; import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; @@ -13,31 +25,31 @@ function assertBedrockSpans(container: SerializedStreamedSpanContainer): void { const converseSpan = container.items.find(span => span.name === `chat ${MODEL_ID}`); expect(converseSpan!.status).toBe('ok'); expect(converseSpan!.attributes[SENTRY_ORIGIN].value).toBe('auto.aws.aws_sdk'); - expect(converseSpan!.attributes['sentry.op'].value).toBe('gen_ai.chat'); - expect(converseSpan!.attributes['gen_ai.provider.name'].value).toBe('aws.bedrock'); - expect(converseSpan!.attributes['gen_ai.operation.name'].value).toBe('chat'); - expect(converseSpan!.attributes['gen_ai.request.model'].value).toBe(MODEL_ID); - expect(converseSpan!.attributes['gen_ai.request.max_tokens'].value).toBe(100); - expect(converseSpan!.attributes['gen_ai.request.temperature'].value).toBe(0.5); - expect(converseSpan!.attributes['gen_ai.request.top_p'].value).toBe(0.9); - expect(converseSpan!.attributes['gen_ai.usage.input_tokens'].value).toBe(12); - expect(converseSpan!.attributes['gen_ai.usage.output_tokens'].value).toBe(8); - expect(converseSpan!.attributes['gen_ai.response.finish_reasons'].value).toEqual(['end_turn']); + expect(converseSpan!.attributes[SENTRY_OP].value).toBe('gen_ai.chat'); + expect(converseSpan!.attributes[GEN_AI_PROVIDER_NAME].value).toBe('aws.bedrock'); + expect(converseSpan!.attributes[GEN_AI_OPERATION_NAME].value).toBe('chat'); + expect(converseSpan!.attributes[GEN_AI_REQUEST_MODEL].value).toBe(MODEL_ID); + expect(converseSpan!.attributes[GEN_AI_REQUEST_MAX_TOKENS].value).toBe(100); + expect(converseSpan!.attributes[GEN_AI_REQUEST_TEMPERATURE].value).toBe(0.5); + expect(converseSpan!.attributes[GEN_AI_REQUEST_TOP_P].value).toBe(0.9); + expect(converseSpan!.attributes[GEN_AI_USAGE_INPUT_TOKENS].value).toBe(12); + expect(converseSpan!.attributes[GEN_AI_USAGE_OUTPUT_TOKENS].value).toBe(8); + expect(converseSpan!.attributes[GEN_AI_RESPONSE_FINISH_REASONS].value).toEqual(['end_turn']); // InvokeModel (non-streaming, anthropic.claude request/response body) const invokeModelSpan = container.items.find(span => span.name === `generate_content ${MODEL_ID}`); expect(invokeModelSpan!.status).toBe('ok'); expect(invokeModelSpan!.attributes[SENTRY_ORIGIN].value).toBe('auto.aws.aws_sdk'); - expect(invokeModelSpan!.attributes['sentry.op'].value).toBe('gen_ai.generate_content'); - expect(invokeModelSpan!.attributes['gen_ai.provider.name'].value).toBe('aws.bedrock'); - expect(invokeModelSpan!.attributes['gen_ai.operation.name'].value).toBe('generate_content'); - expect(invokeModelSpan!.attributes['gen_ai.request.model'].value).toBe(MODEL_ID); - expect(invokeModelSpan!.attributes['gen_ai.request.max_tokens'].value).toBe(100); - expect(invokeModelSpan!.attributes['gen_ai.request.temperature'].value).toBe(0.5); - expect(invokeModelSpan!.attributes['gen_ai.request.top_p'].value).toBe(0.9); - expect(invokeModelSpan!.attributes['gen_ai.usage.input_tokens'].value).toBe(15); - expect(invokeModelSpan!.attributes['gen_ai.usage.output_tokens'].value).toBe(9); - expect(invokeModelSpan!.attributes['gen_ai.response.finish_reasons'].value).toEqual(['end_turn']); + expect(invokeModelSpan!.attributes[SENTRY_OP].value).toBe('gen_ai.generate_content'); + expect(invokeModelSpan!.attributes[GEN_AI_PROVIDER_NAME].value).toBe('aws.bedrock'); + expect(invokeModelSpan!.attributes[GEN_AI_OPERATION_NAME].value).toBe('generate_content'); + expect(invokeModelSpan!.attributes[GEN_AI_REQUEST_MODEL].value).toBe(MODEL_ID); + expect(invokeModelSpan!.attributes[GEN_AI_REQUEST_MAX_TOKENS].value).toBe(100); + expect(invokeModelSpan!.attributes[GEN_AI_REQUEST_TEMPERATURE].value).toBe(0.5); + expect(invokeModelSpan!.attributes[GEN_AI_REQUEST_TOP_P].value).toBe(0.9); + expect(invokeModelSpan!.attributes[GEN_AI_USAGE_INPUT_TOKENS].value).toBe(15); + expect(invokeModelSpan!.attributes[GEN_AI_USAGE_OUTPUT_TOKENS].value).toBe(9); + expect(invokeModelSpan!.attributes[GEN_AI_RESPONSE_FINISH_REASONS].value).toEqual(['end_turn']); } describe('awsIntegration - Bedrock', () => {