Cell Protocol v1(M4c)
Coordinator ↔ cell worker。TCP NDJSON,一行请求/一行响应。 与
wire-protocol.md(flow 级)不同:这里是 agent cell 级,worker 持有 cell 状态。
1. 传输
- TCP;coordinator 主动连接;一个连接一个请求。
- 请求/响应各一行 UTF-8 JSON +
\n。 - 超时:15s(cluster demo)/ 2s(测试)。
- 无 TLS;共享 token 鉴权。
2. Envelope / Outbound
type Envelope = {
run: string; // run id;与 id 一起做 dedupe
id: u64; // coordinator 单调递增
channel: string; // "<from>:<port>",per-edge 通道
seq: u64; // per-channel 单调序号
capability: string; // target cell 的 capability
from: string; // cell id 或 "input"
to: string; // target cell id
port: string; // sender port name
message: Message; // { tag, payload, from? }
};
type Outbound = {
from: string;
port: string;
to?: string | null; // null = terminal output
message: Message;
};
3. Request
type CellRequest =
| { type: "ping"; token?: string }
| { type: "spawn"; token?: string; cell: AgentState; capability: string }
| { type: "deliver"; token?: string; envelope: Envelope }
| { type: "snapshot"; token?: string; cell: string; capability: string }
| { type: "remove"; token?: string; cell: string; capability: string }
| { type: "set_capability"; token?: string; cell: string; capability: string }
| { type: "stats"; token?: string };
4. Response
type CellResponse =
| { type: "pong"; node: string; version: 1 }
| { type: "spawned"; node: string }
| { type: "ack"; node: string; id: u64; duplicate: bool;
state: AgentState; sends: Outbound[]; usage: Usage }
| { type: "snapshot"; node: string; cell: AgentState }
| { type: "removed"; node: string }
| { type: "stats"; node: string; cells: u64; deliveries: u64;
failures: u64; uptime_secs: u64 }
| { type: "error"; node: string; error: string };
5. 语义
deliver
- 若
envelope.id已在 workerseen集合 →ack { duplicate: true, sends: [], usage: 0 }。 - 取
tocell,调用 behavior;更新 state。 - 若 action 有 effect:worker 本地执行 EffectBus,usage 累加;把
Message("effect", output)再交给同一 cell(最多 8 轮)。 - action.send 经
cell.ports解析为Outbound.to;null表示终端输出。 - 返回
ack { state, sends, usage }。
spawn / snapshot / remove
spawn:插入AgentState;behavior kind 必须已知。snapshot:返回 cell 当前状态(迁移用)。remove:删除 cell。- 迁移:
snapshot(source)→spawn(target)→remove(source)→ 更新 placement。
dedupe / at-least-once
id由 coordinator 唯一分配;worker 丢弃重复。- 失败重试可能重复投递;
id相同则不会重复执行。 - 但 effect 本身可能已执行(at-least-once),需要 effect idempotency key 才能 exactly-once(M4d)。
5.1 per-edge 通道与 capability(M4d)
- worker 按
(run, channel)维护last_seq:seq == last+1接受;seq <= last返回duplicate:true;seq > last+1返回错误(gap)。
capability在spawn时绑定到 cell;deliver/snapshot/remove必须匹配。set_capability用于撤销/轮换;旧 capability 立即失效。- 有
--secret时 capability 是v1:<run>:<epoch>:<hmac>(HMAC-SHA256),worker 在 spawn 时校验 MAC;无 secret 时退回run-cell-seq字符串。 revoke增加 epoch,旧 capability 立即失效。- mTLS 仍未实现;TCP 明文,依赖共享 token + 受信网络。
5.2 effect 幂等缓存
- worker 以
run:cell:op:input_hash缓存 effect output。 - 同输入再次出现(不同 envelope id)不重复调用 handler,不计费。
- 缓存是 per-worker;跨节点 failover 后丢失(需要持久化幂等键)。
6. 错误
unauthorized:token 不匹配。unknown cell/unknown behavior/ effect 错误。- coordinator 对传输错误执行 failover:用
last_states在存活节点重新 spawn。
7. 限制
- 无 mTLS / capability per cell。
- 无背压;coordinator 队列无界。
- 无 worker 自动心跳/再入;
kill/healthy_nodes手动。 - 无持久化 dedupe;worker 重启后
seen丢失。 - cell 状态快照只在 coordinator 的 last-ack;没有 WAL。
7.1 队列与持久化
- coordinator
with_queue_limit(n)提供 admission control(超限Backpressure)。 - effect cache 是 per-worker 内存;worker 重启/failover 后丢失。
- audit hash = sha256(events),
--save-audit落盘。
8. 版本
version: 1(pong.version)。- 测试:
crates/ain-cluster/tests/cluster.rs。