委派子 Run 的 Actor 传播
wesgine 在 Agent 委派(delegate_task)子 Run 时,必须正确传播 Actor 身份,确保子 Run 的记忆写入、观测记录和资源归因都属于正确的人。
问题背景
委派时 internal/agent/tool.go 创建子 Run 的参数:
pp := RunParams{
Actor: tc.Actor, // ★ 一等字段
Tags: map[string]string{
"actor": tc.Actor, // ★ 审计标签同步
},
// ...
}
历史缺陷:曾经只写 Tags["actor"] 而不写 pp.Actor,导致每个委派子 Run 都是无主的——其记忆写入因 RequireActor 静默失败,其 Run 记录在 actor 收口后对创建者不可见。
两处都写
tool.go 必须把 tc.Actor 同时写进两个位置:
pp.Actor:RunParams 一等字段,引擎所有子系统读这里pp.Tags["actor"]:审计标签,观测面用tags.actor做归属查询
继承兜底
runner.go 在构建子 Run 时有继承逻辑:
如果 childParams.Actor 为空
→ 从 parentParams.Actor 继承
这是防御性兜底,不是设计意图——正确的路径是 tool.go 直接写入。
无主 Run 的后果
子 Run 无 Actor 时:
| 子系统 | 后果 |
|---|---|
| 记忆 | RequireActor 拒绝写入,子 Run 的认知发现不持久化 |
| 观测 | Run 记录无 owner,RunVisible(owner, actor) 判定为不可见 |
| Session | 子 Run 会话无归属,其他 actor 可能看到也可能看不到 |
| Token 归因 | 用量无法归到正确的人 |
INV-OBS-10 裁决:"不知道是谁的"读作隐藏,不是"大家的"。
与 Cron 的类比
Cron executeJob 把 entry.Actor 抄进 JobRequest,job 以所有者身份跑。委派子 Run 同理——不传 Actor 就是以空身份执行代码。
不变量
- 子 Run 的 Actor 来源是父 Run 的
tc.Actor(ToolContext) Tags["actor"]与Actor字段必须一致- 无主子 Run 在 INV-OBS-10 下不可见
相关文档
- Run Actor 传播 →
run-actor-propagation.md - 委派系统 →
delegation.md - 观测面 Actor 边界 →
observe-boundary.md - Cron 执行身份边界 →
cron-boundary.md