Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This Agent 365 observability attribute reference is the canonical attribute-by-attribute spec used by the Agent 365 ingestion pipeline. Every span ingested by Agent 365 - whether emitted by the Microsoft OpenTelemetry Distro, the deprecated Agent 365 Observability SDK, or sent over direct OTel - must conform to it. Each entry lists the operation types the attribute applies to, whether it's mandatory, the field name your value lands in for advanced-hunting queries (where one exists), and the impact if you skip it.
If you use the SDK or the Distro, it records attributes from the agent, caller, request, and operation details you supply, along with context provided by instrumentation or baggage. It doesn't generate every required value for you. Supply the required context for your scenario, and use Picking values when a natural value isn't available. Some defaults aren't emitted explicitly; for example, the .NET scopes omit server.port for default HTTPS endpoints. If you use the direct OTel path, you supply the attributes directly. For how to assemble them into a request, see the Integration guide.
Observability attribute table legends
Use these legends to interpret the operation codes, requirement levels, and column descriptions in the Observability attribute table.
Applies to legend
The Applies to column uses the following codes to identify which operations each attribute applies to.
| Code | Operation |
|---|---|
| IA | invoke_agent |
| ET | execute_tool |
| CH | chat |
| OM | output_messages |
| All | Applies to every operation |
Required legend
The Required column uses the following codes to indicate whether you must emit an attribute.
| Code | Requirement |
|---|---|
| M | Mandatory. |
| M*1 | Mandatory only for agents with their own identity. |
| M*2 | Mandatory only for agent-to-agent calls. |
| O*4 | Optional, only meaningful when span status is Error. |
| O | Optional. |
| N/A | Don't emit from third-party integrations. Reserved for first-party use or auto-populated by Agent 365. |
When a row lists requirement levels by operation, each level applies only to the listed operations. An attribute can be mandatory for one operation and optional for another.
RawEventData field column
This column names a JSON key inside CloudAppEvents.RawEventData that the canonical advanced-hunting query in Verifying ingestion parses. A -- means no downstream mapping is listed in this reference, either because the attribute isn't exposed or because the mapping hasn't been verified. You should still emit it according to the Required column.
Notes / impact if missing column
The .NET invocation scope records request parameters from InvokeAgentScopeDetails.RequestParameters and response parameters from InvokeAgentScopeDetails.ResponseParameters or RecordResponseParameters. The inference scope records response model and cache usage from InferenceCallDetails or the corresponding recording methods. The notes identify attributes you set explicitly and first-party-only attributes.
Observability attribute table
The following table groups attributes by agent identity, caller and run context, model requests and responses, tool execution, errors, service metadata, and span fields. SDK-specific classifications and notes reflect the .NET SDK scopes and processors. Framework instrumentation can supply additional attributes.
Attributes accept string values.
Note
Agent 365 auto-populates the static record fields (Id, RecordType, Workload, UserType, Version) and the generated request and response IDs.
| Attribute | Applies to | Required | RawEventData field | Notes / impact if missing |
|---|---|---|---|---|
gen_ai.operation.name |
All | M | Operation |
One of invoke_agent, execute_tool, chat, output_messages. Span dropped if missing or unrecognized. |
microsoft.tenant.id |
All | M | OrganizationId |
URL {tenantId} is authoritative. If you set this value and it disagrees, request is rejected (403). |
gen_ai.agent.id |
All | M | TargetAgentId (IA); AgentId (ET, CH) |
The calling app's appId. Must match URL {agentId} and the authenticated app. Mismatch returns 403. |
gen_ai.agent.name |
All | M | TargetAgentName (IA); AgentName (ET, CH) |
Defender and admin center show the raw GUID instead of a name if missing. |
microsoft.a365.agent.blueprint.id |
All | M | TargetAgentBlueprintID (IA); AgentBlueprintId (ET, CH) |
The blueprint's appId. For standard Entra apps with no blueprint, reuse the agent's appId. Blueprint roll-ups in admin center break otherwise. |
gen_ai.agent.description |
All | O | -- | Detail view in admin center is blank for the agent. |
gen_ai.agent.version |
All | O | -- | Version of the agent being invoked or performing the operation. Recorded from AgentDetails.AgentVersion. |
microsoft.a365.agent.platform.id |
All | O | PlatformTargetAgentId (IA, also top-level AlternateId); PlatformAgentId (ET, CH) |
The agent's unique ID in your non-Entra identity system. Free-form text. Omit when the agent has an Entra registration. |
microsoft.agent.user.id |
All | M*1 (IA, ET, CH); O (OM) | TargetAgentUserKey (IA); UserKey (ET, CH) |
Microsoft Entra object ID of the agent's own user account. Required for AI teammates and agents with their own identity on IA, ET, and CH. The .NET shared scope also records it on OM when supplied. |
microsoft.agent.user.email |
All | O*1 | UserId (ET, CH) |
UPN of the agent's user account. |
microsoft.a365.caller.agent.id |
IA | M*2 | AgentId (IA) |
Calling agent appId. Required for agent-to-agent. |
microsoft.a365.caller.agent.name |
IA | M*2 | AgentName (IA) |
Calling agent display name. |
microsoft.a365.caller.agent.version |
IA | O | -- | Version of the calling agent in an agent-to-agent invocation. Recorded from caller agent details. |
microsoft.a365.caller.agent.blueprint.id |
IA | M*2 | AgentBlueprintId |
Calling agent's blueprint appId. Required for agents with their own identity A2A. |
microsoft.a365.caller.agent.user.id |
IA | M*2 | -- | Calling agent's user ID. |
microsoft.a365.caller.agent.user.email |
IA | M*2 | -- | Calling agent UPN. |
microsoft.a365.caller.agent.platform.id |
IA | N/A | -- | Reserved for first-party integrations. Don't emit from third-party integrations. |
user.id |
All | M | UserKey (IA) |
Microsoft Entra object ID of the human caller. Required on every span. "Who ran this agent" is blank without it. The .NET shared scope records it on any operation when user details are supplied. |
user.email |
All | O | UserId (IA) |
UPN of the caller. |
user.name |
All | O | -- | Display name of the caller. |
client.address |
All | M (IA, ET, CH); O (OM) | ClientIP (IA, ET) |
Caller IP. IP-based investigation blocked if blank. |
gen_ai.conversation.id |
All | M | ConversationId (IA, ET); CopilotEventData.ConversationId / CopilotEventData.ThreadId (CH) |
The primary join key for a run. Without it, the run doesn't appear in Defender agent-activity views or admin center. |
microsoft.channel.name |
All | M | ChannelName (IA, ET) |
The surface the agent runs in. Use a short lowercase token. The canonical values used by Defender and admin center filters today are msteams and outlook. Custom strings (for example web, <your-product-name>) are accepted but don't pivot in built-in channel filters. Use the same value on every span. See Picking values. |
microsoft.channel.link |
All | O | -- | Channel deep-link. |
microsoft.session.id |
All | O | SessionIdentity |
Session pivots blank if missing. |
microsoft.session.description |
All | O | -- | Session description. |
microsoft.conversation.item.link |
All | O | -- | Deep link to the message. |
server.address |
IA, ET, CH | M | ServerAddress (IA, ET) |
Endpoint your service is calling. |
server.port |
IA, ET, CH | M | ServerPort (IA) |
Port of the endpoint your service is calling. |
gen_ai.request.model |
IA, CH | M (CH); O (IA) | -- | Requested model name (for example, gpt-4o). The .NET invocation scope records it from request parameters. Captured but not yet surfaced in advanced hunting. |
gen_ai.provider.name |
All | M (CH); O (IA, ET, OM) | -- | Provider name (for example, openai). The .NET shared scope records it from agent details; the inference scope also records it from inference details. |
gen_ai.request.choice.count |
IA | O | -- | Requested number of candidate completions. |
gen_ai.request.seed |
IA | O | -- | Seed used to improve reproducibility. |
gen_ai.request.frequency_penalty |
IA | O | -- | Frequency penalty requested for generation. |
gen_ai.request.max_tokens |
IA | O | -- | Maximum number of tokens to generate. |
gen_ai.request.presence_penalty |
IA | O | -- | Presence penalty requested for generation. |
gen_ai.request.stop_sequences |
IA | O | -- | Sequences that stop generation. |
gen_ai.request.temperature |
IA | O | -- | Temperature requested for generation. |
gen_ai.request.top_p |
IA | O | -- | Nucleus sampling setting requested for generation. |
gen_ai.data_source.id |
IA | O | -- | Identifier of the data source used for grounding or retrieval, such as a knowledge base or index. |
gen_ai.output.type |
IA | O | -- | Requested output content type, such as text, json, or image. |
gen_ai.system_instructions |
IA | O | -- | System or developer instructions supplied to the model. Review for sensitive content before recording. |
gen_ai.input.messages |
IA, CH | M | -- | Request payload (JSON string). Captured for downstream analysis but not yet surfaced in advanced hunting. |
gen_ai.output.messages |
IA, CH, OM | M | -- | Response payload (JSON string). |
microsoft.a365.agent.thought.process |
IA, CH | O | -- | Free-text reasoning or chain of thought. |
gen_ai.response.model |
CH | O | -- | Model name returned by the provider. It can differ from the requested model name. |
gen_ai.response.finish_reasons |
IA, CH | O | -- | Reasons generation stopped. The .NET invocation scope records them from response parameters. |
gen_ai.usage.input_tokens |
IA, CH | O | -- | Input token count. The .NET invocation scope records it from response parameters. |
gen_ai.usage.output_tokens |
IA, CH | O | -- | Output token count. The .NET invocation scope records it from response parameters. |
gen_ai.usage.cache_creation.input_tokens |
IA | O | -- | Input tokens written to a provider-managed cache, recorded through invocation response parameters. |
gen_ai.usage.cache_write.input_tokens |
CH | O | -- | Input tokens written to cache, recorded through inference details or RecordCacheWriteInputTokens. |
gen_ai.usage.cache_read.input_tokens |
IA, CH | O | -- | Input tokens served from cache. Recorded through invocation response parameters or inference details and recording methods. |
gen_ai.tool.name |
ET | M | ToolName |
Tool name. Defender tool-usage views are blank if missing. |
gen_ai.tool.type |
ET | M | ToolType |
The .NET SDK defines function, extension, and datastore. Other integration-specific values include Power Platform Connector, MCP Server, API, Knowledge Source, bing_grounding, code_interpreter, and file_search. |
gen_ai.tool.call.id |
ET | M | ToolId |
Identifier for this tool call. |
gen_ai.tool.description |
ET | O | ToolDescription |
Tool description. |
gen_ai.tool.server.name |
ET | O | -- | Tool server hostname. Set this attribute for MCP tools. |
gen_ai.tool.call.arguments |
ET | M | -- | Tool arguments (JSON string). Captured but not yet surfaced in advanced hunting. |
gen_ai.tool.call.result |
ET | M | -- | Tool result (JSON string). |
url.full |
ET | O | -- | Full tool endpoint URL. Remove credentials, access tokens, and other sensitive URL components before supplying it. |
gen_ai.skill.name |
ET | O | -- | Name of the skill loaded, the skill whose resource is read, or the skill whose script is executed. |
gen_ai.skill.description |
ET | O | -- | Description of the skill. Review for sensitive content before recording. |
gen_ai.skill.source.uri |
ET | O | -- | Original skill source URI, not a temporary local path. Remove credentials and access tokens before recording. |
gen_ai.skill.resource.name |
ET | O | -- | Skill-relative resource or script name. |
process.executable.name |
ET | O | -- | Executable name. Set only when the tool directly executes a single process. |
process.executable.path |
ET | O | -- | Executable path. Set only when the tool directly executes a single process. |
process.exit.code |
ET | O | -- | Reported process exit code, including zero for success. Recording an exit code doesn't change the span's error status. |
microsoft.a365.transfer.mode |
ET | O | -- | Control transfer mode: return_to_caller or pass_control. Recorded from tool transfer details. |
microsoft.a365.transfer.target.type |
ET | O | -- | Transfer target: agent, human, or workflow. |
microsoft.a365.transfer.target.agent.id |
ET | O | -- | Identifier of the agent receiving the transfer. Set target agent details only for an agent target. |
microsoft.a365.transfer.target.agent.name |
ET | O | -- | Name of the agent receiving the transfer. |
microsoft.a365.transfer.target.agent.blueprint.id |
ET | O | -- | Blueprint identifier of the agent receiving the transfer. |
microsoft.a365.transfer.target.agent.platform.id |
ET | O | -- | Platform identifier of the agent receiving the transfer. |
microsoft.a365.transfer.target.agent.version |
ET | O | -- | Version of the agent receiving the transfer. |
error.type |
All | O | -- | Error classification. The .NET scope records the exception type, an Azure request failure status, or a cancellation type when the scope ends after an error or cancellation is recorded. |
error.message |
All | O | -- | Error message key defined by the SDK. The .NET scope's RecordError path sets span.Status.Message instead of automatically emitting this attribute. Set it explicitly if your instrumentation uses it. |
span.Status.Message |
All | O*4 | ErrorMessage (IA, ET); CopilotEventData.ErrorMessage (CH) |
Failed runs' root cause is empty if missing. |
span.Status.Code |
All | O*4 | ErrorType (IA); CopilotEventData.ErrorType (CH) |
Error category blank if missing. |
operation.source |
All | O | InvokeSource (IA) |
Identifier for the SDK or service emitting the telemetry. Might be a Resource attribute. |
service.name |
All | O | -- | Name of the service emitting telemetry. The .NET SDK records Request.OperationSource under this key, not operation.source. |
span.StartTimeUnixNano |
All | M | top-level TimeGenerated (also CreationTime in RawEventData) |
Unix epoch nanos as a string. |
span.EndTimeUnixNano |
All | M | CompletionTime (IA, ET); CopilotEventData.CompletionTime (CH) |
Duration can't be computed if missing. |
Note
Agent 365 accepts several attributes you emit, such as tool arguments and results, model parameters, and channel deep-links. Downstream Microsoft Defender views use these attributes, but Agent 365 doesn't yet expose them as a CloudAppEvents.RawEventData JSON key. Set them according to the Required column. They might be added to the hunting payload in a future release.
Important
On invoke_agent (IA) records, the AgentId, AgentName, and AgentBlueprintId fields describe the calling agent, not the invoked agent. Agent 365 populates them from the microsoft.a365.caller.agent.* attributes. When a human invokes your agent, omit those attributes, so AgentId and AgentBlueprintId appear as an all-zeros GUID (00000000-0000-0000-0000-000000000000) and AgentName is empty in audit records and Microsoft Purview. The all-zeros value is expected for human-initiated runs. To identify the invoked agent, use TargetAgentId, TargetAgentName, and TargetAgentBlueprintID.
Pick values when you don't have a natural one
Some required attributes describe concepts that might not exist in your agent's architecture. If the natural value isn't available, set the following values instead. Do not leave a mandatory field empty. Even an all-zeros GUID hides your run from some customer-facing experiences. This rule applies to mandatory attributes only. It doesn't apply to the caller-agent attributes on human-initiated runs, where an all-zeros AgentId on invoke_agent records is expected.
| Question / scenario | Field(s) | What to set |
|---|---|---|
| My agent is a standard Entra app registration (not built from an Entra Agent ID blueprint). | gen_ai.agent.id |
The Entra app's appId. |
| ↑ same scenario | microsoft.a365.agent.blueprint.id |
Reuse the same value as gen_ai.agent.id (the agent's appId). The schema requires a non-empty value; reusing the agent appId is the safe default when there's no blueprint. |
| My agent is built from an Entra Agent ID blueprint - one or many agent identities minted from the same blueprint. | gen_ai.agent.id |
The agent identity's appId (the instance appId, not the blueprint's). |
| ↑ same scenario | microsoft.a365.agent.blueprint.id |
The blueprint's appId. All instances minted from the same blueprint share this value. |
| The caller is a human user, not another agent. | All microsoft.a365.caller.agent.* attributes |
Omit. They're mandatory only in agent-to-agent scenarios. On invoke_agent records, the caller fields AgentId and AgentBlueprintId show an all-zeros GUID. Use TargetAgentId to identify your agent. |
| In agent-to-agent: the calling agent is a standard Entra app (no blueprint). | microsoft.a365.caller.agent.blueprint.id |
Reuse the calling agent's appId. |
| My agent is not an AI teammate - it doesn't have its own user account in the tenant. | All microsoft.agent.user.* attributes |
Omit. They're mandatory only when the agent has its own Entra Agent ID user account. |
| My agent has no concept of a session beyond a single run. | microsoft.session.id |
Optional - omit. If you want each run to be its own session, set to a per-run GUID. |
| My agent has no concept of a conversation (one-shot, stateless). | gen_ai.conversation.id |
Generate a fresh GUID per run. The field is mandatory; skipping it removes the run from Defender agent-activity views and the Microsoft 365 admin center. |
| The caller has no IP (for example, an autonomous scheduled trigger). | client.address |
Use a stable placeholder you control (for example, "0.0.0.0"). The field is mandatory; an empty value removes the run from IP-based investigation pivots. |
| The agent runs in-process; there's no separate "server" being called. | server.address / server.port |
Use the hostname of the machine that ran the agent (for example, myagent.example.com) and the port your endpoint listens on. Required even when there's no separate downstream service. |
My chat span has no model token usage. |
gen_ai.usage.input_tokens / gen_ai.usage.output_tokens |
Optional - omit. If approximate counts are available, you can include them. |
| My span has no error to report. | span.Status.Message, span.Status.Code |
Set the OTel status to OK (numeric code 1) and omit the message. The pipeline only consults these fields when status is Error. |
What value should I put in microsoft.channel.name? |
microsoft.channel.name |
The surface the agent runs in. Defender and admin center filters key off the literal string, so use a short, stable, lowercase token. Today the canonical values are msteams and outlook; common customer-facing surfaces also use web, office, sharepoint, or <your-product-name>. Pick one value and stick to it - tooling can't reconcile msteams and Microsoft Teams as the same channel. |
What OTLP kind should I set on my spans? |
span.kind |
Use the integer enum value, not the proto enum string - 1 (INTERNAL), 2 (SERVER), 3 (CLIENT), 4 (PRODUCER), 5 (CONSUMER). Agent 365 accepts any of these and doesn't derive customer-visible behavior from kind, so 1 (INTERNAL) is a safe default for every span. If you want kind to reflect the call shape, INTERNAL for invoke_agent / output_messages and CLIENT for chat / execute_tool is reasonable. |