Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/agents-a365-observability/src/tracing/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,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_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';
public static readonly GEN_AI_CONVERSATION_ITEM_LINK_KEY = 'gen_ai.conversation.item.link';
public static readonly GEN_AI_TOKEN_TYPE_KEY = 'gen_ai.token.type';
Expand Down Expand Up @@ -79,6 +80,7 @@ export class OpenTelemetryConstants {
public static readonly GEN_AI_CALLER_AGENT_ID_KEY = 'gen_ai.caller.agent.id';
public static readonly GEN_AI_CALLER_AGENT_APPLICATION_ID_KEY = 'gen_ai.caller.agent.applicationid';
public static readonly GEN_AI_CALLER_AGENT_CLIENT_IP_KEY = 'gen_ai.caller.agent.user.client.ip';
public static readonly GEN_AI_CALLER_AGENT_PLATFORM_ID_KEY = 'gen_ai.caller.agent.platformid';
// Agent-specific dimensions
public static readonly AGENT_ID_KEY = 'gen_ai.agent.id';
public static readonly GEN_AI_TASK_ID_KEY = 'gen_ai.task.id';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ export interface AgentDetails {

/** Optional icon identifier or URL for visual representation of the agent */
iconUri?: string;

/** Optional platform identifier for the agent */
platformId?: string;

/** The agent user ID (AUID) */
agentAUID?: string;
Expand Down Expand Up @@ -172,7 +175,7 @@ export interface CallerDetails {
callerClientIp?: string;
}

/**
/*
* @deprecated Use AgentDetails. EnhancedAgentDetails is now an alias of AgentDetails.
*/
export type EnhancedAgentDetails = AgentDetails;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,16 @@ export class BaggageBuilder {
return this;
}

/**
* Set the agent platform ID baggage value.
* @param value The agent platform ID
* @returns Self for method chaining
*/
agentPlatformId(value: string | null | undefined): BaggageBuilder {
this.set(OpenTelemetryConstants.GEN_AI_AGENT_PLATFORM_ID_KEY, value);
return this;
}

/**
* Set the session description baggage value.
* @param value The session description
Expand Down Expand Up @@ -179,11 +189,28 @@ export class BaggageBuilder {
return this;
}

/**
* Set the caller client IP baggage value.
* Used to capture the originating client IP for the request
* so it can be propagated via OpenTelemetry baggage.
* @param value The caller client IP address
* @returns Self for method chaining
*/
callerClientIp(value: string | null | undefined): BaggageBuilder {
this.set(OpenTelemetryConstants.GEN_AI_CALLER_CLIENT_IP_KEY, value);
return this;
}

/**
* Set the caller agent platform ID baggage value.
* @param value The caller agent platform identifier
* @returns Self for method chaining
*/
callerAgentPlatformId(value: string | null | undefined): BaggageBuilder {
this.set(OpenTelemetryConstants.GEN_AI_CALLER_AGENT_PLATFORM_ID_KEY, value);
return this;
}

/**
* Set the conversation ID baggage value.
* @param value The conversation ID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const GENERIC_ATTRIBUTES: readonly string[] = [
consts.GEN_AI_AGENT_UPN_KEY,
consts.GEN_AI_AGENT_BLUEPRINT_ID_KEY,
consts.GEN_AI_AGENT_AUID_KEY,
consts.GEN_AI_AGENT_PLATFORM_ID_KEY,
];

/**
Expand All @@ -44,6 +45,7 @@ export const INVOKE_AGENT_ATTRIBUTES: readonly string[] = [
consts.GEN_AI_CALLER_AGENT_TENANT_ID_KEY,
consts.GEN_AI_CALLER_AGENT_APPLICATION_ID_KEY,
consts.GEN_AI_CALLER_AGENT_CLIENT_IP_KEY,
consts.GEN_AI_CALLER_AGENT_PLATFORM_ID_KEY,
// Execution context
consts.GEN_AI_EXECUTION_TYPE_KEY,
consts.GEN_AI_EXECUTION_SOURCE_ID_KEY,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export class InvokeAgentScope extends OpenTelemetryScope {
this.setTagMaybe(OpenTelemetryConstants.GEN_AI_CALLER_AGENT_UPN_KEY, callerAgentDetails.agentUPN);
this.setTagMaybe(OpenTelemetryConstants.GEN_AI_CALLER_AGENT_TENANT_ID_KEY, callerAgentDetails.tenantId);
this.setTagMaybe(OpenTelemetryConstants.GEN_AI_CALLER_AGENT_CLIENT_IP_KEY, callerAgentDetails.agentClientIP);
this.setTagMaybe(OpenTelemetryConstants.GEN_AI_CALLER_AGENT_PLATFORM_ID_KEY, callerAgentDetails.platformId);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export abstract class OpenTelemetryScope implements Disposable {
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_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);
this.setTagMaybe(OpenTelemetryConstants.GEN_AI_ICON_URI_KEY, agentDetails.iconUri);
this.setTagMaybe(OpenTelemetryConstants.GEN_AI_AGENT_AUID_KEY, agentDetails.agentAUID);
Expand Down
23 changes: 23 additions & 0 deletions tests/observability/core/BaggageBuilder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,34 @@ describe('BaggageBuilder', () => {
.agentId('agent-456')
.correlationId('corr-789')
.agentName('TestAgent')
.agentPlatformId('platform-xyz-123')
.conversationId('conv-001');

const scope = builder.build();
expect(scope).toBeInstanceOf(BaggageScope);
});

it('should set agent platform ID', () => {
const builder = new BaggageBuilder();
builder.agentPlatformId('platform-abc-456');

const scope = builder.build();
expect(scope).toBeInstanceOf(BaggageScope);

const bag = propagation.getBaggage((scope as any).contextWithBaggage);
expect(bag?.getEntry(OpenTelemetryConstants.GEN_AI_AGENT_PLATFORM_ID_KEY)?.value).toBe('platform-abc-456');
});

it('should set caller agent platform ID via fluent API', () => {
const builder = new BaggageBuilder();
builder.callerAgentPlatformId('caller-platform-xyz');

const scope = builder.build();
expect(scope).toBeInstanceOf(BaggageScope);

const bag = propagation.getBaggage((scope as any).contextWithBaggage);
expect(bag?.getEntry(OpenTelemetryConstants.GEN_AI_CALLER_AGENT_PLATFORM_ID_KEY)?.value).toBe('caller-platform-xyz');
});
});

describe('setPairs', () => {
Expand Down
59 changes: 59 additions & 0 deletions tests/observability/core/scopes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,19 @@ describe('Scopes', () => {
scope?.dispose();
});

it('should create scope with platformId', () => {
const invokeAgentDetails: InvokeAgentDetails = {
agentId: 'test-agent',
agentName: 'Test Agent',
platformId: 'platform-xyz-123'
};

const scope = InvokeAgentScope.start(invokeAgentDetails, testTenantDetails);

expect(scope).toBeInstanceOf(InvokeAgentScope);
scope?.dispose();
});

it('should create scope with caller details', () => {
const invokeAgentDetails: InvokeAgentDetails = {
agentId: 'test-agent',
Expand Down Expand Up @@ -125,6 +138,52 @@ describe('Scopes', () => {
scope?.dispose();
});

it('should propagate platformId in span attributes', () => {
const spy = jest.spyOn(OpenTelemetryScope.prototype as any, 'setTagMaybe');
const invokeAgentDetails: InvokeAgentDetails = {
agentId: 'test-agent',
agentName: 'Test Agent',
platformId: 'test-platform-123'
};

const scope = InvokeAgentScope.start(invokeAgentDetails, testTenantDetails);
expect(scope).toBeInstanceOf(InvokeAgentScope);

const calls = spy.mock.calls.map(args => ({ key: args[0], val: args[1] }));
expect(calls).toEqual(expect.arrayContaining([
expect.objectContaining({ key: OpenTelemetryConstants.GEN_AI_AGENT_PLATFORM_ID_KEY, val: 'test-platform-123' })
]));

scope?.dispose();
spy.mockRestore();
});

it('should propagate caller agent platformId in span attributes', () => {
const spy = jest.spyOn(OpenTelemetryScope.prototype as any, 'setTagMaybe');
const invokeAgentDetails: InvokeAgentDetails = {
agentId: 'test-agent',
agentName: 'Test Agent'
};
const callerAgentDetails: AgentDetails = {
agentId: 'caller-agent',
agentName: 'Caller Agent',
agentDescription: 'desc',
conversationId: 'conv',
platformId: 'caller-platform-xyz'
} as any;

const scope = InvokeAgentScope.start(invokeAgentDetails, testTenantDetails, callerAgentDetails, undefined);
expect(scope).toBeInstanceOf(InvokeAgentScope);

const calls = spy.mock.calls.map(args => ({ key: args[0], val: args[1] }));
expect(calls).toEqual(expect.arrayContaining([
expect.objectContaining({ key: OpenTelemetryConstants.GEN_AI_CALLER_AGENT_PLATFORM_ID_KEY, val: 'caller-platform-xyz' })
]));

scope?.dispose();
spy.mockRestore();
});

it('should set caller and caller-agent IP tags', () => {
const spy = jest.spyOn(OpenTelemetryScope.prototype as any, 'setTagMaybe');
const invokeAgentDetails: InvokeAgentDetails = {
Expand Down