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:
| Status | Why settings can help |
|---|---|
401 / 403 | The provider refused the API key or account permissions. |
402 | The account is out of credit. |
404 | The 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: falseto 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.