Address valid review comments
Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
@@ -1055,6 +1055,37 @@ describe('McpService', () => {
|
||||
expect(options?.attributes).not.toHaveProperty('gen_ai.agent.id');
|
||||
});
|
||||
|
||||
it('threads baggage end-to-end from a propagated baggage header through context.with into the tool span', async () => {
|
||||
const tracing = tracingServiceMock.mock();
|
||||
// Simulate what the routers do on incoming requests: extract context
|
||||
// from headers and run the handler with that context active.
|
||||
const ctx = tracing.propagation.extract(tracing.context.active(), {
|
||||
baggage: 'gen_ai.conversation.id=conv-end-to-end',
|
||||
});
|
||||
await tracing.context.with(ctx, () => invokeMockAction({ tracing }));
|
||||
|
||||
const [, options] = tracing.startActiveSpan.mock.calls[0];
|
||||
expect(options?.attributes?.['gen_ai.conversation.id']).toBe(
|
||||
'conv-end-to-end',
|
||||
);
|
||||
});
|
||||
|
||||
it('truncates overlong baggage values before stamping them on the span', async () => {
|
||||
const tracing = tracingServiceMock.mock();
|
||||
const longValue = 'a'.repeat(1024);
|
||||
tracing.propagation.getActiveBaggage.mockReturnValue({
|
||||
getAllEntries: () => [['gen_ai.conversation.id', { value: longValue }]],
|
||||
});
|
||||
|
||||
await invokeMockAction({ tracing });
|
||||
|
||||
const [, options] = tracing.startActiveSpan.mock.calls[0];
|
||||
const recorded = options?.attributes?.['gen_ai.conversation.id'];
|
||||
expect(typeof recorded).toBe('string');
|
||||
expect((recorded as string).length).toBe(256);
|
||||
expect(recorded).toBe('a'.repeat(256));
|
||||
});
|
||||
|
||||
it('includes tool arguments in the span options and sets the structured action output as the result attribute when captureToolPayloads is true', async () => {
|
||||
const tracing = tracingServiceMock.mock();
|
||||
await invokeMockAction({ tracing, captureToolPayloads: true });
|
||||
|
||||
@@ -54,6 +54,12 @@ const PROPAGATED_BAGGAGE_ATTRIBUTES: ReadonlySet<string> = new Set([
|
||||
'gen_ai.request.model',
|
||||
]);
|
||||
|
||||
// Cap each forwarded baggage value before it lands on a span attribute.
|
||||
// Baggage values are caller-controlled strings of unbounded length;
|
||||
// allowlisting keys protects against arbitrary attribute names but not
|
||||
// against pathologically large values inflating exported span sizes.
|
||||
const BAGGAGE_ATTRIBUTE_VALUE_MAX_LENGTH = 256;
|
||||
|
||||
function baggageAttributes(
|
||||
tracingService: TracingService,
|
||||
): Record<string, string> {
|
||||
@@ -62,7 +68,7 @@ function baggageAttributes(
|
||||
const attrs: Record<string, string> = {};
|
||||
for (const [key, entry] of baggage.getAllEntries()) {
|
||||
if (PROPAGATED_BAGGAGE_ATTRIBUTES.has(key)) {
|
||||
attrs[key] = entry.value;
|
||||
attrs[key] = entry.value.slice(0, BAGGAGE_ATTRIBUTE_VALUE_MAX_LENGTH);
|
||||
}
|
||||
}
|
||||
return attrs;
|
||||
@@ -219,6 +225,11 @@ export class McpService {
|
||||
}
|
||||
|
||||
// Re-attribute the span to the plugin that owns the action.
|
||||
// This runs after the span has started, so head-based samplers
|
||||
// still see the default `mcp-actions` value when deciding
|
||||
// whether to record the span. The pluginId is only known after
|
||||
// resolving the action via `actions.list`, so the reattribution
|
||||
// is unavoidable.
|
||||
span.setAttribute('backstage.plugin.id', action.pluginId);
|
||||
|
||||
const { output } = await this.actions.invoke({
|
||||
|
||||
Reference in New Issue
Block a user