Resume a persisted ACP session instead of always starting a new one - #3
Open
tmecklem wants to merge 2 commits into
Open
Resume a persisted ACP session instead of always starting a new one#3tmecklem wants to merge 2 commits into
tmecklem wants to merge 2 commits into
Conversation
A Session restarted from its persisted row — after the local runtime crashed, or was lost to a restart — always called session/new. The agent still held the conversation, so the user was handed an empty transcript for work that was still there, and the old session was left stranded in the agent. start_session/7 now takes a :resume_session_id, which Session fills in from the persisted acp_session_id. When present, the client calls session/load so the agent replays the conversation as session/update notifications. The load is best-effort: an agent that doesn't advertise loadSession, or one that has since expired the session, falls back to session/new rather than failing the connect. A resume that can't be honoured still has to leave the user with a working agent.
A host whose only record of a running agent is the environment itself needs that process addressable and tagged from the moment it spawns — not once the runner happens to report back, which leaves a window where a live agent is untagged and therefore undiscoverable. start_session/7 forwards :process_session_id, :process_name and :process_metadata to the process runner. All optional; runners that ignore them behave exactly as before.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
ACPRuntime.Sessionis started from a persisted session row, and that row already carries anacp_session_idwhenever the session has run before — after the local runtime crashed, or was lost to a host restart.Client.start_session/7ignored it and always calledsession/new. Two consequences:Downstream (in Launchbox) this shows up as a coding-agent tab that silently disappears when you close and reopen a card: the runtime can be restarted from the row, but reconnecting produced a blank session, so there was nothing worth showing.
The fix
start_session/7accepts a:resume_session_id, whichSession.connect/2fills in from the persistedacp_session_id. When one is present the client callssession/load, and the agent replays the conversation assession/updatenotifications.The load is best-effort. An agent that doesn't advertise
loadSession, or one that has since expired the session, falls back tosession/newrather than failing the connect — a resume that can't be honoured still has to leave the user with a working agent.Behaviour is unchanged when there's nothing to resume (
acp_session_idisnil), which is every session that has not run before.Notes
ExMCP.ACP.Client.load_session/4already existed and gates on the agent'sloadSessioncapability internally, so there's no duplicated capability check here — an unsupported load simply returns an error and falls through.start_session/7keeps its arity and the new value rides in the existing opts keyword, so alternativeclient_moduleimplementations are unaffected.Test plan
mix precommit— 32 tests, clean build, formatted.New coverage:
client_test.exs— a resumed session sendssession/loadwith the rightsessionId/cwd, and returns that id.client_test.exs— an agent that rejects the load falls back tosession/newand still returns a working session.session_test.exs— a persistedacp_session_idis passed down as:resume_session_id; a session with nothing to resume passesnil.Also verified against a real consumer: pointed Launchbox at this checkout as a path dep and confirmed a Launchbox-persisted
acp_session_idreaches the client as:resume_session_id, and that the assertion fails without theSession.connect/2change. Launchbox's own suite passes against this branch.