--- spec_doc_type: spec spec_id: input/a2a-json-rpc-surface status: 부분 source_evidence: - type: contract path: agent-contract/outer/a2a-json-rpc-api.md notes: A2A JSON-RPC 외부 HTTP 계약 - type: code path: apps/edge/internal/input/a2a/server.go notes: A2A HTTP server, JSON-RPC method dispatch, auth, SubmitRun 연동 - type: code path: apps/edge/internal/input/a2a/task_store.go notes: in-memory task store와 RunEvent drain - type: code path: apps/edge/internal/input/a2a/types.go notes: JSON-RPC envelope와 A2A task/message/artifact DTO - type: test path: apps/edge/internal/input/a2a/server_test.go notes: A2A handler 동작 검증 - type: test path: apps/edge/internal/input/a2a/task_store_test.go notes: task store drain 상태 검증 --- # 스펙: A2A JSON-RPC 입력 표면 ## 목적 Edge가 A2A JSON-RPC 요청을 받아 내부 `adapter + target` 실행으로 넘기는 현재 MVP 동작을 설명한다. ## 기능 목록 | 기능 | 설명 | |------|------| | A2A HTTP server | `a2a.enabled=true`이면 Edge input manager가 A2A HTTP server를 시작한다. 기본 RPC path는 `/a2a`다. | | agent card | `GET /.well-known/agent.json`으로 현재 agent card를 제공한다. | | bearer auth | `a2a.bearer_token`이 있으면 matching bearer authorization header를 요구한다. | | JSON-RPC method 처리 | JSON-RPC 2.0 envelope를 검증하고 `message/send`, `tasks/get`, `tasks/cancel`만 처리한다. | | message/send 실행 | text parts를 newline으로 이어 prompt를 만들고 Edge service `SubmitRun`을 호출한다. | | blocking task | `configuration.blocking`이 true이거나 생략되면 HTTP 요청 안에서 run stream을 drain한 뒤 최종 task snapshot을 반환한다. | | background task | non-blocking 요청은 working snapshot을 먼저 반환하고 background goroutine이 run stream을 drain한다. | | task 조회 | `tasks/get`이 process-local task store의 task snapshot을 반환한다. | | task 취소 | `tasks/cancel`은 working task에 대해 service `CancelRun`을 호출한다. | | task artifact | completed task는 adapter output delta를 text artifact 하나에 누적한다. | ## 범위 - 포함: A2A HTTP listener, agent card, bearer auth, JSON-RPC envelope, message text extraction, blocking/background task drain, task get/cancel. - 제외: A2A streaming, durable task persistence, OpenAI-compatible chat 대체 표면, provider-pool model catalog route, full A2A spec 호환. ## 주요 흐름 ```mermaid sequenceDiagram participant Caller participant A2A as A2A server participant Service as Edge service participant Store as TaskStore Caller->>A2A: message/send(text parts) A2A->>Service: SubmitRun(prompt) Service-->>A2A: run id + stream A2A->>Store: task working 저장 alt blocking A2A->>A2A: run stream drain A2A-->>Caller: final task snapshot else non-blocking A2A-->>Caller: working task snapshot A2A->>A2A: background drain end ``` ## 계약 - `iop.a2a-json-rpc-api`: `agent-contract/outer/a2a-json-rpc-api.md` - 내부 실행 wire: `agent-contract/inner/edge-node-runtime-wire.md` ## 설정/데이터/이벤트 - `configs/edge.yaml`의 `a2a` 섹션이 listener, path, node ref, adapter, target, session id, timeout, bearer token을 제공한다. - A2A run metadata에는 현재 `source=a2a`와 `blocking=true` 또는 `blocking=false`가 들어간다. 이 metadata는 OpenAI-compatible request metadata 계약과 별개인 내부 run metadata다. - TaskStore는 run event `delta`, `complete`, `error`, `cancelled`와 node disconnect를 관찰해 task status를 갱신한다. ## 검증 - `go test ./apps/edge/internal/input/a2a` - `go test ./apps/edge/internal/input` - `go test ./apps/edge/internal/service` ## 한계와 주의사항 - task state는 메모리에만 있고 Edge 재시작 시 사라진다. - agent card URL은 현재 listen/path 기반 단순 표현이다. reverse proxy/public URL 계약은 별도로 확정해야 한다. - A2A 표면은 현재 configured adapter/target으로만 run을 보낸다. request별 provider-pool model route는 이 spec의 현재 동작이 아니다. - streaming capability는 agent card에서 false다. - OpenAI-compatible chat/completions 대체 표면으로 쓰지 않는다. ## 변경 기록 - 2026-07-07: 현재 코드와 A2A 계약 기준으로 bootstrap spec 작성. - 2026-07-07: 기능 목록 중심으로 축소하고 주요 흐름을 Mermaid sequence diagram으로 정리.