diff --git a/packages/agents-a365-observability-hosting/src/utils/TurnContextUtils.ts b/packages/agents-a365-observability-hosting/src/utils/TurnContextUtils.ts index dd548c7..981d4ea 100644 --- a/packages/agents-a365-observability-hosting/src/utils/TurnContextUtils.ts +++ b/packages/agents-a365-observability-hosting/src/utils/TurnContextUtils.ts @@ -77,12 +77,12 @@ export function getTargetAgentBaggagePairs(turnContext: TurnContext): Array<[str const agentId = recipient.agenticAppId; const agentName = recipient.name; const aadObjectId = recipient.aadObjectId; - const agentDescription = recipient.role; + const agentDescription = recipient.role; const pairs: Array<[string, string | undefined]> = [ [OpenTelemetryConstants.GEN_AI_AGENT_ID_KEY, agentId], [OpenTelemetryConstants.GEN_AI_AGENT_NAME_KEY, agentName], + [OpenTelemetryConstants.GEN_AI_AGENT_DESCRIPTION_KEY, agentDescription], [OpenTelemetryConstants.GEN_AI_AGENT_AUID_KEY, aadObjectId], - [OpenTelemetryConstants.GEN_AI_AGENT_DESCRIPTION_KEY, agentDescription] ]; return normalizePairs(pairs); } diff --git a/packages/agents-a365-observability/src/tracing/constants.ts b/packages/agents-a365-observability/src/tracing/constants.ts index bc7426a..0b3eb67 100644 --- a/packages/agents-a365-observability/src/tracing/constants.ts +++ b/packages/agents-a365-observability/src/tracing/constants.ts @@ -41,6 +41,7 @@ export class OpenTelemetryConstants { public static readonly GEN_AI_AGENT_ID_KEY = 'gen_ai.agent.id'; public static readonly GEN_AI_AGENT_NAME_KEY = 'gen_ai.agent.name'; + public static readonly GEN_AI_AGENT_TYPE_KEY = 'gen_ai.agent.type'; public static readonly GEN_AI_AGENT_DESCRIPTION_KEY = 'gen_ai.agent.description'; public static readonly GEN_AI_AGENT_PLATFORM_ID_KEY = 'gen_ai.agent.platformid'; public static readonly GEN_AI_CONVERSATION_ID_KEY = 'gen_ai.conversation.id'; diff --git a/packages/agents-a365-observability/src/tracing/contracts.ts b/packages/agents-a365-observability/src/tracing/contracts.ts index 320b0f7..d67521e 100644 --- a/packages/agents-a365-observability/src/tracing/contracts.ts +++ b/packages/agents-a365-observability/src/tracing/contracts.ts @@ -104,6 +104,9 @@ export interface AgentDetails { /** The human-readable name of the AI agent */ agentName?: string; + /** Optional type of the AI agent */ + agentType?: string; + /** A description of the AI agent's purpose or capabilities */ agentDescription?: string; diff --git a/packages/agents-a365-observability/src/tracing/middleware/BaggageBuilder.ts b/packages/agents-a365-observability/src/tracing/middleware/BaggageBuilder.ts index 1d49936..7a6f49f 100644 --- a/packages/agents-a365-observability/src/tracing/middleware/BaggageBuilder.ts +++ b/packages/agents-a365-observability/src/tracing/middleware/BaggageBuilder.ts @@ -139,6 +139,16 @@ export class BaggageBuilder { return this; } + /** + * Set the agent type baggage value. + * @param value The agent type + * @returns Self for method chaining + */ + agentType(value: string | null | undefined): BaggageBuilder { + this.set(OpenTelemetryConstants.GEN_AI_AGENT_TYPE_KEY, value); + return this; + } + /** * Set the agent description baggage value. * @param value The agent description diff --git a/packages/agents-a365-observability/src/tracing/processors/util.ts b/packages/agents-a365-observability/src/tracing/processors/util.ts index ed0e729..0ef02f5 100644 --- a/packages/agents-a365-observability/src/tracing/processors/util.ts +++ b/packages/agents-a365-observability/src/tracing/processors/util.ts @@ -18,6 +18,7 @@ export const GENERIC_ATTRIBUTES: readonly string[] = [ consts.GEN_AI_OPERATION_NAME_KEY, consts.GEN_AI_AGENT_ID_KEY, consts.GEN_AI_AGENT_NAME_KEY, + consts.GEN_AI_AGENT_TYPE_KEY, consts.GEN_AI_AGENT_DESCRIPTION_KEY, consts.SESSION_DESCRIPTION_KEY, consts.GEN_AI_AGENT_USER_ID_KEY, diff --git a/packages/agents-a365-observability/src/tracing/scopes/OpenTelemetryScope.ts b/packages/agents-a365-observability/src/tracing/scopes/OpenTelemetryScope.ts index 7370fa1..407f501 100644 --- a/packages/agents-a365-observability/src/tracing/scopes/OpenTelemetryScope.ts +++ b/packages/agents-a365-observability/src/tracing/scopes/OpenTelemetryScope.ts @@ -54,6 +54,7 @@ export abstract class OpenTelemetryScope implements Disposable { if (agentDetails) { this.setTagMaybe(OpenTelemetryConstants.GEN_AI_AGENT_ID_KEY, agentDetails.agentId); this.setTagMaybe(OpenTelemetryConstants.GEN_AI_AGENT_NAME_KEY, agentDetails.agentName); + this.setTagMaybe(OpenTelemetryConstants.GEN_AI_AGENT_TYPE_KEY, agentDetails.agentType); this.setTagMaybe(OpenTelemetryConstants.GEN_AI_AGENT_DESCRIPTION_KEY, agentDetails.agentDescription); this.setTagMaybe(OpenTelemetryConstants.GEN_AI_AGENT_PLATFORM_ID_KEY, agentDetails.platformId); this.setTagMaybe(OpenTelemetryConstants.GEN_AI_CONVERSATION_ID_KEY, agentDetails.conversationId); diff --git a/tests/observability/core/BaggageBuilder.test.ts b/tests/observability/core/BaggageBuilder.test.ts index ac95547..b452277 100644 --- a/tests/observability/core/BaggageBuilder.test.ts +++ b/tests/observability/core/BaggageBuilder.test.ts @@ -39,6 +39,7 @@ describe('BaggageBuilder', () => { .agentId('agent-456') .correlationId('corr-789') .agentName('TestAgent') + .agentType('assistant') .agentPlatformId('platform-xyz-123') .conversationId('conv-001'); @@ -57,6 +58,17 @@ describe('BaggageBuilder', () => { expect(bag?.getEntry(OpenTelemetryConstants.GEN_AI_AGENT_PLATFORM_ID_KEY)?.value).toBe('platform-abc-456'); }); + it('should set agent type', () => { + const builder = new BaggageBuilder(); + builder.agentType('assistant'); + + const scope = builder.build(); + expect(scope).toBeInstanceOf(BaggageScope); + + const bag = propagation.getBaggage((scope as any).contextWithBaggage); + expect(bag?.getEntry(OpenTelemetryConstants.GEN_AI_AGENT_TYPE_KEY)?.value).toBe('assistant'); + }); + it('should set caller agent platform ID via fluent API', () => { const builder = new BaggageBuilder(); builder.callerAgentPlatformId('caller-platform-xyz'); diff --git a/tests/observability/extension/hosting/BaggageBuilderUtils.test.ts b/tests/observability/extension/hosting/BaggageBuilderUtils.test.ts index 11a048d..f6d6582 100644 --- a/tests/observability/extension/hosting/BaggageBuilderUtils.test.ts +++ b/tests/observability/extension/hosting/BaggageBuilderUtils.test.ts @@ -48,6 +48,7 @@ describe('BaggageBuilderUtils', () => { expect(asObj[OpenTelemetryConstants.GEN_AI_AGENT_ID_KEY]).toBe('agent-app-1'); expect(asObj[OpenTelemetryConstants.GEN_AI_AGENT_NAME_KEY]).toBe('Agent One'); expect(asObj[OpenTelemetryConstants.GEN_AI_AGENT_AUID_KEY]).toBe('aad-object-2'); + expect(asObj[OpenTelemetryConstants.GEN_AI_AGENT_DESCRIPTION_KEY]).toBe('agent'); expect(asObj[OpenTelemetryConstants.GEN_AI_AGENT_BLUEPRINT_ID_KEY]).toBe('blueprint-123'); expect(asObj[OpenTelemetryConstants.GEN_AI_AGENT_UPN_KEY]).toBe(undefined); expect(asObj[OpenTelemetryConstants.TENANT_ID_KEY]).toBe('tenant1'); diff --git a/tests/observability/extension/hosting/scope-utils.test.ts b/tests/observability/extension/hosting/scope-utils.test.ts index 049962c..876d282 100644 --- a/tests/observability/extension/hosting/scope-utils.test.ts +++ b/tests/observability/extension/hosting/scope-utils.test.ts @@ -45,7 +45,7 @@ function makeTurnContext( describe('ScopeUtils.populateFromTurnContext', () => { let spy: jest.SpyInstance; - beforeEach(() => { + beforeEach(() => { spy = jest.spyOn(OpenTelemetryScope.prototype as any, 'setTagMaybe'); }); @@ -53,7 +53,7 @@ describe('ScopeUtils.populateFromTurnContext', () => { spy.mockRestore(); }); - test('build InferenceScope based on turn context', () => { + test('build InferenceScope based on turn context', () => { const details = { operationName: 'inference', model: 'gpt-4o', providerName: 'openai' } as any; const ctx = makeTurnContext('input text', 'web', 'https://web', 'conv-A'); const scope = ScopeUtils.populateInferenceScopeFromTurnContext(details, ctx) as InferenceScope; @@ -64,8 +64,8 @@ describe('ScopeUtils.populateFromTurnContext', () => { [OpenTelemetryConstants.GEN_AI_CONVERSATION_ID_KEY, 'conv-A'], [OpenTelemetryConstants.GEN_AI_EXECUTION_SOURCE_NAME_KEY, 'web'], [OpenTelemetryConstants.GEN_AI_EXECUTION_SOURCE_DESCRIPTION_KEY, 'https://web'], - [OpenTelemetryConstants.GEN_AI_AGENT_NAME_KEY, 'Agent One'], - [OpenTelemetryConstants.GEN_AI_AGENT_AUID_KEY, 'agent-oid'], + [OpenTelemetryConstants.GEN_AI_AGENT_NAME_KEY, 'Agent One'], + [OpenTelemetryConstants.GEN_AI_AGENT_AUID_KEY, 'agent-oid'], [OpenTelemetryConstants.GEN_AI_AGENT_ID_KEY, 'agent-1'], [OpenTelemetryConstants.GEN_AI_AGENT_DESCRIPTION_KEY, 'assistant'], [OpenTelemetryConstants.TENANT_ID_KEY, 'tenant-123'], @@ -113,7 +113,7 @@ describe('ScopeUtils.populateFromTurnContext', () => { }); }); - test('build InvokeAgentScope based on turn context', () => { + test('build InvokeAgentScope based on turn context', () => { const details = { operationName: 'invoke', model: 'n/a', providerName: 'internal' } as any; const ctx = makeTurnContext('invoke message', 'teams', 'https://teams', 'conv-B'); ctx.activity.from!.role = RoleTypes.AgenticUser; @@ -162,7 +162,7 @@ describe('ScopeUtils.populateFromTurnContext', () => { [OpenTelemetryConstants.TENANT_ID_KEY, 'tenant-123'] ]) ); - scope?.dispose(); + scope?.dispose(); }); });