Errors, usage, and titles

Understand retries, provider failures, context usage, and conversation names.

The Pi session translates low-level provider events into state the widget can act on. It keeps recoverable failures beside the composer, opens settings only when a choice there can fix the turn, and reports the context and cost data attached to completed model messages.

#Provider errors

Agentak extracts useful messages from provider error bodies and replaces bare status lines with actionable text. A network failure becomes a browser-oriented message instead of an SDK exception.

These statuses open the settings page automatically:

StatusWhy settings can help
401 / 403The provider refused the API key or account permissions.
402The account is out of credit.
404The selected model is not offered.

The error remains visible above the composer. Closing settings does not erase it.

Rate limits, timeouts, full context windows, server failures, and network errors stay on the transcript because changing provider settings is not always the answer. The error row can offer Retry and Dismiss.

#Retry behavior

Retry removes a failed empty assistant turn and continues from the user or tool result that preceded it. It does not append a second copy of the failed turn.

A catalog failure is different: retry loads that provider's model catalog again. A turn cannot retry while another turn is streaming.

Stopping aborts the active provider or local-model operation. Any tool confirmation still waiting is denied with a stopped-run reason.

#Context and cost

After a completed assistant turn, the composer can show:

  • context tokens used by the latest request
  • the selected model's context window
  • total input, output, reasoning, and cache tokens across turns
  • accumulated input, output, cache, and total cost

On-device models report zero provider cost. Where a local API cannot provide exact tokens, Agentak uses the best runtime count or estimate available.

The meter turns amber when Pi's compaction threshold says the remaining window is low.

Lower-level hosts can use toContextUsage(messages, model) to produce the same view.

#Compaction

The meter also carries the answer to a spent window. Compact asks the current model to summarize the turns so far, then replaces them with that summary and the recent turns. The conversation continues under the summary, and the transcript shows a checkpoint where the replaced turns were.

  • Compaction runs by itself where the alternative is a conversation that cannot go on: after a turn settles with the window nearly spent, and after a turn the provider refused because the request did not fit. A turn refused that way is run again once the summary has landed, so the message is answered rather than lost. Set autoCompact: false to leave the meter's button as the only way.
  • One summary per answer. A summary that freed less than it hoped, and a retry that failed the same way again, both leave no answer since the last summary — and nothing writes a second one over it. Opening a stored conversation that was left at its limit costs no request either; the next message is what starts one.
  • The button waits while every turn is one a compaction would keep. That is roughly the first 20k tokens on a large model, and a quarter of the window on a small one — summarizing there would replace nothing and shorten nothing, so the panel says so instead of running the request.
  • A compaction leaves a window no provider has counted yet. The meter estimates it from the summary and the turns it kept until the next answer arrives with a real number, so compacting shows as the drop it is.
  • The request runs outside the agent loop, so the transcript never carries the question.
  • The cut never falls between a tool call and its result. A conversation short enough that the recent turns are the whole of it is left exactly as it was.
  • A compaction that fails or is stopped leaves the conversation untouched. A failure shows in the error row with the retry button.
  • Pi keeps 16k tokens for the summary and 20k tokens of recent turns. Both are capped against small windows: half the window for the summary, a quarter of it kept.

session.compact() starts one; usage.compacting reports one running, and usage.canCompact reports whether one would change anything. Lower-level hosts can call compactMessages({ messages, model, apiKey }) and load what it returns.

#Titles

Without another model request, Agentak derives a title from the first user message and limits it to a short header label.

Set generateTitle to ask the current model for a title after the first answer:

const session = createPiSession({ generateTitle: true });

Or declare it on the widget so it can change without replacing the session:

<ChatPanel session={session} generateTitle />

Generation uses one extra request, asks for at most six words, and runs only after the first answer is complete. It does not enter the transcript. If it fails, the first-message title remains.

A generated title is included in PiSnapshot and built-in history. A derived title is recreated from the stored transcript.

#Transcript conversion

toViewMessages() converts Pi messages into the widget parts:

  • user and assistant text
  • reasoning, including a note for provider-redacted thinking
  • tool calls, approval state, results, failures, and returned images
  • untrusted page-tool labels
  • compaction checkpoints, from compact() or supplied by a host, and branch summaries

A provider error can exist on an assistant turn with no text. That turn still renders so the person can see what failed.

Use describeFailure(message) and failureStatus(message) when a custom Pi surface needs the same wording and status extraction.