Skip to content

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

Merged
Leoyzen merged 10 commits into
develop/agenticfrom
feat/acp-elicitation
May 22, 2026
Merged

feat(acp): add elicitation/create JSON-RPC method with capability negotiation#30
Leoyzen merged 10 commits into
develop/agenticfrom
feat/acp-elicitation

Conversation

@Leoyzen

@Leoyzen Leoyzen commented May 13, 2026

Copy link
Copy Markdown
Collaborator

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

Leoyzen and others added 7 commits May 13, 2026 12:20
Wave 1 complete: Add ElicitationCreateRequest, ElicitationCreateResponse,
ElicitationCompleteNotification, URLElicitationRequiredError, and
ElicitationCapabilities types to ACP schema layer.

- elicitation.py: 4 core types with camelCase aliases
- capabilities.py: ElicitationCapabilities on ClientCapabilities
- agent_requests.py: ElicitationCreateRequest in AgentRequest union
- client_responses.py: ElicitationCreateResponse in ClientResponse union
- notifications.py: ElicitationCompleteNotification in ClientNotification union
- messages.py: elicitation/create in ClientMethod Literal
- __init__.py: All types exported
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>

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces a native elicitation protocol to the Agent Client Protocol (ACP), allowing agents to request structured input from users. It includes new schema definitions, capability negotiation, and updates to both agent and client implementations to support the elicitation/create method. The server-side input provider is also updated to use this native method when available, with a fallback to the legacy permission-based approach. Feedback highlights a directional error in the implementation of elicitation completion notifications, which should be sent by the client rather than the agent. Additionally, the URL-based elicitation flow in the input provider needs to be updated to handle the asynchronous arrival of completion notifications.

Comment thread src/acp/agent/notifications.py Outdated
Comment thread src/agentpool_server/acp_server/input_provider.py
Leoyzen and others added 2 commits May 13, 2026 14:33
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>
@Leoyzen

Leoyzen commented May 13, 2026

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces experimental OPSX workflow commands and skills for managing change lifecycles, alongside a significant implementation of structured user input (elicitation) in the Agent Client Protocol (ACP). The ACP changes include new schema types, protocol methods, and a capability-gated input provider. Review feedback highlights the omission of the "elicitation_id" field in several new schema models and protocol methods, which is necessary for correlating requests and notifications. It was also suggested to explicitly include the RFC-specified error code in "URLElicitationRequiredError".

Comment thread src/acp/schema/elicitation.py
Comment thread src/acp/schema/elicitation.py
Comment thread src/agentpool_server/acp_server/input_provider.py
Comment thread src/acp/schema/elicitation.py
Comment thread src/acp/agent/acp_requests.py
Comment thread src/acp/agent/acp_requests.py
- 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>
@Leoyzen

Leoyzen commented May 13, 2026

Copy link
Copy Markdown
Collaborator Author

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.

1 participant