Skip to content

WTA ACP 0.10→1.0 migration#367

Merged
DDKinger merged 30 commits into
mainfrom
dev/yuazha/acp-1.0-phase0
Jul 8, 2026
Merged

WTA ACP 0.10→1.0 migration#367
DDKinger merged 30 commits into
mainfrom
dev/yuazha/acp-1.0-phase0

Conversation

@DDKinger

@DDKinger DDKinger commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

WTA ACP 0.10 → 1.0 migration (behavior-preserving)

Migrates the WTA helper/master ACP plane from agent-client-protocol 0.10 (the removed ClientSideConnection/AgentSideConnection trait-impl model) onto 1.0's builder/dispatch model. The migration itself is behavior-preserving; this PR also bundles the fixes that surfaced while doing it.

Migration

  • Cargo: agent-client-protocol 0.10 → 1.0; dropped the now-stabilized unstable_session_list / unstable_session_model features. Regenerated cgmanifest.json + NOTICE.md. (No agent-client-protocol-tokio — it's stuck at 0.11.1 needing core ^0.11; Client/Agent/ByteStreams ship in core 1.0.)
  • New conn.rs compat shim: re-exposes the old "stash a connection, drive I/O on the side, call typed methods later" shape on top of the 1.0 builder model — ClientLink / AgentLink / spawn_client / spawn_agent / byte_streams, each returning a handle_io liveness future. Re-declares the dropped session/set_model request locally so Copilot/Gemini model switching keeps working (Claude switches via the still-standard session/set_config_option).
  • client.rs / master/mod.rs: ClientSideConnection / AgentSideConnectionClient / Agent.builder().on_receive_*().connect_with(...); conn.method().awaitcx.send_request().block_task().await; the 5 impl acp::Client/Agent blocks → builder callbacks.
  • ~538 mechanical acp::<T>acp::schema::v1::<T> path moves.

Fixes bundled in

  • Preserve the master-death degraded-state contract from fix(agent): consistent disconnected state when wta-master dies — recover with /restart, no split-brain #329 under ACP 1.0: killing wta-master must drop the pane out of Connected into the /restart-only state (no split-brain). The 1.0 rewrite regressed this — a clean pipe EOF no longer resolved handle_io — so the helper now watches the transport reader directly (DeathWatchReadTransportDeath) to restore it.
  • Model-switch fallback: on the config-option channel, a MethodNotFound from session/set_config_option now falls back to legacy session/set_model (and records Legacy), so an agent that advertises a config-option model selector but only implements set_model still switches. Before schema 1.1 dropped NewSessionResponse.models, the legacy field took priority and this couldn't arise.
  • Shared agent-CLI deadlock: a reentrant request_permission mid-prompt no longer wedges the master dispatch loop — 1.0 dispatches handlers serially inline, so the handler is now spawned instead of inline-awaited.
  • ACP 1.0 ext methods: account for the leading-underscore strip 1.0 applies on receive, so the _intellterm.wta/* local methods are matched instead of falling through to the agent CLI.
  • Connection-setup failure surfaces as an error instead of a busy-wait spin, and callers no longer risk spinning until an external timeout.
  • Delegate to a non-launchable agent now opens a persistent single-line error tab instead of a tab that flashes shut before the user can read the error.

Tests

  • New unit guards for TransportDeath / DeathWatchRead and for handle_io resolving on peer death (both client and agent sides).
  • Model-switch fallback tests: config-option MethodNotFound falls back to set_model and flips the channel to Legacy; a non-MethodNotFound error propagates without falling back.
  • Hardened SessionList e2e against the arrow-key re-render race and made draft-preservation view detection read pane text rather than a UIA label.
  • Full WTA unit suite: 998 pass / 0 fail; cargo build clean.

DDKinger and others added 5 commits June 29, 2026 08:08
…h moves

- tools/wta/Cargo.toml: agent-client-protocol 0.10 -> 1.0; drop stabilized
  features (unstable_session_list/model). No agent-client-protocol-tokio:
  AcpAgent ships in core 1.0; the helper crate is stuck at 0.11.1.
- Mechanical: ~538 acp::<T> / agent_client_protocol::<T> -> ::schema::v1::<T>.
- Adds doc/specs/acp-1.0-conductor-migration.md.
- Crate does NOT compile yet: 47 structural errors (connection ctor + 5
  trait impls + call sites) are chunk 2-4.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… 2-4 TODO)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ld + 1017 tests green

Confine 1.0 builder/dispatch to shim protocol/acp/conn.rs (ClientLink/AgentLink
wrap ConnectionTo; spawn_client/agent return link+handle_io). impl Client/Agent
-> on_receive_* enum dispatch. set_session_model removed in schema 1.1 -> local
type, models via config-option. ext_* only enum-falls-through for _-prefixed, so
intellterm.wta/* -> _intellterm.wta/*. N:1 multiplexer stays bespoke.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…entLink::new, helper set_session_model, record_channel_legacy)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 29, 2026 04:41

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check-spelling found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR performs Phase 0 of the WTA ACP 0.10 → 1.0 migration by updating the WTA helper/master ACP plumbing to the agent-client-protocol 1.0 builder/dispatch model while aiming to preserve existing behavior. It also adds a compat layer (protocol::acp::conn) to keep the rest of the WTA code using a “connection handle + handle_io future” shape similar to the pre-1.0 API.

Changes:

  • Upgrades agent-client-protocol to 1.0 and rewrites ACP message/type usage to acp::schema::v1::*.
  • Introduces tools/wta/src/protocol/acp/conn.rs as a compatibility shim around 1.0 ConnectionTo<>, and migrates helper/probe/CLI/test paths to use it.
  • Regenerates third-party notices (cgmanifest.json, NOTICE.md) and adds a new migration design spec.

Reviewed changes

Copilot reviewed 19 out of 20 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tools/wta/src/shell/wt_channel/mod.rs Adjusts public re-exports for wtcli channel helpers.
tools/wta/src/protocol/acp/soft_stop.rs Updates stop-reason typing to acp::schema::v1 and aligns tests.
tools/wta/src/protocol/acp/probe.rs Migrates probe-models ACP path to the 1.0 connection shim and v1 schema types.
tools/wta/src/protocol/acp/model_select.rs Reworks model extraction/switching to schema v1 config-options + legacy set-model compatibility path.
tools/wta/src/protocol/acp/mod.rs Exposes the new conn module in the ACP protocol tree.
tools/wta/src/protocol/acp/mock_agent_tests.rs Updates in-process ACP mock harness to builder/dispatch model using the connection shim.
tools/wta/src/protocol/acp/conn.rs Adds a 1.0 “compat shim” (ClientLink/AgentLink, spawn helpers, and legacy session/set_model request).
tools/wta/src/protocol/acp/client.rs Migrates helper ACP client wiring and dispatcher to builder/dispatch and the connection shim.
tools/wta/src/main.rs Updates CLI entrypoints (probe-models, sessions list, delegate registration) to use builder/dispatch + LocalSet + shim.
tools/wta/src/cli_tests.rs Updates tests for schema v1 SessionId path changes.
tools/wta/src/app.rs Updates app state/event types and ACP call sites to schema v1 ids and requests.
tools/wta/src/agent_hooks_installer.rs Minor signature cleanup to silence unused parameter warnings.
tools/wta/src/agent_check.rs Removes now-unused imports.
tools/wta/cgmanifest.json Updates CG manifest entries for the new ACP crate versions (and new derive crate).
tools/wta/Cargo.toml Bumps agent-client-protocol dependency to 1.0 and drops unstable feature flags.
tools/wta/Cargo.lock Updates lockfile to ACP 1.0 dependency graph and new transitive crates.
NOTICE.md Regenerates third-party attributions to match the updated Rust dependency graph.
doc/specs/acp-1.0-conductor-migration.md Adds a detailed spec/plan for the broader conductor/proxy migration beyond Phase 0.
Comments suppressed due to low confidence (1)

tools/wta/src/protocol/acp/model_select.rs:63

  • models_from_new_session no longer updates MODEL_SWITCH when the agent does not advertise a model selector in config_options. Because MODEL_SWITCH is process-global, this can leave a stale Config { config_id } from a previous session and later route apply_session_model to session/set_config_option with the wrong config_id (or when the agent only supports legacy switching). The doc comment above the function also still claims we prefer the legacy models field, but the schema 1.1 type no longer exposes it.

Reset the channel to Legacy when no config-option model selector is found, and update the doc comment to match the new behavior.

/// Extract the model list and current model id from a `new_session` response,
/// preferring the legacy `models` field and falling back to a `config_options`
/// `Select` with `category == Model`. Records the switch channel as a side
/// effect so [`apply_session_model`] later dispatches correctly.
pub(crate) fn models_from_new_session(
    resp: &acp::schema::v1::NewSessionResponse,
) -> (Vec<AcpModelInfo>, Option<String>) {
    if let Some(opts) = &resp.config_options {
        if let Some((config_id, models, current)) = model_option_from_config(opts) {
            record_channel_config(&config_id);
            return (models, current);
        }
    }

    (Vec::new(), None)
}

Comment thread tools/wta/src/protocol/acp/conn.rs Outdated
@github-actions

This comment has been minimized.

DDKinger and others added 3 commits June 29, 2026 15:59
…drop dev username from spec

cx() awaited a OnceLock via yield_now spin; if connect_with failed pre-ready it would spin forever. Replace with a Notify + failed flag and make cx() fallible so setup errors surface as acp::Error. Reword spec branch ref to dev/<alias>.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…AHP, sacp, reorderable, workstream, etc)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…/list + MCP-inject + session_list/probe-sessions to 1.0

main reworked session-title sourcing from on-disk to host ACP session/list
(host_session_list_raw, try_refresh_title_via_acp, new session_list.rs/
session_history.rs, MCP server inject in session/new). Resolved all conflicts
taking main's evolved code and porting it to the 1.0 builder/shim: ClientLink
agent_conn, schema::v1 paths, StubClient/ProbeClient -> Client.builder().

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 30, 2026 08:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

tools/wta/src/protocol/acp/model_select.rs:59

  • models_from_new_session only records the switch channel when a model config_options entry is found, which can leave a stale ModelSwitchChannel::Config value across agent restarts or across new_session responses that don't carry the model selector. This contradicts the module comment that the channel is refreshed on every parse, and can cause apply_session_model to send session/set_config_option to an agent that only supports legacy session/set_model. Reset the channel to Legacy at the start of each parse, then override to Config when a model selector is found.
    if let Some(opts) = &resp.config_options {
        if let Some((config_id, models, current)) = model_option_from_config(opts) {
            record_channel_config(&config_id);
            return (models, current);
        }

Comment thread tools/wta/src/protocol/acp/conn.rs
Comment thread tools/wta/src/protocol/acp/session_list.rs Outdated
DDKinger and others added 4 commits June 30, 2026 16:50
…tale ACP 0.10/!Send note in session_list

Addresses Copilot review on PR #367.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…re diagrams

Phase 0/2 had detail sections; add matching Phase 1 (master->Conductor) and
Phase 3 (WT control via MCP-over-ACP) details, plus an 'after this phase'
mermaid diagram for each of Phase 0/1/2/3. Chinese spec updated in parallel
(maintained outside the repo).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…hase 2 tables

- Enrich Today/Target diagrams: contrast today's app.rs monolith vs target's composable proxies; add the session-proxy family (list-union / enrichment / activity) plus a residual non-proxy core.

- Correct topology and facts: N x agent-side + 1 x client-side connections, Class A/B session sources, helper-side alive-mirror, and session/list history sourcing.

- Phase 1 diagram now uses dashed edges for what is new vs Phase 0 (mirrors the Phase 2 diagram).

- Merge the four Phase 2 tables into two (app.rs responsibility + extraction; proxy criterion + viability); drop bold on session labels.

- Retitle 'Phase 2 detail' to focus on proxy extraction rather than app.rs; update the anchor link.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update the stale ClientSideConnection / AgentSideConnection names in the module header to the conn.rs shim (ConnectionTo<Client> / ConnectionTo<Agent> via ClientLink / AgentLink / spawn_client / spawn_agent). Comment-only; no behavior change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 1, 2026 09:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

tools/wta/src/protocol/acp/model_select.rs:59

  • models_from_new_session only records the switch channel when a model config option is present. If it previously saw a config-option model selector, then later parses a new_session response with no model config option, MODEL_SWITCH remains stuck in Config, and apply_session_model will incorrectly try session/set_config_option against legacy agents (Copilot/Gemini), causing model switching to fail. Reset the channel back to Legacy when no model option is parsed so the channel is refreshed on every parse as the module docs describe.
    if let Some(opts) = &resp.config_options {
        if let Some((config_id, models, current)) = model_option_from_config(opts) {
            record_channel_config(&config_id);
            return (models, current);
        }

Comment thread tools/wta/src/protocol/acp/model_select.rs Outdated
Comment thread tools/wta/src/protocol/acp/conn.rs Outdated
Comment thread tools/wta/src/protocol/acp/conn.rs Outdated
@github-actions

This comment has been minimized.

…o the right

- Target & Phase 1 diagrams: route the N helper transports into the N:1 bridge (helper -> BR) before it feeds the conductor, so the bridge is no longer drawn without an upstream; keep BR --- AC. In Phase 1 the new bridge->conductor link is dashed (new vs Phase 0) while the helper->bridge transport stays solid.

- Legend now notes the N:1 bridge stays hand-rolled because the library's linear 1:1 chain cannot express N clients sharing one agent, pointing to The topology caveat.

- Target diagram: declare the proxies subgraph before master so the composable proxies render to the right of the conductor spine (layout-only; verified by rendering to SVG).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@DDKinger DDKinger marked this pull request as draft July 1, 2026 10:14
@github-actions

This comment has been minimized.

Resolve the single content conflict in tools/wta/src/agent_check.rs: main's #370 (WTA login-flow cleanup) removed check_all_agents() and all its callers, so the KNOWN_AGENTS import is now unused — take main's 'use crate::agent_registry;'. All other WTA files auto-merged; wta crate builds clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread doc/specs/acp-1.0-conductor-migration.md Fixed
Comment thread doc/specs/acp-1.0-conductor-migration.md Fixed
Comment thread doc/specs/acp-1.0-conductor-migration.md Fixed
Comment thread doc/specs/acp-1.0-conductor-migration.md Fixed
Comment thread doc/specs/acp-1.0-conductor-migration.md Fixed
Comment thread doc/specs/acp-1.0-conductor-migration.md Fixed
Comment thread doc/specs/acp-1.0-conductor-migration.md Fixed
Comment thread doc/specs/acp-1.0-conductor-migration.md Fixed
Comment thread doc/specs/acp-1.0-conductor-migration.md Fixed
Comment thread doc/specs/acp-1.0-conductor-migration.md Fixed
@github-actions

This comment has been minimized.

…ane text

The 'View switch preserves the draft input' case read AgentLabelText's UIA value (winapp get-value) to detect the chat/session view, but that value comes back empty here (the label surfaces text via Name, not a Value pattern, and the per-tab pre-warm can target another pane), so the setup hard-failed. It also clicked the chat toggle unconditionally, stashing an already-chat pane.

Detect the view from the pane text via Get-SessionViewRenderRegex (the same locale-robust footer-hint signal Open-SessionList / Test-SessionListShown use) and only click a toggle when a switch is actually needed. Export Get-SessionViewRenderRegex for test use.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

This comment has been minimized.

…race

The "selection moves with arrow keys" test read the selected row once,
immediately after sending Down. Under load the TUI re-render + capture-pane
read can lag the keypress, so a single read occasionally caught the pre-move
frame (flaky: 12/1/1 in a full-batch run vs 4/4 passing in isolation -- not
an ACP 1.0 regression). Poll (re-pressing Down) until the selected row differs
from the start, and skip cleanly on a single-row list.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

This comment has been minimized.

ACP 1.0's `connect_with(transport, main_fn)` surfaces peer death only by
returning, and `run_until` returns early only when the internal background
I/O *errors*. Killing wta-master produces a clean EOF (not an error), so
with a `pending` main_fn `connect_with` hung forever, `handle_io` never
resolved, and the helper never emitted `TransportLost` — the pane stayed
`Connected` (AgentMasterDeath #329). ACP 0.10's `handle_io` was the direct
I/O future and resolved on EOF, so this is a regression from the rewrite.

Watch the incoming reader directly: `DeathWatchRead` trips a `TransportDeath`
latch on EOF/read-error, and `main_fn` now awaits it (`death.wait()`) instead
of `pending`, so `connect_with` returns and `handle_io` fires on peer death.
Wrapping lives in `byte_streams`/`WatchedTransport`, so all call sites are
unchanged. Adds regression tests for both client and agent sides.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

This comment has been minimized.

The two existing handle_io integration tests (#329) prove the end-to-end
"peer death resolves handle_io" contract but exercise only the clean-EOF path.
Add focused unit tests pinning the primitives the fix is built on so a future
refactor of either can't silently reintroduce the hang (or tear down a live
connection):

- DeathWatchRead classification: real EOF (0-byte read into a non-empty
  buffer) and read errors signal death; a benign empty-buffer 0-byte read
  and a normal non-empty read do NOT (guards the !buf.is_empty() check).
- TransportDeath latch: wait() returns when already signaled, wakes on a
  signal that races in after it starts waiting, and signal() is idempotent.

Full suite: 996 passed / 0 failed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread tools/wta/src/protocol/acp/conn.rs Fixed
Comment thread tools/wta/src/protocol/acp/conn.rs Fixed
Comment thread tools/wta/src/protocol/acp/conn.rs Fixed
Comment thread tools/wta/src/protocol/acp/conn.rs Fixed
Comment thread tools/wta/src/protocol/acp/conn.rs Fixed
@github-actions

This comment has been minimized.

DDKinger and others added 2 commits July 6, 2026 19:28
- conn.rs: spawn_client/spawn_agent now surface a cancelled `done_tx`
  (connection task dropped/panicked) as an `internal_error` instead of
  masking it as a clean `Ok(())` shutdown (Copilot review).
- check-spelling: rename the `dwr` test variable to `reader`
  (unrecognized word) and replace `non-existent` with `nonexistent`
  in coordinator.rs / main.rs (forbidden-pattern rule).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@DDKinger DDKinger marked this pull request as ready for review July 7, 2026 00:40
Copilot AI review requested due to automatic review settings July 7, 2026 00:40
@DDKinger DDKinger changed the title WTA ACP 0.10→1.0 migration (Phase 0: behavior-preserving model rewrite) WTA ACP 0.10→1.0 migration Jul 7, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 26 changed files in this pull request and generated 2 comments.

Comment thread tools/wta/src/protocol/acp/model_select.rs Outdated
Comment thread tools/wta/src/main.rs
…unimplemented

Addresses a PR #367 review comment on the model-switch path. Since schema
1.1 removed NewSessionResponse.models, models_from_new_session records the
Config channel whenever config_options carries a model selector, and
apply_session_model then used session/set_config_option unconditionally. An
agent that advertises a config-option model selector for discovery but only
implements the legacy session/set_model would fail model switching with
MethodNotFound (-32601).

apply_session_model now falls back to session/set_model on a MethodNotFound
from set_config_option, and records the Legacy channel so later switches
skip the dead config channel. Other errors still propagate unchanged. Adds
unit tests for both the fallback (config MethodNotFound -> set_model + channel
flip) and the no-fallback path (a non-MethodNotFound error propagates), driven
over real ACP via a typed session/set_model mock handler.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread tools/wta/src/protocol/acp/model_select.rs Fixed
@github-actions

This comment has been minimized.

check-spelling forbids the noun 'fallback' immediately before 'to'; the
test assertion message must use the verb form 'fall back to'.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 7, 2026 03:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 26 changed files in this pull request and generated 1 comment.

Comment thread tools/wta/src/coordinator.rs
Resolve client.rs import conflict with #385 (Copilot auth flow): keep the
ACP 1.0 `use super::conn;` shim import and add `HandshakeStage` to the
`failure` import (both are used). app.rs / main.rs / Cargo.toml auto-merged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@DDKinger DDKinger merged commit 3de9b3c into main Jul 8, 2026
10 checks passed
DDKinger added a commit that referenced this pull request Jul 9, 2026
Integrates the WTA ACP 0.10->1.0 migration (#367) and other main changes. Conflict resolution: kept the workspace-command re-exports in wt_channel/mod.rs (annotated the now-orphaned spawn_wtcli_focus_pane with #[allow(dead_code)] to match its sibling, since main's dispatch_focus_pane moved to dispatch_session_focus_rpc); took main's Cargo.lock + NOTICE.md then regenerated NOTICE.md + cgmanifest.json for the merged graph (ACP 1.0 + chrono). Verified: wta cargo test 1016 passed/0 failed (all workspace feature tests intact), full C++ bcz no_clean 0 errors.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants