Repository navigation
v0.9.0
Negotiate protocolVersion at init time and emit v1 or v2
session/update payloads accordingly. Same code base, dispatch by
version. The implementation adds:
protocol::ProtocolVersionenum (V1,V2,LATEST) and the
Session::protocol_versionfield for defense-in-depth and future
per-session routing.AppState::protocol_version(set byrun_acp_loopfrom the negotiated
value) so every emit helper branches on the same source of truth.
AppState: Cloneis hand-written; sessions are wrapped in
Arc<RwLock<...>>so the clone shares the map.acp::notify_*_for(version, …)dispatchers that route to the v1 or
v2 implementation. The plain (no-suffix)notify_*functions stay
as the v1 shortcut for code paths that have not migrated.acp::notify_state_idle_for()for v2-onlystate_update(IdleState).negotiate_protocol_version(params)inmain.rs— implements the
ACP spec's "pick the highest version we both support" rule.
Clients that omitprotocolVersionfall back to v1 (conservative
default). Clients requesting a version > 2 fall back to v2 with a
warning.- v2-shaped
InitializeResponse: unifiedinfo+capabilities
(role-agnostic), withcapabilities.session.prompt.imageexpressed
as{}(capability marker) when supported. - v2-shaped
session/updatediscriminators:agent_message_chunk,agent_thought_chunk(chunk variants)tool_call_update(instead of v1'stool_call)plan_updatewithplan: { type: "items", planId, entries[] }
- v2 baseline
session/close(alias for v1'ssession/end) and
session/list(returns active sessions as
{sessions: [{sessionId, cwd}], nextCursor: null}). - v2 graceful rejects for
session/delete,session/resume,
session/load:-32601not_implemented/-32001
no_persistencewith stabledata.reason. LlmConfig.build_bodyis now backend-aware: OpenAI-compatible gets
top-leveltemperature/max_tokens; Ollama native gets them
insideoptions(temperature+num_predict). The previous
top-level-only shape meant every Ollama native request silently used
the model's defaults for sampling.
Tests
9 new tests in tests/clients/protocol_version.rs:
v2_initialize_returns_unified_capabilities_shapev2_tool_call_uses_tool_call_update_not_tool_callv2_plan_uses_plan_update_with_plan_idv2_emits_state_update_at_end_of_turnv2_does_not_emit_state_update_for_v1_clientsv1_client_gets_legacy_shapes_unchangedinspector_style_session_list_returns_empty_array_with_no_sessions
(updated from the pre-0.9.0 negative-test now thatsession/list
is implemented)inspector_style_session_close_succeeds_and_variants(updated
similarly)
168 tests passing; cargo fmt --check and
cargo clippy --all-targets -- -D warnings clean.
Migration
- v1 Clients see no behavior change. The plain
notify_*functions
still emit v1, and every emit site inmain.rswas migrated to
use the_for(version, …)helpers that branch on the negotiated
version. - Existing
inspector_style_session_list_returns_method_not_found_gracefully
andinspector_style_session_close_returns_method_not_found_gracefully
tests were renamed and rewritten as positive tests. The original
intent of those tests (probe capability, get clear error) is
preserved —session/closenow returns-32001 UnknownSession
instead of-32601 MethodNotFoundwhen called on a non-existent
session, andsession/listreturns{sessions: []}with no
sessions open.
Co-Authored-By: Claude noreply@anthropic.com
Full Changelog: v0.8.2...v0.9.0