# A2A Generic Agent Host Integration V0

## 1. 文档定位

- **本文**定义任何 Agent Host 如何接入 A2A 平台，适用于 Hermes、Claude CLI、OpenClaw、Cursor Agent 及自定义 Agent。
- **本文**是接入规范与生命周期说明，不替代 `docs/ARCHITECTURE_V2.md`（系统架构）、`docs/DOMAIN_RULES_V1.md`（领域规则）、`docs/A2A_LOCAL_HTTP_ADAPTER_CONTRACT_V1.md`（adapter HTTP 契约）。
- **不改变**平台执行模型：`task_runs` 主链、pull-based 认领、complete/fail 上报。
- **不改变**Connector/adapter 定位：基础设施桥，不是 Agent 本体，不做调度决策。

---

## 2. 核心概念定义

### 2.1 A2A Agent Account

平台中的 Agent 身份（`agent_id`）。是跨设备、跨运行时的长期持久标识。Agent Account 是协作网络中的 Data Plane 主体。

- 一个 Agent Account 可以被多个 Runtime 连接（V1 同时只允许一个 active runtime）。
- Agent Account 的真相存储在平台的 `agent_accounts` 表中。
- 换设备或重装系统时，**不应创建新 Agent**；应将新 Runtime 绑定到已有 `agent_id`。

### 2.2 Agent Host

真正执行 Agent 任务的本地或云端宿主进程。例如：

- Claude Code CLI 进程
- Hermes workspace 进程
- OpenClaw 本地服务
- Cursor Agent 终端进程
- 自定义 Python/Node.js agent 脚本

Agent Host **不是** A2A 系统的一部分；它是用户已有的执行环境。A2A 只负责把任务送到 Host，Host 负责执行。

### 2.3 Runtime Connector / A2A Runtime

`a2a-runtime` 是官方运行时守护进程（`packages/a2a-runtime/src/cli.js`）。它负责：

- 通过 pairing code 绑定到 Agent Account（`attach-via-pairing`）
- 周期性 heartbeat（保持 online 状态）
- 周期性 pull（拉取待处理的 task_runs）
- 本地 HTTP dispatch（把任务发到 Adapter）
- complete/fail 上报（把执行结果写回平台）

Runtime **不是** Agent 大脑；它是平台与 Agent Host 之间的连接桥。

### 2.4 Runtime Profile

本机连接档案（`~/.a2a/runtime.json`），记录：

- `agent_id` / `runtime_id` — 平台身份标识
- `runtime_token` — 执行凭证（必须隐藏）
- `api_base` — 平台 API 地址
- `local_agent_endpoint` — Adapter HTTP endpoint
- `local_executor` — 本地执行器元数据（type / ref / workspace / cwd）
- `adapter` — Adapter 类型标记
- `last_heartbeat_at` / `heartbeat_timeout_ms` — 心跳状态

Profile 是纯本机概念，不存储于平台。

### 2.5 Adapter

Adapter 是 Runtime 调用本地 Agent Host 的 HTTP 最后一跳。当前官方 adapter 是 `cli-agent-adapter`（`examples/cli-agent-adapter/src/index.mjs`）。

Adapter 的职责：
- 接收 `POST /run-task` 请求（来自 Runtime）
- 提供 `GET /health` 健康检查
- 启动并管理 Agent Host 子进程
- 序列化执行（同时只处理一个任务）
- 将 Host stdout 封装为 success/failure response

Adapter HTTP 契约详见 `docs/A2A_LOCAL_HTTP_ADAPTER_CONTRACT_V1.md`。

**每个 Agent Host 类型需要自己的 Adapter**：
- Claude CLI → 已有 `cli-agent-adapter`（provider: `claude`）
- Hermes → 需要 Hermes Adapter（provider: `hermes`）
- OpenClaw → 需要 OpenClaw Adapter（provider: `openclaw`）
- Cursor Agent → 需要 Cursor Adapter（provider: `cursor`）

### 2.6 Business Instructions

Business Instructions 是 Agent Account 的业务能力描述（例如"你是一个 GEO 分析师"），不是平台 schema 的一部分，不是代码，不是配置文件。

它可以存在以下位置：
- Agent Account 的 `description` / `instructions` 字段（平台侧）
- Conversation metadata 中的 context instructions（会话侧）
- Adapter 启动时的 `--instruction-file` 参数（本地侧）

Business Instructions **不得**写死到 A2A 核心 schema；GEO、客服、数据分析等业务概念不应出现在 `task_runs`、`conversations` 等核心表中。

---

## 3. Pairing Code 与 Runtime Token 的区别

| 概念 | 配对码 (Pairing Code) | Runtime Token |
|------|----------------------|---------------|
| 目的 | 一次性授权，建立 Runtime → Agent Account 绑定 | 长期执行凭证，用于 heartbeat / pull / complete / fail |
| 生成方式 | Web 用户在平台 UI 点击「生成连接码」 | `attach-via-pairing` 服务端签发 |
| 传输 | 用户从 Web 复制，传给本地 Agent | 服务端响应中返回，仅写入本机 profile |
| 有效期 | 一次性使用，过期自动失效 | 长期有效，直到被撤销或重新配对 |
| 可见性 | 用户可见，可复制传输 | 不可输出到日志、聊天、UI、artifact |
| 存储 | 不持久化（用完即弃） | 仅存于 `~/.a2a/runtime.json`（chmod 600） |

**配对流程**：
1. Web 用户在平台选择 Agent → 生成 pairing code
2. 用户将 pairing code 传给本地 Agent / Runtime
3. Runtime 调用 `POST .../agent-runtimes/runtime/attach-via-pairing`（body 含 `pairing_token`）
4. 服务端签发 `runtime_token`，返回 `agent_id`、`runtime_id`
5. Runtime 将 `runtime_token` 写入本机 profile
6. Runtime 使用 `runtime_token` 发起 heartbeat / pull / complete / fail

**`pairing_token` 不是 `runtime_token`**；前者只用于一次性绑定，后者是执行凭证。

---

## 4. 接入生命周期

### 4.1 阶段一：Attach（绑定）

```
用户 → Web UI → 生成 pairing code → 用户传给 Runtime
Runtime → POST /agent-runtimes/runtime/attach-via-pairing
     → 获得 runtime_token + agent_id + runtime_id
     → 写入 ~/.a2a/runtime.json
```

### 4.2 阶段二：Heartbeat（心跳）

```
Runtime → POST /agent-runtimes/runtime/heartbeat
     Header: X-Runtime-Token
     Body: { "agent_id": "..." }
     → 服务端更新 last_heartbeat_at
     → Runtime 标记为 online
```

心跳周期由 `heartbeat_timeout_ms` 决定（默认 120s）。如果 Runtime 停止心跳超时，服务端标记为 offline，不再分配新任务。

### 4.3 阶段三：Pull（拉取任务）

```
Runtime → POST /agent-accounts/{agentId}/task-runs/pull
     Header: X-Runtime-Token
     → 服务端返回待处理的 task_run（pending 状态）
     → Runtime claim 该 task_run（状态变为 running）
```

Pull 是主动拉取，平台不 push。一次 pull 返回一个 task_run。

### 4.4 阶段四：Execute（执行）

```
Runtime → POST {local_agent_endpoint}/run-task
     Body: { task_run_id, conversation_id, workspace_id, task_type, input, ... }
     → Adapter 收到请求
     → Adapter 启动 Agent Host 子进程
     → Host 执行任务
     → Adapter 收集 stdout/stderr
     → Adapter 返回 success/failure response
```

Runtime 在执行前尝试上报 progress（`POST .../task-runs/{id}/progress`），但 progress 调用失败不影响核心执行（非致命）。

### 4.5 阶段五：Artifact Delivery（产物交付）

Agent Host 可以通过 Adapter 输出 workspace artifact 引用。Artifact 通过 `POST /task-runs/{id}/complete` 的 `output` 中的 `artifact_refs` 传递。

Artifact 属于 workspace（与 conversation 1:1 绑定），详见 `docs/WORKSPACE_ARTIFACTS_V1.md`。

**Artifact 不替代 task_runs** — 它是产出物容器；task_run 仍是执行真相。

### 4.6 阶段六：Complete / Fail（上报结果）

```
成功：Runtime → POST /task-runs/{id}/complete
     Body: { output: { text: "...", artifact_refs: [...] } }

失败：Runtime → POST /task-runs/{id}/fail
     Body: { output: { error: "...", ... } }
```

如果 complete/fail API 调用失败，Runtime 会：
1. 重试一次
2. 如果两次都失败 → 写入本地 execution ledger（`~/.a2a/logs/<agent_id>/execution-ledger.jsonl`）
3. 平台 `task_runs` 仍是唯一执行真相；本地 ledger 仅供参考

### 4.7 阶段七：Reconnect（重连）

- 本机已有 profile → 直接启动 Runtime（不需新 pairing code）
- 新电脑 / 无 profile → 在 Web 对**同一 Agent** 生成新 pairing code → 重新 pair
- Runtime token 失效（401/403）→ 同上，重新 pair
- **禁止**创建新 Agent 来修复连接

---

## 5. Runtime Profile 字段规范

### 5.1 推荐字段

| 字段 | 说明 | 来源 |
|------|------|------|
| `agent_id` | Agent Account ID | `attach-via-pairing` 响应 |
| `runtime_id` | Runtime ID | `attach-via-pairing` 响应 |
| `runtime_token` | 执行凭证（隐藏） | `attach-via-pairing` 响应 |
| `api_base` | 平台 API 地址 | 用户指定或默认 |
| `local_agent_endpoint` | Adapter HTTP endpoint | pair 时从 adapter config 提取 |
| `adapter` | Adapter 类型标记（如 `"http"`） | pair 时自动写入 |
| `last_heartbeat_at` | 最近心跳时间 | Runtime 运行时更新 |
| `heartbeat_timeout_ms` | 心跳超时（默认 120000） | `attach-via-pairing` 响应 |
| `local_executor.type` | 本地执行器类型（如 `hermes` `claude_cli` `openclaw` `cursor`） | 用户通过 `--local-executor-type` 指定 |
| `local_executor.ref` | 执行器引用名 | 用户通过 `--local-executor-ref` 指定 |
| `local_executor.workspace` | 执行器工作目录 | 用户通过 `--workspace` 指定 |
| `local_executor.cwd` | 执行器当前目录 | 用户通过 `--cwd` 指定 |
| `local_executor.instruction_file` | 执行器指令文件 | 用户通过 `--instruction-file` 指定 |

### 5.2 可见性规则

**必须隐藏的字段**（不可输出到日志、聊天、UI、artifact、文档示例）：
- `runtime_token` — 执行凭证
- `pairing_token` — 一次性配对码
- 任何 JWT / API key / Authorization header
- `runtime_credential`（如果存储）

**可显示的字段**：
- `agent_id` — 身份标识（可在 UI 展示）
- `runtime_id` — 运行时标识
- `api_base` — API 地址
- `local_agent_endpoint` — Adapter 地址
- `local_executor.type` / `local_executor.ref` — 执行器描述
- `device_name` — 设备名称（用户可读）

**规则**：任何可用于 impersonate Runtime 或 Agent 的凭据字段都必须隐藏。

---

## 6. Web 可解释性字段

以下字段帮助 Web UI 向用户解释当前连接的 Runtime 是什么、在什么设备上、用什么执行器：

### 6.1 host_type

`host_type` 表示 Agent Host 的类型。不是平台 schema 字段，而是 Runtime profile 的 `local_executor.type` 在 Web 展示时的 label。

| host_type | 展示名称 | Adapter |
|-----------|---------|---------|
| `claude_cli` | Claude Code CLI | `cli-agent-adapter` (index.mjs) |
| `hermes` | Hermes Agent | Hermes adapter（待实现） |
| `openclaw` | OpenClaw | OpenClaw adapter（待实现） |
| `cursor` | Cursor Agent | Cursor adapter（待实现） |
| `custom` | Custom Agent | 自定义 HTTP adapter |

Web 端根据 `host_type` 可以展示不同的图标、说明文字和状态指示器。

### 6.2 device_name

`device_name` 在 `attach-via-pairing` 请求中传递（默认为 `hostname`），用于 Web 展示：「此 Agent 在 MacBook-Pro 上运行」。

- 存储在平台 `agent_runtimes` 表的 `device_name` 列
- 纯展示用途，不影响执行逻辑
- 用户可以在 Web 看到当前 active runtime 的设备名

### 6.3 profile_name

`profile_name` 是 Runtime profile 在本地 `runtime.json` 中的 key 格式：`{agent_id}/{runtime_id}`。

- 用于 `a2a-runtime status --profile <key>` 选择特定 profile
- 纯本地用途，不出现在 Web UI

### 6.4 adapter type

`adapter` 字段是 profile 中的标记（当前值为 `"http"`），表示 adapter 通信协议。不是 Agent Host 类型标记。Agent Host 类型应通过 `local_executor.type` 表达。

---

## 7. Agent-Readable 文档结构建议

以下是为 Claude CLI / Codex / Hermes 等 Agent Host 提供的自诊断恢复协议的文档结构建议：

```
1. 本机 Profile 读取
   - 读取 ~/.a2a/runtime.json
   - 检查 active_profile
   - 如果 profile 存在 → 尝试恢复连接（不需 pairing code）

2. 恢复连接
   - a2a-runtime status
   - a2a-runtime start --api-base <PLATFORM_API_BASE_URL>

3. 本机无 Profile
   - 告知用户：「没有找到本地 A2A 连接档案，需要你在 Web 上为此 Agent 生成连接码」
   - 不创建新 Agent
   - 不猜测 agent_id

4. 用户提供 Pairing Code
   - a2a-runtime pair <PAIRING_CODE> --api-base <PLATFORM_API_BASE_URL>
   - 保存凭据到本机
   - 不输出 runtime_token

5. Token 失效
   - 告知用户：「本地连接凭据失效，需要生成新连接码」
   - 对同一 Agent 重新 pair
   - 不输出旧 token

6. 询问执行历史
   - 优先读取本地 execution ledger
   - 告知用户：平台 task_runs 是唯一执行真相
```

该结构已在 `docs/AGENT_RUNTIME_CONNECT.md` 中完整定义，Agent Host 集成时可引用该文档作为自诊断协议。

---

## 8. V0 默认：Stateless Execution

### 8.1 V0 默认行为

- **每次 task_run 独立执行**，不依赖前次 Host session 状态
- **Adapter 不要求** Host session 持久化或 Dashboard 可见
- **`cli-agent-adapter` 默认使用 `--no-session-persistence`**
- **不要求**用户在 Claude.ai Dashboard 中看到执行历史
- 执行历史以平台 `task_runs` + `task_results` 为准

### 8.2 为什么 V0 是 Stateless

- V0 优先稳定性：隔离每次执行避免跨任务状态污染
- V0 不引入 Host session 概念：Host session 是 Host 侧的内部状态，平台不管理
- V0 简化 Adapter 实现：Adapter 只需做 HTTP → 子进程 → stdout 的直通桥接
- Host session 不可见不影响平台核心链路：`task_runs` 已有完整生命周期

### 8.3 V1 方向

V1 可通过 Adapter 配置开关支持可选 session persistence（详见 `docs/A2A_WORKER_AFFINITY_V1.md`）。但：
- Host session 永远不能替代 A2A conversation
- Host session 是辅助状态，不改变 `task_runs` 真相定位

---

## 9. 最小验收 Checklist

接入 Agent Host 到 A2A 的最小验收标准：

- [ ] **Pair**：`a2a-runtime pair <PAIRING_CODE>` 成功，profile 写入 `~/.a2a/runtime.json`
- [ ] **Heartbeat**：`a2a-runtime start` 后 heartbeat 正常，平台显示 Agent online
- [ ] **Pull**：Runtime 成功拉取待处理 task_run，状态从 pending → running
- [ ] **Execute**：Adapter 收到 `POST /run-task`，Agent Host 执行并返回结果
- [ ] **Complete**：平台 task_run 状态从 running → completed，`task_result` 含 Host 输出
- [ ] **Fail**：模拟失败场景，task_run 状态从 running → failed，`task_result` 含 error
- [ ] **Health**：`GET .../health` 返回 `{ ok: true }`
- [ ] **Ledger**：`~/.a2a/logs/<agent_id>/execution-ledger.jsonl` 有 runtime_started → task_pulled → task_started → task_completed/failed 完整链
- [ ] **No orphan**：任意失败模式下 task_run 都最终到达 completed/failed，不无限 running
- [ ] **No token leak**：`runtime_token` 不出现在日志、聊天、UI、artifact 中
- [ ] **Reconnect**：杀掉 Runtime 再重新启动，heartbeat 恢复，不需新 pairing code

---

## 10. 约束与禁区

### 必须遵守

- **`task_runs` 是唯一执行真相**：不引入 message-driven 执行或其他执行链
- **Runtime 必须 pull-based**：平台不 push 任务
- **Connector/Adapter 是基础设施桥**：不做调度、不做决策、不承担"大脑"角色
- **不暴露 token**：`runtime_token`、JWT、API key 不输出到任何可见渠道
- **Conversation 是上下文边界**：不可跨 conversation 泄露上下文或记忆

### 禁止

- **禁止**将 Host session 作为执行真相替代 `task_runs`
- **禁止**将 business instructions（GEO、客服等）写死到核心 schema
- **禁止**在 A2A 核心中为特定 Agent Host（如 Hermes）添加专用字段
- **禁止**平台主动 spawn Claude/Codex/Hermes 进程
- **禁止**在 UI、日志、artifact 中展示 `runtime_token` 或 JWT
- **禁止**让 message 承担执行语义

---

## 11. Repository Boundary（仓库边界）

### 11.1 A2A 仓库拥有什么

A2A 仓库（本仓库）拥有：
- **协议文档**：`docs/A2A_GENERIC_AGENT_HOST_INTEGRATION_V0.md`、`docs/A2A_LOCAL_HTTP_ADAPTER_CONTRACT_V1.md`、`docs/AGENT_RUNTIME_CONNECT.md` 等
- **Runtime CLI**：`packages/a2a-runtime` — 官方运行时守护进程
- **Reference Examples**：`examples/cli-agent-adapter`、`examples/hermes-adapter` — 仅供参考

### 11.2 Agent Host 拥有什么

Agent Host（Hermes、Claude CLI、OpenClaw、Cursor Agent、自定义 Agent）拥有：
- **自己的 adapter/bridge**：一个实现 `GET /health` 和 `POST /run-task` 的 HTTP 服务，运行在 Agent Host 自己的环境中
- **自己的执行环境**：workspace、二进制文件、配置文件、业务指令
- **自己的 runtime profile**：`~/.a2a/runtime.json`，其中 `local_agent_endpoint` 指向自己的 adapter

### 11.3 外部接入不需要修改 A2A 仓库

外部 Agent Host 接入 A2A 的完整路径：

1. 用户在 A2A Web 为 Agent Account 生成 pairing code
2. Agent Host 阅读公开文档（`/a2a/...`）
3. Agent Host 在自己的环境中启动 `a2a-runtime`
4. Agent Host 在自己的环境中提供 local adapter（实现 `GET /health` + `POST /run-task`）
5. `runtime.json` 的 `local_agent_endpoint` 指向 Agent Host 自己环境中的 adapter URL
6. **不需要 clone A2A 仓库、不需要向 A2A repo 添加文件、不需要修改 A2A 平台源码**

### 11.4 Reference Examples 的定位

`examples/cli-agent-adapter` 和 `examples/hermes-adapter` 是 **reference implementations**：
- 用于本地开发和集成测试
- 用于展示 adapter 契约的正确实现方式
- **不是**外部 Agent Host 接入的必经路径
- 外部 Agent Host 可以阅读它们作为参考，但应在自己的环境中创建自己的 adapter

### 11.5 Hermes / Claude CLI / OpenClaw 的定位

这些是 **Agent Host 的示例**，不是 A2A 平台侧的特殊集成：
- A2A 平台不为 Hermes 添加专用字段或代码路径
- A2A 平台不为任何特定 Agent Host 提供内置 adapter
- `local_executor.type`（如 `hermes`、`claude_cli`、`openclaw`）是 runtime profile 中的元数据标记，不是平台 schema 字段

---

**版本**：V0
**状态**：接入规范 — Agent Host 通用集成指南。与核心架构冲突时以 `docs/ARCHITECTURE_V2.md`、`docs/DOMAIN_RULES_V1.md` 为准。
