Skip to content

ACP: Config-based live session resume across app restarts #361

Description

@julianromli

Problem or Opportunity

Live session resume (session/load / session/resume) only works within a single app session where the agent never disconnected. After an app restart, reopened history sessions always fall back to read-only local transcripts, even when the user re-spawns the same agent config.

Root cause in src/renderer/stores/acp-store.ts:968-969:

const connected = get().agentStatus[meta.agentId] === 'connected'
const capabilities = get().agents[meta.agentId]?.capabilities ?? null

The resume decision keys on meta.agentId — the specific live agent process UUID persisted with the session. After a restart:

  • No agent is connected, so connected is always falsedecideResume returns 'local' (read-only).
  • Even if the user re-spawns the same agent config, it gets a fresh AgentId UUID (src-tauri/src/acp/config.rs:20-22), so it never matches meta.agentId from before the restart.

The agentConfigId is persisted with the session (acp-store.ts:402), which could in principle enable config-based resume matching, but that matching is not implemented.

This is not a crash (the local fallback ensures history is always viewable), but it is a significant UX limitation: a core ACP selling point — closing a chat and picking up the conversation later with full agent context — degrades to read-only after every restart.

Proposed Solution

Switch the resume matching from agent-process-id to agent-config-id, so a freshly-spawned agent of the same config can load/resume a prior session.

  1. Re-key the resume lookup on agentConfigId. In openHistorySession, after loading meta, find any connected agent whose configId matches meta.agentConfigId (instead of requiring meta.agentId to be live). Use that agent's live agentId + capabilities for the decideResume decision and the subsequent session/load / session/resume call.

  2. Offer to re-spawn if no warm agent matches. If no connected agent matches the config, offer a one-click "Reconnect and resume" action that spawns the agent config first (reusing the warm-agent path in startChat), then runs the load/resume flow.

  3. Surface the resume strategy to the user. Make it visible whether a reopened session is live-resumed (agent replays history) or read-only (local transcript), and provide a path to upgrade read-only → live when a matching agent is available.

  4. Persist enough to reconnect. Ensure agentConfigId, cwd, and the originally-selected MCP server ids are all persisted so the re-spawn reproduces the original session context.

Success Criteria

  • Reopening a history session after a restart, with the same agent config spawned, performs a live session/load or session/resume (not a read-only fallback) when the agent advertises the capability.
  • If no matching agent is warm, the UI offers to spawn the config and then resume.
  • The resume strategy (live vs. read-only) is visible to the user.
  • Read-only fallback still works when no matching agent can be produced.

Additional Context

  • Resume decision: src/renderer/stores/acp-store.ts:957-1018, src/renderer/lib/acp-resume-policy.ts.
  • Persistence includes agentConfigId: src/renderer/stores/acp-store.ts:402.
  • Agent ids are fresh UUIDs per spawn: src-tauri/src/acp/config.rs:20-22.
  • Backend capability gates (gate_load_session / gate_resume_session) already handle the capability check once a matching agent is found: src-tauri/src/acp/manager.rs:563-587.
  • Related: ADR-003.7 (cited in acp-resume-policy.ts:2, but the ADR is missing — see docs: Restore missing ADR-003/ADR-004 referenced 40+ times in ACP source #357).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions