Skip to content

Shared view state

Conversation routes, draft text and surface resume state must agree across native windows and browser channels. Their owners differ; copying them into one frontend preference store makes a second resolver and lets a surface choose a provider independently of the conversation.

Routing and reasoning

The conversation's explicit route wins. An unresolved model asks the server for the last choice for that agent, its authored default, the project default, then the session's route. A provider connection travels with its model. The UI reads this result through the existing session and provider clients; no surface has an independent resolver.

Reasoning is settled at conversation birth and stays concrete for that task. Explicit reasoning selections have their own timestamp: later message activity, pinning and inherited worker routes must not become new preferences. The server carries recent max/xhigh as high into a fresh conversation and excludes off from carried history. Explicit task choices remain unchanged. The old local reasoning helpers are no longer consulted by live creation or picker flows.

Durable resume records

user_view_state stores typed records under (user, kind, key). Currently supported records are:

KindKeyValueConsumers
surfaceSurface keySurface-specific resume stateOwning views
draftConversation IDUnsent text or nullMain composer

Session references must belong to the authenticated user. A missing record has revision zero. Writes compare expectedRevision in SQL and return the current snapshot on a conflict. Each accepted write increments the revision; null retains the revision rather than recreating a key. Drafts are limited to 32,000 characters. Other channel state requires a new typed contract, not arbitrary profile JSON.

The frontend uses the existing resourceSync scheduler and socket. Accepted writes invalidate view-state; events contain no text. Draft writes debounce for 600 ms and participate in the shared quit-flush registry. The existing local draft cache remains an offline recovery and migration cache. An edit made during a save is retained and subsequently saved against the next revision.

If another channel changes a dirty draft, the local text stays visible until the person chooses Keep mine or Use other draft. Clean readers adopt the server value. Transient failures retain the draft and expose Retry.

Frontend persistence audit

This inventory records current ownership and remaining migrations. It does not claim every local preference is already synchronized.

StateCurrent ownerDecision
Models, provider connections, reasoningConversation/provider APIsReuse resolved session routes in every surface
Account UI/agent settingsUser profile API with optimistic cacheKeep existing profile merge and invalidation
Unsent conversation textUser view-state API; local recovery cacheShared useComposerDraft in every composer
Main workspace scope, selected chat, URLWorkspace navigation and chat persistenceKeep independent per window; remote creation must not navigate another window
Grid tabs, rail order/width, editor caret/scroll, transcript measurementsWindow/device persistenceKeep local; geometry and open views differ by screen
Unsaved file bodiesFile draft/editor ownerKeep separate from chat drafts; require file conflict semantics
Preview/browser history, mini app view state, folder expansionInspector/mini app ownersKeep scoped to the owning view; mini apps retain their typed data APIs
Prompt history, recent model menu ordering, palette/project MRULocal convenience historyDoes not decide executable routes; review cross-device history separately
Last workspace tip and tip countersLocal progress cachesCandidate for explicit profile fields; not conversation state
Notification preferences and spend thresholdLocal preference modulesRemaining candidates for profile migration
Notification journal/outbox and delivery receiptsExisting notification subsystemPreserve existing deduplication
Editor wrap, whitespace, autosave and inlay preferencesLocal editor preferencesCandidate for typed profile settings; do not mix with caret/geometry
Hover, focus, drag depth, open menus, HITL form controlsEphemeral UINever synchronize pointer or focus between channels
HITL requests, questions, answers, work and queueExisting server domain APIsShared forms/actions/transcript projection

The implementation lives in features/user/view-state-*, shared/lib/view-state, and entities/chat/model/useComposerDraft.ts. The decision is recorded in docs/adr/0001-shared-view-state.md; resource synchronization is documented in docs/internals/client-server-sync.md.