diff --git a/packages/agents-a365-observability/src/tracing/constants.ts b/packages/agents-a365-observability/src/tracing/constants.ts index 162c91a2..3301212d 100644 --- a/packages/agents-a365-observability/src/tracing/constants.ts +++ b/packages/agents-a365-observability/src/tracing/constants.ts @@ -102,6 +102,7 @@ export class OpenTelemetryConstants { public static readonly GEN_AI_EXECUTION_SOURCE_ID_KEY = 'gen_ai.execution.sourceMetadata.id'; public static readonly GEN_AI_EXECUTION_SOURCE_NAME_KEY = 'gen_ai.channel.name'; public static readonly GEN_AI_EXECUTION_SOURCE_DESCRIPTION_KEY = 'gen_ai.channel.link'; + public static readonly GEN_AI_EXECUTION_SOURCE_SUBCHANNEL_KEY = 'gen_ai.channel.subchannel'; // Custom parent id and parent name key public static readonly CUSTOM_PARENT_SPAN_ID_KEY = 'custom.parent.span.id'; diff --git a/packages/agents-a365-observability/src/tracing/contracts.ts b/packages/agents-a365-observability/src/tracing/contracts.ts index a2db33cd..322dd9ba 100644 --- a/packages/agents-a365-observability/src/tracing/contracts.ts +++ b/packages/agents-a365-observability/src/tracing/contracts.ts @@ -64,6 +64,9 @@ export interface SourceMetadata { /** Optional description providing additional context about the source */ description?: string; + + /** Optional subchannel identifier */ + subchannel?: string; } /** diff --git a/packages/agents-a365-observability/src/tracing/middleware/BaggageBuilder.ts b/packages/agents-a365-observability/src/tracing/middleware/BaggageBuilder.ts index d7feb434..0d66f6fd 100644 --- a/packages/agents-a365-observability/src/tracing/middleware/BaggageBuilder.ts +++ b/packages/agents-a365-observability/src/tracing/middleware/BaggageBuilder.ts @@ -219,6 +219,16 @@ export class BaggageBuilder { return this; } + /** + * Set the execution source metadata subchannel. + * @param value The source metadata subchannel + * @returns Self for method chaining + */ + sourceMetadataSubchannel(value: string | null | undefined): BaggageBuilder { + this.set(OpenTelemetryConstants.GEN_AI_EXECUTION_SOURCE_SUBCHANNEL_KEY, value); + return this; + } + /** * Set multiple baggage pairs from a dictionary or iterable. * @param pairs Dictionary or iterable of key-value pairs diff --git a/packages/agents-a365-observability/src/tracing/processors/util.ts b/packages/agents-a365-observability/src/tracing/processors/util.ts index 4b960dae..8d5f33d7 100644 --- a/packages/agents-a365-observability/src/tracing/processors/util.ts +++ b/packages/agents-a365-observability/src/tracing/processors/util.ts @@ -47,4 +47,5 @@ export const INVOKE_AGENT_ATTRIBUTES: readonly string[] = [ consts.GEN_AI_EXECUTION_SOURCE_ID_KEY, consts.GEN_AI_EXECUTION_SOURCE_NAME_KEY, consts.GEN_AI_EXECUTION_SOURCE_DESCRIPTION_KEY, + consts.GEN_AI_EXECUTION_SOURCE_SUBCHANNEL_KEY, ]; diff --git a/packages/agents-a365-observability/src/tracing/scopes/InvokeAgentScope.ts b/packages/agents-a365-observability/src/tracing/scopes/InvokeAgentScope.ts index 0d6b2807..68c43737 100644 --- a/packages/agents-a365-observability/src/tracing/scopes/InvokeAgentScope.ts +++ b/packages/agents-a365-observability/src/tracing/scopes/InvokeAgentScope.ts @@ -71,6 +71,7 @@ export class InvokeAgentScope extends OpenTelemetryScope { this.setTagMaybe(OpenTelemetryConstants.GEN_AI_EXECUTION_SOURCE_ID_KEY, requestToUse.sourceMetadata.id); this.setTagMaybe(OpenTelemetryConstants.GEN_AI_EXECUTION_SOURCE_NAME_KEY, requestToUse.sourceMetadata.name); this.setTagMaybe(OpenTelemetryConstants.GEN_AI_EXECUTION_SOURCE_DESCRIPTION_KEY, requestToUse.sourceMetadata.description); + this.setTagMaybe(OpenTelemetryConstants.GEN_AI_EXECUTION_SOURCE_SUBCHANNEL_KEY, requestToUse.sourceMetadata.subchannel); } } diff --git a/packages/agents-a365-observability/src/tracing/scopes/OpenTelemetryScope.ts b/packages/agents-a365-observability/src/tracing/scopes/OpenTelemetryScope.ts index 71370153..44f0abc2 100644 --- a/packages/agents-a365-observability/src/tracing/scopes/OpenTelemetryScope.ts +++ b/packages/agents-a365-observability/src/tracing/scopes/OpenTelemetryScope.ts @@ -169,5 +169,4 @@ export abstract class OpenTelemetryScope implements Disposable { public dispose(): void { this[Symbol.dispose](); } - } diff --git a/tests/observability/core/BaggageBuilder.test.ts b/tests/observability/core/BaggageBuilder.test.ts index e3afd04a..e90ecde4 100644 --- a/tests/observability/core/BaggageBuilder.test.ts +++ b/tests/observability/core/BaggageBuilder.test.ts @@ -154,6 +154,16 @@ describe('BaggageBuilder', () => { }); }); + describe('metadata support', () => { + it('should set source metadata subchannel', () => { + const scope = new BaggageBuilder() + .sourceMetadataSubchannel('sub-A') + .build(); + const bag = propagation.getBaggage((scope as any).contextWithBaggage); + expect(bag?.getEntry(OpenTelemetryConstants.GEN_AI_EXECUTION_SOURCE_SUBCHANNEL_KEY)?.value).toBe('sub-A'); + }); + }); + }); describe('BaggageScope', () => { diff --git a/tests/observability/core/scopes.test.ts b/tests/observability/core/scopes.test.ts index f99ce01d..d9ee7296 100644 --- a/tests/observability/core/scopes.test.ts +++ b/tests/observability/core/scopes.test.ts @@ -122,6 +122,25 @@ describe('Scopes', () => { expect(() => scope?.recordError(error)).not.toThrow(); scope?.dispose(); }); + + it('should accept sourceMetadata attributes without error', () => { + const invokeAgentDetails: InvokeAgentDetails = { + agentId: 'test-agent', + request: { + content: 'hello', + sourceMetadata: { + id: 'chan-123', + name: 'RootChannel', + description: 'Primary channel', + subchannel: 'thread-7' + } + } + }; + expect(() => { + const scope = InvokeAgentScope.start(invokeAgentDetails, testTenantDetails); + scope?.dispose(); + }).not.toThrow(); + }); }); describe('ExecuteToolScope', () => {