Files
cleveragents-core/features/a2a_jsonrpc.feature
freemo 33900eab03 feat(a2a): implement JSON-RPC 2.0 wire format and method routing
Implement the JSON-RPC 2.0 wire format layer and method routing for the
A2A protocol, building on the ACP-to-A2A rename from #688.

New modules in src/cleveragents/a2a/:
- jsonrpc_models.py: Pydantic v2 models for JSON-RPC 2.0 request,
  response, error, and notification envelopes
- jsonrpc_router.py: Method router that dispatches JSON-RPC requests
  to registered handlers, with support for standard A2A methods and
  _cleveragents/ extension methods
- jsonrpc_handlers.py: Handlers for standard A2A methods (message/send,
  message/stream, tasks/get, tasks/cancel) and extension method factory
  that delegates to A2aLocalFacade
- jsonrpc_errors.py: Maps domain error taxonomy to JSON-RPC 2.0 error
  codes (standard -32700 to -32603, application -32001 to -32008)
- agent_card.py: Agent Card model and generation for the
  /.well-known/agent.json capability advertisement endpoint

Standard A2A methods:
- message/send: Create/update tasks via messages
- message/stream: Streaming variant with SSE event indicators
- tasks/get: Retrieve task by ID
- tasks/cancel: Cancel running tasks

CleverAgents extension methods (_cleveragents/ prefix):
- plan/use, execute, status, diff, apply, cancel
- registry/list_tools, list_resources
- context/show
- sync/status
- namespace/list
- health

Tests:
- Behave BDD: features/a2a_jsonrpc.feature (28 scenarios)
- Robot Framework: robot/a2a_jsonrpc.robot (9 integration tests)

ISSUES CLOSED: #690
2026-03-12 01:00:37 +00:00

183 lines
7.8 KiB
Gherkin

Feature: A2A JSON-RPC 2.0 wire format and method routing
As a client of the A2A protocol
I want JSON-RPC 2.0 framing for all A2A operations
So that communication follows the standard wire format
# ---------------------------------------------------------------
# JSON-RPC 2.0 request/response models
# ---------------------------------------------------------------
Scenario: Valid JSON-RPC request has correct fields
Given a JSON-RPC request with method "message/send" and id 1
Then the request jsonrpc field should be "2.0"
And the request method should be "message/send"
And the request id should be 1
And the request should not be a notification
Scenario: Request without id is a notification
Given a JSON-RPC notification with method "task/statusUpdate"
Then the request should be a notification
And the request id should be None
Scenario: Success response has result and no error
Given a JSON-RPC success response with id 1 and result {"status": "ok"}
Then the response jsonrpc field should be "2.0"
And the response id should be 1
And the response should have result
And the response should not have error
Scenario: Error response has error and no result
Given a JSON-RPC error response with id 1 code -32601 and message "Method not found"
Then the response should have error
And the response should not have result
And the response error code should be -32601
And the response error message should be "Method not found"
Scenario: JSON-RPC request rejects invalid version
When I try to create a request with jsonrpc "1.0"
Then a jsonrpc validation error should be raised
Scenario: JSON-RPC request rejects empty method
When I try to create a request with empty method
Then a jsonrpc validation error should be raised
# ---------------------------------------------------------------
# JSON-RPC router dispatch
# ---------------------------------------------------------------
Scenario: Router dispatches to registered handler
Given a JSON-RPC router with "echo" handler
When I dispatch a request for method "echo" with id 1 and params {"msg": "hello"}
Then the dispatch response should be successful
And the dispatch result should contain key "echo" with value "hello"
Scenario: Router returns method-not-found for unknown method
Given a JSON-RPC router with "echo" handler
When I dispatch a request for method "unknown/method" with id 2
Then the dispatch response should have error code -32601
Scenario: Router returns None for notifications
Given a JSON-RPC router with "echo" handler
When I dispatch a notification for method "echo"
Then the dispatch response should be None
Scenario: Router lists registered methods
Given a JSON-RPC router with standard A2A handlers
Then the router should have method "message/send"
And the router should have method "message/stream"
And the router should have method "tasks/get"
And the router should have method "tasks/cancel"
And the router standard methods should have 4 entries
Scenario: Router lists extension methods
Given a JSON-RPC router with extension handlers
Then the router extension methods should include "_cleveragents/plan/status"
And the router extension methods should include "_cleveragents/health"
Scenario: Router unregister removes handler
Given a JSON-RPC router with "echo" handler
When I unregister the "echo" handler
Then the router should not have method "echo"
# ---------------------------------------------------------------
# Standard A2A method handlers
# ---------------------------------------------------------------
Scenario: message/send creates a task
Given a JSON-RPC router with standard A2A handlers
When I dispatch message/send with message role "user" and text "Hello agent"
Then the dispatch response should be successful
And the dispatch result should contain key "id"
And the dispatch result status state should be "working"
Scenario: message/stream creates a streaming task
Given a JSON-RPC router with standard A2A handlers
When I dispatch message/stream with message role "user" and text "Stream me"
Then the dispatch response should be successful
And the dispatch result should contain key "streaming" with value true
Scenario: tasks/get retrieves a task
Given a JSON-RPC router with standard A2A handlers
And a task created via message/send
When I dispatch tasks/get with the created task id
Then the dispatch response should be successful
And the dispatch result should contain key "id"
Scenario: tasks/get returns error for missing task
Given a JSON-RPC router with standard A2A handlers
When I dispatch tasks/get with id "nonexistent-task-id"
Then the dispatch response should have error code -32001
Scenario: tasks/cancel cancels a running task
Given a JSON-RPC router with standard A2A handlers
And a task created via message/send
When I dispatch tasks/cancel with the created task id
Then the dispatch response should be successful
And the dispatch result status state should be "canceled"
Scenario: tasks/cancel rejects already-completed task
Given a JSON-RPC router with standard A2A handlers
And a completed task
When I dispatch tasks/cancel with the completed task id
Then the dispatch response should have error code -32006
# ---------------------------------------------------------------
# JSON-RPC error code mapping
# ---------------------------------------------------------------
Scenario: ResourceNotFoundError maps to -32001
When I map a ResourceNotFoundError to JSON-RPC
Then the mapped error code should be -32001
Scenario: ValidationError maps to -32602
When I map a ValidationError to JSON-RPC
Then the mapped error code should be -32602
Scenario: PlanError maps to -32002
When I map a PlanError to JSON-RPC
Then the mapped error code should be -32002
Scenario: AuthenticationError maps to -32003
When I map an AuthenticationError to JSON-RPC
Then the mapped error code should be -32003
Scenario: Generic exception maps to -32603
When I map a generic Exception to JSON-RPC
Then the mapped error code should be -32603
# ---------------------------------------------------------------
# Agent Card generation
# ---------------------------------------------------------------
Scenario: Agent Card has required fields
Given a generated Agent Card with name "TestAgent"
Then the agent card name should be "TestAgent"
And the agent card protocol version should be "1.0"
And the agent card should have capabilities
And the agent card should have streaming enabled
Scenario: Agent Card includes extension methods
Given a generated Agent Card with default extensions
Then the agent card should have extensions
And the first extension should have uri "_cleveragents"
And the extension methods should include "_cleveragents/plan/status"
Scenario: Agent Card serializes to dict
Given a generated Agent Card with name "SerializeTest"
When I serialize the agent card to dict
Then the serialized card should have key "name" with value "SerializeTest"
And the serialized card should have key "protocol_version" with value "1.0"
Scenario: Agent Card well-known path is correct
Then the agent card path should be "/.well-known/agent.json"
# ---------------------------------------------------------------
# Notification model
# ---------------------------------------------------------------
Scenario: Notification has method and params but no id
Given a JSON-RPC notification model with method "task/statusUpdate" and params {"taskId": "t1"}
Then the notification jsonrpc should be "2.0"
And the notification method should be "task/statusUpdate"
And the notification params key "taskId" should be "t1"