Skip to content

docs(develop): Update AI Agents module span conventions - #20033

Draft
cleptric wants to merge 4 commits into
masterfrom
cleptric/ai-agents-develop-docs
Draft

cleptric wants to merge 4 commits into
masterfrom
cleptric/ai-agents-develop-docs

Conversation

@cleptric

Copy link
Copy Markdown
Member

No description provided.

List only the gen_ai attributes Sentry and Relay read, with a description
of each. Drop requirement levels, deprecated attributes, and attributes
Relay derives during ingestion.

Add decision, memory, and handoff spans, the span hierarchy, and common
rules for conversation IDs, errors, and data collection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
develop-docs Ready Ready Preview Oct 19, 2026 4:58am UTC
1 Skipped Deployment
Project Deployment Actions Updated
sentry-docs Ignored Ignored Preview Oct 19, 2026 4:58am UTC

Request Review

@github-actions github-actions Bot added sdk-develop-docs PRs touching develop-docs/sdk Priority: Needs Triage The PR description is missing valid priority information labels Oct 16, 2026
| `gen_ai.agent.name` | string | The agent's name. Powers the agent filter and grouping in Agents insights, the agent flow in Conversations, and span titles. | `"Weather Agent"` |
| `gen_ai.input.messages` | string | The messages the agent received. Sentry uses them for the conversation preview and transcript when the child model spans don't carry messages. **[0]** | `'[{"role": "user", "parts": [{"type": "text", "content": "..."}]}]'` |
| `gen_ai.output.messages` | string | The agent's final response. Used the same way as the input messages. **[0]** | `'[{"role": "assistant", "parts": [{"type": "text", "content": "..."}]}]'` |
| `gen_ai.tool.definitions` | string | The tools available to the agent, as a JSON array of name and description objects. Shown as **Available Tools** in the span details. Omit it when the agent has no tools. | `'[{"name": "get_weather", "description": "..."}]'` |

@alexander-alderman-webb alexander-alderman-webb Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not doing a full review now.
This immediately stands out because available tools are provided on a per-call basis.
A similar caveat to what OTel has for setting gen_ai.request.model on Invoke Agent spans applies

This attribute SHOULD be populated if and only if the instrumented library allows to set only a single model per agent. . It SHOULD NOT be populated for agents that support multiple models or dynamic selection.

All libraries we instrument in Python allow dynamic tool configuration during an agent execution.
As a result, we don't set gen_ai.tool.definitions on Invoke Agent spans in Python.

I know that this doesn't work nicely with the product today, so we should discuss how to resolve this conflict.

Co-authored-by: Andrei <168741329+andreiborza@users.noreply.github.com>
@cleptric cleptric removed the Priority: Needs Triage The PR description is missing valid priority information label Oct 19, 2026
SDKs no longer drop earlier messages from gen_ai.input.messages. Replace the
trimming rule with guidance to send every message the model received.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@alexander-alderman-webb alexander-alderman-webb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a brief read

## Notes

Reasoning tokens are a subset of output tokens; `gen_ai.usage.output_tokens` includes `gen_ai.usage.reasoning.output_tokens`.
**[0]** Messages use the format `{role, parts}`, where `role` is `"user"`, `"assistant"`, `"tool"`, or `"system"`, and `parts` is an array of typed objects:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No system messages go in the gen_ai.system_instructions attribute, so there should be no system roles in gen_ai.input.messages.

| `gen_ai.tool.call.arguments` | string | The arguments the tool was called with, as a JSON string. Shown in the span's **Input** tab and as the timeline preview. | `'{"location": "Paris"}'` |
| `gen_ai.tool.call.result` | string | What the tool returned. Shown in the span's **Output** tab, and its size is shown in the timeline. | `'{"temperature": 18}'` |

## Handoff Span

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're removing handoff spans from the SDKs, they're not in OTel either.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please deprecate it in conventions and let's remove it here.

- `gen_ai.usage.total_tokens`
- `gen_ai.response.tokens_per_second`
- `gen_ai.context.window_size` and `gen_ai.context.utilization`
- `gen_ai.cost.*`, calculated from the model and token counts. Relay keeps an existing `gen_ai.cost.total_tokens` so users can set costs for self-hosted or unpriced models, but SDKs don't calculate costs themselves.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These can be set by SDKs (requirement from the Seer team).


### Request Data
- `gen_ai.operation.type`
- `gen_ai.usage.total_tokens`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gen_ai.usage.total_tokens does not always equal

gen_ai.usage.input_tokens + gen_ai.usage.output_tokens.

according to the values the SDKs send. So I would keep sending them from the SDK even if the Relay transform is wrong.

| Attribute | Type | Requirement Level | Description | Example |
| :--------------------------------- | :----- | :---------------- | :-------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------- |
| `gen_ai.input.messages` | string | optional | List of dictionaries describing the messages (prompts) given to the agent. **[0]**, **[1]**, **[4]**, **[5]**, **[7]** | `'[{"role": "user", "parts": [{"type": "text", "content": "..."}]}]'` |
| `gen_ai.system_instructions` | string | optional | The system instructions passed to the model. | `"You are a helpful assistant."` |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do invoke agent spans no longer carry system instructions?
Surely the same justification as for gen_ai.input.messages applies:

Sentry uses them for the conversation preview and transcript when the child model spans don't carry messages.

- On failure, set the span status to error. Sentry counts errors from the span status alone.
- When the application has a conversation, chat, or session ID, set `gen_ai.conversation.id` to it on every `gen_ai.*` span. Conversations are keyed on this attribute, so spans without it don't appear in any conversation. Omit it when there is no such ID; never derive one from a trace or request ID.
- Send structured values (messages, tool definitions, records) as JSON strings. Span attributes only accept primitives, so set `'[{"foo": "bar"}]'`, not `[{"foo": "bar"}]`.
- Gate prompt, response, and tool content with the `genAI` option of the [data collection](/sdk/foundations/client/data-collection/) configuration. When collection is off, omit those attributes. Metadata such as model names, token counts, and tool names is always sent.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confusing what data collection off means. It's always on in new JS and Python SDKs, and if you omit explicit config, then all GenAI attributes are set.


- Span `op`: `"gen_ai.decide"`
- Span `name`: `"decide {gen_ai.request.model}"` (e.g. `"decide typesafe/jev-1.13"`)
- `gen_ai.operation.name`: `"decide"`. Decisions share the `ai_client` operation type with model calls, so this attribute is what tells them apart.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confusing, the SDKs never set ai_client.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add that this is inferred by Relay with a link to the codebase.

| Attribute | Type | Description | Example |
| :----------------------------------------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------- |
| `gen_ai.request.model` | string | The model the SDK asked for, as the raw provider string. Drives model breakdowns, cost calculation, and model icons. Without a model, Relay doesn't classify the span as a model call. | `"gpt-4o"` |
| `gen_ai.response.model` | string | The concrete model that responded, which Models views group by. Omit it when the provider doesn't report one; Relay copies `gen_ai.request.model` instead. | `"gpt-4o-2024-08-06"` |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not relevant what Relay does here, and I also don't think Relay should pretend that the response model is the request model.

Suggested change
| `gen_ai.response.model` | string | The concrete model that responded, which Models views group by. Omit it when the provider doesn't report one; Relay copies `gen_ai.request.model` instead. | `"gpt-4o-2024-08-06"` |
| `gen_ai.response.model` | string | The concrete model that responded, which Models views group by. Omit it when the provider doesn't report one. | `"gpt-4o-2024-08-06"` |

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's find out if they are both strictly needed?

Describes AI agent invocation.
Agent invocations represent operations that can include multiple model calls, or some auxiliary work that goes beyond transforming the model input and output.
- Set `gen_ai.operation.name` on every span. Sentry uses it to recognize AI spans and to tell decision, memory, and embeddings spans apart from ordinary model calls. Relay derives `gen_ai.operation.type` from it, and every Agents insights view filters on that type.
- Set `gen_ai.operation.name`, `gen_ai.request.model`, `gen_ai.agent.name`, and `gen_ai.tool.name` when the span starts, so sampling decisions can use them.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gen_ai.tool.name only appears on child Execute Tool spans, how is this relevant for sampling decisions?

The AI Agents module is agnostic to the library used. SDKs instrument supported AI frameworks and provider clients automatically. Users instrument anything else manually with the same span conventions.

## Spans Conventions
This page lists every attribute SDKs send on AI spans. Send all of them. The descriptions call out the few cases where an attribute can be omitted. Don't send attributes that aren't listed here: no part of the product reads them, or Relay derives them during ingestion.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agent name doesn't always exist, and with all our populate integrations we care about gen_ai.function.id.

This branch was successfully deployed

2 active (1 outdated) deployments
Preview – develop-docs — bb26a6a7 Deployed Oct 19, 2026 by vercel[bot]
Preview – sentry-docs — 1db73bac Deployed Oct 16, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sdk-develop-docs PRs touching develop-docs/sdk

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants