Skip to content

Commit b82a26b

Browse files
committed
Revert "[ISSUE #5259] Add A2A Gateway: REST API, SSE streaming, Task lifecycle, Java SDK and tests (#5260)"
This reverts commit 2527428.
1 parent 2527428 commit b82a26b

27 files changed

Lines changed: 37 additions & 6084 deletions

File tree

docs/a2a-protocol/ARCHITECTURE.md

Lines changed: 3 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -64,80 +64,16 @@ graph TD
6464

6565
### 3.2 Component Design (`eventmesh-protocol-a2a`)
6666

67-
The core protocol logic resides in the `eventmesh-protocol-plugin` module.
67+
The core logic resides in the `eventmesh-protocol-plugin` module.
6868

6969
* **`EnhancedA2AProtocolAdaptor`**: The central brain of the protocol.
7070
* **Intelligent Parsing**: Automatically detects message format (MCP vs. Raw CloudEvent).
7171
* **Protocol Delegation**: Delegates to `CloudEvents` or `HTTP` adaptors when necessary.
7272
* **Semantic Mapping**: Transforms JSON-RPC methods and IDs into CloudEvent attributes.
7373
* **`A2AProtocolConstants`**: Defines standard operations like `task/get`, `message/sendStream`.
7474
* **`JsonRpc*` Models**: Strictly typed POJOs for JSON-RPC 2.0 compliance.
75-
* **`AgentCard` / `AgentSkill` / `AgentInterface`**: Agent capability discovery models.
76-
* **`A2ATopicFactory`**: Topic naming and parsing utility for request/response/status topics.
77-
* **`A2AClient`**: Java SDK for agent developers — AgentCard registration, task submission (sync/async), task status query, heartbeat, and transport-based request handling. Returns typed `TaskResult` objects.
78-
* **`A2AMessageTransport`**: Transport-agnostic pub/sub interface (InMemory implementation for dev/testing).
7975

80-
### 3.3 Gateway Runtime Architecture (`eventmesh-runtime`)
81-
82-
The Gateway runtime provides a standalone Netty HTTP server bridging external clients to the A2A event bus.
83-
84-
```mermaid
85-
graph TD
86-
Client["Client / A2AClient SDK"] -- "HTTP REST" --> Server["A2AGatewayServer<br/>(Netty HTTP)"]
87-
Server --> Handler["A2AGatewayHttpHandler"]
88-
Handler --> GwService["A2AGatewayService"]
89-
GwService --> Registry["TaskRegistry<br/>(state machine + TTL)"]
90-
GwService --> Transport["InMemoryA2AMessageTransport"]
91-
GwService --> PubSub["A2APublishSubscribeService<br/>(AgentCard discovery)"]
92-
Transport -- "publish/subscribe" --> Agent["Target Agent"]
93-
Agent -- "response event" --> Transport
94-
Transport --> GwService
95-
96-
style Server fill:#f9f,stroke:#333,stroke-width:2px
97-
style Registry fill:#cfc,stroke:#333
98-
style Transport fill:#ccf,stroke:#333
99-
```
100-
101-
#### Core Components
102-
103-
| Component | Module | Responsibility |
104-
| :--- | :--- | :--- |
105-
| `A2AGatewayServer` | runtime | Standalone Netty HTTP server entry point. Pre-registers mock agents, wires all components. |
106-
| `A2AGatewayHttpHandler` | runtime | HTTP request router. Maps REST endpoints to service calls. Supports SSE streaming. |
107-
| `A2AGatewayService` | runtime | Core orchestration: task submission, response handling, status subscription, SSE push. |
108-
| `TaskRegistry` | runtime | In-memory task lifecycle state machine with TTL auto-cleanup. |
109-
| `A2APublishSubscribeService` | runtime | AgentCard registration, discovery, and heartbeat management. |
110-
| `InMemoryA2AMessageTransport` | runtime | In-memory pub/sub (replaceable by EventMesh broker). |
111-
| `A2ACardHttpHandler` | runtime | AgentCard CRUD REST endpoints (`/a2a/cards/*`). |
112-
| `A2AClient` | protocol-a2a | Java SDK for agent developers (HTTP + transport). |
113-
114-
#### Task Lifecycle State Machine
115-
116-
```
117-
SUBMITTED → WORKING → COMPLETED
118-
↘ FAILED
119-
↘ CANCELLED
120-
```
121-
122-
* **TTL Auto-Cleanup**: Terminal-state tasks are automatically removed after a configurable TTL (default: 5 minutes). A daemon thread runs cleanup every 60 seconds.
123-
* **Race Condition Prevention**: `pendingTasks.put(taskId, future)` is called **before** `transport.publish()` to ensure the future is registered before any synchronous delivery could trigger `handleResponse()`.
124-
125-
#### REST API
126-
127-
| Method | Path | Description |
128-
| :--- | :--- | :--- |
129-
| `POST` | `/a2a/tasks?mode=sync` | Submit task synchronously (wait for result) |
130-
| `POST` | `/a2a/tasks?mode=async` | Submit task asynchronously (return taskId immediately) |
131-
| `GET` | `/a2a/tasks/{taskId}` | Get task status and result |
132-
| `DELETE` | `/a2a/tasks/{taskId}` | Cancel a task |
133-
| `GET` | `/a2a/tasks/{taskId}/wait` | Long-poll wait for task result |
134-
| `GET` | `/a2a/tasks/{taskId}/stream` | **SSE** stream of task status updates |
135-
| `GET` | `/a2a/agents` | List all registered agents |
136-
| `POST` | `/a2a/heartbeat` | Agent heartbeat |
137-
| `GET` | `/a2a/cards/list` | List all AgentCards |
138-
| `POST` | `/a2a/cards/card/{org}/{unit}/{agent}` | Register an AgentCard |
139-
140-
### 3.4 Asynchronous RPC Mapping ( The "Async Bridge" )
76+
### 3.3 Asynchronous RPC Mapping ( The "Async Bridge" )
14177

14278
To support MCP on an Event Bus, synchronous RPC concepts are mapped to asynchronous events:
14379

@@ -177,18 +113,6 @@ To support MCP on an Event Bus, synchronous RPC concepts are mapped to asynchron
177113
* **Operation**: `message/sendStream`
178114
* **Mechanism**: Maps to `.stream` event type and preserves sequence order via `seq` extension attribute.
179115

180-
#### D. SSE Task Streaming (Gateway)
181-
* **Endpoint**: `GET /a2a/tasks/{taskId}/stream`
182-
* **Mechanism**: Server-Sent Events (`text/event-stream`) pushes real-time task state transitions.
183-
* **Flow**: Initial state → WORKING updates → terminal state → connection close.
184-
* **Implementation**: Handler writes `DefaultHttpContent` chunks directly to the Netty channel, returning `null` to skip the standard `FullHttpResponse` path.
185-
186-
#### E. Task TTL Auto-Cleanup (Gateway)
187-
* Terminal-state tasks are automatically removed by a daemon scheduler after a configurable TTL (default: 5 minutes, cleanup interval: 60 seconds), preventing memory leaks.
188-
189-
#### F. AgentCard Discovery & Heartbeat (Gateway)
190-
* AgentCards expire after 60 seconds without heartbeat. `POST /a2a/heartbeat` refreshes the last-seen timestamp.
191-
192116
## 5. Usage Examples
193117

194118
### 5.1 Sending a Tool Call (Request)
@@ -225,92 +149,7 @@ To support MCP on an Event Bus, synchronous RPC concepts are mapped to asynchron
225149
* `subject`: `market.crypto.btc`
226150
* `targetagent`: (Empty)
227151

228-
### 5.3 Gateway REST API (HTTP)
229-
230-
The A2A Gateway provides a REST API for external clients and non-Java agents.
231-
232-
#### 5.3.1 Submit Task (Sync)
233-
234-
```bash
235-
curl -X POST 'http://localhost:10105/a2a/tasks?mode=sync' \
236-
-H 'Content-Type: application/json' \
237-
-d '{"targetAgent":"weather-agent","message":"Beijing"}'
238-
```
239-
240-
Response:
241-
```json
242-
{
243-
"taskId": "task-a1b2c3d4",
244-
"state": "COMPLETED",
245-
"data": "The weather in Beijing is sunny, 25°C"
246-
}
247-
```
248-
249-
#### 5.3.2 Submit Task (Async)
250-
251-
```bash
252-
curl -X POST 'http://localhost:10105/a2a/tasks?mode=async' \
253-
-H 'Content-Type: application/json' \
254-
-d '{"targetAgent":"weather-agent","message":"Shanghai"}'
255-
```
256-
257-
#### 5.3.3 SSE Stream
258-
259-
```bash
260-
curl -N http://localhost:10105/a2a/tasks/{taskId}/stream
261-
```
262-
263-
Response (`text/event-stream`):
264-
```
265-
data: {"taskId":"task-a1b2c3d4","state":"SUBMITTED"}
266-
267-
data: {"taskId":"task-a1b2c3d4","state":"WORKING","data":"processing..."}
268-
269-
data: {"taskId":"task-a1b2c3d4","state":"completed","data":"result..."}
270-
```
271-
272-
#### 5.3.4 List Agents
273-
274-
```bash
275-
curl http://localhost:10105/a2a/agents
276-
```
277-
278-
### 5.4 A2AClient SDK (Java)
279-
280-
```java
281-
A2AClient client = A2AClient.builder()
282-
.gatewayUrl("http://localhost:10105")
283-
.namespace("global")
284-
.agentName("my-agent")
285-
.agentCard(card)
286-
.heartbeatInterval(30_000)
287-
.build();
288-
289-
client.start();
290-
291-
// Synchronous task (returns typed TaskResult)
292-
TaskResult result = client.sendTaskSync("weather-agent", "Beijing", null);
293-
294-
// Asynchronous task (returns taskId immediately)
295-
String taskId = client.sendTaskAsync("weather-agent", "Shanghai", null);
296-
297-
// Poll status
298-
TaskResult status = client.getTaskStatus(taskId);
299-
300-
// Cancel
301-
boolean cancelled = client.cancelTask(taskId);
302-
303-
// List registered agents (typed List<String>)
304-
List<String> agents = client.listAgents();
305-
306-
client.shutdown();
307-
```
308-
309152
## 6. Future Roadmap
310153

311-
* **EventMesh Broker Integration**: Replace `InMemoryA2AMessageTransport` with the real EventMesh broker for production deployment.
312154
* **Schema Registry**: Implement dynamic discovery of Agent capabilities via `methods/list`.
313-
* **Sidecar Injection**: Fully integrate the adaptor into the EventMesh Sidecar.
314-
* **WebSocket Streaming**: Extend SSE to bidirectional WebSocket for real-time agent dialogue.
315-
* **Task Persistence**: Persist `TaskRegistry` state to a durable store for crash recovery.
316-
* **Authentication**: Add API key / JWT authentication to the Gateway REST API.
155+
* **Sidecar Injection**: Fully integrate the adaptor into the EventMesh Sidecar.

docs/a2a-protocol/IMPLEMENTATION_SUMMARY.md

Lines changed: 8 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ A2A 协议已成功重构为采用 **MCP (Model Context Protocol)** 架构,将
1313
- **请求 (Requests)** 映射为 `*.req` 事件,属性 `mcptype=request`
1414
- **响应 (Responses)** 映射为 `*.resp` 事件,属性 `mcptype=response`
1515
- **关联 (Correlation)** 通过将 JSON-RPC `id` 映射到 CloudEvent `collaborationid` 来处理。
16-
- **路由优化**: 实现了"深度内容路由提取"
16+
- **路由优化**: 实现了深度内容路由提取
1717
- `params._agentId` -> CloudEvent 扩展属性 `targetagent` (P2P)。
1818
- `params._topic` -> CloudEvent Subject (Pub/Sub)。
1919

@@ -24,80 +24,14 @@ A2A 协议已成功重构为采用 **MCP (Model Context Protocol)** 架构,将
2424
### 3. 标准化与兼容性
2525
- **数据模型**: 定义了符合 JSON-RPC 2.0 规范的 `JsonRpcRequest``JsonRpcResponse``JsonRpcError` POJO 对象。
2626
- **方法定义**: 引入了 `McpMethods` 常量,支持标准操作如 `tools/call``resources/read`
27-
- **AgentCard 模型**: 实现了 `AgentCard``AgentSkill``AgentInterface``AgentCapabilities` 等完整的 Agent 能力描述模型。
2827

29-
### 4. Gateway 运行时架构 (`eventmesh-runtime`)
30-
31-
完整的独立 HTTP Gateway 服务,桥接外部客户端到 A2A 事件总线。
32-
33-
#### 核心组件
34-
35-
| 组件 | 职责 |
36-
| :--- | :--- |
37-
| `A2AGatewayServer` | Netty HTTP 服务器入口,预注册 mock agent,组装所有组件 |
38-
| `A2AGatewayHttpHandler` | HTTP 请求路由,支持 SSE 流式响应 |
39-
| `A2AGatewayService` | 核心编排:任务提交、响应处理、状态订阅、SSE 推送 |
40-
| `TaskRegistry` | 内存任务状态机 + TTL 自动清理 |
41-
| `A2APublishSubscribeService` | AgentCard 注册、发现、心跳管理 |
42-
| `InMemoryA2AMessageTransport` | 内存 pub/sub 实现(可替换为 EventMesh broker) |
43-
| `A2ACardHttpHandler` | AgentCard CRUD REST 端点 |
44-
| `A2AClient` | Java SDK,提供类型化 API |
45-
46-
#### REST API
47-
48-
| 方法 | 路径 | 说明 |
49-
| :--- | :--- | :--- |
50-
| `POST` | `/a2a/tasks?mode=sync` | 同步提交任务 |
51-
| `POST` | `/a2a/tasks?mode=async` | 异步提交任务 |
52-
| `GET` | `/a2a/tasks/{taskId}` | 查询任务状态 |
53-
| `DELETE` | `/a2a/tasks/{taskId}` | 取消任务 |
54-
| `GET` | `/a2a/tasks/{taskId}/wait` | 长轮询等待结果 |
55-
| `GET` | `/a2a/tasks/{taskId}/stream` | SSE 流式推送状态更新 |
56-
| `GET` | `/a2a/agents` | 列出已注册 agents |
57-
| `POST` | `/a2a/heartbeat` | Agent 心跳 |
58-
| `GET` | `/a2a/cards/list` | 列出所有 AgentCard |
59-
| `POST` | `/a2a/cards/card/{org}/{unit}/{agent}` | 注册 AgentCard |
60-
61-
### 5. 关键改进
62-
63-
#### 5.1 TaskRegistry TTL 自动清理
64-
- **问题**: 终态任务(COMPLETED/FAILED/CANCELLED)无限累积导致内存泄漏。
65-
- **方案**: 守护线程 `ScheduledExecutorService` 每 60 秒扫描一次,清理超过 TTL(默认 5 分钟)的终态任务。
66-
- **配置**: `TaskRegistry(taskTtlMs, cleanupIntervalMs)` 构造函数支持自定义调优。
67-
68-
#### 5.2 竞态条件修复
69-
- **问题**: `InMemoryTransport` 同步投递消息,若 `transport.publish()``pendingTasks.put()` 之前执行,`handleResponse()` 会先于 `put()` 运行,导致 future 永不完成。
70-
- **方案**: 严格保证 `pendingTasks.put(taskId, future)``transport.publish()` 之前执行,并添加注释说明顺序重要性。
71-
72-
#### 5.3 A2AClient 类型化返回
73-
- **改进**: `getTaskStatus()` 返回 `TaskResult` 对象(而非原始 JSON 字符串),`listAgents()` 返回 `List<String>`(而非原始 JSON)。
74-
- **兼容**: `TaskResult.data` 字段使用 `@JsonAlias("result")` 注解,兼容服务端 `result` 字段名。
75-
76-
#### 5.4 SSE 流式响应
77-
- **端点**: `GET /a2a/tasks/{taskId}/stream`
78-
- **实现**: Handler 直接写入 Netty channel(`DefaultHttpContent` chunks),返回 `null` 跳过标准 `FullHttpResponse` 路径。通过 `StatusSubscriber` 回调实时推送状态变更。
79-
80-
#### 5.5 使用文档
81-
- 新建 `eventmesh-examples/.../demo/README.md`,包含架构图、API 表、curl 示例、SDK 用法、运行方式。
82-
83-
### 6. 测试与质量
84-
- **协议层单元测试**: `EnhancedA2AProtocolAdaptorTest` 覆盖请求/响应循环、错误处理、通知和批处理。
85-
- **Topic 工具测试**: `A2ATopicFactoryTest` 覆盖 topic 生成与解析。
86-
- **Gateway 运行时测试**:
87-
- `TaskRegistryTest` — 任务状态机 + TTL 清理验证
88-
- `InMemoryA2AMessageTransportTest` — 内存传输投递
89-
- `A2AGatewayServiceTest` — Gateway 服务层
90-
- `A2AGatewayEndToEndTest` — 进程内全链路
91-
- `A2AClientServerIntegrationTest` — 真实 HTTP 客户端-服务端集成测试
92-
- **集成演示**: `McpIntegrationDemoTest``McpPatternsIntegrationTest``McpComprehensiveDemoTest``CloudEventsComprehensiveDemoTest`
93-
- **总计**: 73 个测试场景,全部通过。
28+
### 4. 测试与质量
29+
- **单元测试**: 在 `EnhancedA2AProtocolAdaptorTest` 中实现了对请求/响应循环、错误处理、通知和批处理的全面覆盖。
30+
- **集成演示**: `McpIntegrationDemoTest` 模拟了 P2P RPC 闭环。
31+
- **模式测试**: `McpPatternsIntegrationTest` 模拟了 Pub/Sub 和 Streaming 流程。
9432

9533
## 下一步计划
9634

97-
1. **EventMesh Broker 集成**: 用真实 EventMesh broker 替换 `InMemoryA2AMessageTransport`,实现生产级部署。
98-
2. **路由集成**: 更新 EventMesh Runtime Router,利用 `targetagent``a2amethod` 扩展属性实现高级路由规则。
99-
3. **Schema 注册中心**: 实现"注册中心智能体 (Registry Agent)",允许智能体动态发布 MCP 能力 (`methods/list`)。
100-
4. **Sidecar 支持**: 将 A2A 适配器逻辑暴露在 Sidecar 代理中,允许非 Java 智能体通过 HTTP/JSON 交互。
101-
5. **WebSocket 流式**: 将 SSE 扩展为双向 WebSocket,支持实时 agent 对话。
102-
6. **任务持久化**: 将 `TaskRegistry` 状态持久化到 Redis/DB,支持崩溃恢复。
103-
7. **认证授权**: 为 Gateway REST API 添加 API Key / JWT 认证。
35+
1. **路由集成**: 更新 EventMesh Runtime Router,利用新的 `targetagent``a2amethod` 扩展属性实现高级路由规则。
36+
2. **Schema 注册中心**: 实现一个“注册中心智能体 (Registry Agent)”,允许智能体动态发布其 MCP 能力 (`methods/list`)。
37+
3. **Sidecar 支持**: 将 A2A 适配器逻辑暴露在 Sidecar 代理中,允许非 Java 智能体 (Python, Node.js) 通过简单的 HTTP/JSON 进行交互。

0 commit comments

Comments
 (0)