A2A
A2A (camel-a2a)
A2A 컴포넌트는 Agent-to-Agent (A2A) v1.0 프로토콜을 구현해서, Camel 라우트가 A2A 호환 에이전트를 노출하거나 호출할 수 있게 해 줘요. 컨슈머로 쓰면 라우트가 에이전트 카드 서빙부터 태스크 상태 관리까지 갖춘 A2A 에이전트로 바뀌고, 프로듀서로 쓰면 원격 A2A 에이전트를 호출해요. agentCardSource, protocolBinding, dataFormat 같은 엔드포인트 옵션과 SSE 스트리밍·비동기 태스크·푸시 알림·보안 관련 옵션들이 제공돼요.
출처: 문서
본문
Camel 4.21부터 지원
컨슈머와 프로듀서를 모두 지원해요
A2A 컴포넌트는 Agent-to-Agent (A2A) v1.0 프로토콜을 구현해서, Camel 라우트가 A2A 호환 에이전트를 노출하고 호출할 수 있게 해 줘요.
컨슈머로 쓰면 Camel 라우트를 A2A 에이전트로 바꿔 줘요 — /.well-known/agent-card.json에서 에이전트 카드를 자동으로 서빙하고, 모든 A2A 연산을 HTTP로 노출하며, 태스크 상태를 관리해요. 프로듀서로 쓰면 원격 A2A 에이전트를 호출하는데, 에이전트 카드 자동 발견, 프로토콜 래핑, 자격 증명 관리가 알아서 처리돼요.
이 컴포넌트는 REST OpenAPI와 같은 설계 철학을 따라요: 프로토콜 잡무는 컴포넌트가 처리하고, 비즈니스 로직은 전부 라우트에 맡기는 거죠.
참고 A2A 프로토콜
A2A 프로토콜은 AI 에이전트 간 통신을 위한 오픈 표준이에요. 에이전트들이 에이전트 카드로 서로를 발견하고, 메시지를 주고받고, 오래 실행되는 태스크를 관리하고, 진행 상황 업데이트를 스트리밍하고, 푸시 알림을 전달하는 방법을 정의해요. 이 프로토콜은 HTTP 위에서 REST(HTTP+JSON)와 JSON-RPC 2.0 바인딩을 모두 지원해요.
프리뷰 제한 사항 (Preview Limitations)
A2A 컴포넌트는 Camel 4.21에서 프리뷰 상태예요. A2A v1.0 프로토콜을 목표로 하지만, 컴포넌트가 안정 지원에 도달하기 전까지는 엔드포인트 옵션, 모델 클래스, 생성된 메타데이터, 태스크 스토어 SPI가 여전히 바뀔 수 있어요.
현재 프리뷰 제한 사항은 다음과 같아요:
-
확장 에이전트 카드 /
GetExtendedAgentCard는 이번 첫 릴리스에서 구현되지 않았어요. -
컨슈머는 기본으로 연산 요청을 검증해요. 이 페이지의 로컬 전용 예제들은
validateAuth=false로 설정하지만, 네트워크에 노출되는 에이전트는securitySchemes와securityRequirements가 들어간 에이전트 카드에apiKey,bearerToken,oauthProfile엔드포인트 설정을 더해서 사용해야 해요. -
REST 바인딩은
/message:send처럼 콜론이 들어간 A2A 커스텀 메서드 경로를 사용해요. 이런 경로는 Vert.x/platform-http에서 충돌해요. platform-http에서는protocolBinding=JSONRPC를 쓰거나, REST 커스텀 메서드 라우트에는httpServerComponent=undertow나httpServerComponent=jetty를 사용하세요. -
실시간 SSE 스트리밍은 Vert.x/platform-http, Undertow, Jetty로 검증되었어요.
-
기본 태스크 스토어는 인메모리이고 단일 JVM이에요. 내구성 있는 태스크 상태나 노드 간 태스크 상태가 필요하면 커스텀
A2ATaskStore를 등록하세요.
Maven 사용자라면 pom.xml에 다음 의존성을 추가해야 해요:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-a2a</artifactId>
<version>x.x.x</version>
<!-- use the same version as your Camel core version -->
</dependency>
컨슈머 라우트는 런타임에 HTTP 서버 컴포넌트도 필요해요. 예를 들어 JSON-RPC 에이전트(SSE 스트리밍 포함)에는 camel-platform-http-vertx를, REST 커스텀 메서드 라우트에는 camel-undertow나 camel-jetty를 추가하세요. Dependencies와 HTTP Server Component Discovery를 참고하세요.
URI 형식 (URI Format)
a2a:agentCardSource[?options]
agentCardSource가 에이전트 카드를 어디서 불러올지 결정하는 방식이에요:
| Source | Example |
|---|---|
| Remote URL (partial) | a2a:\https://agent.example.com — auto-expands to https://agent.example.com/.well-known/agent-card.json |
| Remote URL (full) | a2a:\https://agent.example.com/.well-known/agent-card.json |
| Classpath | a2a:classpath:cards/weather.json |
| File | a2a:file:/etc/agents/weather.json |
| Plain name | a2a:weather-agent?name=Weather&description=… — card built from params |
같은 URI를 from()(컨슈머: "나 이 에이전트야")와 to()(프로듀서: "이 에이전트를 호출할 거야") 양쪽에서 모두 쓸 수 있어요.
옵션 설정 (Configuring Options)
Camel 컴포넌트는 서로 다른 두 단계로 설정해요:
-
component level
-
endpoint level
컴포넌트 옵션 설정 (Configuring Component Options)
컴포넌트 레벨에서는 엔드포인트들이 이어서 물려받는 일반적이고 공유되는 설정을 해요. 가장 상위의 설정 레벨이죠.
예를 들어 컴포넌트에는 보안 설정, 인증용 자격 증명, 네트워크 연결 URL 같은 것들이 있을 수 있어요.
컴포넌트에 따라 옵션이 몇 개뿐인 것도 있고 아주 많은 것도 있어요. 컴포넌트는 보통 널리 쓰이는 기본값이 미리 설정되어 있어서, 몇 가지 옵션만 설정하거나 아예 하나도 건드리지 않아도 되는 경우가 많아요.
컴포넌트는 다음 방법으로 설정할 수 있어요:
-
the Component DSL.
-
in a configuration file (
application.properties,*.yamlfiles, etc). -
directly in the Java code.
엔드포인트 옵션 설정 (Configuring Endpoint Options)
엔드포인트는 옵션이 많아서 설정에 시간을 더 쓰게 될 거예요. 이 옵션들이 엔드포인트가 원하는 일을 하도록 커스터마이즈해 줘요. 옵션은 엔드포인트가 컨슈머(from)로 쓰이는지, 프로듀서(to)로 쓰이는지, 둘 다인지에 따라 분류되기도 해요.
엔드포인트 설정은 대부분 엔드포인트 URI에 _path_와 query 파라미터로 바로 하는 경우가 많아요. Endpoint DSL과 DataFormat DSL을 쓰면 자바에서 엔드포인트와 데이터 포맷을 _타입 세이프_하게 설정할 수도 있어요.
옵션을 설정할 때 좋은 습관은 Property Placeholders를 사용하는 거예요.
프로퍼티 플레이스홀더는 이런 장점이 있어요:
-
They help prevent using hardcoded urls, port numbers, sensitive information, and other settings.
-
They allow externalizing the configuration from the code.
-
They help the code to become more flexible and reusable.
다음 두 섹션에서 모든 옵션을 나열해요. 먼저 컴포넌트 옵션, 그다음 엔드포인트 옵션 순서예요.
컴포넌트 옵션 (Component Options)
A2A 컴포넌트는 아래 나열된 옵션들을 지원해요.
| Name | Description | Default | Type |
|---|---|---|---|
| bridgeErrorHandler (consumer) | 컨슈머를 Camel 라우팅 에러 핸들러(Error Handler)에 브리지할 수 있게 해 줘요. 즉, Camel 컨슈머가 들어오는 메시지를 집어 올리는 동안 등에서 예외가 발생하면(가능한 경우), 그 예외를 메시지로 처리해서 라우팅 에러 핸들러가 다루게 돼요. 중요: 이것은 서드파티 컴포넌트가 예외가 던져졌을 때 Camel에 알릴 수 있도록 허용하는 경우에만 가능해요. 일부 컴포넌트는 내부에서만 처리하기 때문에 bridgeErrorHandler를 쓸 수 없어요. 다른 상황에서는 Camel 컴포넌트를 개선해서 서드파티 컴포넌트에 연결(hook)해 이를 가능하게 만들 수도 있어요. 기본으로 컨슈머는 org.apache.camel.spi.ExceptionHandler로 예외를 처리하는데, WARN 또는 ERROR 레벨로 로그를 남기고 무시해요. | false | boolean |
| lazyStartProducer (producer) | 프로듀서를 느리게(lazy, 첫 메시지가 올 때) 시작할지 여부예요. 느리게 시작하면, 프로듀서가 시작 중에 실패해서 라우트 시작 자체가 실패하는 상황에서도 CamelContext와 라우트를 시작할 수 있어요. 시작을 늦춰 두면 실패가 발생했을 때 메시지를 라우팅하는 동안 Camel의 라우팅 에러 핸들러로 처리할 수 있죠. 단, 첫 메시지를 처리할 때 프로듀서를 만들고 시작하는 데 시간이 조금 걸려서 전체 처리 시간이 길어질 수 있다는 점은 감안하세요. | false | boolean |
| autowiredEnabled (advanced) | 오토와이어링(autowiring)을 활성화할지 여부예요. 레지스트리에서 일치하는 타입의 인스턴스가 딱 하나 있는지 찾아서, 그 인스턴스로 오토와이어링 옵션(옵션이 autowired로 표시되어 있어야 함)을 자동 설정하는 데 쓰여요. JDBC 데이터 소스, JMS 커넥션 팩토리, AWS 클라이언트 등을 자동 설정할 때 사용할 수 있어요. | true | boolean |
엔드포인트 옵션 (Endpoint Options)
A2A 엔드포인트는 다음 URI 문법으로 설정해요:
a2a:agentCardSource
다음 path 및 query 파라미터를 사용해요:
경로 파라미터 (Path Parameters)
| Name | Description | Default | Type |
|---|---|---|---|
| agentCardSource (common) | 필수 에이전트 카드 소스(classpath:, file:, http://, https://, 또는 일반 이름)예요. | String |
쿼리 파라미터 (Query Parameters)
| Name | Description | Default | Type |
|---|---|---|---|
| agentCard (common) | 에이전트 카드 빈 참조 또는 인라인 설정. | AgentCard | |
| basePath (common) | HTTP 요청의 베이스 경로. | String | |
| dataFormat (common) | |||
| 교환 바디에 담길 데이터 포맷이에요. CXF DataFormat 컨벤션을 따라요. PAYLOAD(기본값)는 메시지 파트에서 텍스트 내용을 String으로 뽑아요 — 하위 호환이고 챗봇 라우트에 간단해요. POJO는 바디를 완전한 Java 모델 객체로 설정해요(컨슈머는 Message, 프로듀서는 Task 또는 Message) — 모든 파트, 메타데이터, 파일 내용을 보존해요. RAW는 역직렬화 없이 원시 JSON 문자열을 전달해요 — 포워딩, 로깅, 컴플라이언스에 유용해요. |
Enum values:
-
PAYLOAD
-
POJO
-
RAW
| PAYLOAD | A2ADataFormat | | description (common) | 에이전트 설명(에이전트 카드보다 우선해요). | | String | | historyLength (common) | 컨텍스트에 포함할 히스토리 메시지의 최대 개수. | | Integer | | host (common) | 프로듀서가 접속할 호스트. | | String | | name (common) | 에이전트 이름(에이전트 카드보다 우선해요). | | String | | port (common) | 프로듀서가 접속할 포트. | | Integer | | protocolBinding (common) |
통신에 사용할 프로토콜 바인딩이에요. 레거시 별칭 rest와 jsonrpc도 받아들여요.
Enum values:
-
HTTP+JSON
-
JSONRPC
| HTTP+JSON | String | | returnImmediately (common) | 태스크 완료를 기다리지 않고 바로 반환할지 여부. | false | boolean | | validateAuth (common) | 들어오는 컨슈머 연산 요청에 대해 인증을 검증할지 여부. 인증 없는 A2A 연산 서빙이 필요할 때만 명시적으로 비활성화하세요. | true | boolean | | version (common) | 에이전트 버전(에이전트 카드보다 우선해요). | | String | | bridgeErrorHandler (consumer (advanced)) | 컨슈머를 Camel 라우팅 에러 핸들러(Error Handler)에 브리지할 수 있게 해 줘요. 즉, Camel 컨슈머가 들어오는 메시지를 집어 올리는 동안 등에서 예외가 발생하면(가능한 경우), 그 예외를 메시지로 처리해서 라우팅 에러 핸들러가 다루게 돼요. 중요: 이것은 서드파티 컴포넌트가 예외가 던져졌을 때 Camel에 알릴 수 있도록 허용하는 경우에만 가능해요. 일부 컴포넌트는 내부에서만 처리하기 때문에 bridgeErrorHandler를 쓸 수 없어요. 다른 상황에서는 Camel 컴포넌트를 개선해서 서드파티 컴포넌트에 연결(hook)해 이를 가능하게 만들 수도 있어요. 기본으로 컨슈머는 org.apache.camel.spi.ExceptionHandler로 예외를 처리하는데, WARN 또는 ERROR 레벨로 로그를 남기고 무시해요. | false | boolean | | exceptionHandler (consumer (advanced)) | 컨슈머가 커스텀 ExceptionHandler를 쓰게 할 수 있어요. bridgeErrorHandler 옵션이 활성화되어 있으면 이 옵션은 사용되지 않는다는 점에 주의하세요. 기본으로 컨슈머는 예외를 처리하는데, WARN 또는 ERROR 레벨로 로그를 남기고 무시해요. | | ExceptionHandler | | exchangePattern (consumer (advanced)) |
컨슈머가 교환(exchange)을 만들 때 교환 패턴을 설정해요.
Enum values:
-
InOnly
-
InOut
| | ExchangePattern | | httpServerComponent (consumer (advanced)) | 들어오는 A2A 요청을 서빙하는 데 쓸 Camel HTTP 컴포넌트(컨슈머 쪽)예요. RestConsumerFactory를 구현해야 해요(예: platform-http, jetty, netty-http, undertow, servlet). 설정하지 않으면 클래스패스에서 자동 발견하거나, 전역 camel.rest.component 설정으로 폴백해요. | | String | | maxConcurrentTasks (consumer (advanced)) | 에이전트가 동시에 처리할 수 있는 태스크의 최대 개수. 한도에 도달하면 새 요청은 ServerBusyError(HTTP 429)로 거절돼요. 무제한 동시성은 0(기본값)으로 설정하세요. | 0 | int | | sseHeartbeatInterval (consumer (advanced)) | SSE keep-alive 하트비트 코멘트 간격(밀리초). 프록시가 유휴 연결을 닫지 않도록 ':' 코멘트 라인으로 보내요. 태스크 처리 타임아웃을 담당하는 asyncTimeout과는 독립적이에요. | 15000 | long | | sseQueueCapacity (consumer (advanced)) | 스트리밍 연결 하나당 버퍼링할 수 있는 SSE 이벤트의 최대 개수. 큐가 가득 차면 새 이벤트는 경고 로그를 남기고 버려져요. 느린 클라이언트로 인한 무한한 메모리 성장을 막아 줘요. | 1000 | int | | taskQueueSize (consumer (advanced)) | 모든 동시 슬롯이 점유된 상태에서 대기 큐에 들어갈 수 있는 태스크의 최대 개수. 비동기 요청(returnImmediately=true)에만 적용돼요. 큐에 들어간 태스크는 SUBMITTED 상태를 받고, 용량이 나는 대로 처리돼요. 0(기본값)이면 큐잉 없이 용량 초과 시 요청이 즉시 거절돼요. | 0 | int | | operation (producer) |
수행할 A2A 연산이에요.
Enum values:
-
MESSAGE_SEND
-
MESSAGE_STREAM
-
TASK_GET
-
TASK_LIST
-
TASK_CANCEL
-
TASK_SUBSCRIBE
-
PUSH_CONFIG_CREATE
-
PUSH_CONFIG_GET
-
PUSH_CONFIG_LIST
-
PUSH_CONFIG_DELETE
| MESSAGE_SEND | A2AOperations | | connectTimeout (producer (advanced)) | 프로듀서가 쓰는 HTTP 클라이언트의 연결 타임아웃(밀리초). | 30000 | long | | lazyStartProducer (producer (advanced)) | 프로듀서를 느리게(lazy, 첫 메시지가 올 때) 시작할지 여부예요. 느리게 시작하면, 프로듀서가 시작 중에 실패해서 라우트 시작 자체가 실패하는 상황에서도 CamelContext와 라우트를 시작할 수 있어요. 시작을 늦춰 두면 실패가 발생했을 때 메시지를 라우팅하는 동안 Camel의 라우팅 에러 핸들러로 처리할 수 있죠. 단, 첫 메시지를 처리할 때 프로듀서를 만들고 시작하는 데 시간이 조금 걸려서 전체 처리 시간이 길어질 수 있다는 점은 감안하세요. | false | boolean | | streamingReadTimeout (producer (advanced)) | 프로듀서의 SSE 스트리밍 연결에 대한 읽기 타임아웃(밀리초). 이 기간 안에 SSE 이벤트가 도착하지 않으면 스트림은 에러로 닫혀요. 원격 에이전트가 이벤트 전송을 멈췄을 때 무한 블로킹을 막아 줘요. | 300000 | long | | asyncTimeout (advanced) | 비동기 태스크 연산의 타임아웃(밀리초). | 300000 | long | | completedTaskTtl (advanced) | 완료된 태스크가 정리되기 전까지의 TTL(밀리초). | 3600000 | long | | followRedirects (advanced) | HTTP 클라이언트가 리다이렉트를 따를지 여부. 교차 오리진 리다이렉트에서 자격 증명이 새어 나가는 걸 막기 위해 기본으로 비활성화되어 있어요. 원격 에이전트가 리다이렉트를 발생시킨다는 게 확인된 경우(예: 로드밸런서 뒤)에만 활성화하세요. | false | boolean | | maxPayloadSize (advanced) | 최대 페이로드 크기(바이트, 기본 6MB). | 6291456 | long | | pushRetryAttempts (advanced) | 푸시 알림 웹훅 전송의 최대 재시도 횟수. | 3 | int | | pushRetryBackoffMs (advanced) | 푸시 알림 재시도의 초기 백오프(밀리초). 재시도는 이 지연 값에 시도 번호만큼 2를 거듭 곱한 지수 백오프를 사용해요. | 1000 | long | | allowLocalWebhookUrls (security) | localhost/루프백 주소를 가리키는 웹훅 URL을 허용할지 여부. false(기본값)면 127.0.0.0/8, ::1, localhost를 대상으로 하는 푸시 알림 웹훅 URL은 SSRF 방지를 위해 거절돼요. 로컬 개발에서만 활성화하세요. | false | boolean | | apiKey (security) | 인증용 API 키. | | String | | apiKeyHeader (security) | API 키 인증에 쓰일 HTTP 헤더 이름(예: X-API-Key, Authorization). | Authorization | String | | bearerToken (security) | 인증용 베어러 토큰. | | String | | oauthProfile (security) | OAuth 2.0 Client Credentials 그랜트로 액세스 토큰을 얻기 위한 OAuth 프로필 이름이에요. 설정하면 구성된 아이덴티티 프로바이더에서 토큰을 받아 인증에 사용해요. 클래스패스에 camel-oauth가 필요해요. 프로필 프로퍼티는 camel.oauth.profile-name.client-id, camel.oauth.profile-name.client-secret, camel.oauth.profile-name.token-endpoint에서 확인해요. | | String |
메시지 헤더 (Message Headers)
A2A 컴포넌트는 아래 나열된 메시지 헤더(들)를 지원해요:
| Name | Description | Default | Type |
|---|---|---|---|
CamelA2AOperation (producer) Constant: OPERATION |
호출할 A2A 연산. | String | |
CamelA2ATaskId (common) Constant: TASK_ID |
태스크 ID. | String | |
CamelA2APushConfigId (common) Constant: PUSH_CONFIG_ID |
푸시 알림 설정 ID. | String | |
CamelA2AContextId (common) Constant: CONTEXT_ID |
멀티턴 대화용 컨텍스트 ID. | String | |
CamelA2AMessageId (common) Constant: MESSAGE_ID |
메시지 ID. | String | |
CamelA2ATaskState (common) Constant: TASK_STATE |
태스크 상태. | String | |
CamelA2AMethod (producer) Constant: METHOD |
호출된 A2A 메서드 이름. | String | |
CamelA2AResponseType (common) Constant: RESPONSE_TYPE |
응답 타입: task 또는 message. | String | |
CamelA2AReturnImmediately (common) Constant: RETURN_IMMEDIATELY |
즉시 반환 플래그. | Boolean | |
CamelA2AHistoryLength (common) Constant: HISTORY_LENGTH |
최대 히스토리 메시지 수. | Integer | |
CamelA2AStreamEmitter (consumer) Constant: STREAM_EMITTER |
라우트 프로세서용 SSE 스트림 이미터. | A2AStreamEmitter | |
CamelA2AListContextId (common) Constant: LIST_CONTEXT_ID |
태스크 목록 조회용 컨텍스트 ID 필터. | String | |
CamelA2AListPageSize (common) Constant: LIST_PAGE_SIZE |
태스크 목록 조회용 페이지 크기. | Integer | |
CamelA2AListPageToken (common) Constant: LIST_PAGE_TOKEN |
태스크 목록 페이징용 페이지 토큰. | String | |
CamelA2AListIncludeArtifacts (common) Constant: LIST_INCLUDE_ARTIFACTS |
태스크 목록에 아티팩트를 포함할지 여부. | Boolean | |
CamelA2AListHistoryLength (common) Constant: LIST_HISTORY_LENGTH |
태스크 목록 조회용 히스토리 길이. | Integer | |
CamelA2AListStatusTimestampAfter (common) Constant: LIST_STATUS_TIMESTAMP_AFTER |
이 값 이후의 상태 타임스탬프로 태스크를 필터링해요. | String | |
CamelA2AListStatus (common) Constant: LIST_STATUS |
태스크 목록 조회용 콤마 구분 상태 필터. | String | |
CamelA2AExtensions (consumer) Constant: EXTENSIONS |
클라이언트가 요청한, 협상된 A2A 확장 URI. | List |
하위 페이지 (Sub-Pages)
컨슈머와 프로듀서 사용법의 자세한 내용은 다음을 참고하세요:
-
Consumer Guide - 인증, SSE 스트리밍, 비동기 태스크, 푸시 알림, 용량 제한을 갖춘 A2A 에이전트 노출하기
-
Producer Guide - 스트리밍, 비동기 태스크 라이프사이클, 푸시 알림, 병렬 멀티캐스트로 원격 에이전트 호출하기
심플 언어 함수 (Simple Language Functions)
이 컴포넌트는 a2a: 네임스페이스 아래에 커스텀 심플 언어(Simple) 함수를 등록해요:
| Function | Description |
|---|---|
${a2a:emit('message')} |
WORKING 상태로 상태 업데이트를 내보내요. SSE 스트리밍 부수 효과를 위해 script EIP에서 사용해요. |
${a2a:emit(STATE, 'message')} |
명시적인 TaskState(예: INPUT_REQUIRED)로 상태 업데이트를 내보내요. |
${a2a:text} |
바디(Task 또는 Message)에서 TextPart 내용을 추출해요. 바디가 Task면 히스토리의 마지막 메시지에서 추출해요. |
${a2a:text(expression)} |
심플 표현식의 결과에서 TextPart 내용을 추출해요. |
${a2a:data} |
바디에서 DataPart 내용을 JSON 문자열로 추출해요. |
${a2a:data(expression)} |
심플 표현식의 결과에서 DataPart 내용을 추출해요. |
${a2a:file} |
FilePart 내용을 추출해요 — URL 파일 파트라면 url 값, 인라인 base64 raw 내용이라면 바이너리 크기 설명이에요. |
${a2a:file(expression)} |
심플 표현식의 결과에서 FilePart 내용을 추출해요. |
${a2a:card} |
에이전트 카드 전체를 JSON 문자열로 돌려줘요. A2A 엔드포인트에서 카드를 가져와요(컨슈머의 자기 카드 또는 프로듀서가 캐시한 원격 카드). |
${a2a:card.name} |
에이전트 카드 이름. |
${a2a:card.description} |
에이전트 카드 설명. |
${a2a:card.url} |
에이전트 카드 URL. |
${a2a:card.version} |
에이전트 카드 버전. |
${a2a:card.skills} |
스킬을 사람이 읽기 좋은 텍스트로, 한 줄에 하나씩 포맷해요: * Skill Name: description. |
${a2a:card.skills.json} |
스킬을 JSON 배열 문자열로. |
${a2a:card.iconUrl} |
에이전트 카드 아이콘 URL. |
${a2a:card.documentationUrl} |
에이전트 카드 문서 URL. |
${a2a:card.provider} |
에이전트 프로바이더를 JSON 문자열로. |
${a2a:card.capabilities} |
에이전트 기능(capabilities)을 JSON 문자열로. |
${a2a:card.supportedInterfaces} |
지원 인터페이스를 JSON 배열 문자열로. |
${a2a:card.securitySchemes} |
보안 스킴을 JSON 객체 문자열로. |
${a2a:card.securityRequirements} |
A2A v1.0 보안 요구 사항을 JSON 배열 문자열로. |
${a2a:card.security} |
레거시 초안의 security 필드를 JSON 배열 문자열로. |
${a2a:card} 함수들은 교환 컨텍스트에서 에이전트 카드를 찾아 와요. 컨슈머 라우트에서는 exchange.getFromEndpoint()가 에이전트 자신의 카드를 제공해요. 프로듀서 라우트에서는 컴포넌트가 등록된 엔드포인트를 훑으면서 캐시된 원격 카드를 찾아요. 카드를 찾지 못하면 빈 문자열을 반환해요.
참고 카드 함수는 플랫 필드 접근만 지원해요 —
${a2a:card.skills[0].name}이나${a2a:card.provider.organization}같은 중첩 프로퍼티 접근은 지원하지 않아요. 구조화된 데이터가 필요하면${a2a:card.skills.json}이나${a2a:card}(전체 JSON)을 사용하고 아래쪽에서 파싱하세요.
예제 — 원격 에이전트 스킬을 LLM 프롬프트에 포함하기:
steps:
- setBody:
expression:
simple:
expression: |
Generate a plan using these available skills:
${a2a:card.skills}
모든 파트를 합친 전체 텍스트가 필요하면 TypeConverter를 사용하세요:
steps:
- convertBodyTo:
type: String
교환 헤더 (Exchange Headers)
| Header | Type | Description |
|---|---|---|
CamelA2AOperation |
String |
호출할 A2A 연산. 열거형 이름(TASK_GET, PUSH_CONFIG_CREATE)과 파스칼케이스 메서드 이름(GetTask, CreateTaskPushNotificationConfig)을 모두 받아들여요. |
CamelA2ATaskId |
String |
GetTask, CancelTask, SubscribeToTask, 푸시 알림 연산에 쓰이는 태스크 ID. |
CamelA2APushConfigId |
String |
조회/삭제 연산에 쓰이는 푸시 알림 설정 ID. |
CamelA2AContextId |
String |
멀티턴 대화용 컨텍스트 ID. 컨슈머 인바운드와 프로듀서 응답에 자동으로 설정돼요. |
CamelA2AMessageId |
String |
요청/응답의 메시지 ID. |
CamelA2ATaskState |
String |
응답의 태스크 상태(예: TASK_STATE_COMPLETED, TASK_STATE_WORKING). |
CamelA2AMethod |
String |
호출된 A2A 메서드 이름(프로듀서 응답에 설정돼요). |
CamelA2AResponseType |
String |
프로듀서 호출 후의 응답 타입(task, message, taskList, pushConfigList, 또는 stream). 컨슈머 라우트에서 이 헤더를 message로 설정하면 메시지만 담은 SendMessage 응답을 돌려줘요. 기본은 태스크 응답이에요. |
CamelA2AReturnImmediately |
Boolean |
요청별로 returnImmediately를 재정의해요. 엔드포인트 레벨 설정보다 우선해요. |
CamelA2AHistoryLength |
Integer |
GetTask와 SubscribeToTask의 프로듀서 요청 필드. |
CamelA2AUserProfile |
Map<String, Object> |
인증된 사용자 프로필(헤더가 아니라 교환 프로퍼티로 설정돼요). validateAuth=true이고 인증이 성공했을 때 채워져요. 심플 표현식에서 $\{exchangeProperty.CamelA2AUserProfile}로 접근하세요. |
CamelA2AListContextId |
String |
ListTasks의 컨텍스트 ID 필터. |
CamelA2AListPageSize |
Integer |
ListTasks의 페이지 크기. |
CamelA2AListPageToken |
String |
ListTasks의 페이지네이션 토큰. |
CamelA2AListStatus |
String |
ListTasks의 콤마 구분 상태 필터. |
CamelA2AListIncludeArtifacts |
Boolean |
ListTasks 응답에 아티팩트를 포함할지 여부. |
CamelA2AListHistoryLength |
Integer |
ListTasks 응답에서 태스크별로 포함할 최대 히스토리 메시지 수. |
CamelA2AListStatusTimestampAfter |
String |
ListTasks의 상태 타임스탬프 필터. ISO-8601 오프셋 날짜-시간을 사용하세요. |
CamelA2AExtensions |
List<String> |
A2A-Extensions 요청 헤더에서 온, 컨슈머 쪽 협상된 A2A 확장 URI. 검증 후 교환 프로퍼티와 라우트 헤더 둘 다로 설정돼요. |
CamelA2AStreamEmitter |
A2AStreamEmitter |
컨슈머 쪽: 스트리밍 라우트에 주입된 스트림 이미터. 고급 사용 사례용이에요 — 대부분의 에이전트는 ${a2a:emit()}나 A2AProgress API를 쓰는 게 좋아요. |
참고
CamelA2AResponseTask와CamelA2AUserProfile은 헤더가 아니라 교환 프로퍼티예요. 심플 표현식에서$\{exchangeProperty.CamelA2AResponseTask}와$\{exchangeProperty.CamelA2AUserProfile}로 접근하세요.CamelA2AResponseTask에는 프로듀서 응답의 전체Task객체가 담겨서 폴링 워크플로우에서 유용해요.CamelA2AUserProfile에는 인증된 사용자의 프로필 맵이 담기고,validateAuth=true일 때 사용할 수 있어요.
지원 연산 (Supported Operations)
| Operation (enum) | Method Name | Producer | Consumer |
|---|---|---|---|
MESSAGE_SEND |
SendMessage |
메시지를 보내고 Task 또는 Message를 받아요 | 라우트가 메시지를 처리해요 |
MESSAGE_STREAM |
SendStreamingMessage |
지연 Iterator<StreamResponse> (PAYLOAD/POJO), 또는 원시 InputStream (RAW) |
라우트가 ${a2a:emit()}로 내보내요 |
TASK_GET |
GetTask |
원격에서 태스크를 조회해요 | 태스크 스토어에서 읽어요 |
TASK_LIST |
ListTasks |
원격의 태스크를 나열해요 | 태스크 스토어를 질의해요 |
TASK_CANCEL |
CancelTask |
원격 태스크를 취소해요 | 스토어를 갱신하고 진행 중인 비동기를 취소해요 |
TASK_SUBSCRIBE |
SubscribeToTask |
태스크 업데이트의 지연 Iterator<StreamResponse> |
REST와 JSON-RPC 바인딩용 이벤트-투-스트림 브리지(실시간 SSE) |
PUSH_CONFIG_CREATE |
CreateTaskPushNotificationConfig |
웹훅을 등록해요 | 설정을 저장하고 SSRF 검증해요 |
PUSH_CONFIG_GET |
GetTaskPushNotificationConfig |
설정을 조회해요 | 스토어에서 읽어요 |
PUSH_CONFIG_LIST |
ListTaskPushNotificationConfigs |
설정을 나열해요 | 스토어에서 읽어요 |
PUSH_CONFIG_DELETE |
DeleteTaskPushNotificationConfig |
설정을 삭제해요 | 스토어에서 제거해요 |
CamelA2AOperation 헤더는 열거형 이름(왼쪽 열)과 파스칼케이스 메서드 이름(두 번째 열)을 모두 받아들여요.
내장 JSON-RPC 컨슈머는 SendMessage, SendStreamingMessage, GetTask, ListTasks, CancelTask, SubscribeToTask, 그리고 푸시 알림 설정 연산들을 디스패치해요.
플러그형 인증 (Pluggable Authentication)
인증은 A2ASecuritySchemeHandler SPI를 통한 스킴별 전략(strategy-per-scheme) 패턴으로 동작해요. 하나의 핸들러가 특정 보안 스킴 타입에 대해 프로듀서(자격 증명 적용)와 컨슈머(자격 증명 검증)를 모두 커버해요.
기본 핸들러:
| Scheme Type | Handler | Description |
|---|---|---|
http (bearer) |
HttpBearerSchemeHandler |
OAuth 프로필 또는 정적 베어러 토큰 |
apiKey |
ApiKeySchemeHandler |
header, query, cookie 위치의 API 키. 보안 스킴이 location=header와 name을 선언하면 그 헤더를 쓰고, 그렇지 않으면 apiKeyHeader를 사용해요. |
oauth2 |
OAuth2SchemeHandler |
camel-oauth SPI를 통한 토큰 |
openIdConnect |
OpenIdConnectSchemeHandler |
OAuth2와 같지만 OIDC 디스커버리 URL을 저장해요 |
커스텀 핸들러 빈을 등록해서 재정의하거나 확장할 수 있어요:
자바 전용: 커스텀 A2ASecuritySchemeHandler 구현하기
@BindToRegistry("myCustomAuth")
public class MutualTlsHandler implements A2ASecuritySchemeHandler {
public String schemeType() { return "mutualTls"; }
public void applyCredentials(Exchange exchange, SecurityScheme scheme,
A2AConfiguration config, CamelContext context) {
// producer: configure mTLS
}
public A2AUserProfile validateCredentials(Exchange exchange,
SecurityScheme scheme, A2AConfiguration config) {
// consumer: extract client certificate
return A2AUserProfile.fromMap(Map.of(
"scheme", "mutualTls",
"subject", "CN=client"));
}
}
보안 스킴 우선순위 (Security Scheme Priority)
에이전트 카드가 여러 보안 스킴을 선언했을 때는 설정 힌트를 기준으로 선택해요:
-
oauthProfile이 설정되면 → OAuth2 / OpenID Connect 스킴을 먼저 시도해요 -
bearerToken이 설정되면 → HTTP 베어러 스킴을 먼저 시도해요 -
apiKey가 설정되면 → API 키 스킴을 먼저 시도해요 -
힌트가 없으면 → 에이전트 카드 선언 순서대로 스킴을 시도해요
프로듀서에서는 일치하는 첫 번째 핸들러가 자격 증명을 적용해요. 컨슈머에서는 선언된 모든 스킴을 하나가 성공할 때까지(아니면 전부 401로 실패할 때까지) 시도해요.
태스크 상태 머신 (Task State Machine)
A2A 태스크는 다음 상태 머신을 따라요:
+--> COMPLETED
|
SUBMITTED --> WORKING +--> FAILED | +--> CANCELED | +--> INPUT_REQUIRED --> WORKING (resumed) | +--> AUTH_REQUIRED --> WORKING (after re-auth) | +--> REJECTED
유효한 태스크 상태 전부예요(와이어 값은 아래의 A2A v1.0 proto 이름을 쓰고, $\{a2a:emit()} 함수는 짧은 Java 열거형 이름을 써요 — 예를 들어 TASK_STATE_INPUT_REQUIRED가 아니라 INPUT_REQUIRED예요):
| State | Description |
|---|---|
TASK_STATE_UNSPECIFIED |
알 수 없거나 누락된 태스크 상태의 폴백 |
TASK_STATE_SUBMITTED |
태스크가 접수됨, 아직 처리 전 |
TASK_STATE_WORKING |
태스크가 활발히 처리되고 있어요 |
TASK_STATE_COMPLETED |
태스크가 성공적으로 완료됨(종결) |
TASK_STATE_FAILED |
오류나 타임아웃으로 태스크 실패(종결) |
TASK_STATE_CANCELED |
클라이언트가 태스크를 취소함(종결) |
TASK_STATE_INPUT_REQUIRED |
진행 전에 에이전트가 클라이언트에게 추가 입력이 필요해요 |
TASK_STATE_AUTH_REQUIRED |
진행 전에 에이전트가 클라이언트의 재인증이 필요해요 |
TASK_STATE_REJECTED |
에이전트가 태스크를 거절함(종결) |
컨슈머가 전이를 자동으로 관리해요:
-
SUBMITTED—returnImmediately=true이고 태스크가 접수되었을 때 -
WORKING— 라우트가 처리를 시작할 때(비동기 태스크) -
COMPLETED—setBody가 null이 아닌 응답을 만들어 낼 때 -
FAILED— 라우트가 예외를 던지거나asyncTimeout이 만료되었을 때
라우트는 ${a2a:emit(INPUT_REQUIRED, 'Please provide your address')} 또는 A2AProgress.emit(exchange, TaskState.AUTH_REQUIRED, "Re-authentication needed")로 어떤 상태든 명시적으로 내보낼 수 있어요.
통합 바디-응답 패턴 (Unified Body-as-Response)
스트리밍 에이전트와 비동기 에이전트가 같은 라우트 패턴을 사용해요 — setBody가 항상 최종 응답이에요:
steps:
- script:
expression:
simple:
expression: "${a2a:emit('progress...')}" # optional status events
- setBody:
expression:
constant:
expression: "final response" # consumer handles delivery
컨슈머가 전달 방식과 관계없이 전송을 알아서 처리해요:
-
동기(synchronous): HTTP 응답에 바로 담겨 반환돼요
-
스트리밍: SSE 메시지 이벤트로 내보내져요
-
비동기 + 폴링: 태스크의 히스토리와 상태 메시지에 저장되고,
GetTask로 반환돼요 -
푸시 알림:
COMPLETED상태 웹훅 페이로드에 포함돼요
에이전트 카드 해석 (Agent Card Resolution)
카드 필드는 계층화된 우선순위(낮은 것부터 높은 것)로 해석돼요:
-
에이전트 카드 JSON 파일 — URI 소스에서 불러와요(베이스)
-
빈 참조 —
agentCard=#myBean이 프로그래매틱 객체의 필드를 채우거나 덮어써요 -
URI 파라미터 —
name,description,version이 모든 것을 덮어써요
빈 참조 예제 — 카드를 프로그래매틱하게 구성해야 할 때(예: 동적 스킬) 유용해요:
- route:
from:
uri: a2a:classpath:agent-card.json
parameters:
agentCard: "#myCardBean"
steps:
- setBody:
expression:
constant:
expression: "final response"
URI 파라미터 재정의 — 프로퍼티로 환경별 기본 카드를 커스터마이즈해요:
- route:
from:
uri: a2a:classpath:agent-card.json
parameters:
name: "{{agent.name}}"
version: "{{agent.version}}"
steps:
- setBody:
expression:
constant:
expression: "final response"
카드의 보안 스킴이 인증 핸들러 선택을 결정해요. 설정 파라미터(oauthProfile, bearerToken, apiKey)는 런타임 자격 증명을 제공하고 스킴 우선순위에도 영향을 줘요.
리졸버는 현재 파일 카드와 빈 카드에서 다음 카드 필드들을 병합해요: name, description, url, version, provider, capabilities, skills, supportedInterfaces, securitySchemes, securityRequirements, iconUrl, documentationUrl, defaultInputModes, defaultOutputModes, supportsAuthenticatedExtendedCard, 그리고 알 수 없는 확장 프로퍼티. security를 쓰는 레거시 입력 카드는 securityRequirements로 변환돼요. URI 파라미터는 name, description, version만 덮어쓸 수 있어요.
참고 카드는 엔드포인트 시작 때 한 번 불러와서 캐시해요. 주기적인 카드 갱신은 아직 구현되지 않았어요.
HTTP 서버 컴포넌트 발견 (HTTP Server Component Discovery)
컨슈머는 A2A 엔드포인트를 등록할 HTTP 서버가 필요해요. 발견 순서는 다음과 같아요:
-
명시적인
httpServerComponent파라미터(예:undertow,jetty) -
전역
camel.rest.component/ REST DSL 컴포넌트 설정 -
이미 등록된
platform-http컴포넌트 -
RestConsumerFactory를 구현한, 등록된 Camel 컴포넌트가 정확히 하나일 때 -
RestConsumerFactory를 구현한 레지스트리 빈이 정확히 하나일 때
프리뷰 컴포넌트는 임의의 HTTP 서버 컴포넌트를 자동 생성하지 않고, 발견된 여러 서버 팩토리 사이에서 골라 주지도 않아요. 검증된 서버 컴포넌트 중 하나를 추가해서 등록하거나 httpServerComponent를 명시적으로 설정하세요.
이 프리뷰 릴리스에서 검증된 동작이에요:
-
camel-platform-http/ Vert.x - JSON-RPC 에이전트(SSE 스트리밍 포함)와 공개 에이전트 카드 서빙에 적합해요. 콜론이 들어간 REST 커스텀 메서드 경로는 충돌할 수 있어요. -
camel-undertow와camel-jetty- REST 커스텀 메서드 경로와 실시간 SSE 스트리밍에 적합해요.
데이터 포맷 (Data Format)
dataFormat 파라미터는 교환 바디에 무엇이 담길지 제어해요. CXF 컴포넌트와 같은 컨벤션을 따라요. 컨슈머(인바운드 요청)와 프로듀서(응답) 양쪽 모두에 적용돼요.
| Value | Default | Description |
|---|---|---|
PAYLOAD |
Yes | 메시지 파트에서 텍스트 내용을 String으로 추출해요. 컨슈머에서는 들어오는 Message 파트를 messageToString()으로 평탄화해요. 프로듀서에서는 응답 Task 또는 Message 객체를 텍스트로 변환해요. 하위 호환 — ${body}를 쓰는 간단한 라우트는 깔끔한 텍스트를 받아요. 스트리밍: POJO와 같아요(프로듀서는 지연 이터레이터, 컨슈머는 이미터 기반). |
POJO |
No | 완전한 Java 모델 객체예요. 컨슈머에서는 바디가 모든 파트, 메타데이터, 파일이 온전한 Message 레코드예요 — $\{body.parts()[0]}로 개별 파트에 접근하세요. 프로듀서에서는 바디가 Task 또는 Message 응답 객체예요. 스트리밍: 바디는 필요할 때 파싱되는 지연 Iterator<StreamResponse>예요(Split EIP와 함께 사용하세요). |
RAW |
No | 역직렬화 없는 원시 JSON 문자열이에요. 컨슈머에서는 바디가 들어오는 Message의 JSON 표현이에요. 프로듀서에서는 바디가 원시 JSON 응답 문자열이에요. 바이트 단위 충실도가 중요한 포워딩, 로깅, 컴플라이언스에 유용해요. 스트리밍: 바디는 원시 InputStream — 버퍼링 없는 진짜 SSE 패스스루예요. |
예제 — 멀티모달 처리를 위한 POJO 모드 컨슈머:
- route:
from:
uri: a2a:classpath:agent-card.json?dataFormat=POJO
steps:
- log:
message: "Received ${body.parts().size()} parts"
- setBody:
expression:
simple:
expression: "Processed ${body.parts()[0]}"
예제 — 프록시잉을 위한 RAW 모드 프로듀서:
- route:
from:
uri: direct:proxy
steps:
- to:
uri: a2a:http://remote-agent:8080?dataFormat=RAW
- log:
message: "Raw JSON: ${body}"
태스크 스토어 (Task Store)
기본 InMemoryTaskStore는 지연 정리(lazy cleanup)로 태스크 상태를 관리해요. 스레드 세이프하고, 저장에는 동시성 맵을, 메시지-id 매핑, 구독자, 푸시 설정 같은 태스크 관련 데이터에는 락으로 보호되는 축출(eviction)을 사용해요.
completedTaskTtl URI 파라미터(기본 3,600,000 ms / 1시간)는 종결 태스크의 TTL을 제어해요. 만료된 태스크는 읽을 때나 주기 정리 때 축출돼요.
다음 설정은 URI 파라미터가 아니라 InMemoryTaskStore 빈에서 프로그래매틱하게 설정하는 것들이에요:
| Property | Default | Description |
|---|---|---|
maxStoredTasks |
10000 |
스토어에 담을 수 있는 최대 태스크 수. 초과하면 가장 오래된 종결 태스크를 축출해요. 종결 태스크가 없으면 아무것도 축출하지 않아요. 무제한은 0으로 설정하세요. |
cleanupInterval |
100 |
주기 벌크 정리 실행 사이의 put() 호출 횟수. |
stuckTaskTtlMs |
0 (disabled) |
종결되지 않은 막힌 태스크(SUBMITTED, WORKING)의 TTL. 양수로 설정하면 이 기간보다 오래된 태스크는 읽을 때나 주기 정리 때 FAILED로 표시되고, 구독자에게 알림이 가요. 이 프리뷰 안전망은 기본으로 비활성화되어 있어요. 일반적인 타임아웃 처리는 엔드포인트의 asyncTimeout을 사용하는 게 좋아요. |
커스터마이즈하려면 A2ATaskStore를 구현한 빈을 Camel 레지스트리에 등록하세요. 프리뷰 SPI는 더 좁은 부모 계약들(A2ATaskRepository, A2ATaskSubscriptions, A2APushConfigStore, A2ATaskCleanup)로도 나뉘어서, 커스텀 스토어가 저장, 구독, 푸시 설정, 정리 책임을 분리해서 유지할 수 있어요. 레지스트리가 제공한 스토어는 가드로 감싸는데, 이 가드가 종결 상태 보호를 강제하고, 구독자 등록과 알림을 커스텀 스토어에 위임하고, 종결 이벤트 정리를 위해 엔드포인트 구독자를 추적하고, 푸시 웹훅 URL을 검증하고, 엔드포인트 경로의 푸시 설정 ID/태스크 ID를 정규화해요. 커스텀 스토어는 여전히 자기 구현 안에서 내구성 있는 저장과 노드 간 알림 의미를 지켜야 해요; 디스패처가 전달 전에 웹훅 URL을 다시 검증하거든요.
감사 로깅, 메트릭, 커스텀 전달을 위해 태스크 스토어 빈에 커스텀 구독자를 등록할 수 있어요:
자바 전용: 전역 구독자가 있는 커스텀 A2ATaskStore 등록하기
@BindToRegistry
public A2ATaskStore taskStore() {
MyAuditingTaskStore store = new MyAuditingTaskStore();
store.addGlobalSubscriber((taskId, event) -> auditLog.record(taskId, event));
return store;
}
모델 클래스 (Model Classes)
이 컴포넌트는 A2A v1.0에 맞춘 Java 모델 클래스를 사용해요:
| Class | Description |
|---|---|
Task |
id, contextId, status (TaskStatus), history (List<Message>), artifacts (List<Artifact>), metadata (Map<String, Object>)를 가진 태스크예요. contextId는 멀티턴 대화의 키예요(CamelA2AContextId 헤더에 매핑돼요). Task.latest()는 히스토리의 마지막 메시지를 반환해요. |
Message |
role, parts, messageId, contextId, taskId, referenceTaskIds, metadata, extensions를 가진 에이전트 또는 사용자 메시지예요. Role 열거형은 ROLE_USER, ROLE_AGENT, ROLE_UNSPECIFIED를 사용하고, ROLE_UNSPECIFIED는 역직렬화 때 알 수 없는 role 값의 폴백이에요. |
SendMessageRequest |
message, configuration, metadata를 가진 연산 요청 래퍼예요. 컨슈머는 message.role과 최소 한 개의 메시지 파트를 요구해요. |
SendMessageConfiguration |
returnImmediately, blocking, historyLength, 보존된 확장 프로퍼티를 가진 메시지 전송 런타임 옵션이에요. returnImmediately가 blocking보다 우선하고, blocking=false는 즉시 반환으로 취급돼요. |
SendMessageResponse |
task 또는 message 중 정확히 하나를 담는 응답 래퍼예요. |
TaskListRequest |
contextId, status, statusTimestampAfter, includeArtifacts, historyLength, pageSize, pageToken을 가진 태스크 목록 요청이에요. |
ListTasksResponse |
tasks, nextPageToken, pageSize, totalSize를 가진 태스크 목록 응답이에요. |
StreamResponse |
task, message, statusUpdate, artifactUpdate 중 정확히 하나를 담는 SSE 이벤트 래퍼예요. |
TextPart |
Part<String>을 구현하는 텍스트 내용 파트예요. |
DataPart |
Part<Object>를 구현하는 구조화 데이터 파트예요. |
FilePart |
인라인 base64 데이터용 raw, 참조 콘텐츠용 url을 가진 파일 콘텐츠예요. 선택적인 mediaType, filename, metadata도 있어요. |
TaskStatus |
state (TaskState), 선택적 message (Message), timestamp (OffsetDateTime)를 가진 상태 스냅샷이에요. |
Artifact |
artifactId, name, description, parts (List<Part<?>>), metadata, extensions를 가진 이름 붙은 출력이에요. |
TaskPushNotificationConfig |
id, taskId, url, token(단순 베어러 토큰), authentication(scheme + credentials을 가진 AuthenticationInfo)을 가진 푸시 알림 웹훅 설정이에요. token 필드는 웹훅 인증에 전체 authentication 대신 쓸 수 있는 더 간단한 대안이에요. |
ListPushNotificationConfigsResponse |
configs를 가진 푸시 알림 설정 목록 응답이에요. |
Task, Message, Artifact, AgentCard 같은 핵심 불변 모델 타입은 빌더를 제공해요. 예를 들면: Task.builder().id("t1").contextId("ctx-1").status(new TaskStatus(TaskState.WORKING)).build(). 가변 요청/설정 클래스는 표준 getter와 setter를 사용해요.
프리뷰 API와 SPI 경계 (Preview API and SPI Boundaries)
이 프리뷰 릴리스의 안정적인 사용자 대면 표면은 엔드포인트 URI/옵션, 교환 헤더, 문서화된 모델 클래스, 타입 컨버터, 그리고 다음 레지스트리 SPI들이에요: A2ATaskStore, A2AExtensionHandler, A2ASecuritySchemeHandler.
org.apache.camel.component.a2a.protocol과 org.apache.camel.component.a2a.operation 아래의 프로토콜 및 연산 구현 클래스는, 컴포넌트가 패키지와 테스트 간에 구현 코드를 공유할 수 있도록 public이에요. 하지만 확장 SPI는 아니에요. A2AProtocol은 내장 REST와 JSON-RPC 바인딩으로 의도적으로 sealed 처리되어 있어요; 커스텀 프로토콜 클래스를 구현하기보다 protocolBinding으로 바인딩을 선택하세요.
JSON 매퍼 헬퍼는 설정된 매퍼의 복사본을 반환해요. 반환된 ObjectMapper를 커스터마이즈해도 컴포넌트 전역 직렬화 동작은 바뀌지 않아요.
의존성 (Dependencies)
이 컴포넌트는 어떤 HTTP 라이브러리와도 컴파일 타임 결합이 전혀 없어요. 전송 계층은 런타임에 발견해요:
| Role | SPI | Examples |
|---|---|---|
| Consumer HTTP server | RestConsumerFactory |
camel-platform-http, camel-undertow, camel-jetty |
| Producer HTTP client | Built-in java.net.http.HttpClient |
No additional dependency |
| OAuth tokens | OAuthClientAuthenticationFactory |
camel-oauth (optional, discovered via FactoryFinder) |
| Task state | A2ATaskStore |
Built-in InMemoryTaskStore (default), custom implementations via registry |
원하는 HTTP 서버 컴포넌트를 런타임 의존성으로 추가하세요. 컨슈머 라우트는 이 의존성 중 하나가 필요하고, 프로듀서 전용 라우트는 필요 없어요.
<!-- Consumer: JSON-RPC or non-streaming HTTP endpoint serving -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-platform-http-vertx</artifactId>
<version>x.x.x</version>
<!-- use the same version as your Camel core version -->
</dependency>
<!-- Consumer: REST custom-method routes and real-time SSE streaming -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-undertow</artifactId>
<version>x.x.x</version>
<!-- use the same version as your Camel core version -->
</dependency>
<!-- Alternative consumer transport for REST custom-method routes and real-time SSE streaming -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jetty</artifactId>
<version>x.x.x</version>
<!-- use the same version as your Camel core version -->
</dependency>
<!-- Optional: OAuth authentication -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-oauth</artifactId>
<version>x.x.x</version>
<!-- use the same version as your Camel core version -->
</dependency>
더 알아보기 (Learn more)
- Camel 4.21 업그레이드 노트의 A2A 항목 — 4.21로 올라갈 때 확인할 점
- A2A v1.0 프로토콜 명세와 A2A 프로토콜 정의 — 와이어 포맷의 공식 기준
- A2A 프로토콜 GitHub — 프로토콜 소스와 커뮤니티
실전 사용법은 위의 Consumer Guide와 Producer Guide 하위 문서부터 살펴보고, 업그레이드 전에는 4.21 업그레이드 노트를 꼭 확인하세요.