Area
apps/server (related areas: packages/contracts, apps/web)
Problem or use case
After a provider-process restart, idle-session cleanup, resume failure, or provider-instance change, a T3 thread can still contain its projected messages and activities while the provider session is resumed, recreated, started fresh, or unavailable.
T3 stores the projected thread history and provider session bindings separately. Provider bindings contain provider-specific resume cursors and runtime metadata. ProviderSendTurnInput contains the next input, attachments, model selection, and interaction mode; it does not contain a transcript or transcript-handoff field.
The current provider paths include:
- Same-instance recovery passing a persisted cursor to the adapter.
- OpenCode creating a fresh session for confirmed missing sessions and malformed or wrong-version resume data, while propagating non-not-found resume errors.
- Codex falling back from
thread/resume to thread/start for selected recoverable errors and treating malformed cursor data as no resume.
- ACP using
session/load when a resume ID exists and propagating session-load failures.
- Claude, Cursor, and Grok creating a new provider session when no usable provider session identifier is obtained.
The current web UI displays context usage, automatic compaction, and a generic Context compacted activity. It does not display a persisted outcome distinguishing native resume, native session creation, fresh fallback, transcript handoff, or unknown continuity.
apps/web/src/historyBootstrap.ts contains a transcript-formatting helper, but it has no production call site in the current checkout. Fresh-session paths do not use it to send the projected transcript to a provider.
Proposed solution
Add an explicit provider-continuity outcome at the server and contract boundary. The outcome should distinguish:
- native session resumed;
- native session created;
- fresh fallback after resume failure or missing native state;
- native resume failed;
- transcript handoff; and
- continuity unknown.
Persist and project the outcome so it is visible in the thread timeline. Include the provider and available pre/post token values for compaction events.
When a requested native resume is missing, invalid, rejected, or falls back to a fresh session, stop before the next user turn or tool execution and expose recovery actions for retrying native resume, starting a fresh provider session with an explicitly labeled transcript handoff, or opening a new thread.
Carry provider-native turn, item, request, and message identifiers into durable orchestration metadata where available. Use those identifiers when reconciling replayed provider events.
Keep provider-instance switching rejected when driver or continuation identities are incompatible. Require an explicit handoff for switches that cannot reuse native continuation.
Why this matters
The projected T3 transcript and the provider-native session are separate state sources. A user needs to know which provider-native state the next turn will use before sending it.
Smallest useful scope
A first implementation can:
- add a persisted continuity outcome to provider-session start/recovery results;
- emit a visible activity for native resume, fresh fallback, and resume failure;
- block a turn when a requested resume falls back to a fresh session;
- include available compaction boundary usage and provider identifiers; and
- add focused tests for Codex/OpenCode fallback, same-instance recovery, replayed provider events, idle reaping, and stopped-session provider-instance changes.
Cross-provider transcript generation and provider-specific handoff formatting can be implemented as a separate follow-up once the continuity outcome is available.
Alternatives considered
- Keep provider-specific fresh-session fallbacks and expose only logs or analytics. This does not put the outcome in the thread timeline.
- Start a new T3 thread for every provider-instance change. This avoids reusing incompatible native state but also prevents compatible-instance continuation.
- Automatically inject the existing
historyBootstrap output into a fresh provider session. That helper is not currently wired into production and does not contain native tool state, hidden context, skills, MCP state, or provider memory.
Risks or tradeoffs
- Providers expose different resume, compaction, and replay metadata; some fields may be unavailable.
- A provider may accept a resume request without exposing enough information to prove that native context was restored.
- Blocking a turn after a resume failure changes current provider-specific fallback behavior and requires a user recovery action.
- Provider-native identifiers are not populated consistently across all adapters.
- Persisted continuity state requires contract, server, and client changes.
Examples or references
Area
apps/server(related areas:packages/contracts,apps/web)Problem or use case
After a provider-process restart, idle-session cleanup, resume failure, or provider-instance change, a T3 thread can still contain its projected messages and activities while the provider session is resumed, recreated, started fresh, or unavailable.
T3 stores the projected thread history and provider session bindings separately. Provider bindings contain provider-specific resume cursors and runtime metadata.
ProviderSendTurnInputcontains the next input, attachments, model selection, and interaction mode; it does not contain a transcript or transcript-handoff field.The current provider paths include:
thread/resumetothread/startfor selected recoverable errors and treating malformed cursor data as no resume.session/loadwhen a resume ID exists and propagating session-load failures.The current web UI displays context usage, automatic compaction, and a generic
Context compactedactivity. It does not display a persisted outcome distinguishing native resume, native session creation, fresh fallback, transcript handoff, or unknown continuity.apps/web/src/historyBootstrap.tscontains a transcript-formatting helper, but it has no production call site in the current checkout. Fresh-session paths do not use it to send the projected transcript to a provider.Proposed solution
Add an explicit provider-continuity outcome at the server and contract boundary. The outcome should distinguish:
Persist and project the outcome so it is visible in the thread timeline. Include the provider and available pre/post token values for compaction events.
When a requested native resume is missing, invalid, rejected, or falls back to a fresh session, stop before the next user turn or tool execution and expose recovery actions for retrying native resume, starting a fresh provider session with an explicitly labeled transcript handoff, or opening a new thread.
Carry provider-native turn, item, request, and message identifiers into durable orchestration metadata where available. Use those identifiers when reconciling replayed provider events.
Keep provider-instance switching rejected when driver or continuation identities are incompatible. Require an explicit handoff for switches that cannot reuse native continuation.
Why this matters
The projected T3 transcript and the provider-native session are separate state sources. A user needs to know which provider-native state the next turn will use before sending it.
Smallest useful scope
A first implementation can:
Cross-provider transcript generation and provider-specific handoff formatting can be implemented as a separate follow-up once the continuity outcome is available.
Alternatives considered
historyBootstrapoutput into a fresh provider session. That helper is not currently wired into production and does not contain native tool state, hidden context, skills, MCP state, or provider memory.Risks or tradeoffs
Examples or references