Skip to content

Threads and runs

Keep conversation identity, native lifecycle and durable history with their actual owners.

Three identities

A thread/session names the conversation. A run/turn/task names work within it. A message/part names content that may be replaced as it streams. Keep these separate; a new token is not a new run, and a reconnect is not a new thread.

Ghost's runtime identity is { threadId, revision, runId? }. Use the native thread/session/context ID. Increase revision when replacing the bound context, including A→B→A, clearing history, or replacing its command owner. Keep it unchanged for ordinary updates within that context. Use a real run ID when available.

Switch without crossing contexts

Create native hooks/stores per authenticated conversation owner. Mount a hook integration with a key derived from the thread and replacement revision when the SDK reads initial configuration once. Create a new createAgUiRuntime for each native thread/revision; do not mutate its bound client's thread ID in place.

A command captured in an old Ghost snapshot rejects after context replacement. An asynchronous upload must call its supplied context.assertCurrent() before native dispatch. The host must also reject late network results before publishing them: Ghost cannot retract a write made inside an application callback.

Preserve native workflows

Stop, disconnect and recover

A UI stop request is not proof that remote work stopped. Use the SDK's cancellation API when available and render its eventual outcome. A disconnect may only stop local observation. Preserve failed, cancelled and denied states; do not replace them with a successful final answer.

Persistence, authorization, event cursors, retention, title generation and multi-thread lists remain caller-owned. Rehydrate the native store first, then project it. For SSR use request-local owners and matching getServerSnapshot hydration data; no shared user store at module scope. See external stores and each runtime guide for native recovery details.