This is an automated email from the ASF dual-hosted git repository.
xwm1992 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/eventmesh-site.git
The following commit(s) were added to refs/heads/master by this push:
new 3f583efbf [ISSUE #256]update website and docs (#255)
3f583efbf is described below
commit 3f583efbfa1eb442df64637155d180a05915a3ef
Author: Eason Chen <[email protected]>
AuthorDate: Mon Jul 6 17:54:20 2026 +0800
[ISSUE #256]update website and docs (#255)
* docs: add A2A protocol doc, fix stream typo, add chatgpt connector zh
translation
- Add A2A (Agent-to-Agent) protocol design document (EN + ZH)
Based on real source code: EnhancedA2AProtocolAdaptor, A2AGatewayServer,
A2AClient SDK, Gateway REST API, MCP/CloudEvents dual-mode architecture
- Fix typo in filename: data-steam-processing -> data-stream-processing (EN
+ ZH)
- Add Chinese translation for chatgpt-connector doc
- Register A2A doc in sidebar (sidebars/docs.js)
* fix: self-close <br/> tags in A2A docs for MDX build; fix architecture
diagram spacing
- Replace <br> with <br/> in EN/ZH a2a-protocol.md (Docusaurus 2.4.3 MDX v1
requires JSX-valid tags; caused CI build failure)
- Redistribute all 4 layers in architecture.svg with symmetric margins and
even spacing; fixes RabbitMQ box overlapping the Event Store outer frame
* feat: point 'Explore A2A Documentation' button to new A2A protocol doc
- EN: /docs/introduction -> /docs/design-document/a2a-protocol
- ZH: /zh/docs/introduction -> /zh/docs/design-document/a2a-protocol
* feat(site): add A2A protocol docs, dynamic version dropdown, and navbar
improvements
- Fix 404 for /docs/design-document/a2a-protocol by adding the A2A protocol
doc to the v1.12.0 versioned snapshot (EN + ZH) and its sidebar entry
- Merge the docs version list into the "Documentation" navbar dropdown
(dynamic via Docusaurus version hooks / native docsVersionDropdown
source),
applied consistently to the homepage (EN/ZH) and internal doc pages
- Add an "Agent Mesh" navbar dropdown with an "Event Bus" item linking to
the
Ecosystem section; keep the toggle itself linking to the A2A section
- Swap navbar positions: Documentation <-> Community, and Blog <->
Documentation
- Remove the hero release badge from the homepage (EN/ZH)
- Increase hero top padding and give nav dropdown menus a solid opaque
background so they no longer overlap or bleed through the hero content
---
.../design-document/04-a2a-protocol.md | 293 +++++++++++++++++++++
i18n/zh/docusaurus-plugin-content-pages/index.tsx | 34 ++-
src/pages/index.tsx | 34 ++-
static/css/docusaurus-override.css | 5 +
static/css/site-redesign.css | 16 +-
static/js/eventmesh-internal.js | 127 ++++++++-
.../design-document/04-a2a-protocol.md | 293 +++++++++++++++++++++
versioned_sidebars/version-v1.12.0-sidebars.json | 3 +-
8 files changed, 781 insertions(+), 24 deletions(-)
diff --git
a/i18n/zh/docusaurus-plugin-content-docs/version-v1.12.0/design-document/04-a2a-protocol.md
b/i18n/zh/docusaurus-plugin-content-docs/version-v1.12.0/design-document/04-a2a-protocol.md
new file mode 100644
index 000000000..b118d7220
--- /dev/null
+++
b/i18n/zh/docusaurus-plugin-content-docs/version-v1.12.0/design-document/04-a2a-protocol.md
@@ -0,0 +1,293 @@
+---
+title: A2A 协议
+sidebar_position: 4
+---
+
+# EventMesh A2A(Agent-to-Agent)协议
+
+## 概述
+
+**EventMesh A2A(Agent-to-Agent)协议**是一个专用的高性能协议插件,用于实现自治 Agent 之间的异步通信、协作和任务协调。
+
+从 v2.0 开始,A2A 采用了 **MCP(Model Context Protocol)** 架构,将 EventMesh 转变为一个强大的
**Agent 协作总线**。它弥合了基于 LLM 的同步工具调用(JSON-RPC
2.0)与异步事件驱动架构(EDA)之间的差距,实现了可扩展、分布式和解耦的 Agent 系统。
+
+## 核心特性
+
+### 1. MCP over CloudEvents
+
+- **标准合规**:完全支持 MCP 定义的标准方法,如 `tools/call`、`resources/read` 和 `tools/list`。
+- **事件驱动**:将同步 RPC 调用映射为异步请求/响应事件流,充分利用 EventMesh 的高并发处理能力。
+- **传输无关**:所有 MCP 消息都封装在标准 CloudEvents 信封中,可在 EventMesh
支持的任意传输层(HTTP、TCP、gRPC、Kafka)上运行。
+
+### 2. 双模式支持(混合架构)
+
+A2A 协议具有独特的双模式架构,同时支持:
+
+1. **JSON-RPC 2.0(MCP 模式)**:
+ - **目标用户**:LLM、脚本(Python/JS)、LangChain 集成。
+ - **优势**:极低的使用门槛。客户端发送简单的 JSON 对象,适配器自动将其封装为 CloudEvents。
+2. **原生 CloudEvents(Power 模式)**:
+ - **目标用户**:EventMesh 原生应用、Knative、Serverless 函数。
+ - **优势**:完全控制事件元数据,支持自定义或二进制数据的透传。
+
+`EnhancedA2AProtocolAdaptor` 会智能检测负载格式。如果存在 `jsonrpc: "2.0"`,则启用 MCP
翻译引擎;否则,将负载视为标准 CloudEvent(委托给底层 CloudEvents 适配器处理)。
+
+### 3. 原生 Pub/Sub 语义
+
+- **O(1) 广播**:发布者只需向 Topic 发送一次消息,EventMesh 即可高效扇出到所有订阅者。
+- **时间解耦**:解决了传统 P2P Webhook 回调的可扩展性问题(消费者无需在发布时在线)。
+- **背压隔离**:慢速订阅者不会阻塞发布者。
+
+### 4. 高性能与路由
+
+- **批处理**:原生支持 JSON-RPC Batch 请求。EventMesh 自动将其拆分为并行事件流。
+- **智能路由**:从 MCP 参数中提取路由提示(`_agentId` 用于 P2P,`_topic` 用于 Pub/Sub),注入到
CloudEvents 属性中,实现零解码路由。
+
+### 5. 流式支持
+
+通过序列 ID(`seq` 扩展属性)为流式操作(`message/sendStream`)保持消息顺序。
+
+### 6. Agent 发现与生命周期
+
+- **AgentCard**:Agent 通过 AgentCard 注册自身能力,支持在线/离线状态和心跳。
+- **任务管理**:完整的任务生命周期,支持 `task/get`、`task/list`、`task/cancel`、`task/subscribe`
操作及基于 TTL 的自动清理。
+
+## 架构
+
+### 核心组件
+
+```
++-------------------------------------------------------------+
+| EventMesh A2A Protocol v2.0 |
+| (MCP over CloudEvents 架构) |
++-------------------------------------------------------------+
+| +-------------+ +-------------+ +-------------+ |
+| | MCP/JSON-RPC| | 原生 | | 协议 | |
+| | 处理器 | | Pub/Sub | | 委托器 | |
+| +-------------+ +-------------+ +-------------+ |
++-------------------------------------------------------------+
+| +-------------------------------------------------------+ |
+| | 增强 A2A 协议适配器 | |
+| | (智能解析与 CloudEvent 映射) | |
+| +-------------------------------------------------------+ |
++-------------------------------------------------------------+
+| EventMesh 协议基础设施 |
+| +-------------+ +-------------+ +-------------+ |
+| | CloudEvents | | HTTP | | gRPC | |
+| | 协议 | | 协议 | | 协议 | |
+| +-------------+ +-------------+ +-------------+ |
++-------------------------------------------------------------+
+```
+
+### 网关运行时架构
+
+A2A 网关提供独立的 HTTP 服务器(基于 Netty),负责编排 Agent 任务提交、响应处理和 SSE 流式推送。
+
+| 组件 | 模块 | 职责 |
+| :--- | :--- | :--- |
+| `A2AGatewayServer` | runtime | Netty HTTP 服务器入口,预注册 mock agent |
+| `A2AGatewayHttpHandler` | runtime | HTTP 请求路由,支持 SSE 流式响应 |
+| `A2AGatewayService` | runtime | 核心编排:任务提交、响应处理、SSE 推送 |
+| `TaskRegistry` | runtime | 内存任务状态机 + TTL 自动清理(5 分钟) |
+| `A2APublishSubscribeService` | runtime | AgentCard 注册、发现、心跳 |
+| `InMemoryA2AMessageTransport` | runtime | 内存 Pub/Sub(可替换为 EventMesh broker) |
+| `A2AClient` | protocol-a2a | Java SDK,提供类型化 API |
+| `EnhancedA2AProtocolAdaptor` | protocol-a2a | 智能解析与 CloudEvent 映射 |
+| `A2AProtocolConstants` | protocol-a2a | 协议版本、标准操作、CE 扩展属性 |
+
+### 异步 RPC 映射
+
+为在事件驱动架构中支持 MCP 请求/响应模型,A2A 定义了以下映射规则:
+
+| MCP 概念 | CloudEvent 映射 | 说明 |
+| :--- | :--- | :--- |
+| **动作**(`method`) | **Type**: `org.apache.eventmesh.a2a.<method>.req` <br/>
**Extension**: `a2amethod` | 请求事件类型 |
+| **响应**(`result`) | **Type**: `org.apache.eventmesh.a2a.common.response`
<br/> **Extension**: `mcptype=response` | 响应事件类型 |
+| **关联**(`id`) | **Extension**: `collaborationid`(响应上) <br/> **ID**: 请求上保留 |
将响应关联到请求 |
+| **P2P 路由**(`params._agentId`) | **Extension**: `targetagent` | 路由目标 Agent ID
|
+| **Pub/Sub Topic**(`params._topic`) | **Subject**: `<topic_name>` | 广播 Topic |
+| **流式序列**(`params._seq`) | **Extension**: `seq` | 流式消息顺序 |
+
+### 协议常量
+
+`A2AProtocolConstants` 类定义了以下标准操作(协议版本 `0.3`):
+
+| 类别 | 操作 |
+| :--- | :--- |
+| **消息** | `message/send`、`message/sendStream` |
+| **任务** | `task/get`、`task/list`、`task/cancel`、`task/subscribe` |
+| **通知配置** | `notification/config/set`、`get`、`list`、`delete` |
+| **Agent Card** | `agent/card/get`、`register`、`delete`、`list`、`update` |
+
+## 协议消息格式
+
+### 1. MCP 请求(P2P)
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "tools/call",
+ "params": {
+ "name": "get_weather",
+ "_agentId": "weather-service"
+ },
+ "id": "req-123"
+}
+```
+
+### 2. MCP 请求(Pub/Sub)
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "market/update",
+ "params": {
+ "price": 50000,
+ "_topic": "market.btc"
+ }
+}
+```
+
+### 3. 原生 CloudEvents 请求
+
+```json
+{
+ "specversion": "1.0",
+ "type": "com.example.rpc.request",
+ "source": "my-app",
+ "id": "evt-123",
+ "data": "...",
+ "protocol": "A2A",
+ "targetagent": "target-agent-001"
+}
+```
+
+## 使用指南
+
+### 1. A2AClient Java SDK
+
+```java
+A2AClient client = A2AClient.builder()
+ .gatewayUrl("http://localhost:10105")
+ .namespace("global")
+ .agentName("my-agent")
+ .agentCard(card)
+ .heartbeatInterval(30_000)
+ .build();
+
+client.start();
+
+// 同步任务(返回类型化的 TaskResult)
+TaskResult result = client.sendTaskSync("weather-agent", "Beijing", null);
+
+// 异步任务(返回 taskId)
+String taskId = client.sendTaskAsync("weather-agent", "Shanghai", null);
+
+// 查询状态
+TaskResult status = client.getTaskStatus(taskId);
+
+// 取消任务
+boolean cancelled = client.cancelTask(taskId);
+
+// 列出 Agent
+List<String> agents = client.listAgents();
+
+client.shutdown();
+```
+
+### 2. EventMesh SDK(CloudEvents 模式)
+
+```java
+// 参见
eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/ce/CloudEventsCaller.java
+
+CloudEvent event = CloudEventBuilder.v1()
+ .withId(UUID.randomUUID().toString())
+ .withSource(URI.create("ce-client"))
+ .withType("com.example.rpc.request")
+ .withData("application/text", "RPC Payload".getBytes())
+ .withExtension("protocol", "A2A")
+ .withExtension("targetagent", "target-agent-001")
+ .build();
+
+producer.publish(event);
+```
+
+### 3. 网关 REST API
+
+A2A 网关为外部客户端和非 Java Agent 提供完整的 REST API:
+
+```bash
+# 同步任务
+curl -X POST 'http://localhost:10105/a2a/tasks?mode=sync' \
+ -H 'Content-Type: application/json' \
+ -d '{"targetAgent":"weather-agent","message":"Beijing"}'
+
+# 异步任务
+curl -X POST 'http://localhost:10105/a2a/tasks?mode=async' \
+ -H 'Content-Type: application/json' \
+ -d '{"targetAgent":"weather-agent","message":"Shanghai"}'
+
+# 查询状态
+curl http://localhost:10105/a2a/tasks/{taskId}
+
+# SSE 流
+curl -N http://localhost:10105/a2a/tasks/{taskId}/stream
+
+# 列出 Agent
+curl http://localhost:10105/a2a/agents
+```
+
+#### REST API 端点
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| POST | `/a2a/tasks?mode=sync` | 同步提交任务(等待结果) |
+| POST | `/a2a/tasks?mode=async` | 异步提交任务(返回 taskId) |
+| GET | `/a2a/tasks/{taskId}` | 获取任务状态 |
+| DELETE | `/a2a/tasks/{taskId}` | 取消任务 |
+| GET | `/a2a/tasks/{taskId}/wait` | 长轮询等待结果 |
+| GET | `/a2a/tasks/{taskId}/stream` | SSE 流式获取任务状态更新 |
+| GET | `/a2a/agents` | 列出已注册的 Agent |
+| POST | `/a2a/heartbeat` | Agent 心跳 |
+| GET | `/a2a/cards/list` | 列出所有 AgentCard |
+| POST | `/a2a/cards/card/{org}/{unit}/{agent}` | 注册 AgentCard |
+
+## SPI 注册
+
+A2A 协议适配器通过 Java SPI 注册:
+
+```
+# META-INF/eventmesh/org.apache.eventmesh.protocol.api.ProtocolAdaptor
+a2a=org.apache.eventmesh.protocol.a2a.EnhancedA2AProtocolAdaptor
+```
+
+运行时,`ProtocolPluginFactory` 通过 key `a2a` 加载适配器。适配器将底层传输委托给 `cloudevents` 或
`http` 适配器。
+
+## 版本历史
+
+- **v2.0.0**:全面拥抱 MCP(Model Context Protocol)
+ - 引入 `EnhancedA2AProtocolAdaptor`,支持 JSON-RPC 2.0。
+ - 实现基于 CloudEvents 的异步 RPC 模式。
+ - 通过 `_topic` 参数添加原生 Pub/Sub 支持。
+ - 通过 `_seq` 参数添加流式支持。
+
+- **v2.1.0**:网关运行时架构
+ - 添加 `A2AGatewayServer`(Netty HTTP)独立网关服务。
+ - 实现 `TaskRegistry` 任务状态机 + TTL 自动清理(5 分钟)。
+ - 添加 SSE 流式响应(`GET /a2a/tasks/{taskId}/stream`)。
+ - `A2AClient` SDK 返回类型化对象(`TaskResult`、`List<String>`)。
+ - AgentCard 注册、发现和心跳管理。
+
+## 模块结构
+
+| 模块 | 路径 | 说明 |
+| :--- | :--- | :--- |
+| 协议插件 | `eventmesh-protocol-plugin/eventmesh-protocol-a2a` | A2A
协议适配器、JSON-RPC 模型、MCP 方法 |
+| 运行时网关 | `eventmesh-runtime/src/main/java/.../a2a/` | 网关服务器、服务、任务注册表、传输层 |
+| 示例 | `eventmesh-examples/src/main/java/.../a2a/demo/` | MCP
调用方/提供方、CloudEvents 调用方/提供方、网关示例 |
+
+## 参考
+
+- [A2A
协议设计文档](https://github.com/apache/eventmesh/tree/master/docs/a2a-protocol)(源码)
+- [MCP 规范](https://modelcontextprotocol.io/)
+- [CloudEvents 规范](https://cloudevents.io/)
diff --git a/i18n/zh/docusaurus-plugin-content-pages/index.tsx
b/i18n/zh/docusaurus-plugin-content-pages/index.tsx
index 10a3415df..9aea2f920 100644
--- a/i18n/zh/docusaurus-plugin-content-pages/index.tsx
+++ b/i18n/zh/docusaurus-plugin-content-pages/index.tsx
@@ -1,6 +1,7 @@
import React from 'react';
import Head from '@docusaurus/Head';
import {useEffect} from 'react';
+import {useVersions, useLatestVersion} from
'@docusaurus/plugin-content-docs/client';
const publishCode = `<span class="com"># 通过 HTTP 发布 CloudEvent</span>
<span class="fn">curl</span> -X POST \
@@ -30,6 +31,16 @@ const subscribeCode = `<span class="com"># 通过 HTTP Webhook
订阅主题</spa
<span class="com"># 事件以 CloudEvents 格式推送到你的 Webhook 📨</span>`;
export default function Home() {
+ // 动态版本列表(发版后自动更新,无需手动维护)
+ const versions = useVersions('default');
+ const latestVersion = useLatestVersion('default');
+
+ // 每个版本解析到其主文档 URL(裸版本路径如 /zh/docs/next 没有落地页)
+ const docHref = (v) => {
+ const main = v.docs.find((d) => d.id === v.mainDocId);
+ return (main && main.path) || v.path;
+ };
+
useEffect(() => {
document.body.classList.add('is-homepage');
return () => document.body.classList.remove('is-homepage');
@@ -58,9 +69,12 @@ export default function Home() {
<div className="nav-links">
<a href="#features" className="nav-link">特性</a>
<a href="#architecture" className="nav-link">架构</a>
- <a href="#a2a" className="nav-link">Agent Mesh</a>
- <a href="/zh/docs/introduction" className="nav-link">文档</a>
- <a href="/zh/download" className="nav-link">下载</a>
+ <div className="nav-dropdown">
+ <a href="#a2a" className="nav-link nav-dropdown-toggle">Agent
Mesh</a>
+ <div className="nav-dropdown-menu">
+ <a href="#ecosystem" className="nav-dropdown-item">Event
Bus</a>
+ </div>
+ </div>
<div className="nav-dropdown">
<span className="nav-link nav-dropdown-toggle">社区</span>
<div className="nav-dropdown-menu">
@@ -68,7 +82,16 @@ export default function Home() {
<a href="/zh/team" className="nav-dropdown-item">团队</a>
</div>
</div>
+ <a href="/zh/download" className="nav-link">下载</a>
<a href="/zh/blog" className="nav-link">博客</a>
+ <div className="nav-dropdown nav-docs-dropdown">
+ <a href={docHref(latestVersion)} className="nav-link
nav-dropdown-toggle">文档</a>
+ <div className="nav-dropdown-menu">
+ {versions.map((v) => (
+ <a key={v.name} href={docHref(v)}
className="nav-dropdown-item">{v.label}</a>
+ ))}
+ </div>
+ </div>
</div>
<div className="nav-actions">
@@ -107,11 +130,6 @@ export default function Home() {
<div className="hero-glow-2"></div>
<div className="container hero-content">
- <div className="hero-badge">
- <span className="dot"></span>
- v1.12.0 已发布 — 新增 A2A 协议支持
- </div>
-
<h1>
面向 Agent 时代的<br />
<span className="gradient-text">事件驱动基础设施</span>
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 23abc8c26..ca2581785 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,6 +1,7 @@
import React from 'react';
import Head from '@docusaurus/Head';
import {useEffect} from 'react';
+import {useVersions, useLatestVersion} from
'@docusaurus/plugin-content-docs/client';
const publishCode = `<span class="com"># Publish a CloudEvent via HTTP</span>
<span class="fn">curl</span> -X POST \
@@ -35,6 +36,16 @@ export default function Home() {
return () => document.body.classList.remove('is-homepage');
}, []);
+ // Dynamic docs versions (auto-updates when a new version is released — no
manual edit needed)
+ const versions = useVersions('default');
+ const latestVersion = useLatestVersion('default');
+
+ // Resolve each version to its main doc URL (the bare version path like
/docs/next has no landing page)
+ const docHref = (v) => {
+ const main = v.docs.find((d) => d.id === v.mainDocId);
+ return (main && main.path) || v.path;
+ };
+
return (
<div className="homepage-wrapper">
<Head>
@@ -58,9 +69,12 @@ export default function Home() {
<div className="nav-links">
<a href="#features" className="nav-link">Features</a>
<a href="#architecture" className="nav-link">Architecture</a>
- <a href="#a2a" className="nav-link">Agent Mesh</a>
- <a href="/docs/introduction" className="nav-link">Documentation</a>
- <a href="/download" className="nav-link">Download</a>
+ <div className="nav-dropdown">
+ <a href="#a2a" className="nav-link nav-dropdown-toggle">Agent
Mesh</a>
+ <div className="nav-dropdown-menu">
+ <a href="#ecosystem" className="nav-dropdown-item">Event
Bus</a>
+ </div>
+ </div>
<div className="nav-dropdown">
<span className="nav-link nav-dropdown-toggle">Community</span>
<div className="nav-dropdown-menu">
@@ -68,7 +82,16 @@ export default function Home() {
<a href="/team" className="nav-dropdown-item">Team</a>
</div>
</div>
+ <a href="/download" className="nav-link">Download</a>
<a href="/blog" className="nav-link">Blog</a>
+ <div className="nav-dropdown nav-docs-dropdown">
+ <a href={docHref(latestVersion)} className="nav-link
nav-dropdown-toggle">Documentation</a>
+ <div className="nav-dropdown-menu">
+ {versions.map((v) => (
+ <a key={v.name} href={docHref(v)}
className="nav-dropdown-item">{v.label}</a>
+ ))}
+ </div>
+ </div>
</div>
<div className="nav-actions">
@@ -107,11 +130,6 @@ export default function Home() {
<div className="hero-glow-2"></div>
<div className="container hero-content">
- <div className="hero-badge">
- <span className="dot"></span>
- v1.12.0 Released — Now with A2A Protocol Support
- </div>
-
<h1>
Event-Driven<br />
Infrastructure for<br />
diff --git a/static/css/docusaurus-override.css
b/static/css/docusaurus-override.css
index a07472b4d..655070521 100644
--- a/static/css/docusaurus-override.css
+++ b/static/css/docusaurus-override.css
@@ -271,6 +271,11 @@ body {
opacity: 1;
visibility: visible;
}
+/* Docs/version dropdown holds a long version list — cap height with scroll */
+.em-docs-dropdown .nav-dropdown-menu {
+ max-height: 320px;
+ overflow-y: auto;
+}
.nav-dropdown-item {
display: block;
padding: 8px 16px;
diff --git a/static/css/site-redesign.css b/static/css/site-redesign.css
index 779dec0ee..79e67b8fe 100644
--- a/static/css/site-redesign.css
+++ b/static/css/site-redesign.css
@@ -198,7 +198,9 @@ img { max-width: 100%; display: block; }
left: 0;
min-width: 160px;
padding: 6px 0;
- background: var(--bg-card);
+ /* Solid, opaque surface so the menu never shows the hero text bleeding
+ through when it opens over the content (bg-base is opaque in both
themes). */
+ background: var(--bg-base);
border: 1px solid var(--border-subtle);
border-radius: 10px;
box-shadow: 0 8px 32px rgba(0,0,0,0.2);
@@ -236,6 +238,14 @@ img { max-width: 100%; display: block; }
background: var(--bg-card-hover);
}
+/* ---- Docs dropdown (Documentation → version list, dynamic) ---- */
+.nav-docs-dropdown .nav-dropdown-menu,
+.em-docs-dropdown .nav-dropdown-menu {
+ min-width: 140px;
+ max-height: 320px;
+ overflow-y: auto;
+}
+
.nav-actions { display: flex; align-items: center; gap: 12px; }
.nav-lang {
@@ -352,7 +362,9 @@ img { max-width: 100%; display: block; }
display: flex;
align-items: center;
overflow: hidden;
- padding-top: var(--nav-h);
+ /* Extra breathing room below the fixed navbar so the nav dropdown menus
+ have clean space to open into and never overlap the hero content. */
+ padding-top: calc(var(--nav-h) + 72px);
}
#hero-canvas {
diff --git a/static/js/eventmesh-internal.js b/static/js/eventmesh-internal.js
index 6598748df..828afe64b 100644
--- a/static/js/eventmesh-internal.js
+++ b/static/js/eventmesh-internal.js
@@ -10,18 +10,20 @@
const HOMEPAGE_NAV_LINKS = [
{ href: '/#features', label: 'Features', en: 'Features', zh:
'\u7279\u6027' },
{ href: '/#architecture', label: 'Architecture', en: 'Architecture', zh:
'\u67b6\u6784' },
- { href: '/#a2a', label: 'Agent Mesh', en: 'Agent Mesh', zh: 'Agent Mesh' },
- { href: '/docs/introduction', label: 'Documentation', en: 'Documentation',
zh: '\u6587\u6863' },
- { href: '/download', label: 'Download', en: 'Download', zh: '\u4e0b\u8f7d'
},
+ { type: 'linkDropdown', href: '/#a2a', label: 'Agent Mesh', en: 'Agent
Mesh', zh: 'Agent Mesh', children: [
+ { href: '/#ecosystem', label: 'Event Bus', en: 'Event Bus', zh: 'Event
Bus' },
+ ]},
{ type: 'dropdown', label: 'Community', en: 'Community', zh:
'\u793e\u533a', children: [
{ href: '/community/how-to-subscribe', label: 'Subscribe', en:
'Subscribe', zh: '\u8ba2\u9605' },
{ href: '/team', label: 'Team', en: 'Team', zh: '\u56e2\u961f' },
]},
+ { href: '/download', label: 'Download', en: 'Download', zh: '\u4e0b\u8f7d'
},
{ href: '/blog', label: 'Blog', en: 'Blog', zh: '\u535a\u5ba2' },
+ { type: 'docsVersions', href: '/docs/introduction', label:
'Documentation', en: 'Documentation', zh: '\u6587\u6863' },
];
// Count expected non-dropdown links
- const EXPECTED_LINK_COUNT = HOMEPAGE_NAV_LINKS.filter(function (i) { return
!i.type || i.type !== 'dropdown'; }).length;
+ const EXPECTED_LINK_COUNT = HOMEPAGE_NAV_LINKS.filter(function (i) { return
!i.type; }).length;
const ICON_SUN = '<svg class="em-theme-icon-sun" viewBox="0 0 24 24"
width="20" height="20" aria-hidden="true"><path fill="currentColor" d="M12
7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zM2 13h2c.55 0 1-.45
1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45
1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM11 2v2c0 .55.45 1 1 1s1-.45
1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45
1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1zM5.99 4.58c-.39-.39-1.03-.39-1.41 0-.3 [...]
const ICON_MOON = '<svg class="em-theme-icon-moon" viewBox="0 0 24 24"
width="20" height="20" aria-hidden="true" style="display:none"><path
fill="currentColor" d="M9.37 5.51c-.18.64-.27 1.31-.27 1.99 0 4.08 3.32 7.4 7.4
7.4.68 0 1.35-.09 1.99-.27C17.45 17.19 14.93 19 12 19c-3.86 0-7-3.14-7-7 0-2.93
1.81-5.45 4.37-6.49zM12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9 9-4.03
9-9c0-.46-.04-.92-.1-1.36-.98 1.37-2.58 2.26-4.4 2.26-2.98 0-5.4-2.42-5.4-5.4
0-1.81.89-3.42 2.26-4.4C12.92 3.04 12.46 3 12 3z" [...]
@@ -90,6 +92,17 @@
var langToggle = document.querySelector('.navbar__items--right >
.em-lang-toggle');
if (!langToggle) return false;
+ // Check if the docs/version dropdown was merged into the left
"Documentation"
+ // item (only when the site actually exposes a version source).
+ var rightItems = document.querySelector('.navbar__items--right');
+ if (rightItems) {
+ var hasSourceVersion = !!findVersionDropdownSource(rightItems);
+ if (hasSourceVersion) {
+ var docsDropdown =
document.querySelector('.navbar__items:not(.navbar__items--right) >
.em-docs-dropdown');
+ if (!docsDropdown || !docsDropdown.querySelector('.nav-dropdown-menu
.nav-dropdown-item')) return false;
+ }
+ }
+
// Check if em-brand-logo exists (we now remove .navbar__logo entirely)
var brand = document.querySelector('.navbar__brand');
if (!brand) return false;
@@ -171,7 +184,87 @@
leftItems.querySelectorAll('.em-injected-link,
.em-injected-dropdown').forEach(function (el) { el.remove(); });
HOMEPAGE_NAV_LINKS.forEach(function (item) {
- if (item.type === 'dropdown') {
+ if (item.type === 'docsVersions') {
+ // Documentation dropdown holding the docs version list (merged from
the
+ // native docsVersionDropdown so it stays dynamic — no manual
maintenance).
+ var vSource =
findVersionDropdownSource(document.querySelector('.navbar__items--right'));
+ var vDropdown = document.createElement('div');
+ vDropdown.className = 'nav-dropdown em-injected-dropdown
em-docs-dropdown';
+
+ var vToggle = document.createElement('a');
+ vToggle.className = 'nav-link nav-dropdown-toggle';
+ vToggle.href = isZh ? '/zh' + item.href : item.href;
+ vToggle.textContent = isZh ? item.zh : item.en;
+ vDropdown.appendChild(vToggle);
+
+ var vMenu = document.createElement('div');
+ vMenu.className = 'nav-dropdown-menu';
+ if (vSource) {
+ vSource.querySelectorAll('.dropdown__menu a').forEach(function
(srcLink) {
+ var ca = document.createElement('a');
+ ca.className = 'nav-dropdown-item';
+ var href = srcLink.getAttribute('href');
+ if (href) ca.href = href;
+ ca.textContent = srcLink.textContent.trim();
+ vMenu.appendChild(ca);
+ });
+ }
+ vDropdown.appendChild(vMenu);
+ leftItems.appendChild(vDropdown);
+
+ vToggle.addEventListener('click', function (e) {
+ // Let a real click on the toggle navigate to the docs; only toggle
the
+ // menu open state when the version list has items to show.
+ if (!vMenu.children.length) return;
+ e.preventDefault();
+ e.stopPropagation();
+ var isOpen = vDropdown.classList.contains('open');
+ document.querySelectorAll('.nav-dropdown.open,
.em-injected-dropdown.open').forEach(function (d) {
+ d.classList.remove('open');
+ });
+ if (!isOpen) vDropdown.classList.add('open');
+ });
+ } else if (item.type === 'linkDropdown') {
+ // A dropdown whose toggle is itself a real anchor link (e.g. Agent
Mesh
+ // -> /#a2a) while the menu holds extra section links (e.g. Event Bus
+ // -> /#ecosystem). Clicking the toggle navigates; hover reveals the
menu.
+ var ldDropdown = document.createElement('div');
+ ldDropdown.className = 'nav-dropdown em-injected-dropdown';
+
+ var ldToggle = document.createElement('a');
+ ldToggle.className = 'nav-link nav-dropdown-toggle';
+ ldToggle.href = (isZh ? '/zh' : '') + item.href;
+ ldToggle.textContent = isZh ? item.zh : item.en;
+ if (item.href.startsWith('/#')) {
+ (function (href) {
+ ldToggle.addEventListener('click', function (e) {
+ e.preventDefault();
+ window.location.href = (isZh ? '/zh' : '') + href;
+ });
+ })(item.href);
+ }
+ ldDropdown.appendChild(ldToggle);
+
+ var ldMenu = document.createElement('div');
+ ldMenu.className = 'nav-dropdown-menu';
+ item.children.forEach(function (child) {
+ var ca = document.createElement('a');
+ ca.className = 'nav-dropdown-item';
+ ca.href = (isZh ? '/zh' : '') + child.href;
+ ca.textContent = isZh ? child.zh : child.en;
+ if (child.href.startsWith('/#')) {
+ (function (href) {
+ ca.addEventListener('click', function (e) {
+ e.preventDefault();
+ window.location.href = (isZh ? '/zh' : '') + href;
+ });
+ })(child.href);
+ }
+ ldMenu.appendChild(ca);
+ });
+ ldDropdown.appendChild(ldMenu);
+ leftItems.appendChild(ldDropdown);
+ } else if (item.type === 'dropdown') {
var dropdown = document.createElement('div');
dropdown.className = 'nav-dropdown em-injected-dropdown';
@@ -294,6 +387,30 @@
rightItems.insertBefore(langLink, rightItems.firstChild);
}
+ /* ---- Version dropdown: rebuild Docusaurus docsVersionDropdown in site
style ---- */
+
+ // Identify the native docs version dropdown among the right-side dropdowns.
+ // Distinguishing rule:
+ // - version dropdown: menu links point to /docs/... (or /zh/docs/...) and
have NO lang attr
+ // - locale dropdown: menu links carry a lang="en"/lang="zh" attribute
+ // Its contents are merged into the left "Documentation" dropdown; skip our
own injected ones.
+ function findVersionDropdownSource(container) {
+ var dropdowns = container.querySelectorAll('.navbar__item.dropdown,
.dropdown');
+ for (var i = 0; i < dropdowns.length; i++) {
+ if (dropdowns[i].classList.contains('em-injected-dropdown')) continue;
+ var links = dropdowns[i].querySelectorAll('.dropdown__menu a');
+ if (!links.length) continue;
+ var isVersion = false;
+ for (var j = 0; j < links.length; j++) {
+ var href = links[j].getAttribute('href') || '';
+ if (links[j].hasAttribute('lang')) { isVersion = false; break; }
+ if (/(^|\/)docs(\/|$)/.test(href)) isVersion = true;
+ }
+ if (isVersion) return dropdowns[i];
+ }
+ return null;
+ }
+
function hideOriginalRightItems() {
var rightItems = document.querySelector('.navbar__items--right');
if (!rightItems) return;
diff --git a/versioned_docs/version-v1.12.0/design-document/04-a2a-protocol.md
b/versioned_docs/version-v1.12.0/design-document/04-a2a-protocol.md
new file mode 100644
index 000000000..82dc1f6fb
--- /dev/null
+++ b/versioned_docs/version-v1.12.0/design-document/04-a2a-protocol.md
@@ -0,0 +1,293 @@
+---
+title: A2A Protocol
+sidebar_position: 4
+---
+
+# EventMesh A2A (Agent-to-Agent) Protocol
+
+## Overview
+
+The **EventMesh A2A (Agent-to-Agent) Protocol** is a specialized,
high-performance protocol plugin that enables asynchronous communication,
collaboration, and task coordination between autonomous agents.
+
+Starting from v2.0, A2A adopts the **MCP (Model Context Protocol)**
architecture, transforming EventMesh into a robust **Agent Collaboration Bus**.
It bridges the gap between synchronous LLM-based tool calls (JSON-RPC 2.0) and
asynchronous Event-Driven Architectures (EDA), enabling scalable, distributed,
and decoupled agent systems.
+
+## Core Features
+
+### 1. MCP over CloudEvents
+
+- **Standard Compliance**: Fully supports standard MCP methods such as
`tools/call`, `resources/read`, and `tools/list`.
+- **Event-Driven**: Maps synchronous RPC calls to asynchronous
Request/Response event streams, leveraging EventMesh's high-concurrency
processing capabilities.
+- **Transport Agnostic**: All MCP messages are encapsulated within standard
CloudEvents envelopes, running over any transport layer supported by EventMesh
(HTTP, TCP, gRPC, Kafka).
+
+### 2. Dual-Mode Support (Hybrid Architecture)
+
+A2A Protocol features a unique Dual-Mode architecture that simultaneously
supports:
+
+1. **JSON-RPC 2.0 (MCP Mode)**:
+ - **Target**: LLMs, scripts (Python/JS), LangChain integration.
+ - **Benefit**: Extremely low barrier to entry. Clients send simple JSON
objects; the adaptor automatically wraps them in CloudEvents.
+2. **Native CloudEvents (Power Mode)**:
+ - **Target**: EventMesh native apps, Knative, serverless functions.
+ - **Benefit**: Full control over event metadata. Allows pass-through of
custom or binary data.
+
+The `EnhancedA2AProtocolAdaptor` intelligently detects the payload format. If
`jsonrpc: "2.0"` is present, it engages the MCP translation engine; otherwise,
it treats the payload as a standard CloudEvent (delegating to the underlying
CloudEvents adaptor).
+
+### 3. Native Pub/Sub Semantics
+
+- **O(1) Broadcast**: Publishers send messages once to a topic, and EventMesh
efficiently fans out to all subscribers.
+- **Temporal Decoupling**: Solves the scalability issues of traditional P2P
webhook callbacks (consumers need not be online at publish time).
+- **Backpressure Isolation**: A slow subscriber does not block the publisher.
+
+### 4. High Performance and Routing
+
+- **Batch Processing**: Natively supports JSON-RPC Batch requests. EventMesh
automatically splits them into parallel event streams.
+- **Intelligent Routing**: Extracts routing hints (`_agentId` for P2P,
`_topic` for Pub/Sub) from MCP parameters and injects them into CloudEvents
attributes for zero-decoding routing.
+
+### 5. Streaming Support
+
+Preserves message order for streaming operations (`message/sendStream`) using
sequence IDs (`seq` extension attribute).
+
+### 6. Agent Discovery and Lifecycle
+
+- **AgentCard**: Agents register their capabilities via AgentCard, supporting
online/offline status and heartbeat.
+- **Task Management**: Full task lifecycle with `task/get`, `task/list`,
`task/cancel`, `task/subscribe` operations and TTL-based auto-cleanup.
+
+## Architecture
+
+### Core Components
+
+```
++-------------------------------------------------------------+
+| EventMesh A2A Protocol v2.0 |
+| (MCP over CloudEvents Architecture) |
++-------------------------------------------------------------+
+| +-------------+ +-------------+ +-------------+ |
+| | MCP/JSON-RPC| | Native | | Protocol | |
+| | Handler | | Pub/Sub | | Delegator | |
+| +-------------+ +-------------+ +-------------+ |
++-------------------------------------------------------------+
+| +-------------------------------------------------------+ |
+| | Enhanced A2A Protocol Adaptor | |
+| | (Intelligent Parsing & CloudEvent Mapping) | |
+| +-------------------------------------------------------+ |
++-------------------------------------------------------------+
+| EventMesh Protocol Infrastructure |
+| +-------------+ +-------------+ +-------------+ |
+| | CloudEvents | | HTTP | | gRPC | |
+| | Protocol | | Protocol | | Protocol | |
+| +-------------+ +-------------+ +-------------+ |
++-------------------------------------------------------------+
+```
+
+### Gateway Runtime Architecture
+
+The A2A Gateway provides a standalone HTTP server (Netty-based) that
orchestrates agent task submission, response handling, and SSE streaming.
+
+| Component | Module | Responsibility |
+| :--- | :--- | :--- |
+| `A2AGatewayServer` | runtime | Netty HTTP server entry point, pre-registers
mock agents |
+| `A2AGatewayHttpHandler` | runtime | HTTP request router, supports SSE
streaming |
+| `A2AGatewayService` | runtime | Core orchestration: task submission,
response handling, SSE push |
+| `TaskRegistry` | runtime | In-memory task state machine + TTL auto-cleanup
(5 min) |
+| `A2APublishSubscribeService` | runtime | AgentCard registration, discovery,
heartbeat |
+| `InMemoryA2AMessageTransport` | runtime | In-memory pub/sub (replaceable by
EventMesh broker) |
+| `A2AClient` | protocol-a2a | Java SDK with typed API |
+| `EnhancedA2AProtocolAdaptor` | protocol-a2a | Intelligent parsing and
CloudEvent mapping |
+| `A2AProtocolConstants` | protocol-a2a | Protocol version, standard
operations, CE extensions |
+
+### Asynchronous RPC Mapping
+
+To support the MCP Request/Response model within an event-driven architecture,
A2A defines the following mapping rules:
+
+| MCP Concept | CloudEvent Mapping | Description |
+| :--- | :--- | :--- |
+| **Action** (`method`) | **Type**: `org.apache.eventmesh.a2a.<method>.req`
<br/> **Extension**: `a2amethod` | Request event type. |
+| **Response** (`result`) | **Type**:
`org.apache.eventmesh.a2a.common.response` <br/> **Extension**:
`mcptype=response` | Response event type. |
+| **Correlation** (`id`) | **Extension**: `collaborationid` (on Response)
<br/> **ID**: Preserved on Request | Links Response to Request. |
+| **P2P Routing** (`params._agentId`) | **Extension**: `targetagent` | Routing
target Agent ID. |
+| **Pub/Sub Topic** (`params._topic`) | **Subject**: `<topic_name>` |
Broadcast Topic. |
+| **Streaming Seq** (`params._seq`) | **Extension**: `seq` | Sequence order
for streaming. |
+
+### Protocol Constants
+
+The `A2AProtocolConstants` class defines the following standard operations
(protocol version `0.3`):
+
+| Category | Operations |
+| :--- | :--- |
+| **Message** | `message/send`, `message/sendStream` |
+| **Task** | `task/get`, `task/list`, `task/cancel`, `task/subscribe` |
+| **Notification Config** | `notification/config/set`, `get`, `list`, `delete`
|
+| **Agent Card** | `agent/card/get`, `register`, `delete`, `list`, `update` |
+
+## Protocol Message Format
+
+### 1. MCP Request (P2P)
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "tools/call",
+ "params": {
+ "name": "get_weather",
+ "_agentId": "weather-service"
+ },
+ "id": "req-123"
+}
+```
+
+### 2. MCP Request (Pub/Sub)
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "market/update",
+ "params": {
+ "price": 50000,
+ "_topic": "market.btc"
+ }
+}
+```
+
+### 3. Native CloudEvents Request
+
+```json
+{
+ "specversion": "1.0",
+ "type": "com.example.rpc.request",
+ "source": "my-app",
+ "id": "evt-123",
+ "data": "...",
+ "protocol": "A2A",
+ "targetagent": "target-agent-001"
+}
+```
+
+## Usage Guide
+
+### 1. A2AClient Java SDK
+
+```java
+A2AClient client = A2AClient.builder()
+ .gatewayUrl("http://localhost:10105")
+ .namespace("global")
+ .agentName("my-agent")
+ .agentCard(card)
+ .heartbeatInterval(30_000)
+ .build();
+
+client.start();
+
+// Sync task (returns typed TaskResult)
+TaskResult result = client.sendTaskSync("weather-agent", "Beijing", null);
+
+// Async task (returns taskId)
+String taskId = client.sendTaskAsync("weather-agent", "Shanghai", null);
+
+// Query status
+TaskResult status = client.getTaskStatus(taskId);
+
+// Cancel
+boolean cancelled = client.cancelTask(taskId);
+
+// List agents
+List<String> agents = client.listAgents();
+
+client.shutdown();
+```
+
+### 2. EventMesh SDK (CloudEvents Mode)
+
+```java
+// See
eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/ce/CloudEventsCaller.java
+
+CloudEvent event = CloudEventBuilder.v1()
+ .withId(UUID.randomUUID().toString())
+ .withSource(URI.create("ce-client"))
+ .withType("com.example.rpc.request")
+ .withData("application/text", "RPC Payload".getBytes())
+ .withExtension("protocol", "A2A")
+ .withExtension("targetagent", "target-agent-001")
+ .build();
+
+producer.publish(event);
+```
+
+### 3. Gateway REST API
+
+The A2A Gateway provides a full REST API for external clients and non-Java
agents:
+
+```bash
+# Sync task
+curl -X POST 'http://localhost:10105/a2a/tasks?mode=sync' \
+ -H 'Content-Type: application/json' \
+ -d '{"targetAgent":"weather-agent","message":"Beijing"}'
+
+# Async task
+curl -X POST 'http://localhost:10105/a2a/tasks?mode=async' \
+ -H 'Content-Type: application/json' \
+ -d '{"targetAgent":"weather-agent","message":"Shanghai"}'
+
+# Query status
+curl http://localhost:10105/a2a/tasks/{taskId}
+
+# SSE stream
+curl -N http://localhost:10105/a2a/tasks/{taskId}/stream
+
+# List agents
+curl http://localhost:10105/a2a/agents
+```
+
+#### REST API Endpoints
+
+| Method | Path | Description |
+|------|------|------|
+| POST | `/a2a/tasks?mode=sync` | Submit task synchronously (wait for result) |
+| POST | `/a2a/tasks?mode=async` | Submit task asynchronously (return taskId) |
+| GET | `/a2a/tasks/{taskId}` | Get task status |
+| DELETE | `/a2a/tasks/{taskId}` | Cancel task |
+| GET | `/a2a/tasks/{taskId}/wait` | Long-poll wait for result |
+| GET | `/a2a/tasks/{taskId}/stream` | SSE stream of task status updates |
+| GET | `/a2a/agents` | List registered agents |
+| POST | `/a2a/heartbeat` | Agent heartbeat |
+| GET | `/a2a/cards/list` | List all AgentCards |
+| POST | `/a2a/cards/card/{org}/{unit}/{agent}` | Register AgentCard |
+
+## SPI Registration
+
+The A2A protocol adaptor is registered via Java SPI:
+
+```
+# META-INF/eventmesh/org.apache.eventmesh.protocol.api.ProtocolAdaptor
+a2a=org.apache.eventmesh.protocol.a2a.EnhancedA2AProtocolAdaptor
+```
+
+At runtime, `ProtocolPluginFactory` loads the adaptor by key `a2a`. The
adaptor delegates to `cloudevents` or `http` adaptors for underlying transport.
+
+## Version History
+
+- **v2.0.0**: Fully embraced MCP (Model Context Protocol)
+ - Introduced `EnhancedA2AProtocolAdaptor` supporting JSON-RPC 2.0.
+ - Implemented async RPC over CloudEvents pattern.
+ - Added native Pub/Sub support via `_topic` parameter.
+ - Added streaming support via `_seq` parameter.
+
+- **v2.1.0**: Gateway Runtime Architecture
+ - Added `A2AGatewayServer` (Netty HTTP) standalone gateway service.
+ - Implemented `TaskRegistry` task state machine + TTL auto-cleanup (5 min).
+ - Added SSE streaming response (`GET /a2a/tasks/{taskId}/stream`).
+ - `A2AClient` SDK returns typed objects (`TaskResult`, `List<String>`).
+ - AgentCard registration, discovery, and heartbeat management.
+
+## Module Structure
+
+| Module | Path | Description |
+| :--- | :--- | :--- |
+| Protocol Plugin | `eventmesh-protocol-plugin/eventmesh-protocol-a2a` | A2A
protocol adaptor, JSON-RPC models, MCP methods |
+| Runtime Gateway | `eventmesh-runtime/src/main/java/.../a2a/` | Gateway
server, service, task registry, transport |
+| Examples | `eventmesh-examples/src/main/java/.../a2a/demo/` | MCP
caller/provider, CloudEvents caller/provider, gateway demo |
+
+## References
+
+- [A2A Protocol Design
Document](https://github.com/apache/eventmesh/tree/master/docs/a2a-protocol)
(source code)
+- [MCP Specification](https://modelcontextprotocol.io/)
+- [CloudEvents Specification](https://cloudevents.io/)
diff --git a/versioned_sidebars/version-v1.12.0-sidebars.json
b/versioned_sidebars/version-v1.12.0-sidebars.json
index fde499425..cddbfb7a2 100644
--- a/versioned_sidebars/version-v1.12.0-sidebars.json
+++ b/versioned_sidebars/version-v1.12.0-sidebars.json
@@ -58,7 +58,8 @@
},
"design-document/schema-registry",
"design-document/spi",
- "design-document/stream"
+ "design-document/stream",
+ "design-document/a2a-protocol"
]
},
{
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]