Skip to content

feat(external_websocket_sync): mirror ACP elicitations to Helix and accept answers - #83

Closed
lukemarsden wants to merge 7 commits into
mainfrom
feature/002731-agent-questions
Closed

lukemarsden wants to merge 7 commits into
mainfrom
feature/002731-agent-questions

Conversation

@lukemarsden

Copy link
Copy Markdown

Companion to helixml/helix#3009, which pins this branch via ZED_COMMIT in sandbox-versions.txt. Merge this one first.

crates/external_websocket_sync/ mirrors the Zed agent thread into Helix, but its entry mapping in thread_service.rs matched only UserMessage | AssistantMessage | ToolCall and _ => returned everything else. acp_thread::AgentThreadEntry::Elicitation was silently dropped, so when Claude Code asked the user a question through AskUserQuestion — which claude-agent-acp turns into an ACP form elicitation that blocks the turn — Helix saw nothing answerable and the turn eventually died with Tool use aborted.

What this adds

  • SyncEvent::{ElicitationRequested, ElicitationResolved, ElicitationResync, ElicitationResponseAck} with their to_outgoing_message() arms, and one elicitation_status_str() mapping Zed's Canceled to the wire's cancelled so the two spellings cannot spread.
  • Emission from AcpThreadEvent::ElicitationRequested / ElicitationResponded and the EntryUpdated arm, with the requested_schema serialized verbatim — Helix renders the options, so nothing may be lossily flattened.
  • A heartbeat plus a full resync on reconnect / open_thread, so Helix can tell "the agent still holds this question" from "the process that held it is gone" without guessing from the reconnect itself.
  • A respond_elicitation command: GLOBAL_ELICITATION_RESPONSE_CALLBACK + pending queue, dispatched to a GPUI task calling AcpThread::respond_to_elicitation, which already no-ops safely on an unknown id or a non-Pending status. The ack reports accepted / noop / not_found rather than failing silently.
  • E2E Phase 18 covering egress and resolution, driven through the synthetic seam so a CI phase never depends on the model choosing to call a tool.

This deliberately does not touch agent_ui: the Zed agent panel's elicitation card renders with no option controls, and it stays that way — Helix is self-sufficient.

Testing

The full dockerized suite is green with Phase 18 (single zed-agent round):

[zed-agent] Phase 18: ✅ question recorded pending with a 363-byte schema carrying both options
[zed-agent] Phase 18a: ✅ respond_elicitation delivered to Zed
[zed-agent] Phase 18a: ✅ Zed's ack round-tripped: question is now cancelled (agent_no_longer_holds)
[zed-agent] Phase 18b: ✅ question is terminal (accepted) and no longer answerable
[zed-agent] Phase 18: ✅ a normal turn still completes after the question cycle
  E2E TEST PASSED

Adding a phase also pushed a zed-agent round to ~190s, past run_e2e.sh's DEFAULT_TIMEOUT=300 * AGENT_COUNT; that budget is raised to 450s/round, which matters for CI since it uses the default.

Not verified: the two-agent matrix (E2E_AGENTS="zed-agent,claude"). The zed-agent round passes; the claude round stalls at Phase 1 — before any elicitation code runs — inside the runtime-installed claude-agent-acp startup. Believed unrelated, but unverified. No live end-to-end run has been done yet either; that is in progress and both PRs should wait for it.

🤖 Generated with Claude Code

…ccept answers

Spec-Ref: helix-specs@7f9f3cc63:002731_implement-the-feature
…-end-agent

Spec-Ref: helix-specs@5878c07a9:002731_implement-the-feature
Spec-Ref: helix-specs@fad4986b2:002750_finish-agent-questions
Spec-Ref: helix-specs@fad4986b2:002750_finish-agent-questions
Spec-Ref: helix-specs@fad4986b2:002750_finish-agent-questions
…est_id

Spec-Ref: helix-specs@fad4986b2:002750_finish-agent-questions
Spec-Ref: helix-specs@b30683e41:002750_finish-agent-questions
@cursor

cursor Bot commented Aug 12, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@nessie993

Copy link
Copy Markdown

Superseded by the merged transport in #95 and the merged Helix implementation in helixml/helix#3220. Closing to keep one maintained implementation path.

@nessie993 nessie993 closed this Sep 13, 2026
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.

3 participants