回应 HM 驾驶舱(heicode-mananger #28/#45/#46)经 agent_swarm#14(runtime-contract)
+ #15(event-schema)提出的消费需求。HM 只读查询已落地(HM PR #53),唯一前置是本
仓契约冻结。本 PR 把回调契约冻结为 v1 并落代码 + 测试。
代码(orchestrator/):
- swarm_runtime.emit_event:回调 envelope 新增 **per-swarm 严格递增 `sequence`**
(INCR 计数键 swarm_event_seq:{swarm_id},从 1、无空洞,供客户端 events?after= 去重/续传)。
- 新增冻结的客户端 13 类事件(FROZEN_CLIENT_EVENT_TYPES)中此前缺的 6 类,均**附加**发出
(不动既有 deployment.status_changed,HM 仍用其更新 AgentDeployment.Status):
· swarm.completed/failed(refresh_swarm_run_status 终态)、swarm.stopped(stop_run);
· approval.approved/rejected(record_approval_decision 决定落地);
· handoff.created(child 任务建立时)。
- artifact.created envelope 补扁平字段:created_at(默认 occurred_at)、task_id(回填)、
size_bytes 透传(未知则省略,不伪造,规则 #9)。
- redis_client 新增原子 incr(真实 + 两处 fake stub)。
文档(docs/integration/,FROZEN v1):
- event-schema.md:envelope sequence、artifact 扁平字段、事件注册表标注 ⭐13 类 + 新增 6 类、
对齐状态更新(title/threshold_pct/sequence/artifact 已在 emit 统一处理)。
- runtime-contract.md:冻结 stop 端点 + ID 映射;§4.1 新增**状态机映射表**——运行时不臆造
preparing/degraded/verifying(规则 #9),由 HM/客户端按表映射真实状态
(blocked→degraded、评审期→verifying 等);终态另发 swarm.* 事件。
测试:
- 新增 scripts/test-contract-freeze.py(hermetic):sequence 单调/每-swarm/无空洞、13 类
round-trip、artifact 形状(含未知 size 不伪造)、approval.*/swarm.stopped 真实发出、
明文凭据脱敏而 azkv secret_ref 透传。接入 CI + CLAUDE.md 提交前清单。
- test-workflow-e2e.py:全流程 e2e 额外断言 swarm.completed + sequence 无空洞。
- 两处 FakeRedis stub 补 incr。
影响范围:仅 agent_swarm(orchestrator + docs/integration + 测试 + CI + CLAUDE.md)。
- Manager:回调**新增** sequence 字段与 6 类事件——向后兼容(旧消费方忽略新字段/新类型即可);
HM 注册表需登记新 6 类方能对外暴露(agent_swarm#15.2,已在 doc 列为剩余项)。
- 计费/审计:不涉及(查询面不计费由 HM 保证;本仓未改计费/审计字段)。
- 密钥:envelope 不含明文凭据;secret_ref 仍为 azkv 引用,HM 对客户端再脱敏。
Refs #2
Refs #14
Refs #15
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8.0 KiB
Swarm 运行时事件 Schema(回调 / 事件流)
状态:FROZEN v1(契约冻结) —— 回应
agent_swarm#15(来自 HM #28/#45/#46 客户端「任务驾驶舱」消费需求)。本文是 Swarm → HM 回调与GET …/{id}/events事件流的统一 schema,已对齐 HM 实现(heicode-mananger/heicode/controller/agent_callback.go,handlerPOST /api/agent/callbacks/runtime-events)。冻结要点(实现见
orchestrator/swarm_runtime.py,契约测试scripts/test-contract-freeze.py):
- envelope 带 per-swarm 严格递增
sequence(从 1、无空洞,供客户端events?after=去重/续传,§2)。- 客户端 13 类事件(§4 标 ⭐)冻结为
FROZEN_CLIENT_EVENT_TYPES(swarm_runtime.py)。- artifact 扁平字段
{uri, checksum, task_id, size_bytes?, created_at}(§3)。- 凭据红线:
secret_ref/credential_ref/signing_secret_ref为azkv://引用(非明文),Swarm 侧_redact_sensitive透传引用、剔除明文*_token/_secret/_key/password;客户端可见视图由 HM 再做递归脱敏。配套:生命周期与签名见
runtime-contract.md。
1. 传输与鉴权
- Swarm → HM:
POST {callback.url}(create 时下发)。 - 鉴权二选一:服务令牌
X-Agent-Service-Token(或Authorization: Bearer),或 HMAC 签名。 - HMAC 签名(已实现,与 HM 一致):
- 头:
X-Agent-Timestamp(Unix 毫秒)、X-Agent-Signature、X-Agent-Event-Id、X-Correlation-ID(均含X-Agnet-兼容别名)。 - 规范串:
canonical = f"{timestamp}.{event_id}.{raw_body}"。 - 签名:
X-Agent-Signature = "sha256=" + hex(HMAC_SHA256(secret, canonical))。 - secret:
AGENT_CALLBACK_SIGNING_SECRET(兼容AGNET_…,支持…_REF的azkv://解析)。 - 时间容差:HM 默认 300s(
AGENT_CALLBACK_SIGNATURE_TOLERANCE_SECONDS)。
- 头:
- 幂等去重:HM 依次按
X-Agent-Event-Id头 → bodyevent_id→idempotency_key。重复返回{inserted:false, idempotent:true, deduplicated:true}。
2. 事件 Envelope
{
"event_id": "evt-...", // 必填;去重主键
"idempotency_key": "...", // 可选;缺省回退 event_id
"sequence": 12, // 必填;per-swarm 严格递增(从 1、无空洞);客户端按此去重/升序/续传
"event_type": "task.completed", // 必填;取值见 §4
"deployment_id": "runtime-dep-...",// 运行时部署 ID
"swarm_id": "swarm-...", // 工作流 ID(事件按此持久化)
"agent_instance_id": "...", // Agent 实例/角色实例 ID(可选)
"task_id": "...", // 任务相关事件填
"occurred_at": "2026-06-08T...Z", // 事件时间
"correlation_id": "corr-...", // 追踪 ID(X-Correlation-ID)
"source": "heicode-swarm-runtime", // 事件来源标识
"metadata": { }, // 自定义元数据(不得含明文密钥)
"payload": { }, // 事件专属字段(见 §4)
"artifact": { } // 可选;见 §3
}
3. Artifact 子对象(artifact.created 及完成事件可带)
{
"artifact_id": "art_...",
"artifact_type": "code_patch | document | deployment_manifest",
"title": "...",
"summary": "...",
"uri": "git://repo#branch | runtime://...", // 仅 uri,绝不含 secret_ref/凭据
"checksum": "<commit_sha>",
"task_id": "...", // 缺省回填 envelope.task_id(#15.4)
"size_bytes": 1234, // 可选;未知则省略(不伪造,规则 #9)
"created_at": "2026-06-08T...Z", // 缺省回填 envelope.occurred_at
"metadata": { "redacted": true, "agent_role": "...", "files_modified": [] }
}
客户端 artifact 视图(HM #28)取扁平
{uri, checksum, task_id, size_bytes?, created_at};HM 由artifact.createdenvelope 的上述字段直接产出,无secret_ref/密钥。
4. 事件类型注册表(与 HM 一致)
⭐ = 冻结的客户端 13 类(FROZEN_CLIENT_EVENT_TYPES,驾驶舱据此渲染;HM agent_callback.go 据此对齐注册表)。其余为 Swarm 也发的辅助/运行时事件(HM 仍消费,但非客户端必需)。
| event_type | payload 必填字段(HM 校验) | 分类 | Swarm 是否发出 |
|---|---|---|---|
⭐ task.created |
task_id, title |
swarm_task_flow | ✅ |
⭐ task.claimed |
task_id, agent_role |
swarm_task_flow | ✅ |
⭐ task.running |
task_id, agent_role |
swarm_task_flow | ✅ |
⭐ task.completed |
task_id |
swarm_task_flow | ✅ |
⭐ task.failed |
task_id, reason |
swarm_task_flow | ✅ |
⭐ handoff.created |
task_id, from_role, to_role |
swarm_task_flow | ✅(child 任务建立时,与 handoff.requested 并发) |
⭐ approval.requested |
approval_id, operation, risk_level |
approval | ✅ |
⭐ approval.approved |
approval_id |
approval | ✅(审批决定落地时) |
⭐ approval.rejected |
approval_id |
approval | ✅(审批决定落地时) |
⭐ artifact.created |
artifact_id, uri, checksum |
artifact | ✅(带 §3 扁平字段) |
⭐ swarm.completed |
status |
swarm_terminal | ✅(终态,与 deployment.status_changed 并发) |
⭐ swarm.failed |
status |
swarm_terminal | ✅(终态) |
⭐ swarm.stopped |
status |
swarm_terminal | ✅(stop_run) |
deployment.status_changed |
status |
deployment | ✅(HM 用于 AgentDeployment.Status;客户端用 swarm.* 终态) |
task.heartbeat |
task_id, agent_role |
swarm_task_flow | ✅ |
task.blocked |
task_id, reason |
swarm_task_flow | ✅ |
task.retried |
task_id, attempt |
swarm_task_flow | ✅ |
task.released |
task_id, agent_role |
swarm_task_flow | ✅ |
handoff.requested |
task_id, from_role, to_role |
swarm_task_flow | ✅ |
timeline.updated |
title |
timeline | ✅(emit 时回填 title=summary) |
budget.alert |
threshold_pct |
budget | ✅(emit 时回填 threshold_pct) |
phase.changed / agent.* / sk_tool.* |
— | ordinary_sub / sk | ❌(本运行时不产生) |
说明:评审/重做循环复用
task.retried+timeline.updated(Review cycle N)表达,无单独 review 事件类型;蜂群内部遥测(提案/竞价/交叉评审/收敛/health)不经回调外发(见各协议文档「事件不进 Manager 流」),故不在本表。swarm.completed/failed/stopped与approval.approved/rejected、handoff.created为本次冻结新增,HM 注册表需据此登记(agent_swarm#15.2)。
5. HM 响应
{ "success": true, "event_id": "evt-...", "inserted": true, "idempotent": false, "deduplicated": false, "deployment_id": "dep_..." }
6. 对齐状态(冻结时已修正 / 剩余小项)
冻结时 orchestrator/swarm_runtime.emit_event 已统一处理下列历史缺口:
- ✅
timeline.updated:emit 时若缺title自动回填(复用summary)。 - ✅
budget.alert:emit 时若缺threshold_pct由threshold自动换算(≤1 视为比例 ×100)。 - ✅
sequence:每事件带 per-swarm 严格递增序号(INCR 计数键swarm_event_seq:{swarm_id})。 - ✅ artifact 扁平字段:
created_at/task_id自动回填,size_bytes透传(未知则省略,不伪造)。
剩余小项(不影响客户端 13 类冻结):
handoff.completed的from_role/to_role:辅助事件,客户端 13 类用handoff.created(已带 from/to);如 HM 仍消费handoff.completed,在 handoff 完成处补两字段为后续小修。
契约由
scripts/test-contract-freeze.py守护(断言 sequence 单调、13 类 round-trip、artifact 形状、审批/停止真实发出、明文凭据脱敏);scripts/test-workflow-e2e.py在全流程 e2e 中额外断言swarm.completed+ sequence 无空洞。