Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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";
Comment thread
fpfp100 marked this conversation as resolved.
Outdated
// 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
6 changes: 6 additions & 0 deletions packages/agents-a365-observability/src/tracing/contracts.ts
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;
}

/**
Expand Down Expand Up @@ -175,6 +178,9 @@ export interface EnhancedAgentDetails extends AgentDetails {

/** The client IP address for the agent user */
agentClientIP?: string;

/** Optional platform identifier for the agent */
platformId?: string;
Comment thread
fpfp100 marked this conversation as resolved.
Outdated
Comment thread
fpfp100 marked this conversation as resolved.
Outdated
}

/**
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,29 @@ 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
*/

Comment thread
fpfp100 marked this conversation as resolved.
Outdated
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,8 @@ 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);

Comment thread
juliomenendez marked this conversation as resolved.
Outdated
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,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