Skip to content

feat(acp): add elicitation/create JSON-RPC method with capability negotiation - #99

Closed
Million-mo wants to merge 9 commits into
develop/agenticfrom
feat/acp-elicitation
Closed

feat(acp): add elicitation/create JSON-RPC method with capability negotiation#99
Million-mo wants to merge 9 commits into
develop/agenticfrom
feat/acp-elicitation

Conversation

@Million-mo

Copy link
Copy Markdown
Owner

Summary

Add elicitation/create JSON-RPC method support to agentpool as an ACP server, enabling proper structured user input with backward-compatible fallback to request_permission for legacy clients.

Key Changes

Wave 1 — Schema Types (already committed in 6aa2167f9)

  • New src/acp/schema/elicitation.py with 4 types: ElicitationCreateRequest, ElicitationCreateResponse, ElicitationCompleteNotification, URLElicitationRequiredError
  • ElicitationCapabilities(create: bool) added to ClientCapabilities
  • Types registered in AgentRequest, ClientResponse, ClientNotification unions, ClientMethod literal, and __init__.py exports

Wave 2 — Protocol & Routing

  • elicitation_create() method on Client protocol, ACPRequests, and both connection handlers
  • Routing case for "elicitation/create" in _handle_client_method()
  • All 3 client implementations: DefaultACPClient (auto-accept + tracking), HeadlessACPClient (gated auto-grant), NoOpClient (cancel)

Wave 3 — Server Integration

  • Dual-path ACPInputProvider.get_elicitation(): uses elicitation_create when client declares capability, falls back to request_permission hack for legacy clients
  • send_elicitation_complete() on ACPNotifications
  • _map_elicitation_create_response() static method for response mapping

Accepted Plan Divergences (ACP Spec Alignment)

The implementation follows the actual ACP RFD specification, which differs from the original plan in these ways:

  • ElicitationCapabilities.create: bool instead of form: bool + url: bool
  • No mode field on ElicitationCreateRequest — URL mode determined by url field presence
  • ElicitationCompleteNotification in ClientNotification (client→agent direction is correct per ACP spec)
  • ElicitationCompleteNotification has action/content following ACP response model pattern

Test plan

  • uv run mypy src/acp/ src/agentpool_server/acp_server/ — 0 new errors (pre-existing in event_converter.py)
  • uv run ruff check src/acp/ src/agentpool_server/acp_server/ — 0 new errors (pre-existing in event_converter.py)
  • uv run pytest tests/ -k "acp" — 190 passed, 2 pre-existing failures
  • All elicitation types importable from acp.schema
  • DefaultACPClient.elicitation_create returns action=accept
  • NoOpClient.elicitation_create returns action=cancel
  • ClientCapabilities with ElicitationCapabilities round-trips correctly
  • ACPInputProvider._client_supports_elicitation() checks capability correctly

Ultraworked with Sisyphus

备份迁移自 SRC-PR#30 · 作者 @Leoyzen · 创建于 2026-05-13T06:26:02Z · head=feat/acp-elicitation base=develop/agentic
源状态: merged · merge_commit_sha=8f4f10c2821825324e11c08e498ed796616f75d4

Leoyzen and others added 9 commits May 13, 2026 14:25
Remove unused noqa comments, fix import ordering, add missing docstring arg.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add elicitation_create() to Client protocol, ACPRequests, both connection handlers.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
DefaultACPClient auto-accepts with tracking, HeadlessACPClient gates on auto_grant, NoOpClient cancels.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Dual-path in ACPInputProvider: use elicitation_create when client declares capability, fall back to request_permission for legacy clients. Add send_elicitation_complete to ACPNotifications.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add openspec changes for acp-elicitation and acp-streamable-http-ws-server, plus .claude skills/commands for openspec workflows.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This reverts commit bcc0d06. RFC docs should not have been deleted - they were unrelated working tree pollution from subagents.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
… async gap

- Remove send_elicitation_complete from ACPNotifications: it was sending a ClientNotification (client→agent) in the wrong direction via session/update with type: ignore
- Add elicitation/complete handler in agent connection to receive client notifications
- Add TODO comment in input_provider explaining URL-mode async completion is deferred

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- Add elicitation_id field to ElicitationCreateRequest (required for URL mode correlation)
- Restructure ElicitationCompleteNotification: Agent→Client direction, only elicitation_id field
- Move ElicitationCompleteNotification from ClientNotification to AgentNotification
- Add ElicitationItem schema and restructure URLElicitationRequiredError with code -32042
- Add elicitation_complete() to Client protocol and AgentSideConnection
- Add send_elicitation_complete() to ACPNotifications with correct RFD structure
- Add elicitation/complete handler to ClientSideConnection (receives Agent→Client)
- Remove elicitation/complete from _agent_handler (no longer Client→Agent)
- Pass elicitation_id in _get_url_elicitation
- Add elicitation_complete stubs to all 3 client implementations

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@Million-mo

Copy link
Copy Markdown
Owner Author

评论 by @Leoyzen 于 2026-05-13T06:48:15Z(备份迁移)

/gemini review

@Million-mo

Copy link
Copy Markdown
Owner Author

评论 by @Leoyzen 于 2026-05-13T07:42:23Z(备份迁移)

All Review Comments Resolved ✅

All 8 review comments from Gemini Code Assist have been addressed and resolved:

Round 1 (commit b415dc1)

# Priority Issue Fix
1 HIGH send_elicitation_complete wrong direction (agent sending client→agent notification) Removed method from ACPNotifications; added "elicitation/complete" handler in _agent_handler
2 MEDIUM URL mode needs async wait for ElicitationCompleteNotification Added TODO comment documenting the gap; deferred to when a real consumer exists

Round 2 (commit d86ad65) — RFD Spec Alignment

# Priority Issue Fix
3 HIGH ElicitationCreateRequest missing elicitation_id field Added `elicitation_id: str
4 HIGH ElicitationCompleteNotification missing elicitation_id + wrong direction Restructured per RFD: Agent→Client with only session_id + elicitation_id; moved from ClientNotification to AgentNotification
5 HIGH elicitation_id not passed to elicitation_create in input_provider Now passes elicitation_id=elicit_id in _get_url_elicitation
6 MEDIUM URLElicitationRequiredError missing error code -32042 Restructured with code: int = -32042, added ElicitationItem schema and elicitations list
7 MEDIUM ACPRequests.elicitation_create() missing elicitation_id param Added `elicitation_id: str
8 MEDIUM elicitation_id not passed to ElicitationCreateRequest constructor Now passes elicitation_id=elicitation_id through

Key Design Decision

After re-reading the ACP RFD spec, elicitation/complete is Agent→Client (not Client→Agent as initially assumed in Round 1). The Round 2 commit corrects this: ElicitationCompleteNotification is now in AgentNotification, sent via AgentSideConnection.elicitation_complete(), and received by the client in _handle_client_method.

Verification

  • ruff check src/acp/ — all passed
  • mypy src/acp/ — success
  • ✅ 190 ACP tests passed (2 pre-existing failures unrelated to our changes)

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.

2 participants