Use Activity helpers and ResolveAgentIdentity for agent telemetry#211
Use Activity helpers and ResolveAgentIdentity for agent telemetry#211
Conversation
Replace direct ChannelAccount property access with Activity class helpers (getAgenticInstanceId, getAgenticUser, getAgenticTenantId) in ScopeUtils and TurnContextUtils. Use RuntimeUtility.ResolveAgentIdentity for blueprint ID resolution when authToken is provided, falling back to recipient.agenticAppBlueprintId. Add authToken parameter with overloaded signatures (required + deprecated no-arg) for backward compatibility. Upgrade @microsoft/agents-hosting and agents-activity to ^1.3.1. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This pull request refactors agent telemetry collection to use Activity class helper methods instead of direct ChannelAccount property access, adds authentication token-based agent identity resolution, and upgrades key dependencies. The changes aim to improve blueprint ID resolution for telemetry and standardize how agent identity information is extracted from TurnContext.
Changes:
- Replace direct ChannelAccount property access with Activity helper methods (
getAgenticInstanceId(),getAgenticUser(),getAgenticTenantId()) - Add
authTokenparameter to telemetry scope population methods with TypeScript overloads for backward compatibility - Upgrade
@microsoft/agents-hostingand@microsoft/agents-activityfrom alpha to stable release (1.3.1)
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-workspace.yaml | Updates catalog versions for agents-hosting and agents-activity to 1.3.1 |
| pnpm-lock.yaml | Reflects dependency upgrades including msal-node 5.0.4, axios 1.13.5, jwks-rsa 3.2.2, and @types/express 5.0.6 |
| packages/agents-a365-observability-hosting/src/utils/ScopeUtils.ts | Adds authToken parameter with overloads to scope population methods; uses RuntimeUtility.ResolveAgentIdentity for blueprint resolution; switches to Activity helpers |
| packages/agents-a365-observability-hosting/src/utils/TurnContextUtils.ts | Replaces direct property access with getAgenticInstanceId() and getAgenticTenantId() helpers; removes channelData tenant ID fallback |
| tests/observability/extension/hosting/scope-utils.test.ts | Updates test fixtures to use Activity helper methods and removes agenticAppBlueprintId from recipient to test undefined fallback |
| tests/observability/extension/hosting/TurnContextUtils.test.ts | Updates test fixtures to use Activity helpers and adjusts assertions to expect undefined for aadObjectId and agenticAppBlueprintId |
| tests/observability/extension/hosting/BaggageBuilderUtils.test.ts | Updates test fixtures to use Activity helpers and adjusts baggage assertions to expect undefined values |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
| const agentBlueprintId = authToken | ||
| ? RuntimeUtility.ResolveAgentIdentity(turnContext, authToken) | ||
| : recipient.agenticAppBlueprintId; |
There was a problem hiding this comment.
RuntimeUtility.ResolveAgentIdentity returns the app ID, not the blueprint ID, so it should not be used to populate agentBlueprintId. According to the utility.ts documentation, ResolveAgentIdentity returns "Agent identity (App ID)" by calling either getAgenticInstanceId() or GetAppIdFromToken() (which uses appid or azp claims). To get the blueprint ID from the token, you should use RuntimeUtility.getAgentIdFromToken(authToken) instead, which checks the xms_par_app_azp claim (the actual blueprint ID claim). This bug will result in incorrect telemetry data being recorded for agent blueprint identification.
packages/agents-a365-observability-hosting/src/utils/ScopeUtils.ts
Outdated
Show resolved
Hide resolved
| /** | ||
| * Derive target agent details from the activity recipient. | ||
| * Uses {@link RuntimeUtility.ResolveAgentIdentity} to resolve the agent identity (Blueprint vs App) | ||
| * when an auth token is provided; otherwise falls back to recipient.agenticAppBlueprintId. |
There was a problem hiding this comment.
The JSDoc comment states that ResolveAgentIdentity is used to "resolve the agent identity (Blueprint vs App)", but this is inaccurate. ResolveAgentIdentity only returns the App ID, not the Blueprint ID. The comment should be corrected to accurately reflect what the method does, or the implementation should be changed to use RuntimeUtility.getAgentIdFromToken if the Blueprint ID is actually needed (which is what the variable name agentBlueprintId suggests).
…atures - Extract deriveAgentDetailsCore and buildInvokeAgentDetailsCore as private methods so internal callers bypass deprecated overloads (fixes @typescript-eslint/no-deprecated lint errors) - Remove `public` from implementation signatures of overloaded methods (only the two declared overloads should be public-facing) - Fix stale JSDoc on getTenantIdPair (removed ChannelData reference) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| private static deriveAgentDetailsCore(turnContext: TurnContext, authToken?: string): AgentDetails | undefined { | ||
| const recipient = turnContext?.activity?.recipient; | ||
| if (!recipient) return undefined; | ||
| const agentBlueprintId = authToken |
There was a problem hiding this comment.
Nit: its not aways a blueprintID.
There was a problem hiding this comment.
changed to use getAgentIdFromToken
| if (!recipient) return undefined; | ||
| const agentBlueprintId = authToken | ||
| ? RuntimeUtility.ResolveAgentIdentity(turnContext, authToken) | ||
| : recipient.agenticAppBlueprintId; |
There was a problem hiding this comment.
You should not use this property ever.. this can and will be spoofed,
if you are trying to resolve an appID for an app that does not have user auth, then we should work this out based on the default connection or active connection to the upstream, or support Guid.empty here.
| endTime?: TimeInput | ||
| ): ExecuteToolScope { | ||
| const agent = ScopeUtils.deriveAgentDetails(turnContext); | ||
| const agent = ScopeUtils.deriveAgentDetailsCore(turnContext, authToken); |
There was a problem hiding this comment.
Where are you getting the authtoken here? Im am worried about it becoming stale over time.
There was a problem hiding this comment.
The developer needs to provide the agent uer token when calling the method.
…token blueprint claim for agentBlueprintId - agentId now uses ResolveAgentIdentity (works for both app-based and blueprint agents) - agentBlueprintId now reads xms_par_app_azp from token for blueprint agents - Remove deprecated overloads and backward-compat code, authToken is now required - Consolidate deriveAgentDetailsCore into deriveAgentDetails Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| const recipient = turnContext?.activity?.recipient; | ||
| if (!recipient) return undefined; | ||
| const agentId = RuntimeUtility.ResolveAgentIdentity(turnContext, authToken); | ||
| const agentBlueprintId = turnContext?.activity?.isAgenticRequest() |
There was a problem hiding this comment.
no. Based on the implementation of method, if it is blueprint case, it will call getAgenticInstanceId() which returns recipient.agenticAppId not blueprintId.
…adoption Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Summary
ScopeUtils.deriveAgentDetailsnow usesRuntimeUtility.ResolveAgentIdentity()foragentId(works for both app-based and blueprint-based agents) instead ofrecipient.agenticAppIdwhich only worked for blueprint agents.agentBlueprintIdis now resolved from the JWTxms_par_app_azpclaim viaRuntimeUtility.getAgentIdFromToken()for agentic requests, instead of incorrectly using the instance ID.ChannelAccountproperty access with Activity helpers (getAgenticInstanceId(),getAgenticUser(),getAgenticTenantId()) inScopeUtilsandTurnContextUtils.channelDatatenant ID fallback ingetTenantIdPair()— now usesgetAgenticTenantId().@microsoft/agents-hostingand@microsoft/agents-activityfrom^1.1.0-alpha.85to^1.3.1.Breaking Changes
ScopeUtils.deriveAgentDetails(turnContext, authToken)— new requiredauthTokenparameter.ScopeUtils.populateInferenceScopeFromTurnContext(details, turnContext, authToken, ...)— new requiredauthTokenparameter.ScopeUtils.populateInvokeAgentScopeFromTurnContext(details, turnContext, authToken, ...)— new requiredauthTokenparameter.ScopeUtils.populateExecuteToolScopeFromTurnContext(details, turnContext, authToken, ...)— new requiredauthTokenparameter.ScopeUtils.buildInvokeAgentDetails(details, turnContext, authToken)— new requiredauthTokenparameter.Test plan
pnpm buildsucceeds (including CJS + ESM for all packages)deriveAgentDetailsresolvesagentIdviaResolveAgentIdentity()andagentBlueprintIdviagetAgentIdFromToken()deriveTenantDetailsusesgetAgenticTenantId()helpergetTargetAgentBaggagePairsusesgetAgenticInstanceId()getTenantIdPairusesgetAgenticTenantId()🤖 Generated with Claude Code