Skip to content

[EPIC][A2A]: A2A Protocol v0.3.0 Full Compliance Implementation #2547

@crivetimihai

Description

@crivetimihai

🔌 Epic: A2A Protocol v0.3.0 Full Compliance Implementation

Goal

Achieve 100% compliance with the official A2A (Agent-to-Agent) Protocol specification v0.3.0 by implementing all three transport bindings (JSON-RPC 2.0, HTTP+JSON/REST, gRPC), correct message schemas with kind discriminator fields, proper Agent Card discovery, streaming support, and task lifecycle management. This ensures ContextForge can interoperate with any A2A-compliant agent ecosystem including Google's A2A SDK implementations.

Why Now?

The A2A protocol is gaining adoption as the standard for agent-to-agent communication:

  1. Interoperability: Current implementation uses type instead of kind for message parts and message/send method naming, causing compatibility issues with strict A2A v0.3.0 implementations
  2. Ecosystem Growth: Google's A2A SDK and other implementations expect spec-compliant behavior
  3. User Confusion: Issue [BUG]: A2A Agent "Test Agent" returns HTTP 500 error message #2544 demonstrates users struggle with format mismatches between "Generic" agents and simple REST endpoints
  4. Missing Features: No support for tasks, streaming (SendStreamingMessage), or Agent Card discovery (.well-known/agent-card.json)
  5. Transport Gaps: Only JSON-RPC supported; no REST binding (/v1/message:send) or gRPC binding
  6. Production Readiness: Enterprise customers need certified A2A compliance for vendor evaluation

📖 User Stories

US-1: Integration Developer - JSON-RPC 2.0 Compliance

As an Integration Developer
I want ContextForge to send spec-compliant JSON-RPC 2.0 requests to A2A agents
So that my agents built with Google's A2A SDK work without modification

Acceptance Criteria:

Given an A2A agent registered with agent_type="a2a" or "jsonrpc"
When ContextForge invokes the agent with a message
Then the request should use JSON-RPC 2.0 format:
  {
    "jsonrpc": "2.0",
    "id": "<unique-request-id>",
    "method": "message/send",
    "params": {
      "message": {
        "messageId": "<unique-message-id>",
        "role": "user",
        "parts": [{"kind": "text", "text": "Hello!"}]
      }
    }
  }
And message parts should use "kind" field (not "type")
And the "id" field should be a unique string (not integer 1)
And the response should be parsed correctly:
  - Success: {"jsonrpc": "2.0", "result": {...}, "id": "..."}
  - Error: {"jsonrpc": "2.0", "error": {"code": ..., "message": ...}, "id": "..."}

Technical Requirements:

  • Update a2a_service.py to use kind instead of type for message parts
  • Generate unique request IDs (UUID) instead of hardcoded 1
  • Support all A2A error codes (-32001 to -32005)
  • Parse JSONRPC error responses correctly
US-2: Platform Admin - REST Transport Binding

As a Platform Administrator
I want ContextForge to support the A2A REST transport binding
So that I can integrate with A2A agents that expose REST endpoints instead of JSON-RPC

Acceptance Criteria:

Given an A2A agent registered with agent_type="a2a-rest"
And endpoint_url="https://agent.example.com/v1"
When ContextForge sends a message
Then the request should use REST format:
  POST https://agent.example.com/v1/message:send
  Content-Type: application/json

  {
    "message": {
      "messageId": "<unique-message-id>",
      "role": "user",
      "parts": [{"kind": "text", "text": "Hello!"}]
    }
  }
And the A2A-Version header should be included: "A2A-Version: 0.3"
And task operations should map correctly:
  - GetTask → GET /v1/tasks/{id}
  - ListTasks → GET /v1/tasks
  - CancelTask → POST /v1/tasks/{id}:cancel

Technical Requirements:

  • Add a2a-rest agent type
  • Implement REST endpoint mapping per A2A spec
  • Add A2A-Version header to requests
  • Support all REST operations (message, tasks, push notifications)
US-3: Enterprise Developer - gRPC Transport Binding

As an Enterprise Developer
I want ContextForge to support the A2A gRPC transport binding
So that I can achieve high-performance communication with A2A agents using Protocol Buffers

Acceptance Criteria:

Given an A2A agent registered with agent_type="a2a-grpc"
And endpoint_url="grpc://agent.example.com:50051"
When ContextForge sends a message
Then the request should use gRPC with Protocol Buffers:
  - Service: A2AService
  - Method: SendMessage
  - Request: SendMessageRequest protobuf
And the connection should support:
  - Unary RPCs for SendMessage, GetTask, etc.
  - Server streaming for SendStreamingMessage, SubscribeToTask
  - TLS encryption (grpcs://)

Technical Requirements:

  • Generate Python gRPC stubs from a2a.proto
  • Implement gRPC client in A2A service
  • Support streaming responses
  • Handle gRPC status codes mapped to A2A errors
US-4: AI Engineer - Agent Card Discovery

As an AI Engineer
I want ContextForge to discover A2A agent capabilities via Agent Cards
So that I can auto-configure agents and understand their supported features

Acceptance Criteria:

Given an A2A agent endpoint at https://agent.example.com
When I register the agent with only the base URL
Then ContextForge should:
  - Fetch /.well-known/agent-card.json
  - Parse the Agent Card JSON:
    {
      "name": "MyAgent",
      "description": "...",
      "url": "https://agent.example.com",
      "protocolVersions": ["0.3"],
      "capabilities": {
        "streaming": true,
        "pushNotifications": false
      },
      "skills": [...],
      "securitySchemes": {...}
    }
  - Auto-detect transport binding (JSON-RPC, REST, gRPC)
  - Store capabilities in database
  - Display capabilities in Admin UI
And if the Agent Card has security requirements
Then ContextForge should prompt for credentials

Technical Requirements:

  • Implement Agent Card fetching and parsing
  • Auto-detect transport from Agent Card
  • Store agent capabilities in database
  • Display Agent Card info in Admin UI
  • Support extended Agent Card (/extendedAgentCard with auth)
US-5: Platform Admin - Streaming Message Support

As a Platform Administrator
I want ContextForge to support A2A streaming messages
So that users can receive real-time responses from AI agents

Acceptance Criteria:

Given an A2A agent with capabilities.streaming=true
When a user invokes the agent via the streaming endpoint
Then ContextForge should:
  - Call SendStreamingMessage (JSON-RPC) or POST /v1/message:stream (REST)
  - Receive Server-Sent Events (SSE) stream
  - Parse streaming events:
    - MessageStart: {"type": "message_start", ...}
    - ContentDelta: {"type": "content_delta", "delta": {"text": "..."}}
    - MessageEnd: {"type": "message_end", ...}
  - Forward events to client via SSE
  - Handle stream errors gracefully
And metrics should track streaming message duration and throughput

Technical Requirements:

  • Implement streaming invocation endpoint
  • Parse A2A SSE event format
  • Forward SSE to MCP clients
  • Handle stream interruptions and reconnection
  • Track streaming metrics
US-6: Integration Developer - Task Lifecycle Management

As an Integration Developer
I want ContextForge to support the full A2A task lifecycle
So that I can track long-running agent operations and handle multi-turn conversations

Acceptance Criteria:

Given an A2A agent returns a Task object instead of immediate result:
  {
    "kind": "task",
    "id": "task-123",
    "contextId": "ctx-456",
    "status": {"state": "working"},
    "history": [...]
  }
When the task is in "working" state
Then ContextForge should:
  - Store the task reference
  - Allow polling via GetTask
  - Allow subscription via SubscribeToTask
  - Handle status transitions:
    - PENDING → WORKING → COMPLETED
    - PENDING → WORKING → INPUT_REQUIRED → WORKING → COMPLETED
    - PENDING → FAILED/CANCELLED/REJECTED
  - Support task cancellation via CancelTask
And multi-turn conversations should use contextId for continuity

Technical Requirements:

  • Create Task database model for tracking A2A tasks
  • Implement GetTask, ListTasks, CancelTask operations
  • Support SubscribeToTask streaming
  • Handle INPUT_REQUIRED state with user prompts
  • Link tasks via contextId for conversations
US-7: DevOps Engineer - Push Notifications

As a DevOps Engineer
I want ContextForge to support A2A push notifications
So that long-running tasks can notify webhooks instead of requiring polling

Acceptance Criteria:

Given an A2A agent with capabilities.pushNotifications=true
When I configure a push notification for a task:
  POST /tasks/{taskId}/pushNotificationConfigs
  {
    "url": "https://my-webhook.example.com/notify",
    "authentication": {"type": "bearer", "token": "..."}
  }
Then the agent should POST updates to my webhook
And ContextForge should:
  - Allow registering push notification configs
  - Provide webhook receiver endpoint for incoming notifications
  - Verify notification authenticity
  - Update task status based on notifications

Technical Requirements:

  • Implement push notification config CRUD
  • Create webhook receiver endpoint
  • Verify notification signatures/tokens
  • Update task status from notifications
  • Handle notification delivery failures
US-8: Platform Admin - Simple REST Passthrough Mode

As a Platform Administrator
I want a passthrough mode for simple REST endpoints
So that I can integrate AWS Lambda and other non-A2A endpoints without format wrapping

Acceptance Criteria:

Given an agent registered with agent_type="rest-passthrough"
When I invoke the agent with parameters:
  {"query": "Hello", "custom_field": "value"}
Then ContextForge should:
  - Send the parameters directly as the request body (no wrapping)
  - NOT wrap in {interaction_type, parameters, protocol_version}
  - NOT wrap in JSON-RPC format
  - Pass through the raw JSON body:
    {"query": "Hello", "custom_field": "value"}
And the response should be returned without parsing/wrapping

Technical Requirements:

  • Add rest-passthrough agent type
  • Skip all format wrapping for passthrough mode
  • Pass raw request body to endpoint
  • Return raw response to client
  • Document clearly in UI with warnings about compatibility
US-9: Security Engineer - A2A Authentication Schemes

As a Security Engineer
I want ContextForge to support all A2A security schemes
So that I can securely authenticate with any A2A agent

Acceptance Criteria:

Given an A2A agent with securitySchemes in its Agent Card:
  {
    "securitySchemes": {
      "bearerAuth": {"type": "http", "scheme": "bearer"},
      "apiKey": {"type": "apiKey", "in": "header", "name": "X-API-Key"},
      "oauth2": {"type": "oauth2", "flows": {...}}
    },
    "security": [{"bearerAuth": []}, {"apiKey": []}]
  }
When registering the agent
Then ContextForge should:
  - Parse security requirements from Agent Card
  - Prompt for required credentials
  - Support HTTP Basic, Bearer, API Key authentication
  - Support OAuth 2.0 flows (client credentials, authorization code)
  - Support OpenID Connect
  - Include credentials in requests per scheme specification

Technical Requirements:

  • Parse Agent Card security schemes
  • Implement all HTTP auth schemes
  • Implement OAuth 2.0 token management
  • Encrypt and store credentials securely
  • Refresh tokens automatically
US-10: Platform Admin - Clear Agent Type Labeling

As a Platform Administrator
I want clear, accurate labels for agent types in the Admin UI
So that I can correctly configure agents without confusion

Acceptance Criteria:

Given the Admin UI agent type dropdown
Then the options should be clearly labeled:
  | Value            | Display Label                      | Description                                      |
  |------------------|-----------------------------------|--------------------------------------------------|
  | a2a-jsonrpc      | A2A Protocol (JSON-RPC 2.0)       | Official A2A spec - JSON-RPC transport           |
  | a2a-rest         | A2A Protocol (REST)               | Official A2A spec - HTTP+JSON transport          |
  | a2a-grpc         | A2A Protocol (gRPC)               | Official A2A spec - gRPC transport               |
  | rest-passthrough | Simple REST (Passthrough)         | Raw JSON passthrough - no format wrapping        |
  | custom           | ContextForge Custom Format        | Legacy wrapper format (interaction_type/params)  |
And tooltips should explain each format with example payloads
And a "Preview Request" button should show the exact JSON to be sent

Technical Requirements:

  • Rename agent types with clear labels
  • Add tooltips with format examples
  • Implement request preview modal
  • Warn about trailing slash behavior
  • Migration path for existing agents

🏗 Architecture

A2A Protocol Transport Bindings

graph TB
    subgraph "ContextForge A2A Gateway"
        Router[A2A Router]
        Service[A2A Service]

        subgraph "Transport Adapters"
            JSONRPC[JSON-RPC 2.0 Adapter]
            REST[REST Adapter]
            GRPC[gRPC Adapter]
            Passthrough[Passthrough Adapter]
        end

        subgraph "Protocol Handlers"
            MessageHandler[Message Handler]
            TaskHandler[Task Handler]
            StreamHandler[Stream Handler]
            CardHandler[Agent Card Handler]
        end
    end

    subgraph "A2A Agents"
        Agent1[JSON-RPC Agent]
        Agent2[REST Agent]
        Agent3[gRPC Agent]
        Agent4[Simple REST API]
    end

    Router --> Service
    Service --> JSONRPC --> Agent1
    Service --> REST --> Agent2
    Service --> GRPC --> Agent3
    Service --> Passthrough --> Agent4

    MessageHandler --> Service
    TaskHandler --> Service
    StreamHandler --> Service
    CardHandler --> Service
Loading

Message Part Schema (A2A v0.3.0)

classDiagram
    class Part {
        <<union>>
    }

    class TextPart {
        +kind: "text"
        +text: string
        +metadata?: object
    }

    class FilePart {
        +kind: "file"
        +file: FileContent
        +metadata?: object
    }

    class DataPart {
        +kind: "data"
        +data: object
        +metadata?: object
    }

    class FileContent {
        +name?: string
        +mimeType?: string
        +bytes?: string (base64)
        +uri?: string
    }

    Part <|-- TextPart
    Part <|-- FilePart
    Part <|-- DataPart
    FilePart --> FileContent
Loading

Task State Machine

stateDiagram-v2
    [*] --> PENDING: Task Created
    PENDING --> WORKING: Agent Processing
    WORKING --> COMPLETED: Success
    WORKING --> FAILED: Error
    WORKING --> CANCELLED: User Cancelled
    WORKING --> INPUT_REQUIRED: Need User Input
    INPUT_REQUIRED --> WORKING: User Provided Input
    PENDING --> REJECTED: Agent Rejected

    COMPLETED --> [*]
    FAILED --> [*]
    CANCELLED --> [*]
    REJECTED --> [*]
Loading

Agent Card Discovery Flow

sequenceDiagram
    participant Admin as Admin UI
    participant GW as ContextForge
    participant Agent as A2A Agent

    Admin->>GW: Register agent (base URL only)
    GW->>Agent: GET /.well-known/agent-card.json
    Agent-->>GW: Agent Card JSON

    GW->>GW: Parse capabilities
    GW->>GW: Detect transport binding
    GW->>GW: Parse security schemes

    alt Security Required
        GW-->>Admin: Prompt for credentials
        Admin->>GW: Provide credentials
        GW->>Agent: GET /extendedAgentCard (authenticated)
        Agent-->>GW: Extended Agent Card
    end

    GW->>GW: Store agent with capabilities
    GW-->>Admin: Agent registered successfully
Loading

📋 Implementation Tasks

Phase 1: Core Schema Updates ✅

  • Update Message Part Schema

    • Change type to kind in all message part creation
    • Update admin.py line 14890: {"type": "text"{"kind": "text"
    • Update a2a_service.py to use kind field
    • Add backward compatibility: accept both type and kind on input
    • Output always uses kind per spec
  • Update Request ID Generation

    • Change hardcoded "id": 1 to UUID string
    • Use str(uuid.uuid4()) for request IDs
    • Store request ID for response correlation
  • Fix Trailing Slash Behavior

    • Remove automatic JSON-RPC triggering on trailing slash
    • Make format selection based solely on agent_type
    • Add migration for existing agents with trailing slashes
    • Add UI warning about URL format

Phase 2: Agent Type Refactoring ✅

  • Define New Agent Types

    class A2AAgentType(str, Enum):
        A2A_JSONRPC = "a2a-jsonrpc"      # A2A spec JSON-RPC 2.0
        A2A_REST = "a2a-rest"            # A2A spec REST binding
        A2A_GRPC = "a2a-grpc"            # A2A spec gRPC binding
        REST_PASSTHROUGH = "rest-passthrough"  # Raw passthrough
        CUSTOM = "custom"                # Legacy ContextForge format
        # Deprecated aliases
        GENERIC = "generic"              # → a2a-jsonrpc
        JSONRPC = "jsonrpc"              # → a2a-jsonrpc
  • Migration for Existing Agents

    • Create Alembic migration for agent_type values
    • Map generica2a-jsonrpc
    • Map jsonrpca2a-jsonrpc
    • Keep custom as-is
    • Log migration changes
  • Update Format Selection Logic

    def get_transport_adapter(agent_type: str, endpoint_url: str):
        if agent_type in ["a2a-jsonrpc", "generic", "jsonrpc"]:
            return JSONRPCAdapter()
        elif agent_type == "a2a-rest":
            return RESTAdapter()
        elif agent_type == "a2a-grpc":
            return GRPCAdapter()
        elif agent_type == "rest-passthrough":
            return PassthroughAdapter()
        else:  # custom
            return CustomFormatAdapter()

Phase 3: JSON-RPC 2.0 Full Compliance ✅

  • Request Format

    • Method: message/send (correct per spec)
    • Parts use kind field
    • Request ID is unique string
    • Include all required message fields
  • Response Parsing

    • Parse success: {"result": {...}}
    • Parse error: {"error": {"code": ..., "message": ..., "data": ...}}
    • Map A2A error codes:
      • -32001 → TaskNotFoundError
      • -32002 → TaskNotCancelableError
      • -32003 → PushNotificationNotSupportedError
      • -32004 → UnsupportedOperationError
      • -32005 → ContentTypeNotSupportedError
  • Batch Requests (Optional)

    • Support JSON-RPC batch requests
    • Parse batch responses

Phase 4: REST Transport Binding ✅

  • Endpoint Mapping

    Operation Method Endpoint
    SendMessage POST /v1/message:send
    SendStreamingMessage POST /v1/message:stream
    GetTask GET /v1/tasks/{id}
    ListTasks GET /v1/tasks
    CancelTask POST /v1/tasks/{id}:cancel
    SubscribeToTask POST /v1/tasks/{id}:subscribe
  • Headers

    • Content-Type: application/json
    • A2A-Version: 0.3
    • A2A-Extensions: <comma-separated URIs> (if any)
    • Authentication headers per security scheme
  • REST Adapter Implementation

    class RESTAdapter:
        async def send_message(self, endpoint: str, message: dict) -> dict:
            url = f"{endpoint}/v1/message:send"
            headers = {"A2A-Version": "0.3", "Content-Type": "application/json"}
            response = await client.post(url, json={"message": message}, headers=headers)
            return response.json()

Phase 5: gRPC Transport Binding ✅

  • Proto Generation

    • Download official a2a.proto from A2A repo
    • Generate Python stubs with grpcio-tools
    • Include generated files in package
  • gRPC Client

    class GRPCAdapter:
        def __init__(self, endpoint: str):
            self.channel = grpc.aio.insecure_channel(endpoint)
            self.stub = a2a_pb2_grpc.A2AServiceStub(self.channel)
    
        async def send_message(self, message: dict) -> dict:
            request = a2a_pb2.SendMessageRequest(message=to_proto(message))
            response = await self.stub.SendMessage(request)
            return from_proto(response)
  • Streaming Support

    • Implement SendStreamingMessage with async generator
    • Implement SubscribeToTask streaming
    • Handle stream errors and reconnection
  • TLS Support

    • Support grpcs:// for TLS
    • Certificate verification options

Phase 6: Agent Card Discovery ✅

  • Fetch Agent Card

    async def discover_agent_card(base_url: str) -> AgentCard:
        card_url = f"{base_url.rstrip('/')}/.well-known/agent-card.json"
        response = await client.get(card_url)
        return AgentCard.model_validate(response.json())
  • Agent Card Schema

    class AgentCard(BaseModel):
        name: str
        description: Optional[str]
        url: str
        version: Optional[str]
        protocol_versions: List[str] = Field(alias="protocolVersions")
        capabilities: AgentCapabilities
        skills: Optional[List[AgentSkill]]
        security_schemes: Optional[Dict[str, SecurityScheme]] = Field(alias="securitySchemes")
        security: Optional[List[Dict[str, List[str]]]]
        extensions: Optional[List[Extension]]
  • Auto-Configuration

    • Detect transport from Agent Card
    • Store capabilities in database
    • Parse and store security requirements
    • Display in Admin UI
  • Extended Agent Card

    • Support authenticated /extendedAgentCard endpoint
    • Parse additional protected capabilities

Phase 7: Task Management ✅

  • Task Database Model

    class A2ATask(Base):
        __tablename__ = "a2a_tasks"
    
        id: Mapped[str] = mapped_column(String(100), primary_key=True)
        context_id: Mapped[Optional[str]] = mapped_column(String(100))
        agent_id: Mapped[str] = mapped_column(ForeignKey("a2a_agents.id"))
        status_state: Mapped[str] = mapped_column(String(50))  # PENDING, WORKING, etc.
        status_message: Mapped[Optional[str]]
        history: Mapped[Optional[dict]] = mapped_column(JSON)
        artifacts: Mapped[Optional[list]] = mapped_column(JSON)
        created_at: Mapped[datetime]
        updated_at: Mapped[datetime]
  • Task Operations

    • get_task(task_id) → GetTask
    • list_tasks(context_id, status) → ListTasks
    • cancel_task(task_id) → CancelTask
    • subscribe_to_task(task_id) → SubscribeToTask (streaming)
  • Task State Handling

    • Handle INPUT_REQUIRED state
    • Support multi-turn conversations via contextId
    • Clean up completed/failed tasks

Phase 8: Streaming Support ✅

  • SSE Client

    async def stream_message(self, endpoint: str, message: dict):
        async with client.stream("POST", f"{endpoint}/v1/message:stream",
                                 json={"message": message}) as response:
            async for line in response.aiter_lines():
                if line.startswith("data: "):
                    event = json.loads(line[6:])
                    yield event
  • Event Types

    • message_start - New message started
    • content_delta - Incremental content
    • message_end - Message complete
    • error - Stream error
  • SSE Forwarding

    • Forward A2A SSE events to MCP clients
    • Map A2A events to MCP streaming format
    • Handle client disconnection

Phase 9: Passthrough Mode ✅

  • Passthrough Adapter

    class PassthroughAdapter:
        async def invoke(self, endpoint: str, body: dict, headers: dict) -> dict:
            # No wrapping - send body directly
            response = await client.post(endpoint, json=body, headers=headers)
            return response.json()
  • No Format Wrapping

    • Skip interaction_type/parameters wrapper
    • Skip JSON-RPC wrapper
    • Pass raw request body
    • Return raw response
  • UI Warnings

    • Warn that passthrough has no format validation
    • Explain this is for simple REST APIs only
    • Document expected request/response format

Phase 10: Admin UI Updates ✅

  • Agent Type Dropdown

    • Clear labels with descriptions
    • Tooltips explaining each format
    • Group by protocol family
  • Request Preview

    • "Preview Request" button
    • Show exact JSON that will be sent
    • Syntax highlighting
  • Agent Card Display

    • Show discovered capabilities
    • Display supported skills
    • Show security requirements
  • Trailing Slash Warning

    • Detect trailing slash in URL
    • Show warning banner
    • Suggest correction

Phase 11: Testing ✅

  • Unit Tests

    • Test kind vs type field handling
    • Test all transport adapters
    • Test Agent Card parsing
    • Test task state machine
    • Test streaming event parsing
    • Test error code mapping
  • Integration Tests

    • Test against A2A SDK HelloWorld sample
    • Test against mock A2A servers
    • Test all three transports
    • Test task lifecycle
    • Test streaming
  • Compatibility Tests

    • Test backward compatibility with existing agents
    • Test migration of existing agent_type values
    • Test both type and kind input acceptance

Phase 12: Documentation ✅

  • A2A Integration Guide

    • Transport binding selection guide
    • Agent Card discovery documentation
    • Task management guide
    • Streaming setup guide
  • Migration Guide

    • Upgrading from old agent types
    • Updating endpoint URLs
    • Testing after migration
  • API Documentation

    • OpenAPI spec for A2A endpoints
    • Agent Card schema reference
    • Error code reference

⚙️ Configuration Example

Agent Registration with Auto-Discovery

# Register agent with just base URL - auto-discovers capabilities
curl -X POST "http://localhost:4444/a2a" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "agent": {
      "name": "smart-assistant",
      "endpoint_url": "https://agent.example.com",
      "auto_discover": true
    }
  }'

# Response includes discovered capabilities
{
  "id": "...",
  "name": "smart-assistant",
  "agentType": "a2a-jsonrpc",  # Auto-detected
  "capabilities": {
    "streaming": true,
    "pushNotifications": false,
    "tasks": true
  },
  "skills": [
    {"name": "search", "description": "Web search"},
    {"name": "calculate", "description": "Math operations"}
  ]
}

Manual Configuration

# JSON-RPC A2A Agent
curl -X POST "http://localhost:4444/a2a" \
  -d '{
    "agent": {
      "name": "jsonrpc-agent",
      "endpoint_url": "https://agent.example.com/jsonrpc",
      "agent_type": "a2a-jsonrpc"
    }
  }'

# REST A2A Agent
curl -X POST "http://localhost:4444/a2a" \
  -d '{
    "agent": {
      "name": "rest-agent",
      "endpoint_url": "https://agent.example.com",
      "agent_type": "a2a-rest"
    }
  }'

# Simple REST Passthrough (AWS Lambda, etc.)
curl -X POST "http://localhost:4444/a2a" \
  -d '{
    "agent": {
      "name": "my-lambda",
      "endpoint_url": "https://lambda.amazonaws.com/prod/invoke",
      "agent_type": "rest-passthrough"
    }
  }'

✅ Success Criteria

  • JSON-RPC Compliance: Parts use kind field; unique request IDs; correct error handling
  • REST Binding: Full /v1/message:send endpoint support with proper headers
  • gRPC Binding: Working proto-based communication with streaming
  • Agent Card: Auto-discovery from .well-known/agent-card.json
  • Tasks: Full lifecycle support (create, poll, cancel, subscribe)
  • Streaming: SSE message streaming works end-to-end
  • Passthrough: Raw JSON passthrough for simple REST endpoints
  • UI Clarity: Clear agent type labels with request preview
  • Backward Compatibility: Existing agents continue to work
  • Testing: 80%+ coverage; passes A2A SDK sample tests
  • Documentation: Complete integration guide

🏁 Definition of Done

  • Message parts use kind field (not type)
  • Request IDs are unique UUIDs (not hardcoded 1)
  • Trailing slash no longer forces JSON-RPC
  • All three transports implemented (JSON-RPC, REST, gRPC)
  • Agent Card discovery working
  • Task management implemented
  • Streaming support working
  • Passthrough mode available
  • Agent type labels clear in UI
  • Request preview feature working
  • Existing agents migrated
  • Unit tests with 80%+ coverage
  • Integration tests passing
  • A2A SDK samples working
  • Documentation complete
  • Code passes make verify

📝 Additional Notes

🔹 A2A Spec Versions:

  • v0.1.0: Used type for parts (legacy)
  • v0.3.0: Uses kind for parts (current)
  • ContextForge should support both on input, output kind

🔹 Transport Selection:

  • JSON-RPC: Best for simple request/response
  • REST: Best for HTTP-native environments
  • gRPC: Best for high-performance, streaming-heavy use cases
  • Passthrough: For non-A2A REST endpoints

🔹 Breaking Changes:

  • generic agent type renamed to a2a-jsonrpc
  • Parts output changes from type to kind
  • Trailing slash behavior changes
  • Migration required for existing agents

🔹 Performance Considerations:

  • Agent Card caching (5 min TTL)
  • gRPC connection pooling
  • Streaming buffer management
  • Task cleanup for completed tasks

🔗 Related Issues


📚 References

Metadata

Metadata

Assignees

Labels

MUSTP1: Non-negotiable, critical requirements without which the product is non-functional or unsafea2aSupport for A2A protocolenhancementNew feature or requestepicLarge feature spanning multiple issuesicaICA related issuespythonPython / backend development (FastAPI)readyValidated, ready-to-work-on items

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions