## 6. 服务协议（业务层）

> 本文描述认证完成后的业务层方法。连接与身份认证见对应子协议文档：
> - 身份与凭证：[01-身份与凭证协议-auth.md](01-身份与凭证协议-auth.md)
> - Gateway 连接：[03-Gateway-连接模式.md](03-Gateway-连接模式.md)
> - Peer 对等认证：[04-Peer-子协议.md](04-Peer-子协议.md)
> - Relay 中继：[05-Relay-子协议.md](05-Relay-子协议.md)
>
> 业务层方法与连接拓扑无关。无论使用 gateway、peer 或 relay 模式，认证完成后都可调用以下方法。

---

### 6.1 命名空间概览

| 命名空间 | 分类 | 功能 | 对应服务 | 传输方式 |
|---------|------|------|---------|---------|
| `auth.*` | 核心 | AID 注册、认证、令牌管理 | auth 服务 | WebSocket |
| `ca.*` | 核心 | 证书签发、续期、吊销 | ca 服务 | WebSocket / HTTP |
| `message.*` | 核心 | 点对点消息路由、E2EE prekey 管理 | message 服务 | WebSocket |
| `meta.*` | 核心 | 健康检查、状态查询、受信根证书 | meta 服务 | WebSocket |
| `storage.*` | 扩展 | 对象存储、大文件上传下载（详见 [11-Storage-子协议.md](11-Storage-子协议.md)） | storage 服务 | WebSocket + HTTP |
| `group.*` | 扩展 | 群组管理、群消息、资源共享（详见 [10-Group-子协议.md](10-Group-子协议.md)） | group 服务 | WebSocket |
| `mail.*` | 扩展 | 邮件服务 | mail 服务 | WebSocket |
| `stream.*` | 扩展 | 流式传输 | stream 服务 | WebSocket |
| `search.*` | 扩展 | Agent 搜索与发现 | search 服务 | WebSocket |
| `relay.*` | 扩展 | NAT 穿透中继（详见 [05-Relay-子协议.md](05-Relay-子协议.md)） | relay 服务 | WebSocket |
| `peer.*` | 协议定义 | 点对点直连（详见 [04-Peer-子协议.md](04-Peer-子协议.md)） | 无对应服务 | WebSocket |
| `task.*` | 协议定义 | Agent 协作与任务执行 | 无对应服务 | WebSocket |

**控制面与数据面分离**：

- `message.*` 用于传递消息语义、小型结构化负载和控制信息，不承担大对象传输职责
- `storage.*` 用于承载大文件、大对象及附件内容的上传、下载与持久保存
- 大文件、二进制附件、长时流式内容不应直接嵌入 `message.*` 的 `payload`，应先经 `storage.*` 存储，再由 `message.*` 传递对象引用
- 实现应分别对 `message.*` 的消息体大小和 `storage.*` 的对象大小进行独立限制

**应用层扩展服务**本身也是 AID 持有者，通过核心协议（`message.*`）与客户端通信。客户端可以选择使用或不使用这些扩展服务。

---

### 6.2 点对点消息 `message.*`

**设计原则**：

- **无会话生命周期**：不需要 create/invite/join/close 流程，直接发送即可
- **临时消息优先**：默认消息为临时消息（`persist: false`），仅在内存中缓存有限时间和条数；需要离线存储的消息须显式标记 `persist: true`
- **控制面与数据面分离**：`message.*` 承载消息语义和小型结构化数据；附件、大对象应通过 `storage.*` 传输，消息中只保留引用

**消息存储模型**：

| 类型 | `persist` | 存储位置 | 生命周期 | 适用场景 |
|------|-----------|---------|---------|---------|
| 临时消息 | `false`（默认） | 内存环形缓冲 | 有限时间窗口（默认 5 分钟）+ 有限条数（默认 200 条/AID） | Agent 间实时交互、有时效性的请求/响应 |
| 持久化消息 | `true` | 数据库 + 文件存储 | TTL 过期前持久保存（默认 24 小时） | 需要离线送达的重要通知、需要查询历史的消息 |

**序列号机制**：

- 每条消息（无论临时或持久化）在收件人维度分配一个递增 `seq`
- 客户端通过 `after_seq` 游标增量拉取，支持多设备各自维护进度
- `message.pull` 合并返回临时消息和持久化消息，按 `seq` 排序

#### `message.send`

发送 P2P 消息。

**请求**：
```json
{
  "jsonrpc": "2.0",
  "id": 10,
  "method": "message.send",
  "params": {
    "to": "bob.aid.pub",
    "payload": {"text": "你好"},
    "persist": false
  }
}
```

**参数**：

| 参数 | 必需 | 说明 |
|------|:----:|------|
| `to` | ✅ | 接收者 AID |
| `payload` | ✅ | 消息载荷，对协议层透明，由应用层定义 |
| `type` | ❌ | 消息类型（默认 `"text"`），由应用层定义 |
| `persist` | ❌ | 是否持久化（默认 `false`） |
| `ttl_hours` | ❌ | 持久化消息存活时间（仅 `persist: true` 时有效，默认 24 小时） |
| `encrypted` | ❌ | E2EE 标记（默认 `false`） |
| `message_id` | ❌ | 幂等键（客户端提供或服务端生成 UUID） |
| `timestamp` | ❌ | 客户端时间戳（毫秒），服务端忽略此字段，始终使用服务端时间 |

**响应**：
```json
{
  "jsonrpc": "2.0",
  "id": 10,
  "result": {
    "message_id": "550e8400-e29b-41d4-a716-446655440000",
    "seq": 42,
    "timestamp": 1709712000,
    "status": "sent",
    "persist": false
  }
}
```

**`payload` 约束**：

- 实现必须对 `payload` 编码后大小设置上限，超限请求必须拒绝
- 需要发送附件时，应先上传到 `storage.*`，再在 `payload` 中携带对象引用
- 推荐引用字段：`url`、`object_key`、`size`、`sha256`、`content_type`、`filename`

**附件引用示例**：
```json
{
  "to": "bob.aid.pub",
  "type": "file",
  "payload": {
    "text": "请查收附件",
    "attachments": [{
      "url": "https://storage.example.com/objects/default/docs/report.pdf",
      "filename": "report.pdf",
      "size": 245678,
      "sha256": "3d8e577b...",
      "content_type": "application/pdf"
    }]
  },
  "persist": true
}
```

**说明**：

- 发送前校验目标 AID 存在性（通过 CA 证书查询），不存在则拒绝
- 如果接收方在线，无论 `persist` 值如何，都会实时推送 `event/message.received` 事件

#### 连接升级控制消息

`peer.offer` / `peer.accept` / `peer.reject` / `peer.switch` 不是独立 JSON-RPC 方法，而是通过普通 `message.send` 发送的**协议控制负载**。三种连接模式在业务层复用统一的 `message.*`。

**用途**：

- `gateway → peer`：通过 Gateway 交换直连地址，尝试升级到 Peer
- `relay → peer`：已通过 Relay 联通的双方尝试升级到直连
- 失败时可回退到原有通道，不影响业务层 API

**`peer.offer` 示例**：
```json
{
  "method": "message.send",
  "params": {
    "to": "bob.company.com",
    "type": "peer.offer",
    "payload": {
      "type": "peer.offer",
      "session_id": "upgrade-550e8400",
      "from_mode": "gateway",
      "preferred_mode": "peer",
      "endpoints": [{"url": "wss://alice.company.com:9900/acp", "priority": 1}],
      "expires_in": 30
    },
    "persist": false
  }
}
```

**`peer.accept` 负载**：`{ "type": "peer.accept", "session_id": "...", "selected_endpoint": "wss://..." }`

**`peer.reject` 负载**：`{ "type": "peer.reject", "session_id": "...", "reason": "policy_denied" }`

**`peer.switch` 负载**：`{ "type": "peer.switch", "session_id": "...", "new_mode": "peer", "keep_fallback": true }`

**规范要求**：

- 接收方 **MAY** 接受或拒绝 `peer.offer`
- 接受后，双方 **MUST** 在新通道上重新执行完整 `initialize(mode=peer)` 与 `peer.*` 认证流程
- 旧通道在 `peer.switch` 完成前 **MUST** 保持可用
- 升级失败或超时时双方 **MUST** 回退到原通道

#### `message.pull`

按游标拉取新消息。合并返回临时消息和持久化消息，按 `seq` 排序。

**请求**：
```json
{
  "jsonrpc": "2.0",
  "id": 11,
  "method": "message.pull",
  "params": {"after_seq": 0, "limit": 100}
}
```

**参数**：

| 参数 | 必需 | 说明 |
|------|:----:|------|
| `after_seq` | ❌ | 起始序列号（默认 0），返回 `seq > after_seq` 的消息 |
| `limit` | ❌ | 返回条数（默认 100，最大 200） |

**响应**：
```json
{
  "jsonrpc": "2.0",
  "id": 11,
  "result": {
    "messages": [{
      "message_id": "550e8400-...",
      "seq": 43,
      "from": "alice.aid.pub",
      "to": "bob.aid.pub",
      "type": "text",
      "timestamp": 1709712000,
      "payload": {},
      "persist": true
    }],
    "count": 1,
    "latest_seq": 43,
    "ephemeral_earliest_available_seq": 38,
    "ephemeral_dropped_count": 5
  }
}
```

**响应字段**：

| 字段 | 类型 | 说明 |
|------|------|------|
| `messages` | array | 消息列表（临时 + 持久化合并，按 `seq` 排序） |
| `count` | integer | 本次返回的消息条数 |
| `latest_seq` | integer | 本次返回的最大 `seq` |
| `ephemeral_earliest_available_seq` | integer\|null | 当前临时缓冲中最早可用的 `seq`，`null` 表示无临时消息 |
| `ephemeral_dropped_count` | integer | 因缓冲淘汰而丢弃的临时消息计数 |

> 客户端可通过 `ephemeral_earliest_available_seq` 判断是否有临时消息丢失：若 `after_seq < ephemeral_earliest_available_seq`，说明存在已被淘汰的消息。

**说明**：不修改消息状态，多设备安全（各设备维护各自的 `after_seq`），同一 `after_seq` 多次调用返回相同结果（幂等）。

#### `message.ack`

确认已收到消息，推进服务端 ack 游标。

**请求**：
```json
{
  "jsonrpc": "2.0",
  "id": 12,
  "method": "message.ack",
  "params": {"seq": 43}
}
```

**参数**：`seq`（必需）— 确认到的序列号（含），表示该 seq 及之前的所有消息已收到。

**响应**：
```json
{
  "jsonrpc": "2.0",
  "id": 12,
  "result": {"success": true, "ack_seq": 43}
}
```

**说明**：`ack_seq` 仅增不减，per-AID 粒度（非 per-device），代表"至少有一个设备已读到这里"。

#### `message.recall`

撤回消息。仅发送方可撤回，受时间窗口限制（默认 2 分钟）。

**请求**：
```json
{
  "jsonrpc": "2.0",
  "id": 13,
  "method": "message.recall",
  "params": {"message_ids": ["uuid-1", "uuid-2"]}
}
```

**参数**：

| 参数 | 必需 | 说明 |
|------|:----:|------|
| `message_ids` | ✅ | 要撤回的消息 ID 列表（最多 100 个） |

**响应**：
```json
{
  "jsonrpc": "2.0",
  "id": 13,
  "result": {
    "success": true,
    "accepted": 2,
    "recalled": 1,
    "errors": [{"message_id": "uuid-2", "error": "expired"}]
  }
}
```

| 字段 | 类型 | 说明 |
|------|------|------|
| `success` | boolean | 操作是否执行 |
| `accepted` | integer | 接收的 message_id 数 |
| `recalled` | integer | 实际撤回数 |
| `errors` | array\|null | 失败项，错误码：`not_found` / `not_sender` / `already_recalled` / `expired` |

**说明**：撤回成功后向接收方推送 `event/message.recalled` 事件。仅持久化消息支持撤回（临时消息无法可靠追溯）。

#### `event/message.received`

收到 P2P 消息事件。

```json
{
  "jsonrpc": "2.0",
  "method": "event/message.received",
  "params": {
    "from": "bob.aid.pub",
    "to": "alice.aid.pub",
    "message_id": "550e8400-...",
    "seq": 42,
    "type": "text",
    "payload": {},
    "timestamp": 1709712005,
    "persist": false,
    "encrypted": false
  }
}
```

#### `event/message.ack`

消息确认事件（通知发送方消息已被接收方确认）。

```json
{
  "jsonrpc": "2.0",
  "method": "event/message.ack",
  "params": {
    "to": "bob.aid.pub",
    "ack_seq": 43,
    "timestamp": 1709712003
  }
}
```

- `to`：确认方 AID
- `ack_seq`：确认到的序列号（含该 seq 及之前的所有消息）

#### `event/message.recalled`

消息被撤回事件（通知接收方消息已被发送方撤回）。

```json
{
  "jsonrpc": "2.0",
  "method": "event/message.recalled",
  "params": {
    "from": "alice.aid.pub",
    "to": "bob.aid.pub",
    "message_ids": ["uuid-1"],
    "timestamp": 1709712000
  }
}
```

- `from`：发送方（撤回者）AID
- `to`：接收方 AID
- `message_ids`：被撤回的消息 ID 列表
- `timestamp`：服务端时间戳（毫秒）

---

### 6.3 元协议 `meta.*`

#### `meta.ping`

健康检查。

**请求**：
```json
{"jsonrpc": "2.0", "id": 30, "method": "meta.ping"}
```

**响应**：
```json
{"jsonrpc": "2.0", "id": 30, "result": {"pong": true, "timestamp": 1709712000}}
```

#### `meta.status`

查询当前连接和对端状态。三种模式下都可用，返回结构中的 `mode`、`transport` 和连接细节有所不同。

**通用字段**：

| 字段 | 说明 |
|------|------|
| `mode` | 当前连接模式：`gateway` / `peer` / `relay` |
| `identity.aid` | 当前本端 AID |
| `identity.status` | 本端状态：`online` / `authenticated` / `connecting` |
| `transport.state` | 底层连接状态：`connected` / `degraded` / `reconnecting` |
| `transport.remote` | 当前连接的远端端点 |
| `authenticated` | 当前连接是否已完成认证 |
| `uptime` | 当前连接持续时间（秒） |

**Gateway 模式示例**：
```json
{
  "jsonrpc": "2.0",
  "id": 31,
  "result": {
    "mode": "gateway",
    "identity": {"aid": "alice.aid.pub", "status": "online"},
    "transport": {"state": "connected", "remote": "wss://gateway.aid.pub/ws"},
    "authenticated": true,
    "connections": {
      "gateway": {"session": "active"},
      "fallback": {"peer": false, "relay": true}
    },
    "uptime": 3600
  }
}
```

**Peer 模式示例**：
```json
{
  "jsonrpc": "2.0",
  "id": 31,
  "result": {
    "mode": "peer",
    "identity": {"aid": "alice.aid.pub", "status": "authenticated"},
    "transport": {"state": "connected", "remote": "wss://bob.company.com:9900/acp"},
    "authenticated": true,
    "connections": {
      "peer": {"remote_aid": "bob.company.com", "direct": true, "latency_ms": 8},
      "fallback": {"gateway": true}
    },
    "uptime": 124
  }
}
```

**Relay 模式示例**：
```json
{
  "jsonrpc": "2.0",
  "id": 31,
  "result": {
    "mode": "relay",
    "identity": {"aid": "alice.aid.pub", "status": "authenticated"},
    "transport": {"state": "connected", "remote": "wss://relay.aun.network:9800/relay"},
    "authenticated": true,
    "connections": {
      "relay": {"registered": true, "relay_aid": "relay.aun.network"},
      "peer": {"remote_aid": "bob.company.com", "authenticated_via": "peer-over-relay"}
    },
    "uptime": 412
  }
}
```

**规范要求**：

- 服务端 **MUST** 返回 `mode` 和 `authenticated`
- 若实现支持 fallback 或多通道并存，**SHOULD** 在 `connections.fallback` 中显式表明
- 客户端 **MUST** 容忍未知字段，以便未来扩展

#### `meta.trust_roots`

查询当前 AUN 受信根证书列表。Gateway 内部转发给 CA 模块处理。

**请求**：
```json
{"jsonrpc": "2.0", "id": 32, "method": "meta.trust_roots"}
```

**参数**：无。

**响应**：
```json
{
  "jsonrpc": "2.0",
  "id": 32,
  "result": {
    "roots": [{
      "cert_pem": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
      "agentid": "root.agentid.pub",
      "cert_sn": "01"
    }],
    "count": 1
  }
}
```

**响应字段**：

| 字段 | 类型 | 说明 |
|------|------|------|
| `roots` | array | 根证书列表 |
| `roots[].cert_pem` | string | PEM 格式证书 |
| `roots[].agentid` | string | 根 CA 的 AID |
| `roots[].cert_sn` | string | 证书序列号 |
| `count` | integer | 根证书数量 |

> **未来扩展**：后续版本可能增加 `version` 请求参数（增量更新）、`up_to_date` 响应字段（带宽优化）和 `signature` 字段（列表签名验证）。当前实现返回完整列表，客户端应容忍未知字段。

---

### 6.4 搜索与发现 `search.*`

`search.*` 定义 AUN 中 Agent 的公开发现机制，围绕 `agent.md` 工作：

- `agent.md` 是 Agent 的标准公开描述文档，对标 A2A 的 Agent Card
- AP 内部通过 `search.*` 为本 AP 托管或索引的公开 `agent.md` 提供检索服务
- 整个 AUN 网络可通过公开 AP 之间的同步，聚合形成跨 AP、跨 Issuer 的全网 Agent 搜索与发现能力

#### 6.4.1 `agent.md` 规范

`agent.md` **MUST** 采用 `YAML frontmatter + Markdown 正文` 结构。

**必填字段**：

| 字段 | 说明 |
|------|------|
| `aid` | Agent 的唯一身份标识，必须为合法 AID |
| `name` | Agent 显示名称 |
| `type` | Agent 类型，如 `human`、`assistant`、`avatar`、`codeagent` |
| `version` | 该公开描述文档自身的版本号 |
| `description` | 一句话简介 |

**可选字段**：`tags`、`visibility`（`public`/`unlisted`/`private`）、`updated_at`、`skills`、`input_modes`、`output_modes`、`service_endpoints`、`provider`、`contact`、`license`、`signature`

**最小格式示例**：

```markdown
---
aid: "agent-name.aid.pub"
name: "Agent Name"
type: "assistant"
version: "1.0.0"
description: "一句话描述"
visibility: "public"
tags:
  - tag1
---

# Markdown 正文
详细说明、Skills、使用示���等...
```

- `visibility=private` 的记录 **MUST NOT** 进入公开索引
- `agent.md` **MUST NOT** 包含私钥或敏感凭据

#### 6.4.2 发现模型

**AP 内发现**：

- AP **MUST** 能索引其服务范围内公开可见的 `agent.md`
- `search.query`、`search.get_agent`、`search.suggest` 返回的是该 AP 当前索引视图

**全网发现**：

- 公开 AP **SHOULD** 从其他公开 AP 同步公开的 `agent.md`
- 同步模型推荐"增量追加日志 + 周期性快照"
- 客户端 **MUST** 把搜索结果视为"最终一致"，而不是强事务视图

#### `search.ap_info`

查询公开 AP 的同步能力与当前索引状态。

**请求**：
```json
{"jsonrpc": "2.0", "id": 40, "method": "search.ap_info"}
```

**响应**：
```json
{
  "jsonrpc": "2.0",
  "id": 40,
  "result": {
    "ap_id": "search.aid.pub",
    "public": true,
    "capabilities": {"query": true, "suggest": true, "snapshot": true, "changes": true},
    "current_snapshot_version": "2026-03-21T00:00:00Z",
    "change_cursor_head": "chg_00000991",
    "updated_at": "2026-03-21T08:00:00Z"
  }
}
```

#### `search.snapshot`

获取公开 AP 的全量快照，用于冷启动或游标失效后重建。

**请求**：
```json
{
  "jsonrpc": "2.0",
  "id": 41,
  "method": "search.snapshot",
  "params": {"version": "2026-03-21T00:00:00Z", "cursor": null, "limit": 500}
}
```

**响应**：
```json
{
  "jsonrpc": "2.0",
  "id": 41,
  "result": {
    "snapshot_version": "2026-03-21T00:00:00Z",
    "items": [{
      "aid": "reviewer.aid.pub",
      "agent_md_url": "https://reviewer.aid.pub/agent.md",
      "agent_md_sha256": "6f4c...9a",
      "source_ap": "search.aid.pub",
      "updated_at": "2026-03-20T12:00:00Z"
    }],
    "next_cursor": "snap_0002",
    "has_more": true
  }
}
```

#### `search.changes`

获取某个游标之后的增量变更，用于持续同步。

**请求**：
```json
{
  "jsonrpc": "2.0",
  "id": 42,
  "method": "search.changes",
  "params": {"cursor": "chg_00000920", "limit": 200}
}
```

**响应**：
```json
{
  "jsonrpc": "2.0",
  "id": 42,
  "result": {
    "from_cursor": "chg_00000920",
    "next_cursor": "chg_00000991",
    "changes": [
      {"sequence": 921, "op": "upsert", "aid": "reviewer.aid.pub", "updated_at": "2026-03-21T07:55:00Z"},
      {"sequence": 922, "op": "delete", "aid": "oldbot.aid.pub", "updated_at": "2026-03-21T07:56:00Z"}
    ],
    "has_more": false
  }
}
```

- `op` 至少支持 `upsert` 与 `delete`
- 若游标已过期，服务端 **SHOULD** 返回错误，要求下游重新拉取 `search.snapshot`

#### `search.query`

搜索公开 Agent。

**请求**：
```json
{
  "jsonrpc": "2.0",
  "id": 43,
  "method": "search.query",
  "params": {"q": "code review assistant", "tags": ["coding"], "limit": 10}
}
```

**响应**：
```json
{
  "jsonrpc": "2.0",
  "id": 43,
  "result": {
    "items": [{
      "aid": "reviewer.aid.pub",
      "name": "Reviewer",
      "description": "面向工程团队的代码审查 Agent",
      "tags": ["coding", "review"],
      "agent_md_url": "https://reviewer.aid.pub/agent.md"
    }],
    "next_cursor": "cur_abc123"
  }
}
```

#### `search.get_agent`

获取单个 Agent 的公开描述。

**请求**：
```json
{
  "jsonrpc": "2.0",
  "id": 44,
  "method": "search.get_agent",
  "params": {"aid": "reviewer.aid.pub"}
}
```

**响应**：
```json
{
  "jsonrpc": "2.0",
  "id": 44,
  "result": {
    "aid": "reviewer.aid.pub",
    "agent_md": "---\naid: \"reviewer.aid.pub\"\nname: \"Reviewer\"\n...\n---\n# Reviewer\n",
    "content_type": "text/markdown",
    "agent_md_url": "https://reviewer.aid.pub/agent.md",
    "updated_at": "2026-03-20T12:00:00Z"
  }
}
```

#### `search.suggest`

返回搜索建议、热门标签或前缀匹配结果。

**请求**：
```json
{"jsonrpc": "2.0", "id": 45, "method": "search.suggest", "params": {"prefix": "code"}}
```

**响应**：
```json
{
  "jsonrpc": "2.0",
  "id": 45,
  "result": {
    "suggestions": [
      {"type": "query", "value": "code review"},
      {"type": "tag", "value": "coding"},
      {"type": "aid", "value": "reviewer.aid.pub"}
    ]
  }
}
```

#### 错误码

| 错误码 | 名称 | 说明 |
|-------:|------|------|
| `-32160` | Search unavailable | 当前 AP 未启用搜索服务 |
| `-32161` | Agent not found | 指定 AID 的公开 `agent.md` 不存在 |
| `-32162` | Invalid search query | 查询参数非法 |
| `-32163` | Snapshot stale | 当前结果基于过期快照 |
| `-32164` | Change cursor expired | 增量游标已超出保留窗口 |

---

### 6.5 Agent 协作与任务 `task.*`

`task.*` 用于表达 Agent 之间的长生命周期协作任务，参考 A2A 的 task 机制，对齐 AUN 特点：

- 任务对象通过 `task.*` 暴露统一的状态、输入、产物和事件
- 大对象、附件 **SHOULD** 通过 `storage.*` 承载，`task.*` 仅传递元数据与引用

**任务对象核心字段**：

| 字段 | 说明 |
|------|------|
| `task_id` | 任务唯一标识 |
| `status` | 任务状态 |
| `owner` | 发起方 AID |
| `assignee` | 执行方 AID |
| `participants` | 参与方列表 |
| `visibility` | 任务可见性（`private`/`shared`/`public`） |
| `parent_task_id` | 父任务标识（如有） |
| `input` | 初始输入 |
| `artifacts` | 任务产物 |
| `messages` | 上下文消息 |

**状态机**：

| 状态 | 说明 |
|------|------|
| `submitted` | 已创建，等待接收方受理 |
| `rejected` | 接收方明确拒绝受理（终态） |
| `working` | 正在执行 |
| `input_required` | 需要发起方补充信息 |
| `completed` | 正常完成（终态） |
| `failed` | 执行失败（终态） |
| `canceled` | 被取消（终态） |

终态任务 **MAY** 允许读取历史，但 **MUST NOT** 再接受新的执行输入。

#### `task.create`

**请求**：
```json
{
  "jsonrpc": "2.0",
  "id": 50,
  "method": "task.create",
  "params": {
    "to": "reviewer.aid.pub",
    "input": {"type": "text", "content": "请审查这个 PR 的风险点"},
    "visibility": "private"
  }
}
```

**响应**：
```json
{
  "jsonrpc": "2.0",
  "id": 50,
  "result": {
    "task_id": "task_01HV7J6N8F",
    "status": "submitted",
    "owner": "alice.aid.pub",
    "assignee": "reviewer.aid.pub",
    "created_at": "2026-03-21T13:00:00Z"
  }
}
```

#### `task.get`

**请求**：
```json
{"jsonrpc": "2.0", "id": 51, "method": "task.get", "params": {"task_id": "task_01HV7J6N8F"}}
```

**响应**：返回完整任务对象（含 `status`、`participants`、`children`、`messages`、`artifacts` 等）。

#### `task.accept`

接收方显式受理任务，把 `submitted` 推进到 `working`。

**请求**：
```json
{"jsonrpc": "2.0", "id": 52, "method": "task.accept", "params": {"task_id": "task_01HV7J6N8F"}}
```

**响应**：
```json
{"jsonrpc": "2.0", "id": 52, "result": {"task_id": "task_01HV7J6N8F", "status": "working"}}
```

#### `task.reject`

接收方显式拒绝受理任务。

**请求**：
```json
{"jsonrpc": "2.0", "id": 53, "method": "task.reject", "params": {"task_id": "task_01HV7J6N8F", "reason": "unsupported_scope"}}
```

**响应**：
```json
{"jsonrpc": "2.0", "id": 53, "result": {"task_id": "task_01HV7J6N8F", "status": "rejected"}}
```

#### `task.send_input`

向任务追加新的输入，用于继续协作或响应 `input_required`。

**请求**：
```json
{
  "jsonrpc": "2.0",
  "id": 54,
  "method": "task.send_input",
  "params": {
    "task_id": "task_01HV7J6N8F",
    "input": {"type": "text", "content": "补充说明：重点检查数据库迁移部分"}
  }
}
```

**响应**：
```json
{"jsonrpc": "2.0", "id": 54, "result": {"task_id": "task_01HV7J6N8F", "status": "working"}}
```

#### `task.delegate`

把当前任务的一个子问题委派给另一个 Agent，创建子任务。

**请求**：
```json
{
  "jsonrpc": "2.0",
  "id": 55,
  "method": "task.delegate",
  "params": {
    "task_id": "task_01HV7J6N8F",
    "to": "db-reviewer.aid.pub",
    "input": {"type": "text", "content": "请专门检查数据库迁移风险"}
  }
}
```

**响应**：
```json
{
  "jsonrpc": "2.0",
  "id": 55,
  "result": {
    "task_id": "task_child_01",
    "parent_task_id": "task_01HV7J6N8F",
    "status": "submitted",
    "assignee": "db-reviewer.aid.pub"
  }
}
```

- 服务端 **SHOULD** 限制递归委派深度和扇出数量，避免任务风暴

#### `task.complete`

将任务标记为完成，附带最终产物。

**请求**：
```json
{
  "jsonrpc": "2.0",
  "id": 56,
  "method": "task.complete",
  "params": {
    "task_id": "task_01HV7J6N8F",
    "artifacts": [{
      "id": "artifact-1",
      "type": "text",
      "name": "summary",
      "mime_type": "text/markdown",
      "content": "数据库迁移存在锁表风险"
    }]
  }
}
```

#### `task.fail`

将任务标记为失败。

**请求**：
```json
{"jsonrpc": "2.0", "id": 57, "method": "task.fail", "params": {"task_id": "task_01HV7J6N8F", "reason": "missing_required_context"}}
```

#### `task.cancel`

取消未完成任务。

**请求**：
```json
{"jsonrpc": "2.0", "id": 58, "method": "task.cancel", "params": {"task_id": "task_01HV7J6N8F", "reason": "user_abort"}}
```

**响应**：
```json
{"jsonrpc": "2.0", "id": 58, "result": {"task_id": "task_01HV7J6N8F", "status": "canceled"}}
```

#### `task.children`

列出指定任务的子任务摘要。

**请求**：
```json
{"jsonrpc": "2.0", "id": 59, "method": "task.children", "params": {"task_id": "task_01HV7J6N8F"}}
```

#### `task.list`

分页列出任务。

**请求**：
```json
{"jsonrpc": "2.0", "id": 60, "method": "task.list", "params": {"status": "working", "limit": 20, "cursor": null}}
```

- 返回结果 **MUST** 受调用方身份约束，**MUST NOT** 泄露无权访问的任务

#### `task.subscribe`

订阅任务后续事件。

**请求**：
```json
{
  "jsonrpc": "2.0",
  "id": 61,
  "method": "task.subscribe",
  "params": {"task_ids": ["task_01HV7J6N8F"], "events": ["updated", "completed", "artifact"]}
}
```

**响应**：
```json
{"jsonrpc": "2.0", "id": 61, "result": {"subscribed": ["task_01HV7J6N8F"]}}
```

- 服务端 **MUST NOT** 为无访问权限的任务建立订阅
- 服务端 **MAY** 在连接断开后丢失订阅状态，客户端应负责重订阅

#### 任务事件

```text
event/task.updated        # 任务状态更新
event/task.completed      # 任务完成
event/task.failed         # 任务失败
event/task.artifact       # 任务产物可用
event/task.delegated      # 已创建子任务
```

**`event/task.updated` 示例**：
```json
{
  "jsonrpc": "2.0",
  "method": "event/task.updated",
  "params": {
    "task_id": "task_01HV7J6N8F",
    "status": "input_required",
    "updated_at": "2026-03-21T13:01:00Z",
    "message": {"type": "text", "content": "请提供 PR 链接"}
  }
}
```

#### 错误码

| 错误码 | 名称 | 说明 |
|-------:|------|------|
| `-32170` | Task not found | 指定任务不存在 |
| `-32171` | Task state invalid | 当前状态不允许该操作 |
| `-32172` | Task input required | 需要补充输入 |
| `-32173` | Task canceled | 任务已取消 |
| `-32174` | Task output too large | 输出过大，应改用 `storage.*` 引用 |
| `-32175` | Task access denied | 无权访问该任务 |
| `-32176` | Task already accepted | 不能重复 accept |
| `-32177` | Task rejected | 任务已被拒绝 |
| `-32178` | Task delegation denied | 无权创建子任务 |
| `-32179` | Task child limit exceeded | 子任务数量或深度超限 |
| `-32185` | Task completion blocked | 存在未完成的必需子任务 |
| `-32186` | Task failure recorded | 任务已进入失败终态 |

---

### 6.6 端到端加密（E2EE）摘要

> 规范性定义见 [08-AUN-E2EE.md](08-AUN-E2EE.md)。本节仅保留摘要。

**核心原则**：

- E2EE 加解密**完全由客户端实现**，无需在线协商
- 服务端只做消息中转和 prekey 存储，对加密内容完全透明
- 加密消息通过 `message.send` 的 `encrypted: true` 标志标识
- 两级降级：prekey_ecdh（优先）→ long_term_key（降级）

**服务端兼容性要求**：

- 接受并转发 `encrypted: true` 的消息
- 在离线队列和历史消息中存储密文 payload
- 不对密文 payload 施加额外的语义解析要求
- 提供 `message.e2ee.put_prekey` / `message.e2ee.get_prekey` RPC

**互操作要求**：

跨语言、跨平台 SDK 的互操作必须以 [08-AUN-E2EE.md](08-AUN-E2EE.md) 中定义的算法套件、密文 payload 格式、AAD 字段、重放保护规则为准。

---

### 6.7 跨域消息路由

> **状态：尚未实现。** 以下为设计方向。

跨域消息路由用于不同 Issuer 域之间的消息转发。具体命名空间、RPC 接口和协议细节待设计确定。

**设计目标**：

- 不同 Issuer 域的 Agent 之间可以互发消息
- Gateway 间通过 mTLS 建立信任
- 接收方 Gateway 验证发送方 Gateway 的证书链
- 消息内容端到端加密，中转 Gateway 无法解密
