Files
Agentswarm/CLIENT_GUIDE.md
T
Songhaoz666andClaude Opus 4.8 0cbab3f750 模型 key 注入对接:定死 HM #60 参数(KV value JSON + per-user 吊销握手)(Refs #16 #60)
回应 HM「#60 落地前需 Swarm 定死的参数清单」。Swarm 侧逐条定死并落实现:

- A.2 KV secret value 格式:JSON {"openai_api_key":"sk-..."}(对齐 callback 签名密钥
  约定),解析字段 openai_api_key;裸 sk- 串兼容;解析不到/字段缺失不伪造。实现
  agent_launcher._extract_model_key + _resolve_secret_ref。
- A.5 吊销信号(事件驱动):sk- per-user 长存;stop 为唯一终态(completed/failed 经
  …/input 可重开故保 key)。某用户全部 run 被 stop(retained 集清空)时,运行时发
  恰好一次 swarm.pool_terminated{user_id, secret_ref},HM 据此吊销 sk- + 清 KV。
  单 run swarm.stopped 不触发吊销。实现 swarm_runtime.retain_run_for_user /
  release_run_and_maybe_terminate_pool(per-user retained 集 + 一次性 flag)。
- A.1 粒度:每用户一把、跨 run 复用;KV 命名 swarm-model-key-<user_id>(文档)。
- A.4 OPENAI_API_BASE:Swarm 部署常量(已实现),不经 create 下发(文档确认)。
- A.3 KV 读 RBAC:⚠ 待定(联调阻塞前置)——如实标注归属未敲定,不伪造已就绪。
- B.1:CLIENT_GUIDE §9 /events 游标改 after=<next_after>(HM 不透明游标,非 sequence)。

swarm.pool_terminated 为 HM 控制面生命周期事件,不入 FROZEN_CLIENT_EVENT_TYPES、
不渲染驾驶舱;payload secret_ref 为 azkv:// 引用(非明文 key)。

文档:runtime-contract §3.3.1(参数表)、event-schema(注册 + 说明)、
security-boundary §6(吊销握手 + RBAC 待定)。测试 scripts/test-key-injection-contract.py
(KV 格式解析 + 吊销握手:单 run/多 run 保留/不重复吊销/teardown 后重新武装)+ CI 步。

不动 Manager 面接口、HMAC 回调、审批链、计费/审计字段语义。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 17:57:15 +08:00

189 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 客户端接入指南(Client Guide)
本文说明**客户端如何与 Agent Swarm 运行时交互**。系统总览见 [README.md](README.md);接口契约见 [docs/integration/runtime-contract.md](docs/integration/runtime-contract.md);事件结构见 [docs/integration/event-schema.md](docs/integration/event-schema.md)。
> 架构说明:生产链路中,终端用户通过 **Heicode Manager / 桌面客户端** 提交需求,由 Manager 调用本 Swarm 运行时(见 `heicode-swarm-deferred` 裁定)。「客户端」在本文指**调用 Swarm 运行时 REST API 的一方**(Manager、联调脚本或开发者)。Swarm 不在对话回路,通过**带签名回调**回报状态。
---
## 1. 两个交互面
1. **REST API(客户端 → Swarm)**:创建部署、查询状态/任务/日志/事件/指标、审批、停止。
2. **回调事件流(Swarm → 客户端/Manager)**:生命周期事件经带 HMAC 签名的回调推送(见 §6)。
WebSocket `/ws/{agent_id}` 仅供 **Agent 执行单元** 接入,**不是客户端接口**。
---
## 2. 鉴权
- 客户端调用带 `Authorization: Bearer <token>`,Swarm 校验 `AGENT_RUNTIME_SERVICE_TOKEN`(兼容 `AGNET_RUNTIME_SERVICE_TOKEN`)。
- 未配置令牌时为**非安全开发模式**(不校验,仅本地)。
- 常用请求头:`X-Correlation-ID`(贯穿追踪)、`X-Idempotency-Key`(创建幂等)。
- 响应信封:成功 `{ "success": true, "data": {...} }`;失败 `{ "success": false, "error": {code,message,request_id} }`。
---
## 3. 生命周期:创建 → 观察 →(追加输入)→(审批)→ 取结果 → 停止
### 3.1 创建部署
`POST /api/swarms`(别名 `/api/agent/swarm/deployments`、`/api/agnet/deployments`)
```bash
curl -s -X POST http://<host>:8000/api/swarms \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-H "X-Correlation-ID: corr-123" \
-H "X-Idempotency-Key: idem-123" \
-d '{
"mode": "swarm",
"requirement": { "objective": "实现 add(a,b) 并补充测试与说明" },
"callback": { "url": "https://your-manager/api/agent/callbacks/runtime-events", "subscribed_events": [] },
"metadata": { "manager_deployment_id": "dep-1" }
}'
```
必填:`requirement.objective`(或 `orchestration_plan.objective`)、`callback.url`、`metadata.manager_deployment_id`。
响应 `data`:`deployment_id`、`runtime_deployment_id`、`swarm_id`(=workflow_id)、`manager_deployment_id`、`mode`、`status`、`created`。**请保存 `deployment_id`** 用于后续查询。
### 3.2 观察
| 接口 | 用途 |
|---|---|
| `GET /api/swarms/{deployment_id}` | 部署状态概要 |
| `GET /api/swarms/{deployment_id}/workflow` | 工作流/阶段视图(phases、agents、tokens、tools、artifacts、summary) |
| `GET /api/swarms/{deployment_id}/tasks` | 任务 DAG(task_id、agent_role、status、depends_on…) |
| `GET /api/swarms/{deployment_id}/logs`(`/events`) | 事件流,分页 `?limit=&cursor=`(断线后用 cursor 回补) |
| `GET /api/swarms/{deployment_id}/metrics` | 任务/Agent/预算指标 |
| `GET /api/swarms/{deployment_id}/diagnostics` | 失败、回调尝试、审批诊断 |
| `GET /api/swarms/{deployment_id}/result` | **结果**:`{summary, deliverable, artifacts[], termination_reason, status}`(见 §3.6) |
| `GET /api/swarms/{deployment_id}/audit` | 可回放审计/链路(谁/何模型/何工具/何审批,脱敏) |
状态机:`waiting_approval → running → (blocked ⇄ running) → completed | failed | stopped`。
### 3.3 审批(高危操作)
当部署进入 `waiting_approval` 并推送 `approval.requested` 时,客户端经 Manager 审批后回执:
```bash
curl -s -X POST http://<host>:8000/api/swarms/<deployment_id>/approvals/<approval_id> \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{ "decision": "approved" }' # 或 "rejected",可带 credential_ref / reason
```
### 3.4 停止
```bash
curl -s -X POST http://<host>:8000/api/swarms/<deployment_id>/stop \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{ "reason": "client requested stop" }'
```
### 3.5 追加输入(用户后续 prompt,运行中/已完成均可续)
用户在驾驶舱继续补充要求时调用。指令被注入为 `source=user_append` 的新任务进入共享池,agent 自选执行;若 run 已 `completed`/`failed` 会**自动 reopen 为 running**(「继续」语义),`stopped` 的 run 会被拒绝(请另起新 run)。
```bash
curl -s -X POST http://<host>:8000/api/swarms/<deployment_id>/input \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{ "instruction": "再补一个 subtract(a,b) 并加测试" }'
```
响应 `data`:`task_id`、`status`、`reopened`。**红线**:指令原文仅作任务描述下发给执行 agent,**绝不回显进事件流**——事件流只产一条 `task.created`(`source=user_append`,类别 message,无原文)。
### 3.6 取结果
run 进入终态(推送 `swarm.completed`,其 payload 已带 `summary`+`deliverable`)后,或任意时刻拉取聚合结果:
```bash
curl -s http://<host>:8000/api/swarms/<deployment_id>/result -H "Authorization: Bearer $TOKEN"
```
响应 `data`:`summary`(综述)、`deliverable`(`{has_deliverable, commit_sha, files_modified, artifact_ids, …}`)、`artifacts[]`(`{uri, checksum, …}`)、`termination_reason`、`status`。**产物内容**(代码等)在各 artifact 的 `uri`(如 `git://repo#branch`)——`result` 给的是摘要 + 定位,内容按 uri 取。
---
## 4. 健康检查
- `GET /` → `{status, service}`;`GET /health` → 含 Redis 与连接数;`GET /metrics` → Prometheus。
---
## 5. 工作流(去中心化蜂群 —— 唯一行为,无开关)
本仓**即蜂群运行时**,模式选择(single/chain/sub/swarm)在仓外;**没有「启用 swarm」开关**。下述流程**无条件生效**(cutover 已完成):编排器**播种**单一目标种子任务 → Agent 感知共享池**自选**(信息素 τ + 能力/负载/预算)→ 经 `task_proposal` **自底向上自主分解**(#7)→ 经 `task_bid`/`yield`/`takeover` **竞争/接管**(#8)→ **同伴交叉评审**(≥2 评审者,#11)→ **收敛**(产出 `termination_reason`,#12),最后 `master_agent.synthesize` 汇总。**已删除**:Master/planner 自顶向下分解兜底、单 critic 主控评审环及其 `ENABLE_PLANNER_FALLBACK` / `ENABLE_REVIEW_LOOP` 等开关。
- `MAX_REVIEW_CYCLES`(默认 2):交叉评审/重做的轮次预算(保留)。
- `MAX_AGENTS_PER_USER`(默认 10):每用户并发连接的 Agent 上限(见 security-boundary §6)。
- 仅剩的能力开关:`ENABLE_QUALITY_EVAL` + `HEICODE_SANDBOX_ISOLATED`(代码沙箱评分,见 security-boundary §8.1)、`ENABLE_SUBTASK_HANDOFF`(agent 侧子任务移交)。
- **Agent 拉起 + 限额由 Swarm 运行时负责**(team 决议,runtime-contract §3.3):编排器在 create 播种后由 `agent_launcher` 拉起能力多样的 agent 池(拉起数 `= min(AGENT_LAUNCH_POOL_SIZE, MAX_AGENTS_PER_USER − 已连)`;后端 `AGENT_LAUNCH_BACKEND` = none/subprocess/command)。AM 不再拉蜂群 agent。
- 模型走 HM 模型网关(OpenAI 兼容 `/v1`):`OPENAI_API_KEY` = 该用户 per-user `sk-`(NewAPI token),`OPENAI_API_BASE` = HM `/v1`。**由 Swarm 从 `billing_context.secret_ref`(`azkv://`) 服务端解析**后注入被拉起 agent 的进程 env(**不入 create 请求 / 回调 / 日志 / argv**)。模型调用**扣发起用户 `user.Quota`**、按 token 名归集;HM 侧只需 mint `sk-` → 写 KV → 传 `secret_ref` → 吊销。详见 [usage-billing-schema.md §2](docs/integration/usage-billing-schema.md)。
---
## 6. 回调事件流(Swarm → 客户端/Manager)
Swarm 向 `callback.url` POST 事件,**带 HMAC 签名**(客户端须验签):
- 头:`X-Agent-Timestamp`(ms)、`X-Agent-Signature`、`X-Agent-Event-Id`、`X-Correlation-ID`(+ `X-Agnet-` 兼容别名)。
- 签名:`sha256=hex(HMAC_SHA256(secret, "{timestamp}.{event_id}.{raw_body}"))`,secret = `AGENT_CALLBACK_SIGNING_SECRET`,时间容差 300s。
- 幂等:按 `X-Agent-Event-Id` → body `event_id` → `idempotency_key` 去重。
- 事件类型与必填字段:见 [event-schema.md](docs/integration/event-schema.md)(`deployment.status_changed`、`task.*`、`handoff.*`、`approval.requested`、`artifact.created`、`timeline.updated`、`budget.alert`…)。
客户端可只消费 REST(轮询 `/workflow`+`/logs?cursor=`),或同时接收回调。
---
## 7. 本地联调(无需密钥)
```bash
# 1) 编排器(内存存储;蜂群流程无条件生效,无需开关)
set "REDIS_FAKE=1" & set "MAX_REVIEW_CYCLES=2"
python -m uvicorn orchestrator.main:app --host 0.0.0.0 --port 8000
# 2) 无密钥桩 Agent(联调用)
set "ORCHESTRATOR_URL=ws://localhost:8000" & set "AGENT_ID=stub-1" & set "AGENT_CAPABILITIES=python,code_generation,testing,pytest,technical-writing,general"
python scripts/stub_agent.py
# 3) 用 §3.1 的 curl 提交需求,再用 §3.2 观察
```
---
## 8. 说明与边界
- **桌面/前端 UI**:当前桌面客户端为单 Agent A2A 直连模型;**蜂群图 / 协作时间线**的前端事件 API 尚未冻结(见 [frontend-event-api.md](docs/integration/frontend-event-api.md))。
- **不得在请求/回调/日志中出现明文密钥**;凭据一律 `secret_ref`(`azkv://`)。见 [security-boundary.md](docs/integration/security-boundary.md)。
- **计费主线**:Agent 模型调用走 HM `/v1`,用 **HM 为该用户现签的 per-user `sk-`** 作 `OPENAI_API_KEY`,**扣发起用户 `user.Quota`**;NewAPI 是账本、按请求计量,**Swarm 不是账本、仅上报用量**(随模型请求带 `X-Agent-*` 归因头)。归因主轴 = `user.id`/`channelId`,不引入 tenant。见 [usage-billing-schema.md §1/§2](docs/integration/usage-billing-schema.md)。
---
## 9. 完整工作流地图(client → swarm → output → client)
端到端调用模型(生产链路:终端用户 → HM 控制面/查询面 → Swarm 执行面;Swarm 不在对话回路):
```
[终端用户] 在桌面客户端提交需求
│ 设备配对签名鉴权
▼
[HM Heicode Manager] 控制面 + 查询面
│ ① mint per-user sk- → 写 Azure Key Vault
│ ② POST /api/agent/swarm/deployments (service token)
│ body: requirement.objective(=用户 prompt) + callback.url + metadata.manager_deployment_id
│ + billing_context.secret_ref=azkv://.../<sk-name> (key 仅引用,不传明文)
▼
[Swarm 编排器 orchestrator] 执行面(本仓)
│ ③ 播种单一种子任务(objective) —— 接收「初始 prompt」
│ ④ agent_launcher 拉起 per-user agent 池(≤ MAX_AGENTS_PER_USER);
│ 从 secret_ref 解析 sk- 注入 agent env(OPENAI_API_KEY/BASE/ORCHESTRATOR_URL/...)
▼
[专家 Agent ×N] 主动出站连 WS /ws/{agent_id},register(user_id) → 受每用户限额
│ ⑤ 自选种子 → 自主分解(#7) → 竞争/接管(#8) → 执行(调 HM /v1 模型,扣发起用户 Quota)
│ → 同伴交叉评审(#11) → 收敛(#12) → master_agent.synthesize 汇总
│ 每步经编排器 emit_event → 带签名回调 POST 到 HM callback.url(task.*/handoff.created/
│ approval.*/artifact.created/review.*/rework.*/swarm.*,每条带 per-swarm 严格递增 sequence)
▼
[HM 查询面/回调摄入] 持久化事件 + 透传 sequence
▼
[桌面客户端] ⑥ 经 HM 拉取/SSE:GET /{id}(状态)、/events?after=<next_after>(事件流;游标为 HM 不透明分页游标 next_after,非 per-swarm sequence——sequence 仅客户端去重/排序)、
/tasks(DAG)、/workflow、/metrics、/audit、**/result**(综述+deliverable+artifacts)
终态事件 swarm.completed 已直接带 summary+deliverable
追加输入(运行中或已完成续):客户端 → HM → POST /{id}/input {instruction}
→ 注入 user_append 任务(终态自动 reopen)→ 回 ⑤ 继续;原文不进事件流
停止:客户端 → HM → POST /{id}/stop → 取消任务 + 发 swarm.stopped + 拆除已拉起 agent
```
**要点**:
- **客户端不直连 Swarm / 不直连 agent**:读写都经 HM(鉴权/计费/审计在 HM;Swarm 运行时私网、service-token;agent 无公网子域,仅出站连编排器)。
- **输入**:初始 prompt = create 的 `requirement.objective`;后续 prompt = `POST /{id}/input`(#40)。
- **输出**:`summary`(synthesize 综述)+ `deliverable`(git 分支/commit/文件 + artifact_ids)+ `artifacts[].uri`(内容定位);经 `swarm.completed` 事件与 `GET /{id}/result` 两条路拿到。
- **密钥**:HM mint sk-→写 KV→传 `secret_ref`;Swarm 服务端解析注入 agent;全程不入 create 体/回调/日志/argv。