Skip to content

Commit fd07b23

Browse files
committed
feat(core): Disable gen_ai message truncation by default when streamGenAiSpans is enabled
Setting `streamGenAiSpans: true` now disables gen_ai input truncation by default. Because gen_ai spans are sent as v2 span envelope items, they are not subject to the transaction payload-size limits that truncation works around. Set `enableTruncation: true` on the respective AI integration to opt back into truncation.
1 parent 97d01f9 commit fd07b23

16 files changed

Lines changed: 241 additions & 53 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44

55
- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott
66

7+
### Important Changes
8+
9+
- feat(core): Disable gen_ai message truncation by default when `streamGenAiSpans` is enabled
10+
11+
Setting `streamGenAiSpans: true` now disables gen_ai input truncation by default. Because gen_ai spans are sent as v2 span envelope items, they are not subject to the transaction payload-size limits that truncation works around.
12+
13+
Set `enableTruncation: true` on the respective AI integration to opt back into truncation.
14+
715
## 10.58.0
816

917
### Important Changes
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import * as Sentry from '@sentry/node';
2+
import { loggingTransport } from '@sentry-internal/node-integration-tests';
3+
4+
Sentry.init({
5+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
6+
release: '1.0',
7+
tracesSampleRate: 1.0,
8+
dataCollection: { genAI: { inputs: true, outputs: true } },
9+
transport: loggingTransport,
10+
integrations: [Sentry.anthropicAIIntegration({ enableTruncation: true })],
11+
beforeSendTransaction: event => {
12+
// Filter out mock express server transactions
13+
if (event.transaction.includes('/anthropic/v1/')) {
14+
return null;
15+
}
16+
return event;
17+
},
18+
streamGenAiSpans: true,
19+
});

dev-packages/node-integration-tests/suites/tracing/anthropic/test.ts

Lines changed: 48 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ describe('Anthropic integration', () => {
606606
createEsmAndCjsTests(
607607
__dirname,
608608
'scenario-message-truncation.mjs',
609-
'instrument-with-pii.mjs',
609+
'instrument-with-truncation.mjs',
610610
(createRunner, test) => {
611611
test('truncates messages when they exceed byte limit - keeps only last message and crops it', async () => {
612612
await createRunner()
@@ -659,51 +659,56 @@ describe('Anthropic integration', () => {
659659
},
660660
);
661661

662-
createEsmAndCjsTests(__dirname, 'scenario-media-truncation.mjs', 'instrument-with-pii.mjs', (createRunner, test) => {
663-
test('truncates media attachment, keeping all other details', async () => {
664-
const expectedMediaMessages = JSON.stringify([
665-
{
666-
role: 'user',
667-
content: [
668-
{
669-
type: 'image',
670-
source: {
671-
type: 'base64',
672-
media_type: 'image/png',
673-
data: '[Blob substitute]',
662+
createEsmAndCjsTests(
663+
__dirname,
664+
'scenario-media-truncation.mjs',
665+
'instrument-with-truncation.mjs',
666+
(createRunner, test) => {
667+
test('truncates media attachment, keeping all other details', async () => {
668+
const expectedMediaMessages = JSON.stringify([
669+
{
670+
role: 'user',
671+
content: [
672+
{
673+
type: 'image',
674+
source: {
675+
type: 'base64',
676+
media_type: 'image/png',
677+
data: '[Blob substitute]',
678+
},
674679
},
675-
},
676-
],
677-
},
678-
]);
679-
await createRunner()
680-
.ignore('event')
681-
.expect({
682-
transaction: {
683-
transaction: 'main',
680+
],
684681
},
685-
})
686-
.expect({
687-
span: container => {
688-
expect(container.items).toHaveLength(1);
689-
const [firstSpan] = container.items;
682+
]);
683+
await createRunner()
684+
.ignore('event')
685+
.expect({
686+
transaction: {
687+
transaction: 'main',
688+
},
689+
})
690+
.expect({
691+
span: container => {
692+
expect(container.items).toHaveLength(1);
693+
const [firstSpan] = container.items;
690694

691-
// [0] messages.create with media attachment — image data replaced, other fields preserved
692-
expect(firstSpan!.name).toBe('chat claude-3-haiku-20240307');
693-
expect(firstSpan!.status).toBe('ok');
694-
expect(firstSpan!.attributes[GEN_AI_INPUT_MESSAGES_ATTRIBUTE].value).toBe(expectedMediaMessages);
695-
expect(firstSpan!.attributes[GEN_AI_OPERATION_NAME_ATTRIBUTE].value).toBe('chat');
696-
expect(firstSpan!.attributes['sentry.op'].value).toBe('gen_ai.chat');
697-
expect(firstSpan!.attributes['sentry.origin'].value).toBe('auto.ai.anthropic');
698-
expect(firstSpan!.attributes[GEN_AI_SYSTEM_ATTRIBUTE].value).toBe('anthropic');
699-
expect(firstSpan!.attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE].value).toBe('claude-3-haiku-20240307');
700-
expect(firstSpan!.attributes[GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE].value).toBe(2);
701-
},
702-
})
703-
.start()
704-
.completed();
705-
});
706-
});
695+
// [0] messages.create with media attachment — image data replaced, other fields preserved
696+
expect(firstSpan!.name).toBe('chat claude-3-haiku-20240307');
697+
expect(firstSpan!.status).toBe('ok');
698+
expect(firstSpan!.attributes[GEN_AI_INPUT_MESSAGES_ATTRIBUTE].value).toBe(expectedMediaMessages);
699+
expect(firstSpan!.attributes[GEN_AI_OPERATION_NAME_ATTRIBUTE].value).toBe('chat');
700+
expect(firstSpan!.attributes['sentry.op'].value).toBe('gen_ai.chat');
701+
expect(firstSpan!.attributes['sentry.origin'].value).toBe('auto.ai.anthropic');
702+
expect(firstSpan!.attributes[GEN_AI_SYSTEM_ATTRIBUTE].value).toBe('anthropic');
703+
expect(firstSpan!.attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE].value).toBe('claude-3-haiku-20240307');
704+
expect(firstSpan!.attributes[GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE].value).toBe(2);
705+
},
706+
})
707+
.start()
708+
.completed();
709+
});
710+
},
711+
);
707712

708713
createEsmAndCjsTests(
709714
__dirname,
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import * as Sentry from '@sentry/node';
2+
import { loggingTransport } from '@sentry-internal/node-integration-tests';
3+
4+
Sentry.init({
5+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
6+
release: '1.0',
7+
tracesSampleRate: 1.0,
8+
dataCollection: { genAI: { inputs: true, outputs: true } },
9+
transport: loggingTransport,
10+
integrations: [Sentry.googleGenAIIntegration({ enableTruncation: true })],
11+
beforeSendTransaction: event => {
12+
// Filter out mock express server transactions
13+
if (event.transaction.includes('/v1beta/')) {
14+
return null;
15+
}
16+
return event;
17+
},
18+
streamGenAiSpans: true,
19+
});

dev-packages/node-integration-tests/suites/tracing/google-genai/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ describe('Google GenAI integration', () => {
347347
createEsmAndCjsTests(
348348
__dirname,
349349
'scenario-message-truncation.mjs',
350-
'instrument-with-pii.mjs',
350+
'instrument-with-truncation.mjs',
351351
(createRunner, test) => {
352352
test('truncates messages when they exceed byte limit - keeps only last message and crops it', async () => {
353353
await createRunner()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import * as Sentry from '@sentry/node';
2+
import { loggingTransport } from '@sentry-internal/node-integration-tests';
3+
4+
Sentry.init({
5+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
6+
release: '1.0',
7+
tracesSampleRate: 1.0,
8+
dataCollection: { genAI: { inputs: true, outputs: true } },
9+
transport: loggingTransport,
10+
integrations: [Sentry.langChainIntegration({ enableTruncation: true })],
11+
beforeSendTransaction: event => {
12+
// Filter out mock express server transactions
13+
if (event.transaction.includes('/v1/messages') || event.transaction.includes('/v1/embeddings')) {
14+
return null;
15+
}
16+
return event;
17+
},
18+
streamGenAiSpans: true,
19+
});

dev-packages/node-integration-tests/suites/tracing/langchain/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ describe('LangChain integration', () => {
199199
createEsmAndCjsTests(
200200
__dirname,
201201
'scenario-message-truncation.mjs',
202-
'instrument-with-pii.mjs',
202+
'instrument-with-truncation.mjs',
203203
(createRunner, test) => {
204204
test('truncates messages when they exceed byte limit', async () => {
205205
await createRunner()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import * as Sentry from '@sentry/node';
2+
import { loggingTransport } from '@sentry-internal/node-integration-tests';
3+
4+
Sentry.init({
5+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
6+
release: '1.0',
7+
tracesSampleRate: 1.0,
8+
dataCollection: { genAI: { inputs: true, outputs: true } },
9+
transport: loggingTransport,
10+
integrations: [Sentry.langChainIntegration({ enableTruncation: true })],
11+
beforeSendTransaction: event => {
12+
// Filter out mock express server transactions
13+
if (event.transaction.includes('/v1/messages') || event.transaction.includes('/v1/chat/completions')) {
14+
return null;
15+
}
16+
return event;
17+
},
18+
streamGenAiSpans: true,
19+
});

dev-packages/node-integration-tests/suites/tracing/langchain/v1/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ conditionalTest({ min: 20 })('LangChain integration (v1)', () => {
216216
createEsmAndCjsTests(
217217
__dirname,
218218
'scenario-message-truncation.mjs',
219-
'instrument-with-pii.mjs',
219+
'instrument-with-truncation.mjs',
220220
(createRunner, test) => {
221221
test('truncates messages when they exceed byte limit', async () => {
222222
await createRunner()
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import * as Sentry from '@sentry/node';
2+
import { loggingTransport } from '@sentry-internal/node-integration-tests';
3+
4+
Sentry.init({
5+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
6+
release: '1.0',
7+
tracesSampleRate: 1.0,
8+
dataCollection: { genAI: { inputs: true, outputs: true } },
9+
transport: loggingTransport,
10+
integrations: [Sentry.openAIIntegration({ enableTruncation: true })],
11+
beforeSendTransaction: event => {
12+
if (event.transaction.includes('/openai/')) {
13+
return null;
14+
}
15+
return event;
16+
},
17+
streamGenAiSpans: true,
18+
});

0 commit comments

Comments
 (0)