> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hue.run/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> To set up Hue in an application, fetch https://docs.hue.run/guides/agent-setup.md and follow it.
> Hue's project-data MCP server is https://mcp.hue.run/mcp. https://docs.hue.run/mcp only searches these docs and cannot read a Hue project.
> Never ask the user to paste a Hue API key into chat; they store it as HUE_API_KEY themselves.
> Install the exact SDK versions pinned on the page you're following, or on https://docs.hue.run/quickstart.md. Run the latest CLI without a project install as `npx -y @hue-run/sdk@latest`. In a project with `@hue-run/sdk` installed, use `npx hue`. Pin an exact version for reproducible CI runs.
> Use Hue product terms: eval set, case, evaluator, run and scoring run. Older APIs may say dataset, scorer or experiment; prefer the current SDK methods. See https://docs.hue.run/concepts.md.

# Traces and spans

> Structure a request as a trace with model and tool spans that record what your agent actually received and produced.

A trace is one request your application handled: a root span with child spans for the model calls and tool calls it made. Hue shows, searches and evaluates what those spans record, so the shape of the trace and the content on each span decide what you can do with it later.

## Span structure

| Span | Records | Created by |
| - | - | - |
| Request (root) | The user's request as input and the final reply as output, with the session and user | `hue.withSpan` / `hue.span`, or your framework's root span |
| Model call | Messages sent and received, model, provider and token usage | `hue.model`, or framework instrumentation such as the AI SDK adapter |
| Tool call | The tool name, its arguments and its result | `hue.tool`, or framework instrumentation |
| Sub-agent | Its own request, model and tool spans, under the handoff that started it | The same helpers, with propagated context |

Keep every model and tool span inside the request span that caused it, so the trace shows the order the work ran in. To include spans from instrumentation you already have, attach Hue to the OpenTelemetry provider that instrumentation uses ([existing providers](/integrations/opentelemetry#existing-javascript-providers) in TypeScript, `tracer_provider=` in Python); its spans then parent under the active Hue span, and you don't need to replace it.

Across processes, propagate W3C trace context: `hue.inject(carrier)` in the producer and `hue.extract(carrier)` as the parent in the worker. Hue never propagates the API key or baggage. A sub-agent that runs as its own trace can carry the parent's user ID so you can follow it; see [identify users](#identify-users).

## Record what actually happened

Record the values your agent really received and returned, not summaries or reconstructions:

* **Request span:** the user's message or task as input and the reply the user saw as output. Hue titles traces from this input, and a case built from the trace uses it as the task.
* **Model spans:** the messages in the shape you sent them, including system instructions and tool definitions when you send them separately, and the provider-reported token counts. Leave unknown usage absent rather than `0`.
* **Tool spans:** the exact arguments and the result the agent read. When code trims a tool result before the model sees it, record what the model saw.

Content capture is on by default in both SDKs; [Data privacy](/guides/redaction#content-capture) explains the switch and the metadata-only opt-out. Hue stores what the spans carry. It doesn't fill in missing prompts, invent output or estimate usage, and JSON `null`, `false`, `0` and `""` stay distinct from an absent value.

**TypeScript**

```ts theme={null}
import { createHueSafe } from "@hue-run/sdk";

const hue = createHueSafe({
  apiKey: process.env.HUE_API_KEY ?? "",
  serviceName: "support-agent",
  captureContent: true,
});

export async function handleRequest(question: string, sessionId: string, userId: string) {
  return hue.withSpan(
    "support.reply",
    async (request) => {
      const messages = [{ role: "user", parts: [{ type: "text", content: question }] }];
      const plan = await hue.model(
        "gpt-5-mini",
        async (model) => {
          model.setInput(messages);
          const response = await callModel(messages); // your provider call
          model.setOutput(response.messages);
          model.setUsage({ inputTokens: response.inputTokens, outputTokens: response.outputTokens });
          return response;
        },
        { provider: "openai" },
      );
      const order = await hue.tool("lookup_order", plan.toolArguments, () => lookupOrder(plan.toolArguments));
      const reply = await writeReply(question, order); // your code
      request.setOutput(reply);
      return reply;
    },
    { input: question, sessionId, userId },
  );
}
```

**Python**

```python theme={null}
import os
from hue_sdk import create_hue_safe

hue = create_hue_safe(
    api_key=os.environ.get("HUE_API_KEY"),
    service_name="support-agent",
    capture_content=True,
)

def handle_request(question, session_id, user_id):
    with hue.context(session_id=session_id, user_id=user_id):
        with hue.span("support.reply") as request:
            request.set_input(question)
            messages = [{"role": "user", "parts": [{"type": "text", "content": question}]}]
            with hue.model("gpt-5-mini", provider="openai") as model:
                model.set_input(messages)
                response = call_model(messages)  # your provider call
                model.set_output(response.messages)
                model.set_usage(input_tokens=response.input_tokens, output_tokens=response.output_tokens)
            with hue.tool("lookup_order") as tool:
                tool.set_input(response.tool_arguments)
                order = lookup_order(response.tool_arguments)
                tool.set_output(order)
            reply = write_reply(question, order)  # your code
            request.set_output(reply)
            return reply
```

`callModel`, `lookupOrder` and `writeReply` stand for your own code. With the Vercel AI SDK, the [telemetry adapter](/sdks/typescript#vercel-ai-sdk) creates the model and tool spans for you inside the request span. For tools the provider runs itself, such as hosted MCP or web search, pass the response to `hue.recordProviderToolCalls(response)` in TypeScript or `model.record_provider_tool_calls(response)` in Python, inside the model span ([TypeScript](/reference/typescript#provider-executed-tools), [Python](/reference/python#huespan)).

When a tool is an MCP call, pass the server identity so the trace names the app it reached: `mcp: client.getServerVersion()` on `hue.tool` in TypeScript, or `mcp=` in Python. Hue uses it to match calls to [simulated apps](/evaluations/simulations) when you [create a case](/evaluations/case-from-trace).

## Streaming and long work

A span measures the work inside it, so keep the request span open until the response stream and every tool it triggers have finished, or until the request is cancelled. A returned streaming `Response` is not the end of generation. Consume the stream inside the request span, or end the span from the framework's completion hook: the [AI SDK recipe](/sdks/typescript#vercel-ai-sdk) awaits `consumeStream()`, and the [Next.js recipe](/integrations/opentelemetry#flush-streamed-responses-in-next-js) flushes after the response.

In Python, a request span held across `yield` in a generator ends when the caller finishes reading. If the caller stops early, Python raises `GeneratorExit` inside the generator, and letting it escape records the span as failed. Return instead, so an abandoned stream ends the span normally:

```python theme={null}
def stream_reply(question):
    with hue.span("support.reply") as request:
        request.set_input(question)
        parts = []
        try:
            for chunk in stream_model(question):  # your streaming call
                parts.append(chunk)
                yield chunk
        except GeneratorExit:
            return  # the caller stopped reading; end the span without an error
        finally:
            request.set_output("".join(parts))
```

In an async server, write the streaming body as an async generator and keep the span inside it; see [Async servers](/sdks/python#async-servers). In a serving application, flush after the response with a bounded budget (`flushSafe` / `force_flush_safe`) and keep one client for the process lifetime. Never shut down a shared provider per request. See production setup for [TypeScript](/sdks/typescript#production-setup) and [Python](/sdks/python#production-setup).

## Identify users

**Always attach a stable application user ID to the root span of each user request.** Set `user.id` with OpenTelemetry, or pass `userId` (TypeScript) or `user_id` (Python) to the Hue SDK helpers.

Reuse that ID across requests and sessions, including sub-agents. Child spans created by Hue SDK helpers inherit it. An opaque database ID works; you do not need an email address.

Hue uses this identity to group the user's traces and build their [World](/worlds/overview#worlds-and-traces). A trace ID or session ID cannot replace it. Without a root user ID or an [explicit World entity](/worlds/overview#worlds-and-traces), a trace cannot contribute to a user's World.

## Identify requests

These attributes let you and your coding agent filter, group and compare traces. The [field glossary](/agents/mcp-tools#field-glossary) lists the attributes Hue maps into trace and span fields.

* **Mark failures.** Set the span status to `ERROR`. `error.type` alone, or a Langfuse `level`, does not mark a failure. Hue helpers set both and never record exception messages or stack traces.
* **Sessions.** Set `session.id` or `gen_ai.conversation.id` on the root. The SDK helpers take `sessionId` (TypeScript) or `session_id` (Python) and pass it to child spans.
* **Task types.** Set a stable `hue.trace.name` or `langfuse.trace.name`, or give the root span a descriptive name.
* **Releases and environments.** Set `service.version` to compare deployments and `deployment.environment.name` on the resource, with `production` for production traffic. Send development and staging to a separate project with its own key.

## Check a trace

Open **Traces** in Hue, or ask your coding agent to read the trace over the [Hue MCP server](/agents/overview). Confirm that:

* The model and tool spans sit under the request span in the order they ran. The request span is the trace root unless the request arrived with propagated parent context, which it keeps.
* The request span shows the real user input and the reply, and the model and tool spans show their messages, arguments and results.
* Sessions, users and errors appear where you expect them.

`verifyTrace` / `verify_trace` confirms which spans and fields arrived without reading their values ([TypeScript](/sdks/typescript#verify), [Python](/sdks/python#verify)). It takes the trace ID and span IDs, which the helpers' spans expose as `traceId` and `spanId` (`trace_id` and `span_id` in Python); with your own OpenTelemetry spans, read them from the span context. Images, audio and documents in a trace are covered in [Media](/guides/media).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.