A2A 프로토콜 v1.0의 새로운 점
A2A 프로토콜 v1.0의 새로운 점 (What's New)
이 문서는 A2A 프로토콜 v0.3.0에서 v1.0으로의 변경 사항을 포괄적으로 개괄해요. v1.0 릴리스는 향상된 명확성, 더 강력한 스펙, 중요한 구조적 개선과 함께 프로토콜의 상당한 성숙을 나타내요.
출처: 문서
본문
주요 테마 개요
v1.0 릴리스는 네 가지 주요 테마에 집중해요.
1. 프로토콜 성숙과 표준화
a2a.proto를 gRPC 특화 구현 파일에서 보편적이고 규범적인 소스 오브 트루스로 승격- 공식 스펙 표준(RFC 8785, RFC 7515)과 가능한 곳에서 google.rpc.Status 활용
- REST, gRPC, JSON-RPC 바인딩에 업계 표준 패턴을 더 엄격히 준수
- 명시적 역호환 규칙을 가진 향상된 버전 관리 전략
- 프로토콜별 매핑을 가진 포괄적 오류 분류(taxonomy)
2. 강화된 타입 안전성과 명확성
- 판별자(discriminator)
kind필드 제거, JSON 멤버 기반 다형성으로 대체 - 파괴적 변경: ProtoJSON 스펙 준수를 위해 Enum 값이
kebab-case에서SCREAMING_SNAKE_CASE로 변경 - 더 엄격한 필드 명명 규칙(JSON의
camelCase) - 더 정밀한 타임스탬프 스펙(밀리초 정밀도의 ISO 8601)
- Optional vs Required 의미를 더 명확히 하는 더 잘 정의된 데이터 타입
3. 개선된 개발자 경험
- 일관성과 명확성을 위해 연산 이름 변경
- 논리적 그룹화를 위해 Agent Card 구조 재구성
- 버전 관리와 요구사항 선언을 가진 향상된 확장 메커니즘
- 더 명시적인 서비스 매개변수 처리(A2A-Version, A2A-Extensions 헤더)
- ID 형식 단순화 — 복잡한 복합 ID(예:
tasks/{id})를 제거하고 단순 UUID로 대체 - 인터페이스별 프로토콜 버전 관리 — 각 AgentInterface가 자체 프로토콜 버전을 지정해 더 나은 역호환성 제공
- 멀티테넌시 지원 — gRPC 요청에서 네이티브 테넌트 스코핑
4. 엔터프라이즈 대비 기능
- JWS와 JSON 정규화(JSON Canonicalization)를 사용한 Agent Card 서명 검증
- 동등성 보장을 가진 세 가지 프로토콜 바인딩의 공식 스펙
- 상호 TLS 지원을 가진 향상된 보안 스킴 선언
- 현대 OAuth 2.0 플로우 — Device Code 플로우(RFC 8628) 추가, 폐지된 implicit/password 플로우 제거
- PKCE 지원 — 보안 강화를 위해 Authorization Code 플로우에
pkce_required필드 추가 - 확장 가능한 태스크 목록을 위한 커서 기반 페이지네이션
핵심 연산의 동작 변경
Send Message (message/send → SendMessage)
v0.3.0 동작:
- 연산 이름이
message/send Task대Message가 언제 반환되는지에 대한 공식성이 덜함
v1.0 변경:
- ✅ 이름 변경: 연산이 이제
SendMessage - ✅ 명확화: Task vs Message 반환 의미에 대한 더 정밀한 스펙
Send Streaming Message (message/stream → SendStreamingMessage)
v0.3.0 동작:
- 연산 이름이
message/stream - 스트림 이벤트에
kind판별자 필드가 있었음
v1.0 변경:
- ✅ 이름 변경: 연산이 이제
SendStreamingMessage - ✅ 파괴적 변경: 스트림 이벤트에 더 이상
kind필드 없음.TaskStatusUpdateEvent와TaskArtifactUpdateEvent를 구분하려면 JSON 멤버 이름을 사용 - ✅ 제거:
TaskStatusUpdateEvent에서finalboolean 필드 제거. 대신 프로토콜 바인딩 특화 스트림 종료 메커니즘 활용 - ✅ 명확화: 여러 동시 스트림 허용, 모두 동일한 순서의 이벤트 수신
Get Task (tasks/get → GetTask)
v0.3.0 동작:
- 연산 이름이
tasks/get - 상태, 아티팩트, 선택적으로 이력을 포함한 태스크 반환
- "include history"가 무엇을 의미하는지에 대한 공식성이 덜함
v1.0 변경:
- ✅ 이름 변경: 연산이 이제 GetTask
- ✅ 명확화: 이력 포함 동작에 대한 더 정밀한 스펙
- ✅ 새로움: Task 객체가 이제 메시지와 아티팩트에
extensions[]배열 포함 - ✅ 명확화: 인증/권한 스코핑 — 서버는 호출자에게 보이는 태스크만 반환해야 함
List Tasks (tasks/list → ListTasks)
v0.3.0 동작:
- 연산 사용 불가.
v1.0 변경:
- ✅ 새로움: 필터링 기능을 가진 새 연산 ListTasks
- ✅ 명확화: 태스크 가시성이 인증된 호출자로 스코프됨
Cancel Task (tasks/cancel → CancelTask)
v0.3.0 동작:
- 연산 이름이
tasks/cancel - taskId로 요청, Task 반환
v1.0 변경:
- ✅ 이름 변경: 연산이 이제 CancelTask
- ✅ 명확화: 취소가 허용되는 시점에 대한 더 정밀한 스펙
- ✅ 명확화: 취소 시나리오의 태스크 상태 전이
Get Agent Card (잘 알려진 URI와 GetExtendedAgentCard)
v0.3.0 동작:
/.well-known/agent-card.json을 통한 발견agent/getAuthenticatedExtendedCard를 통한 확장 카드- 최상위의
supportsAuthenticatedExtendedCardboolean
v1.0 변경:
- ✅ 이름 변경:
agent/getAuthenticatedExtendedCard→ GetExtendedAgentCard - ✅ 파괴적 변경:
supportsAuthenticatedExtendedCard가capabilities.extendedAgentCard로 이동 - ✅ 새로움: Agent Card 서명에 대한 정규화(RFC 8785) 명확화
- ✅ 파괴적 변경:
protocolVersion이 AgentCard에서 개별 AgentInterface 객체로 이동 - ✅ 파괴적 변경:
preferredTransport와additionalInterfaces가supportedInterfaces[]로 통합. 각 인터페이스는url,protocolBinding,protocolVersion을 가짐
Subscribe to task (tasks/resubscribe → SubscribeToTask)
v0.3.0 동작:
- 끊긴 SSE 스트림을 다시 연결하는 데
tasks/resubscribe사용 - 백필 동작이 구현에 따라 다름
v1.0 변경:
- ✅ 이름 변경: 연산이 이제 SubscribeToTask
- ✅ 명확화: 스트리밍 구독 수명주기의 공식 스펙
- ✅ 명확화: 태스크가 종료 상태에 도달할 때의 스트림 종료 동작
- ✅ 명확화: 태스크당 여러 동시 구독 지원
푸시 알림 연산
v0.3.0 연산:
tasks/pushNotificationConfig/settasks/pushNotificationConfig/gettasks/pushNotificationConfig/listtasks/pushNotificationConfig/delete
v1.0 변경:
- ✅ 이름 변경: 이제 CreateTaskPushNotificationConfig, GetTaskPushNotificationConfig, ListTaskPushNotificationConfigs, DeleteTaskPushNotificationConfig
- ✅ 명확화: 푸시 알림 페이로드가 이제 StreamResponse 형식 사용
- ✅ 파괴적 변경: 모든 메서드의 모델이 변경되고 TaskPushNotificationConfig가 평탄화됨
새로움: 멀티테넌시 지원
v0.3.0:
- 프로토콜에 네이티브 멀티테넌시 지원 없음
- 테넌트가 인증이나 URL 경로로 암시적으로 처리됨
v1.0 변경:
- ✅ 새로움: 모든 요청 메시지에
tenant필드 추가 - ✅ 새로움: 기본 테넌트를 지정하도록
AgentInterface에tenant필드 추가 - ✅ 명확화: 테넌트가 요청별로 제공되고 AgentInterface에서 상속됨
- ✅ 사용 사례: 단일 엔드포인트에서 여러 에이전트를 서빙할 수 있게 함
프로토콜 단순화
ID 형식 단순화 (#1389)
v0.3.0:
- 일부 연산이
tasks/{taskId}같은 복합 복합 ID를 사용 - 클라이언트/서버가 리소스 이름을 구성/분해해야 했음
v1.0 변경:
- ✅ 파괴적 변경: 모든 ID가 이제 단순 리터럴
- ✅ 파괴적 변경: 이전에 복합 ID를 사용한 연산이 이제 상위(super)와 리소스 ID를 분리. 예:
tasks/{taskId}/pushNotificationConfigs/{configId}→ 별도의task_id와id필드 - ✅ 이점: 구현이 더 단순 — ID가 데이터베이스 키에 직접 매핑
HTTP URL 경로 단순화 (#1269)
v0.3.0:
- HTTP+JSON 바인딩이 URL에서
/v1/접두사 사용 - 예:
POST /v1/message:send
v1.0 변경:
- ✅ 파괴적 변경: HTTP+JSON URL 경로에서
/v1접두사 제거 - ✅ 새로움: 예:
POST /message:send,GET /tasks/{id} - ✅ 근거: 에이전트 소유자가 원하면 버전이 기본 url의 일부가 될 수 있음
- ✅ 이점: 더 깔끔한 URL, 인터페이스 수준에서 버전 관리
핵심 모델 객체의 구조 변경
TaskStatus 객체
수정된 필드:
- ✅
state: 파괴적 변경 — Enum 값이 소문자에서TASK_STATE_접두사를 가진SCREAMING_SNAKE_CASE로 변경- v0.3.0:
"submitted","working","completed","failed","canceled","rejected","input-required","auth-required" - v1.0:
"TASK_STATE_SUBMITTED","TASK_STATE_WORKING","TASK_STATE_COMPLETED","TASK_STATE_FAILED","TASK_STATE_CANCELED","TASK_STATE_REJECTED","TASK_STATE_INPUT_REQUIRED","TASK_STATE_AUTH_REQUIRED"
- v0.3.0:
- ✅
timestamp: 이제 명시적으로 밀리초 정밀도의 ISO 8601 UTC(YYYY-MM-DDTHH:mm:ss.sssZ)
제거된 필드: 없음
마이그레이션 예시:
// v0.3.0
{
"status": {
"state": "completed",
"timestamp": "2024-03-15T10:15:00Z"
}
}
// v1.0
{
"status": {
"state": "TASK_STATE_COMPLETED",
"timestamp": "2024-03-15T10:15:00.000Z"
}
}
Message 객체
추가된 필드:
- ✅
extensions[]: 이 메시지에 적용되는 확장 URI 배열
수정된 필드:
- ✅
role: 파괴적 변경 — Enum 값이 소문자에서ROLE_접두사를 가진SCREAMING_SNAKE_CASE로 변경- v0.3.0:
"user","agent" - v1.0:
"ROLE_USER","ROLE_AGENT"
- v0.3.0:
마이그레이션 예시:
// v0.3.0
{
"role": "user",
"parts": [{"kind": "text", "text": "Hello"}]
}
// v1.0
{
"role": "ROLE_USER",
"parts": [{"text": "Hello"}],
}
동작 변경:
- Parts 배열이 이제
kind필드 대신 멤버 기반 판별을 사용
Part 객체
파괴적 변경 — 완전 재설계:
Part 구조는 v1.0에서 완전히 재설계됐어요. 별도의 TextPart, FilePart, DataPart 메시지 타입 대신 이제 단일 통합 Part 메시지가 있어요.
v0.3.0 구조(별도 타입):
// Text example
{
"kind": "text",
"text": "Hello world"
}
// File example
{
"kind": "file",
"file": {
"fileWithUri": "https://example.com/doc.pdf",
"mimeType": "application/pdf"
}
}
// Data example
{
"kind": "data",
"data": {"key": "value"}
}
v1.0 구조(통합 Part):
// Text example
{
"text": "Hello world",
"mediaType": "text/plain"
}
// File with URL example
{
"url": "https://example.com/doc.pdf",
"filename": "doc.pdf",
"mediaType": "application/pdf"
}
// File with raw bytes example
{
"raw": "base64encodedcontent==",
"filename": "image.png",
"mediaType": "image/png"
}
// Data example
{
"data": {"key": "value"},
"mediaType": "application/json"
}
변경 사항:
- ⛔ 제거: 별도의
TextPart,FilePart,DataPart타입 - ⛔ 제거:
kind판별자 필드 - ⛔ 제거: 중첩
file객체 구조 - ✅ 새로움:
oneof content필드를 가진 단일 통합Part메시지 - ✅ 새로움: 콘텐츠 타입은 어떤 필드가 존재하는지에 따라 결정됨:
text,raw,url, 또는data - ✅ 새로움:
mediaType필드(mimeType대체) — 모든 part 유형에 사용 가능 - ✅ 새로움:
filename필드 — (파일뿐 아니라) 모든 part 유형에 사용 가능 - ✅ 새로움: 인라인 이진 콘텐츠용
raw필드(JSON에서 base64) - ✅ 새로움: 파일 참조용
url필드(file.fileWithUri대체)
마이그레이션 예시:
// v0.3.0
const textPart = { kind: "text", text: "Hello" };
const filePart = { kind: "file", file: { fileWithUri: "https://...", mimeType: "image/png" } };
const dataPart = { kind: "data", data: { key: "value" } };
// v1.0
const textPart = { text: "Hello", mediaType: "text/plain" };
const filePart = { url: "https://...", mediaType: "image/png", filename: "image.png" };
const dataPart = { data: { key: "value" }, mediaType: "application/json" };
// Discrimination changed from kind field to member presence
if (part.kind === "text") { ... } // v0.3.0
if ("text" in part) { ... } // v1.0
Artifact 객체
추가된 필드:
- ✅
extensions[]: 확장 URI 배열
수정된 필드:
- ✅
parts[]: 이제 멤버 기반 Part 판별 사용(위 Part 변경 참고)
AgentCard 객체
추가된 필드:
- ✅
supportedInterfaces[]:AgentInterface객체 배열
제거된 필드:
- ⛔
protocolVersion: AgentCard에서 제거(이제 각 AgentInterface에 있음) - ⛔
preferredTransport:supportedInterfaces로 통합 - ⛔
additionalInterfaces:supportedInterfaces로 통합 - ⛔
supportsAuthenticatedExtendedCard:capabilities.extendedAgentCard로 이동 - ⛔
url: 기본 엔드포인트가 이제supportedInterfaces[0].url에 있음
구조 예시:
v0.3.0:
{
"protocolVersion": "0.3",
"url": "https://agent.example.com/a2a",
"preferredTransport": "JSONRPC",
"supportsAuthenticatedExtendedCard": true,
"additionalInterfaces": [...]
}
v1.0:
{
"supportedInterfaces": [
{
"url": "https://agent.example.com/a2a",
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
}
],
"capabilities": {
"extendedAgentCard": true
},
"signatures": [...]
}
AgentCapabilities 객체
수정된 필드:
- ✅
extendedAgentCard: 최상위supportsAuthenticatedExtendedCard필드에서 이동
PushNotificationConfig 객체
수정된 필드:
- ✅
authentication: 향상된 PushNotificationAuthenticationInfo 구조
스트림 이벤트 객체
TaskStatusUpdateEvent:
v0.3.0:
{
"kind": "status-update",
"taskId": "...",
"contextId": "...",
"status": {...},
"final": true
}
v1.0:
{
"statusUpdate": {
"taskId": "...",
"contextId": "...",
"status": {...}
}
}
변경 사항:
- ⛔ 제거:
kind판별자 - ⛔ 제거:
finalboolean 필드(스트림 종료가 완료를 나타냄) - ✅ 새 패턴: 이벤트 타입이 JSON 멤버 이름(
statusUpdate또는artifactUpdate)으로 결정됨 - ✅ 명확화: 종료 상태가 프로토콜 특화 스트림 종료 메커니즘으로 표시됨
TaskArtifactUpdateEvent:
v0.3.0:
{
"kind": "artifact-update",
"taskId": "...",
"contextId": "...",
"artifact": {...}
}
v1.0:
{
"artifactUpdate": {
"taskId": "...",
"contextId": "...",
"artifact": {...},
"index": 0
}
}
변경 사항:
- ⛔ 제거:
kind판별자 - ✅ 새 패턴:
artifactUpdate객체로 감싸짐 - ✅ 새로움:
index필드가 태스크의 artifacts 배열에서 아티팩트 위치를 나타냄
OAuth 2.0 보안 업데이트 (#1303)
v1.0은 OAuth 2.0 Security Best Current Practice(BCP)에 맞춰 OAuth 2.0 지원을 현대화해요.
제거된 플로우(OAuth BCP가 폐지):
- ⛔
ImplicitOAuthFlow— 브라우저 이력/로그의 토큰 유출 위험으로 폐지 - ⛔
PasswordOAuthFlow— 자격 증명 노출 위험으로 폐지
추가된 플로우:
- ✅
DeviceCodeOAuthFlow(RFC 8628) — CLI 도구, IoT 기기, 입력 제한 시나리오용device_authorization_url엔드포인트 제공verification_uri,user_code패턴 지원- 헤드리스 환경에 이상적
강화된 보안:
- ✅
AuthorizationCodeOAuthFlow(RFC 7636)에pkce_required필드 추가- PKCE(Proof Key for Code Exchange)가 필수인지 나타냄
- 인증 코드 가로채기 공격으로부터 보호
- 모든 OAuth 클라이언트에 권장, 공개 클라이언트에 필수
마이그레이션 가이드:
// v0.3.0 - Implicit Flow (now removed)
{
"implicitFlow": {
"authorizationUrl": "https://auth.example.com/authorize",
"scopes": {"read": "Read access"}
}
}
// v1.0 - Use Authorization Code + PKCE instead
{
"authorizationCodeFlow": {
"authorizationUrl": "https://auth.example.com/authorize",
"tokenUrl": "https://auth.example.com/token",
"pkceRequired": true,
"scopes": {"read": "Read access"}
}
}
다른 스펙에 대한 새로운 의존성
v1.0은 업계 표준 스펙에 대한 여러 새로운 공식 의존성을 도입해요.
추가된 스펙
✅ google.rpc.Status / google.rpc.ErrorInfo
- 목적: ProtoJSON 표현을 가진 표준화된 오류 응답 모델
- 사용: HTTP+JSON과 JSON-RPC 바인딩의 오류 응답
- 영향: HTTP 오류에 RFC 9457을 대체. A2A 특화 오류에 대해
reason과domain을 가진 구조화된ErrorInfo를 시행
✅ RFC 8785 - JSON 정규화 스킴(JCS)
- 목적: 서명을 위한 결정적 JSON 직렬화
- 사용: Agent Card 서명 검증
- 영향: Agent Card 무결성의 암호화 검증 가능
- 세부사항: JWS 서명 전에 사용되는 정규 형식(
signatures필드 제외)
✅ RFC 7515 - JSON 웹 서명(JWS)
- 목적: 암호화 서명 표준
- 사용: Agent Card 서명 필드
- 영향: 신뢰 검증을 위한 업계 표준 서명 형식
- 세부사항:
jku또는 신뢰 키 저장소를 통한 공개 키 검색을 가진 분리 서명 지원
✅ Google API 설계 지침
- 목적: gRPC 모범 관행과 규칙
- 사용: gRPC 바인딩 설계 패턴
- 영향: gRPC 생태계 기대와 더 나은 정렬
✅ ISO 8601
- 목적: 타임스탬프 형식 표준
- 사용:
TaskStatus.timestamp같은 타임스탬프 필드 - 영향: 명시적 형식 요구사항: 밀리초 정밀도의 UTC(
YYYY-MM-DDTHH:mm:ss.sssZ)
기존 의존성(v0.3.0에서 유지)
- JSON-RPC 2.0
- gRPC / Protocol Buffers 3
- HTTP/HTTPS(다양한 RFC)
- Server-Sent Events(SSE) — W3C 스펙
- RFC 8615 — 잘 알려진 URI
- OAuth 2.0, OpenID Connect(인증용)
- TLS(RFC 8446 권장)
보완적 프로토콜
Model Context Protocol(MCP):
- 관계 명확화: MCP는 도구/리소스 통합을, A2A는 에이전트 간 조정을 담당
- 두 프로토콜은 경쟁이 아니라 보완적
- 에이전트는 서로 다른 사용 사례에 두 프로토콜을 모두 지원할 수 있음
개발자에 대한 영향
코드 업데이트가 필요한 파괴적 변경
1. Part 타입 통합(치명적 영향)
가장 중요한 파괴적 변경: TextPart, FilePart, DataPart 타입이 제거되고 단일 통합 Part 구조로 대체됐어요.
이전(v0.3.0):
// Separate types with kind discriminator
if (part.kind === "text") {
return part.text;
} else if (part.kind === "file") {
if (part.file.fileWithUri) {
return fetchFile(part.file.fileWithUri);
} else {
return part.file.fileWithBytes;
}
} else if (part.kind === "data") {
return part.data;
}
이후(v1.0):
// Unified Part with oneof content
if ("text" in part) {
return part.text;
} else if ("url" in part) {
return fetchFile(part.url);
} else if ("raw" in part) {
return decodeBase64(part.raw);
} else if ("data" in part) {
return part.data;
}
2. 스트림 이벤트 판별자 패턴(높은 영향)
스트림 이벤트가 kind 기반에서 래퍼 기반 판별로 변경됐어요.
이전(v0.3.0):
if (event.kind === "status-update") {
handleStatusUpdate(event);
} else if (event.kind === "artifact-update") {
handleArtifactUpdate(event);
}
이후(v1.0):
if ("statusUpdate" in event) {
handleStatusUpdate(event.statusUpdate);
} else if ("artifactUpdate" in event) {
handleArtifactUpdate(event.artifactUpdate);
}
3. Agent Card 구조(높은 영향)
에이전트 발견과 역량 확인에 업데이트가 필요해요.
이전(v0.3.0):
const endpoint = agentCard.url;
const transport = agentCard.preferredTransport;
const supportsExtended = agentCard.supportsAuthenticatedExtendedCard;
이후(v1.0):
const primaryInterface = agentCard.supportedInterfaces[0];
const endpoint = primaryInterface.url;
const transport = primaryInterface.protocolBinding;
const supportsExtended = agentCard.capabilities.extendedAgentCard;
4. 페이지네이션(중간 영향)
List Tasks 구현이 페이지 기반에서 커서 기반으로 전환해야 해요.
이전(v0.3.0):
const response = await listTasks({ page: 1, perPage: 50 });
이후(v1.0):
let pageToken = undefined;
do {
const response = await listTasks({ pageToken, pageSize: 50 });
// process response.tasks
pageToken = response.nextPageToken;
} while (pageToken);
5. Enum 값 변경(높은 영향)
모든 enum 값이 이제 타입 접두사를 가진 SCREAMING_SNAKE_CASE를 사용해요.
TaskState:
// v0.3.0
if (task.status.state === "completed") { ... }
if (task.status.state === "input-required") { ... }
// v1.0
if (task.status.state === "TASK_STATE_COMPLETED") { ... }
if (task.status.state === "TASK_STATE_INPUT_REQUIRED") { ... }
MessageRole:
// v0.3.0
const message = { role: "user", parts: [...] };
// v1.0
const message = { role: "ROLE_USER", parts: [...] };
전체 매핑:
"submitted"→"TASK_STATE_SUBMITTED""working"→"TASK_STATE_WORKING""completed"→"TASK_STATE_COMPLETED""failed"→"TASK_STATE_FAILED""canceled"→"TASK_STATE_CANCELED""rejected"→"TASK_STATE_REJECTED""input-required"→"TASK_STATE_INPUT_REQUIRED""auth-required"→"TASK_STATE_AUTH_REQUIRED""user"→"ROLE_USER""agent"→"ROLE_AGENT"
6. 필드 이름 변경(낮은 영향)
file.mimeType→mediaType- 연산 이름(전환 기간 동안 별칭 제공)
7. google.rpc.Status를 통한 표준화된 오류 처리(높은 영향)
HTTP+JSON 오류 응답이 RFC 9457(Problem Details) 대신 google.rpc.Status의 ProtoJSON 표현을 사용하도록 업데이트됐어요. JSON-RPC와 HTTP+JSON 바인딩은 이제 data/details 배열 안의 google.rpc.ErrorInfo를 사용해 A2A 특화 오류 컨텍스트를 제공해요.
변경 사항:
- HTTP+JSON Content-Type:
application/problem+json에서application/json으로 변경 - 오류 모델:
google.rpc.Status필드(code,message,details) 사용 - A2A 오류 정보:
details에reason(A2A 오류 타입의 UPPER_SNAKE_CASE)과domain: "a2a-protocol.org"를 가진google.rpc.ErrorInfo객체를 반드시 포함해야 함
JSON-RPC 마이그레이션 예시:
// v0.3.0
"error": {
"code": -32001,
"message": "Task not found",
"data": { "taskId": "123" }
}
// v1.0
"error": {
"code": -32001,
"message": "Task not found",
"data": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "TASK_NOT_FOUND",
"domain": "a2a-protocol.org",
"metadata": { "taskId": "123" }
}
]
}
HTTP+JSON 마이그레이션 예시:
// v0.3.0 (Draft using RFC 9457)
HTTP/1.1 404 Not Found
Content-Type: application/problem+json
{
"type": "https://a2a-protocol.org/errors/task-not-found",
"title": "Task Not Found",
"status": 404,
"detail": "The specified task ID does not exist"
}
// v1.0
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"code": 404,
"status": "NOT_FOUND",
"message": "The specified task ID does not exist",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "TASK_NOT_FOUND",
"domain": "a2a-protocol.org"
}
]
}
}
활용할 새 역량
1. 실행 모드 제어
// Wait for task completion (Default)
const result = await sendMessage(message, { returnImmediately: false });
// Return immediately, poll later
const task = await sendMessage(message, { returnImmediately: true });
2. Agent Card 서명 검증
if (agentCard.signatures && agentCard.signatures.length > 0) {
const verified = await verifyAgentCardSignature(agentCard);
if (!verified) {
throw new Error("Agent Card signature verification failed");
}
}
3. 확장 요구사항
const requiredExtensions = agentCard.extensions
.filter(ext => ext.required)
.map(ext => ext.uri);
// Check if client supports required extensions
if (!clientSupportsAll(requiredExtensions)) {
throw new Error("Missing required extension support");
}
4. 버전 협상
// Client sends A2A-Version header
headers["A2A-Version"] = "1.0";
// Server validates and rejects if unsupported
if (!supportedVersions.includes(requestedVersion)) {
throw new VersionNotSupportedError();
}
마이그레이션 전략 권장사항
1단계: 호환성 계층
- 이전 및 새 판별자 패턴을 모두 파싱하는 지원 추가
- 프로토콜 버전 기반 버전 감지 구현
- 전환 동안 두 Agent Card 구조 모두 지원
2단계: 이중 지원
- 모든 API를 v1.0 형식으로 업데이트
- v0.3.0용 역호환 리더 유지
- A2A-Version 헤더 처리 추가
- 레거시 페이지 기반 옆에 커서 기반 페이지네이션 구현
3단계: v1.0 전용
- v0.3.0 호환성 코드 폐지
- 레거시 판별자 파싱 제거
- 페이지 기반 페이지네이션 제거
- 이중 형식 지원 코드 정리
역호환 전략(#1401)
v1.0은 SDK 역호환을 가능하게 하는 프로토콜 버전 관리에 대한 공식 접근을 도입해요.
인터페이스별 프로토콜 버전:
- 각
AgentInterface가 이제 자체protocolVersion필드를 지정 - 에이전트는 여러 인터페이스를 노출해 여러 프로토콜 버전을 동시에 지원할 수 있음
- 클라이언트는 Agent Card에서 적절한 인터페이스를 선택해 버전을 협상
SDK 구현 패턴:
// SDK can support multiple protocol versions
class A2AClient {
async connect(agentCardUrl: string) {
const card = await this.getAgentCard(agentCardUrl);
// Find best matching interface
const interface = card.supportedInterfaces.find(i =>
this.supportedVersions.includes(i.protocolVersion)
);
if (!interface) {
throw new Error("No compatible protocol version");
}
// Use version-specific adapter
return this.createAdapter(interface.protocolVersion, interface);
}
}
이점:
- SDK가 여러 프로토콜 버전 지원을 유지할 수 있음
- 에이전트가 이전·새 버전을 모두 지원해 점진적으로 마이그레이션할 수 있음
- 클라이언트가 최고의 호환 버전을 자동 선택
- 이전 프로토콜 버전의 우아한 폐지 가능
테스트 고려사항
- v0.3.0과 v1.0 형식 데이터 모두로 테스트
- Agent Card 서명 검증 검증
- 커서 기반 페이지네이션 엣지 케이스 테스트(빈 결과, 단일 페이지 등)
- 새 오류 타입의 올바른 처리 검증
- 확장 요구사항 검증 테스트
권장 우선순위
치명(즉시 수행):
- Part 및 스트리밍 이벤트 파싱 업데이트(판별자 패턴)
- Agent Card 파싱 업데이트(구조 변경)
- 모든 요청에 A2A-Version 헤더 추가
높음(1개월 이내):
- 커서 기반 페이지네이션 구현
- enum 값 처리 업데이트(state 필드)
- return_immediately 매개변수 지원 추가
중간(3개월 이내):
- Agent Card 서명 검증 구현
- 확장 요구사항 확인 추가
- 타임스탬프 처리를 ISO 8601 형식으로 업데이트
- 새 오류 타입 구현
낮음(있으면 좋음):
- 향상된 메타데이터 역량 활용
- 상호 TLS 인증 지원 구현
결론
A2A 프로토콜 v1.0은 v0.3.0의 핵심 아키텍처 원칙을 유지하면서 프로토콜 성숙에서 상당한 진전을 나타내요. 변경 사항은 표준화, 타입 안전성, 엔터프라이즈 준비에 집중하며, 개발자가 구현을 업데이트하도록 요구하지만 그 대가로 더 명확한 스펙과 더 나은 개발자 경험을 제공해요. 파괴적 변경은 코드 업데이트가 필요하지만 구현이 간단하고 코드 명확성을 개선해요. 버전 관리, 서명, 향상된 확장을 둘러싼 새 역량은 v1.x 계열 내에서 미래 프로토콜 진화를 위한 견고한 기반을 제공해요. 개발자는 단계적 마이그레이션 접근을 계획하고, 치명적 파괴 변경을 우선시하면서 시간이 지나며 새 역량을 점진적으로 채택해야 해요.
더 알아보기 (Learn more)
- v1.0의 태스크 모델을 더 알고 싶다면 태스크의 수명주기(Life of a Task)를 읽어 보세요.
- 확장 메커니즘은 확장(Extensions) 문서를 확인하세요.
- 정확한 데이터 구조와 RPC 메서드는 A2A 스펙(specification)을 참고하세요.