# A2A Gateway (Sprint 6 Richer Interop Subset)

Pizza x402 ships a standalone A2A-style gateway package for task-oriented agent orchestration over HTTP.

Sprint 6 extends the Sprint 5 REST MVP with:
- JSON-RPC binding (`/a2a/jsonrpc`)
- SSE streaming endpoints for task progress
- multi-turn context/task correlation (`contextId`)
- conformance fixture tests for Agent Card, versioning, and task lifecycle envelopes

Sprint 7 adds policy/assertion propagation through the A2A gateway:
- `create_quote` task results include `quoteHash`, `significance`, `riskHints`, and merchant identity
- `confirm_order` accepts optional `assertions` and returns deterministic failure results when mismatches occur

Sprint 9 adds wrapper observability:
- `GET /metrics`
- `X-Request-Id` response headers
- structured JSON HTTP request logs

## Package

- Package: `packages/a2a-gateway`
- Command (source): `npx tsx packages/a2a-gateway/src/index.ts`
- Default URL: `http://127.0.0.1:3500`
- Agent Card: `GET /.well-known/agent-card.json`
- A2A prefix: `/a2a`
- Metrics: `GET /metrics`

## Commands

```bash
npm run a2a:build
npm run a2a:test
npm run a2a:test:conformance
npx tsx packages/a2a-gateway/src/index.ts
```

## Configuration (Environment Variables)

- `PIZZA_X402_BASE_URL` (default: `http://localhost:3000`)
- `PIZZA_X402_TIMEOUT_MS` (default: `10000`)
- `PIZZA_X402_A2A_HOST` (default: `127.0.0.1`)
- `PIZZA_X402_A2A_PORT` (default: `3500`)
- `PIZZA_X402_A2A_PATH_PREFIX` (default: `/a2a`)
- `PIZZA_X402_A2A_PUBLIC_URL` (optional; used in Agent Card endpoint URLs)

## Version Negotiation

The gateway validates `A2A-Version` on A2A endpoints.

- Supported version: `0.2`
- If omitted: defaults to `0.2`
- If unsupported: returns `400` with `errorCode: "A2A_UNSUPPORTED_VERSION"`
- All A2A responses include an `A2A-Version` response header

## REST Endpoints (Sprint 6)

### Agent Card

```bash
curl -H "A2A-Version: 0.2" http://127.0.0.1:3500/.well-known/agent-card.json
```

### Create task (`POST /a2a/messages`)

```bash
curl -X POST http://127.0.0.1:3500/a2a/messages \
  -H "Content-Type: application/json" \
  -H "A2A-Version: 0.2" \
  -d '{
    "contextId": "ctx-demo",
    "message": {
      "operation": "create_quote",
      "arguments": {
        "items": [{"sku": "PZ-MAR", "qty": 1}],
        "fulfillment": {"type": "pickup"},
        "contact": {"name": "A2A Agent", "phone": "+33600000000"},
        "paymentMethod": "crypto"
      }
    }
  }'
```

Response (`202`): returns `{ "task": ... }`
- `task.status = "completed"` for sync execution (default)
- `task.status = "submitted"` for `executionMode: "deferred"`

### Streaming create task (`POST /a2a/messages/stream`)

Returns `text/event-stream` and emits task lifecycle events (`task.created`, `task.running`, terminal event) plus `done`.

```bash
curl -N -X POST http://127.0.0.1:3500/a2a/messages/stream \
  -H "Content-Type: application/json" \
  -H "A2A-Version: 0.2" \
  -d '{"message":{"operation":"get_menu","arguments":{}}}'
```

### Task lifecycle endpoints

```bash
curl -H "A2A-Version: 0.2" http://127.0.0.1:3500/a2a/tasks
curl -H "A2A-Version: 0.2" http://127.0.0.1:3500/a2a/tasks/TASK_ID
curl -X POST http://127.0.0.1:3500/a2a/tasks/TASK_ID/cancel -H "A2A-Version: 0.2" -H "Content-Type: application/json" -d '{}'
```

### Task event subscription (`GET /a2a/tasks/{taskId}/events`)

Returns `text/event-stream` and emits:
- `task.snapshot`
- subsequent task events (for example `task.canceled`)
- `done` when terminal

```bash
curl -N -H "A2A-Version: 0.2" http://127.0.0.1:3500/a2a/tasks/TASK_ID/events
```

## JSON-RPC Binding (Sprint 6)

### Endpoint

- `POST /a2a/jsonrpc`
- JSON-RPC version: `2.0`
- A2A version header still required/validated (`A2A-Version: 0.2`)

### Supported methods

- `message/send`
- `tasks/get`
- `tasks/list`
- `tasks/cancel`

### Example: `message/send`

```bash
curl -X POST http://127.0.0.1:3500/a2a/jsonrpc \
  -H "Content-Type: application/json" \
  -H "A2A-Version: 0.2" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "message/send",
    "params": {
      "contextId": "ctx-demo",
      "message": { "operation": "get_menu", "arguments": {} }
    }
  }'
```

### JSON-RPC errors (implemented)

- `-32601` Method not found
- `-32602` Invalid params
- `-32603` Internal error
- `-32004` Task not found (gateway-specific)
- `-32009` Task already terminal (gateway-specific)

## Multi-Turn Context Correlation (Sprint 6)

`contextId` is an optional field on `POST /a2a/messages` and JSON-RPC `message/send` params.

When present, the gateway stores a small context snapshot and attaches it to `task.metadata.context`, including:
- `latestQuoteId`
- `latestPaymentRequestId`
- `latestOrderId`
- `recentTaskIds`

### Context fallbacks (implemented)

For multi-turn flows, the gateway can fill missing fields from context:
- `confirm_order`: fills `quoteId` and `paymentSignature` (if previously learned)
- `get_order_status`: fills `orderId`

This enables quote → confirm (`402`) → confirm (`200`) → status flows with less repeated state passing while preserving deterministic task outputs.

## Confirm Assertions (Sprint 7)

`confirm_order` task arguments can include an optional `assertions` object (same fields as the public `/v1/orders/confirm` API), for example:
- `expectedQuoteHash`
- `expectedTotalCents`
- `maxTotalCents`
- `expectedCurrency`
- `expectedPaymentMethod`
- `expectedExpiresAt`
- `expectedMerchantId`
- `expectedMerchantAddress`

When a mismatch occurs, the A2A task is marked `failed` with a structured result (for example `ASSERTION_FAILED_TOTAL`).

## Artifact Mapping

Completed tasks include typed JSON artifacts:

- `pizza.menu`
- `pizza.quote`
- `pizza.payment-requirements` (for `confirm_order` when Pizza x402 returns `402`)
- `pizza.confirmation`
- `pizza.order-status`
- `pizza.wallet-setup`

## Conformance Coverage (Sprint 6 subset)

`packages/a2a-gateway/tests/conformance/` pins and validates:
- Agent Card required fields/capabilities
- version rejection envelope (`A2A_UNSUPPORTED_VERSION`)
- deferred task lifecycle envelope subset (`submitted` → `canceled`)

## Planned for Sprint 7+

- deeper A2A conformance fixtures beyond the current implemented subset
