gen_ai.agent.name and gen_ai.conversation.id.
Before you begin
To get started, install the Agent Lens SDK and initialize your project. This step registers your entity and project with Agent Lens so that the SDK routes spans to the correct location in the UI. The SDK reads your API key from theWANDB_API_KEY environment variable.
- Python
- TypeScript
[YOUR-TEAM] with your Forge entity name and [YOUR-PROJECT] with your project name. The entity is required.tracing.init() before any start_conversation(), start_turn(), start_llm(), start_tool(), or start_subagent() call. Before init() runs, or after shutdown(), the tracing functions no-op silently, so you can leave instrumentation in production code and control it through configuration. Call tracing.shutdown() when your process exits to flush any spans that are still buffered. It’s also registered with atexit.The agent data model
Agent Lens models agent behavior as a hierarchy of one-to-many relationships. Each agent can have many conversations, each conversation can have many turns, each turn can have many LLM calls, and each LLM call can trigger many tool calls.
The following diagram shows how one agent spans many conversations, one conversation spans many turns, and so on.
A conversation groups turns by a shared
conversation_id attribute rather than a parent span, so each turn starts its own OTel trace. This design supports distributed tracing and parallel execution. The client sends spans directly to the OTel collector without any server-side aggregation.
Agent tracing APIs
The following sections describe each top-level tracing function and the arguments it accepts. Use them to instrument the conversation, turn, LLM call, and tool call layers of the data model described in the previous section. Agent Lens exposes the following top-level functions. Each function returns an object that works as a context manager (usingwith in Python, or try/finally in TypeScript) or that you can close manually by calling .end().
Start a conversation
start_conversation() (Python) or startConversation() (TypeScript) stamps a conversation_id attribute on every child span so that turns are grouped in the Conversations tab. If you pass a conversation_id / conversationId, it must be stable across the lifetime of the conversation. Reuse the same ID to add new turns to an existing conversation. When you omit it, the SDK generates a UUID automatically.
The active conversation is stored in context (a Python ContextVar or Node.js AsyncLocalStorage), so any code running in the same async context can retrieve it with tracing.get_current_conversation() / tracing.getCurrentConversation() without passing the conversation object explicitly.
- Python
- TypeScript
Start a turn
start_turn() (Python) and startTurn() (TypeScript) create a new invoke_agent span that becomes the root of a new OTel trace. Agent Lens uses this span to represent one complete user-agent exchange in the timeline view.
- Python
- TypeScript
- As a top-level function (
tracing.start_turn(...)/tracing.startTurn(...)), shown in the examples below. It resolves the active conversation from context and inherits its conversation ID. If no conversation is active, the turn is created without aconversation_idand isn’t grouped with other turns. - As an instance method on a conversation you hold a reference to (
conversation.start_turn(...)/conversation.startTurn(...)). Useful when you have an explicit conversation object in scope, such as inside a context-manager block. The “Context manager or try-finally pattern” example shown later in this guide uses this form. See the data-model table shown previously for direct links to theConversation,Turn,LLM,Tool, andSubAgentrefere nce pages in both SDKs.
Start an LLM call
start_llm() / startLLM() creates a chat span nested under the current turn. Agent Lens uses this span to display token usage, model name, input and output messages, and reasoning in the UI.
- Python
- TypeScript
llm object before it closes:
- Python
- TypeScript
provider_name / providerName explicitly. Agent Lens doesn’t infer it from the model string.
Start a tool call
start_tool() / startTool() creates an execute_tool span. The span becomes a child of whatever OTel span is active in context (typically the chat span of the LLM call that produced the tool call).
- Python
- TypeScript
- Python
- TypeScript
Usage patterns for agent tracing
The following sections describe how to combine these functions depending on how your agent code is structured. The following examples use two types from the Agent Lens SDK:Message(Python · TypeScript) represents a single entry in a conversation: a user input, an assistant response, a system prompt, or a tool result. Assign a list of messages tollm.input_messages/llm.inputMessagesto record what the model received, and tollm.output_messages/llm.outputMessagesto record what it produced.Usage(Python · TypeScript) captures token counts from the LLM response and is assigned tollm.usage.
Context manager or try-finally pattern
For most agents, use a context manager pattern in Python or a try-finally pattern in TypeScript. The span closes and sends at the end of the block, even if an exception occurs. Agent Lens stores the active conversation, turn, and LLM call in context, so any function called within a block can callstart_llm() / startLLM() or start_tool() / startTool() without holding an explicit reference to the parent. This works across module boundaries as long as the code runs in the same async context. To retrieve the active objects from anywhere in the call stack, use tracing.get_current_conversation() / tracing.getCurrentConversation(), tracing.get_current_turn() / tracing.getCurrentTurn(), and tracing.get_current_llm() / tracing.getCurrentLLM().
- Python
- TypeScript
Manual start and end pattern
Use.end() explicitly when you can’t use with blocks or try/finally. For example, when you open and close spans in different function calls, or when you manage async lifecycle outside a coroutine. You’re responsible for calling .end() on every object you create, so that spans close and flush to the collector. In TypeScript, ending a turn or conversation also closes any of its descendants that are still open.
- Python
- TypeScript
Semantic conventions
The Agent Lens SDK emits OTel spans that conform to the GenAI semantic conventions and GenAI agent span conventions. Agent Lens accepts any OTel span, stores all attributes, and makes them queryable. You can add arbitrary attributes to spans withset_attributes() / setAttributes() on any Agent Lens tracing object. See Set attributes on agent spans.
The SDK owns a private OpenTelemetry tracer provider. It exports only the spans created through Agent Lens and doesn’t replace your application’s global provider or export spans from unrelated instrumentation.
How data appears in the Agent Lens UI
After you instrument your agent with the preceding patterns and run it, your traces appear in the Conversations tab of your Agent Lens project athttps://.
- The Conversations tab shows all conversations with a minimap of turn activity.
- The Conversation detail view opens when you click a conversation and shows all turns, its LLM calls, tool executions, token counts, and any attached feedback.