# car-a2a

Agent2Agent (A2A) v1.0 bridge for [Common Agent Runtime](https://github.com/Parslee-ai/car).

## What it does

Exposes a CAR runtime as an A2A-compliant agent so peer agents — built on any A2A SDK (Python, JavaScript, Java, Go, .NET, or one of the Rust crates) — can discover the runtime via an Agent Card and submit work as A2A Tasks.

A2A is the Linux Foundation's open protocol for agent-to-agent interoperability. The full spec lives at <https://a2a-protocol.org/latest/specification/>.

## Mapping

| A2A | CAR |
|-----|-----|
| Agent Card | Manifest of registered tools + host metadata |
| Task | One-shot wrapper around an `ActionProposal` |
| Message (parts) | Free-form input from the peer; structured `data` parts become tool calls |
| Artifact | One per `ActionResult` returned by the runtime |
| `TaskState` SUBMITTED → WORKING → COMPLETED/FAILED | Lifecycle of `Runtime::execute` |

## Surface

| Item | Purpose |
|------|---------|
| `A2aDispatcher` | Transport-neutral JSON-RPC dispatcher for the 11 A2A methods |
| `AgentCardSource` | Trait the dispatcher calls to (re)build the agent card on demand |
| `TaskStore` / `InMemoryTaskStore` | Pluggable task persistence |
| `message_to_proposal` | Compile an A2A `Message` into a CAR `ActionProposal` |
| `action_results_to_artifacts` | Convert a `ProposalResult` into A2A `Artifact`s |

## Methods supported

- `message/send`
- `tasks/get`
- `tasks/list`
- `tasks/cancel`
- `tasks/pushNotificationConfig/{set,get,list,delete}`
- `agent/getAuthenticatedExtendedCard`

Out of scope for this prototype:

- `message/stream` and `tasks/resubscribe` (Server-Sent Events)
- gRPC and HTTP+JSON/REST transport bindings
- Outbound A2A client calls — for those, use `a2a-protocol-client` or `a2a-client` from crates.io.

## Status

Prototype. The dispatcher is exercised by unit tests against an in-process `Runtime` and `InMemoryTaskStore`. It is not yet wired into `car-server-core::handler::run_dispatch` or fronted by an HTTP listener — embedders pick the transport.

## Example

```rust,ignore
use std::sync::Arc;
use car_a2a::{A2aDispatcher, AgentCard, InMemoryTaskStore};
use car_engine::Runtime;

let runtime = Arc::new(Runtime::new());
let store = Arc::new(InMemoryTaskStore::new());
let card_factory = Arc::new(|| AgentCard {
    name: "CAR runtime".into(),
    // ...fill in skills from runtime.tool_schemas() at refresh time
    # version: "1.0.0".into(),
    # description: String::new(),
    # url: String::new(),
    # provider: car_a2a::types::AgentProvider { organization: "you".into(), url: None },
    # capabilities: car_a2a::AgentCapabilities::default(),
    # default_input_modes: vec!["text".into()],
    # default_output_modes: vec!["text".into()],
    # skills: vec![],
    # additional_interfaces: vec![],
    # preferred_transport: Some("JSONRPC".into()),
    # protocol_version: "1.0".into(),
    # security_schemes: Default::default(),
    # supports_authenticated_extended_card: false,
    # security_requirements: vec![],
    # signatures: vec![],
});

let dispatcher = A2aDispatcher::new(runtime, store, card_factory);

// A peer's JSON-RPC request:
let result = dispatcher
    .dispatch("agent/getAuthenticatedExtendedCard", serde_json::Value::Null)
    .await
    .unwrap();
```
