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 is the canonical attribute-by-attribute spec used by Agent 365's ingestion pipeline. Every span ingested by Agent 365 - whether emitted by the Microsoft OpenTelemetry Distro, the Agent 365 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're using the SDK or the Distro, the SDK emits these attributes for you and the Picking values section applies only when you need to override a default. If you're on the direct OTel path, you emit every attribute manually; for how to assemble them into a request, see the Integration guide.
Attribute table
All values are sent as stringValue - token counts must be "42" (not 42); ports must be "443" (not 443).
Operation legend. IA = invoke_agent, ET = execute_tool, CH = chat, OM = output_messages, All = applies to every operation.
Required legend.
- M: mandatory.
- M*¹: mandatory only for embodied agents (the agent has its own Entra Agent ID user account).
- M*²: mandatory only for agent-to-agent calls.
- M*³: mandatory for non-root spans only. The root
invoke_agenthas no parent. - O*⁴: optional, only meaningful when span status is Error.
- O: optional.
- N/A: don't emit. Agent 365 auto-populates.
The "RawEventData field" column names a JSON key inside CloudAppEvents.RawEventData that the canonical advanced-hunting query in Verifying ingestion parses. A blank cell means the attribute is not exposed in CloudAppEvents today--you should still emit it (per the Required column) because Agent 365 uses it for ingestion, parent-resolution, and Microsoft Defender's agent-activity views, but it isn't directly queryable from Microsoft Defender advanced hunting today.
Note
Agent 365 auto-populates the static record fields (Id, RecordType, Workload, UserType, Version) and the generated request / 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 and it disagrees, request is rejected (403). |
gen_ai.agent.id |
All | M | TargetAgentId (IA, also top-level AgentId); 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 / 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.type |
All | O | PlatformTargetAgentType (IA); PlatformAgentType (ET); CopilotEventData.PlatformAgentType (CH) |
A label for your identity system, paired with microsoft.a365.agent.platform.id when the agent doesn't have an Entra registration. Free-form text; pick a value that uniquely identifies your identity system. Omit when the agent has an Entra registration--Agent 365 auto-classifies. Don't use the Microsoft-reserved values (see Picking values). |
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. Set together with gen_ai.agent.type. Omit when the agent has an Entra registration. See Picking values. |
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 / admin center filters today are msteams and outlook. Custom strings (for example web, <your-product-name>) are accepted but won't pivot in built-in channel filters. 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. |
correlation.id |
All | O | -- | Cross-service tracing. Not surfaced in advanced hunting today. |
operation.source |
All | O | InvokeSource (IA) |
Identifier for the SDK / service emitting the telemetry. May be a Resource attribute. |
client.address |
IA, ET, CH | M | ClientIP (IA, ET) |
Caller IP. IP-based investigation blocked if blank. |
server.address |
IA, ET, CH | M | ServerAddress (IA, ET) |
Endpoint your service is calling. |
server.port |
IA, ET, CH | M | ServerPort (IA) |
String-encoded (for example "443"). |
user.id |
IA | M | UserKey |
Microsoft Entra object ID of the human caller. "Who ran this agent" is blank without it. |
user.email |
IA | O | UserId |
UPN of the caller. |
user.name |
IA | O | -- | Display name of the caller. |
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). |
gen_ai.execution.type |
IA | O | -- | One of HumanToAgent, Agent2Agent, EventToAgent. |
microsoft.a365.agent.thought.process |
IA, CH | O | -- | Free-text reasoning / chain of thought. |
gen_ai.author.app.id |
OM | O | -- | Microsoft Entra app ID of the application that authored / created the agent. |
gen_ai.tool.name |
ET | M | ToolName |
Tool name. Defender tool-usage views are blank if missing. |
gen_ai.tool.type |
ET | M | ToolType |
One of function, Power Platform Connector, MCP Server, API, Knowledge Source, bing_grounding, code_interpreter, file_search. |
gen_ai.tool.call.id |
ET | M | ToolId |
Identifier for this tool call. |
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). |
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.request.model |
CH | M | -- | Model name (for example, gpt-4o). Captured but not yet surfaced in advanced hunting. |
gen_ai.provider.name |
CH | M | -- | Provider name (for example, openai). |
gen_ai.usage.input_tokens |
CH | O | -- | Input token count, string-encoded. |
gen_ai.usage.output_tokens |
CH | O | -- | Output token count, string-encoded. |
gen_ai.response.finish_reasons |
CH | O | -- | Finish reason(s). |
microsoft.a365.caller.agent.id |
IA | M*² | -- | Calling agent appId. Required for agent-to-agent. |
microsoft.a365.caller.agent.name |
IA | M*² | -- | Calling agent display name. |
microsoft.a365.caller.agent.blueprint.id |
IA | M*² | AgentBlueprintId |
Calling agent's blueprint appId. Required for embodied A2A. |
microsoft.a365.caller.agent.user.id |
IA | M*² | -- | Calling agent's user ID. |
microsoft.a365.caller.agent.user.email |
IA | M*² | -- | Calling agent UPN. |
microsoft.a365.caller.agent.platform.id |
IA | N/A | -- | Reserved for non-Entra alternate IDs. |
gen_ai.caller.agent.type |
IA | N/A | -- | Agent 365 auto-classifies. |
microsoft.agent.user.id |
IA, ET, CH | M*¹ | TargetAgentUserKey (IA); UserKey (ET, CH) |
Microsoft Entra object ID of the agent's own user account. Required for AI teammates / embodied agents. |
microsoft.agent.user.email |
IA, ET, CH | O*¹ | UserId (ET, CH) |
UPN of the agent's user account. |
span.SpanId |
All | M | OpId |
OTel SDK emits this. |
span.ParentSpanId |
All | M*³ | ParentId |
Required for non-root spans only; the root invoke_agent has none. |
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. |
span.Status.Message |
All | O*⁴ | ErrorMessage (IA, ET); CopilotEventData.ErrorMessage (CH) |
Failed runs' root cause is empty if missing. |
span.Status.Code |
All | O*⁴ | ErrorType (IA); CopilotEventData.ErrorType (CH) |
Error category blank if missing. |
Note
Several attributes you emit (such as tool arguments / results, model parameters, and channel deep-links) are accepted by Agent 365 and used by downstream Microsoft Defender views, but aren't yet exposed as a CloudAppEvents.RawEventData JSON key. Set them per the Required column anyway - they might be added to the hunting payload in a future release.
Picking values when you don't have a natural one
Some required attributes describe concepts that may not exist in your agent's architecture. If the natural value isn't there, here's what to set instead. Do not leave a mandatory field empty--even an all-zeros GUID will hide your run from some customer-facing experiences.
| 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.* and gen_ai.caller.agent.* attributes |
Omit. They're mandatory only in agent-to-agent scenarios. |
| 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 you have approximate counts, send them as stringValue. |
| 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. |
| My agent uses a non-Entra identity system (the agent has no Entra registration). | microsoft.a365.agent.platform.id and gen_ai.agent.type |
Set both, on every span. platform.id is the agent's unique id in your identity system; agent.type is a short label that identifies which identity system that is. Both are free-form text - pick whatever makes sense for your system. Don't use the Microsoft-reserved type values: CustomBuiltAgentsUsingSDK, CopilotStudio, Foundry, DeclarativeAgent, Custom (these values are reserved for internal Microsoft surfaces). The calling app you authenticate as still needs an Entra registration to use these routes - the alternate-id pair describes a target agent, not the caller. |
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. |
Should I set gen_ai.agent.type? |
gen_ai.agent.type |
Only if you're also setting microsoft.a365.agent.platform.id (for example, your agent has no Entra registration). The pair tells Agent 365 which identity system the agent comes from. Pick a short label that uniquely identifies your identity system. Don't use CustomBuiltAgentsUsingSDK, CopilotStudio, Foundry, DeclarativeAgent, or Custom - those values are reserved for internal Microsoft use. For Entra-registered agents, omit the field; Agent 365 backfills it. |
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. |