What the SDK reports about every assistant run, which fields each integration fills, and how to configure and enrich the reports.
Every assistant response is a run. When a run finishes, the SDK sends one run report to the project: what happened, how long it took, which model and tools were involved, and how it ended. Reports never carry the user's messages, but they do carry the assistant's output text and the tool arguments and results, each cut at 50,000 characters, the error message, cut at 2,048, and whatever metadata the integration or your beforeReport hook attaches, so they can contain sensitive content; beforeReport can redact or drop a report and telemetry: false turns reporting off, see Enriching or filtering reports. Reports are the source of the Runs, Models, Users and Overview pages in the dashboard.
Reporting is on by default for every integration that persists messages. This page describes the report, the fields each integration can fill, and the telemetry configuration on AssistantCloud.
The run report
A report is one POST /v1/runs with the fields below. The SDK builds it with createRunReport, so every integration sends the same shape.
| Field | Type | Meaning |
|---|---|---|
thread_id | string | The cloud thread the run belongs to. |
status | "completed", "incomplete", "error" | How the run ended. incomplete carries an outcome_type. |
outcome_type | see Outcomes | Why an incomplete or failed run ended. Omitted for a completed run. |
error, error_code | string | The failed run's message and code. The code is the error's code when it has one, else its class name (AI_APICallError). |
message_id | string | The stored assistant message the run produced, so the dashboard can open it. |
duration_ms | number | Wall clock time from the first request to the last chunk. |
first_token_ms | number | Time to the first streamed token. |
steps | array | One entry per model step: input_tokens, output_tokens, reasoning_tokens, cached_input_tokens, tool_calls, start_ms, end_ms, finish_reason. |
total_steps | number | The number of steps. |
tool_calls | array | Every tool invocation with tool_name, tool_call_id, tool_args, tool_result, tool_source (frontend or mcp) and any nested sampling_calls. |
input_tokens, output_tokens, reasoning_tokens, cached_input_tokens | number | Usage for the whole run. |
model_id, provider | string | The model that served the run and the provider that served the model. |
output_text | string | The assistant output, truncated at 50,000 characters. |
trace_id | string | The W3C trace id of the server spans, when trace correlation is set up. A report with a trace id merges into the run the server spans created. |
environment, release, tags | string, string, string[] | The deployment dimensions from the telemetry configuration. They become facets on the Runs page. |
metadata | object | Attributes attached through beforeReport, shown on the run's page. |
Field limits: error is cut at 2,048 characters and error_code at 64, output_text at 50,000, environment at 64, release at 255, tags at 64 characters each and 20 per report, and duration_ms and first_token_ms are rounded to whole milliseconds. The endpoint is append only: a report may also carry cost_usd or cost_details to override the catalog price, and any key it does not know is kept in the run's attributes rather than rejected, so an older cloud accepts a newer SDK and the other way round.
What each integration reports
The integrations observe runs differently, so they do not all fill every field.
| Field | assistant-ui runtime, aui/v0 | assistant-ui runtime, ai-sdk/v6 | useCloudChat |
|---|---|---|---|
status, error, error_code | yes | yes | yes |
outcome_type | length, content_filter and aborted from the message status | same, plus a finishReason the route puts in message metadata | all four, from the AI SDK finish event |
first_token_ms, duration_ms | yes | yes | yes |
steps with start_ms and end_ms | yes | yes | yes |
Per step finish_reason | no | "tool-calls" on a step that called a tool | the finish event's reason |
tool_calls with tool_source | without tool_source | yes | yes |
| Usage | from message metadata | from message metadata | from message metadata |
model_id, provider | from message metadata | from message metadata | from message metadata |
trace_id | from message metadata | from message metadata | from message metadata |
The assistant-ui runtime rows apply to useLocalRuntime and useChatRuntime, whose history adapter persists and reports every run. The LangGraph, LangChain and Google ADK runtimes keep their own transcripts, so with them the cloud provides the thread list, titles and feedback but no run report; see LangGraph.
Route configuration
Usage, model and provider only exist on the server, so the route has to put them into the message metadata the SDK reads. With the AI SDK, add a messageMetadata callback to the stream response:
import { convertToModelMessages, streamText } from "ai";
import { openai } from "@ai-sdk/openai";
export async function POST(req: Request) {
const { messages } = await req.json();
const model = openai("gpt-5.6-luna");
const result = streamText({
model,
messages: await convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse({
messageMetadata: ({ part }) => {
if (part.type === "finish") {
return { usage: part.totalUsage, finishReason: part.finishReason };
}
if (part.type === "finish-step") {
return { modelId: part.response.modelId, provider: model.provider };
}
return undefined;
},
});
}The SDK reads these metadata keys:
| Key | Becomes |
|---|---|
usage | The run's token counts. inputTokens, outputTokens, reasoningTokens and cachedInputTokens are read, and the AI SDK's older promptTokens and completionTokens names still work. Without usage, per step steps[].usage entries are summed. |
modelId | model_id. A per step response.modelId is read when the run level id is absent. |
provider | provider. Server spans carry the provider as well when trace correlation is on. |
finishReason | outcome_type for length and content-filter, and the error status for error. |
traceId | trace_id. withAssistantCloudTraceMetadata sets it for you. |
samplingCalls | Nested model calls made by tools, attached to the matching tool call. See Traces. |
Without this configuration the report still arrives, without model, provider and usage. The dashboard shows such runs under "No model reported" and cannot price them.
Outcomes
The browser reports four outcomes. Runs the cloud executes itself, through assistants, add the server side ones.
outcome_type | status | Meaning | Reported by |
|---|---|---|---|
aborted | incomplete | The user stopped the run. | the browser, and the assistant run endpoint on an aborted request |
disconnected | incomplete | The stream disconnected before completion. | useCloudChat |
length | incomplete | The model reached its output length limit. | the browser and server spans |
content_filter | incomplete | The provider filtered the response. | the browser and server spans |
timeout | error | The run exceeded the assistant's timeout. | the assistant run endpoint |
rate_limited | error | The provider answered 429. | the assistant run endpoint |
provider_error | error | The provider answered another HTTP error. | the assistant run endpoint |
server_error | error | The run failed inside the cloud. | the assistant run endpoint |
A failed run has status: "error" and, when the cause is known, an outcome from the second group. The Overview and the Runs page turn these into the completion rate and the outcome facets.
Deployment dimensions
environment, release and tags on the telemetry configuration are stamped onto every report the client sends. They become facets on the Runs page, so a regression can be narrowed to one release or one environment.
const cloud = new AssistantCloud({
baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
anonymous: true,
telemetry: {
environment: "production",
release: "2026.09.1",
tags: ["web", "eu"],
},
});release is your application's version, not the SDK's. The SDK identifies itself separately: every request carries an Aui-Sdk header naming the assistant-cloud version and the integration packages on it, and Settings › Telemetry lists the versions a project has seen.
Enriching or filtering reports
beforeReport runs last, with the assembled report. Return a modified report to add attributes, or null to drop it.
const cloud = new AssistantCloud({
baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
authToken: getToken,
telemetry: {
beforeReport: (report) => {
if (report.thread_id === internalTestThread) return null;
return { ...report, metadata: { ...report.metadata, plan: "pro" } };
},
},
});metadata is stored as the run's attributes and shown on the run's page; keep it to a few short keys.
Turning telemetry off
| Setting | Effect |
|---|---|
telemetry: false | No run reports and no engagement events. Threads and messages are still persisted. |
telemetry: { events: false } | Run reports stay on, engagement events stop. |
telemetry: true or omitted | Everything on. |
Where reports appear
- Runs lists every report with facets for status, outcome, model, provider, environment, release, tags and user, and an Analysis view over the same range.
- A run's page shows its steps, tool calls and usage as a timeline, and the server spans when a trace was correlated.
- Models aggregates runs and cost per model and provider, Users per end user, and the Overview carries the completion rate, latency percentiles and daily volume.
The demo project shows each of them on synthetic data.