Repository navigation
fix: pass acp-tck for v1 and v2 agents - #150
Merged
Merged
Conversation
slapoguzov
self-requested a review
October 20, 2026 15:13
The v1 schema (agent-client-protocol 6d08f412) requires only `sessionId` and `cwd` in `ResumeSessionRequest`, but the model required `mcpServers`, so a conforming request failed to decode. Default it to an empty list, as the v2 model already does.
ACP requires the agent to replay the conversation through session/update before it answers session/load. The only session-level hook, postInitialize, runs after the response, so an agent on AgentSession could not meet that order without sending raw notifications from AgentSupport.loadSession. Add AgentSession.replayHistory(). The runtime calls it during session/load after registering the session and before sending the response, with client operations available in the coroutine context. If it throws, session/load fails and the session is unregistered. The v1 TCK agent now replays history there. Fixes acp-tck ACP-LOAD-002.
JSON-RPC lets a request or notification omit `params`, but the typed handlers decoded a missing `params` as `null`. Even a type whose fields all have defaults, such as `session/list`'s ListSessionsRequest, was rejected with -32700. Decode a missing `params` as an empty object, as sendRequest already does for a missing result.
A request whose `params` did not decode into the method's type was answered with -32700 (Parse error), and a value a custom serializer refused, such as a non-object `replayFrom`, with -32603. The message had already been parsed, so JSON-RPC calls this Invalid params (-32602). Decode params in one place for the typed request and notification handlers, and map a decoding failure there to -32602. A SerializationException raised anywhere else keeps its mapping. Fixes acp-tck v2 ACP-RESUME-208 and the v1 advisory ACP-ERROR-002.
agent-client-protocol 26008c5f (unstable v2) changed version
negotiation: the agent selects the highest version it supports at or
below the requested one. If there is none, it refuses `initialize` with
-32022 (Unsupported protocol version), and the error data holds
`requested` and `supported`. A missing, non-integer, or out-of-range
`protocolVersion` gets -32602, and a refused `initialize` does not
initialize the connection.
The v2 Agent now answers a request for version 2 or later with version
2. It refuses a lower version, v1-shaped or not, with -32022 and
`{"requested": n, "supported": [2]}`, and a version outside the uint16
range with -32602. Every method but `initialize` is refused with -32600
until `initialize` succeeds, as the Rust SDK does, so no session work
starts on a connection whose handshake failed. Add
JsonRpcErrorCode.UNSUPPORTED_PROTOCOL_VERSION, marked unstable.
Fixes acp-tck v2 ACP-INIT-003, ACP-INIT-202, ACP-INIT-205, ACP-INIT-206
and ACP-INIT-207.
…on/close ACP requires an agent that cancels active work on `session/close` to send that work's final updates and the idle `state_update` with the `cancelled` stop reason before it answers. The v2 Agent handed `session/close` straight to AgentSupport.closeSession, so the answer could overtake the turn's last updates. If a turn is running, the Agent now cancels it through AgentSession.cancel, as `session/cancel` does, and waits for it to end before it calls closeSession. Closing an idle session cancels nothing. Fixes acp-tck v2 ACP-CLOSE-203.
… cursors ACP requires every successful `session/resume` to send the session's current foreground state as a `state_update` after any replay and before the response, also when `replayFrom` is omitted. An agent must refuse a `replayFrom` cursor type it does not support with -32602 instead of resuming without replay. Only the implementation knows whether a session is idle, running, or waiting for the user, so AgentSupport.resumeSession now documents both duties instead of the SDK guessing. The v2 TCK agent keeps the state it last reported, sends it when it resumes a session, and refuses ReplayFrom.Unknown. Fixes acp-tck v2 ACP-RESUME-206 and ACP-RESUME-207.
EugeneTheDev
force-pushed
the
eugenethedev/tck-fixes
branch
from
October 20, 2026 17:23
7537519 to
aecc730
Compare
slapoguzov
approved these changes
Oct 20, 2026
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.
Fixes the SDK behavior that made acp-tck fail. With these changes, both the v1 and v2 agents pass acp-tck at the pinned revision (
3d46e21). One fix per commit.Behavior changes
session/resumewithoutmcpServersis accepted (v1). The v1 schema makes the field optional, but the SDK rejected such requests.session/loadcan replay history before its response (v1). The runtime calls the newAgentSession.replayHistory()after the session is registered and before the response is sent. If the hook throws,session/loadfails and the session is unregistered. Fixes LOAD-002.paramsare decoded as{}(v1 and v2). Types whose fields all have defaults no longer fail to decode;session/listis one example.-32602(Invalid params) (v1 and v2). They used to get-32700(Parse error), or-32603when a custom serializer rejected the value. A client now seesAcpExpectedErrorwhere it used to seeSerializationException. Fixes RESUME-208 and the v1 advisory ERROR-002.Agentnegotiatesinitializeas the v2 spec requires (upstream26008c5f). A request for version 2 or higher is answered with 2. A lower version is refused with-32022(Unsupported protocol version) and{"requested": n, "supported": [2]}as data. A missing, non-integer, or out-of-range (outside uint16) version gets-32602. Fixes INIT-003/202/205/206.Agentserves nothing butinitializeuntilinitializesucceeds. Other methods get-32600, as in the Rust SDK, so no session work starts on a connection whose handshake was refused. Fixes INIT-207.session/closesends the cancelled turn's final updates before it answers. If a turn is running, theAgentcancels it throughAgentSession.cancel(), assession/canceldoes, and waits for it to end before it callsAgentSupport.closeSession. Fixes CLOSE-203.session/resumeit sends the currentstate_updatesnapshot and refuses unsupportedreplayFromcursor types with-32602. Fixes RESUME-206/207.Public API changes
AgentSession.replayHistory()(acp/api/acp.api). Its default implementation does nothing. An agent that supportssession/loadmust replay history here to comply with the spec. Updates sent frompostInitializearrive after thesession/loadresponse.JsonRpcErrorCode.UNSUPPORTED_PROTOCOL_VERSION(-32022), marked@UnstableApi(acp-model/api/acp-model.api).ResumeSessionRequest.mcpServers(stable model) now defaults toemptyList(). The.apidump doesn't change, because the defaults overload already existed.v2.AgentSupport.resumeSessionnow says the implementation must send the current-statestate_updateafter any replay and must reject cursors it doesn't support with-32602. Only the implementation knows whether a session is idle, running, or waiting for the user, so the SDK doesn't send the snapshot itself.Remaining
session/new. The TCK agent has no MCP client, so this is a gap in the TCK agent, not an SDK defect.Verification
./test-tck/run_tck.sh 1→ CONFORMANT (1 advisory failure, SESSION-004);./test-tck/run_tck.sh 2→ CONFORMANT, no failures../gradlew checkpasses.ResumeSessionSerializationTest,SimpleAgentTest(replay order and replay failure),ProtocolTest(missingparams, undecodable params →-32602),AgentTest(v2 negotiation,-32022data, malformed versions, initialization gate),PromptReceiptTest(close mid-turn and close when idle),V2ClientTest(v1 client refused with-32022).