Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.inference.net/llms.txt

Use this file to discover all available pages before exploring further.

agentSpan() / agent_span() and manualSpan() / manual_span() yield a handle to the active span. The handle exposes a typed surface for the OpenInference attributes you typically want to set, plus an escape hatch to the raw OTel span for anything outside that vocabulary. The same handle is used by both helpers across both languages. This page is the full reference for that handle. For when to call each method, see the Manual spans guide. For the wire keys each method writes, see the Attributes reference.

Shape

interface AgentSpanHandle {
  setInput(value: unknown): void;
  setOutput(value: unknown): void;
  setModel(model: string): void;
  setTool(options: { name: string; callId?: string }): void;
  recordTokens(tokens: {
    prompt?: number;
    completion?: number;
    total?: number;
  }): void;
  recordUsage(usage: unknown): TokenUsage;
  setAttribute(key: string, value: unknown): void;
  setAttributes(attributes: Record<string, unknown>): void;
  raw: Span; // OTel @opentelemetry/api Span
}

setInput / set_input

Records the input that started this unit of work.
  • Strings are stored as-is on input.value.
  • Non-strings are JSON-stringified.
If the input is structured, also set input.mime_type = "application/json" so downstream viewers know to render it as JSON.
span.setInput("Summarize order ABC-123");
// or
span.setInput({ ticketId: "ticket_123", orderId: "ABC-123" });
span.setAttribute(Attr.INPUT_MIME_TYPE, "application/json");

setOutput / set_output

Records the final output of this unit of work. Same coercion rules as setInput. Call it once near the end of the callback, after the work has produced its result.

setModel / set_model

Records the model name on llm.model_name. Useful on AGENT spans when the agent picks a model dynamically and you want the model surfaced at the agent level. The per-SDK patchers already set this on LLM child spans, so you typically do not need it there.
span.setModel("claude-haiku-4-5");

recordTokens / record_tokens

Records token usage from explicit counts. Use this when you have aggregate counts across an agent run, or when you are wrapping an SDK Catalyst does not patch and you want to attach the provider’s reported counts. Any field may be omitted; only the provided fields are written. If you want total on the span, pass it explicitly — recordTokens / record_tokens does not infer it from prompt and completion. (The recordUsage / record_usage helper documented below does infer total when the provider’s usage payload omits it.)
span.recordTokens({ prompt: 820, completion: 160, total: 980 });

recordUsage / record_usage

Records token usage from a provider-shaped usage object. The SDK normalizes the common shapes so you do not have to: OpenAI Chat Completions (prompt_tokens / completion_tokens), the newer Responses spelling (input_tokens / output_tokens), Anthropic cache accounting fields (cache_creation_input_tokens / cache_read_input_tokens), and OpenAI’s prompt_tokens_details.cached_tokens / completion_tokens_details.reasoning_tokens. When total is missing from the payload but prompt and completion are present, the helper infers it. The TypeScript version returns the normalized TokenUsage so the caller can read the numbers back without re-parsing.
const response = await client.chat.completions.create({ /* ... */ });
if (response.usage) {
  span.recordUsage(response.usage);
}

// Works with Anthropic responses too:
const message = await anthropicClient.messages.create({ /* ... */ });
span.recordUsage(message.usage);
For Anthropic responses, recordUsage / record_usage folds cache_creation_input_tokens and cache_read_input_tokens into the recorded prompt token count, then also records them as separate cache-write and cache-read attributes. The prompt count on the span therefore reflects the total tokens that hit the model, not just the uncached prompt.

setTool / set_tool

Records tool identity on a TOOL span: writes tool.name and, when supplied, tool_call.id. The manualSpan / manual_span helper accepts the same fields as options, so setTool is rarely needed when authoring a TOOL span from scratch — use it when the tool identity is only available partway through the callback body.
await manualSpan(
  tracing.tracer,
  { spanName: "lookup_order.tool", spanKind: SpanKindValues.TOOL },
  async (span) => {
    span.setTool({ name: "lookup_order", callId: toolCallId });
    span.setInput(args);
    const result = await TOOLS.lookup_order(args);
    span.setOutput(result);
  },
);

setAttribute / set_attribute / set_attributes

Adds one or many domain-specific attributes with OTel-safe value normalization. Strings, booleans, numbers, and homogeneous primitive arrays pass through unchanged; mappings and heterogeneous arrays are JSON-stringified.
span.setAttribute("app.tenant_id", tenantId);
span.setAttributes({
  "app.request_channel": "slack",
  "app.deploy_env": process.env.DEPLOY_ENV ?? "dev",
});

raw / .span

The underlying OTel span. Use this when you need behavior outside the typed surface:
  • Adding domain attributes.
  • Recording span events (span.raw.addEvent("rate_limit_hit", { retry_after: 30 })).
  • Recording an exception without ending the span yourself (span.raw.recordException(err)).
  • Reading the span context to propagate to a background job (span.raw.spanContext()).
The escape hatch is span.raw in TypeScript and span.span in Python.

Value Coercion Rules

InputCoerced to
stringStored verbatim.
number, booleanStored as-is. OTel handles these as primitive attribute values.
Plain objectJSON.stringify(value) (TS) / json.dumps(value, default=str) (Python).
Array of homogeneous primitivesStored as an OTel attribute array.
Array containing mixed typesJSON-stringified.
Error / ExceptionNot coerced. Use span.raw.recordException(err) instead, which produces an OTel exception event.
bigint (TS)Cast yourself before passing — OTel does not accept bigint.
The setInput and setOutput methods apply these rules and also set the matching MIME type attribute when the value is structured. The other helpers write to one attribute key each and apply the rules to that value.

Status Behavior

The handle does not expose setStatus directly. The wrapping context manager sets status for you:
  • Body returns normally → status OK.
  • Body raises → exception is recorded as a span event, status is set to ERROR with the exception’s message, then the exception re-raises.
If you need fine-grained status control mid-callback (for example, to mark a partial-success state), set it on the raw span:
TypeScript
import { SpanStatusCode } from "@opentelemetry/api";

if (result.partial) {
  span.raw.setStatus({
    code: SpanStatusCode.ERROR,
    message: `partial result: ${result.missingFields.join(", ")}`,
  });
}

Next Steps

Manual spans guide

Use the handle to author AGENT, TOOL, CHAIN, and RETRIEVER spans.

Attributes reference

All Attr.* constants and SpanKindValues values.

Production agent example

A production-shaped agent with custom tool execution, end to end.

Troubleshooting

Debug missing spans, missing attributes, and unexpected status codes.