dsh-superagent 源码分析:Trigger、Ticket、Policy 与 Subscription

作者
DeepSeekAgent.io 编辑部
发布
更新

dsh-superagent-prototype 最值得研究的部分,不是又封装了一层 Sub-agent,而是它为长期运行的 Agent 建立了清楚的领域模型。消息、权限、任务、执行和恢复都对应持久化概念,模型只在需要语义判断的环节参与。

本文沿着一条事件从进入系统到完成工作的路径,解释 Source、Trigger、Thread、Eval、Policy、Mandate、Ticket、Assignment 与 Subscription 如何配合。

Source:事件从哪里进入

Source 是事件流的实现与配置实例。公开原型包含 GitHub Source,并支持可选飞书 Source。Source 负责:

  • 记录读取位置,避免重启后重放旧事件;
  • 把外部消息转换成不可变 Trigger;
  • 判断哪些 Trigger 属于同一个 Thread;
  • 保存回复所需的 Channel 地址;
  • 丢弃 Agent 自己产生的消息和不在监听范围的事件。

因此,Source 不只是一个 Webhook。它负责外部系统和内部领域模型之间的边界。

Trigger 与 Thread:事件和上下文分开

Trigger 是一条不可变事件,包含 Source 提供的 actor 和元数据。Thread 是按时间排序的 Trigger 集合,例如一个 GitHub Issue、一条 Pull Request 评审线程或一个飞书话题。

一个 Trigger 可以关联多个 Thread,但关联关系只增加上下文,不直接授予权限。这个区分很重要:看到相关消息,不等于 Agent 获得了执行新任务的授权。

Eval:是否应该创建工作

没有被现有 Ticket 拥有的 Trigger 会进入 Eval。Eval 分成两层:

  1. Gate 使用确定性规则检查发送者、@ 状态、allowed list、Source 范围和 admission table;
  2. Assessment 使用模型判断推断型候选是否符合启用的主动规则。

Eval 输出 Decision,例如 accept、stop、ignore 或 unavailable。显式请求可以直接路由;主动发现的候选必须经过规则判断。默认 observe 模式会记录“本来会接受”,但不会真正创建任务。

Policy 与 Mandate:谁授权了什么

Policy 包含 Source 的 allowed list、admission table、机器人列表、主动规则和 accept mode。每次变化形成新的 Policy version。

当 Decision 接受工作时,系统创建 Mandate,记录:

  • 使用的 Policy version;
  • 请求来源与发送者;
  • explicit 或 inferred 强度;
  • 允许完成的 scope;
  • 命中的主动规则。

Mandate 是 Ticket 的授权依据。Worker 收到后可以在 scope 内继续处理后续消息,但不能因为某条评论提到另一个任务,就自动扩大权限。

Ticket:持久任务,而不是一次模型调用

Ticket 是一项获得授权的工作。它可以经历多次 Assignment,保持自己的 Channel、Input、Subscription 和 Decision 引用。Executor 失败、重启或被替换时,Ticket 不会跟着消失。

Ticket 状态和 Session 状态也被刻意分开。一个 Ticket 可以等待人工回复、等待评审、结束后被后续人类消息恢复,或在新的 Assignment 中继续执行。这样,任务生命周期不会被某一次模型请求绑死。

Assignment 与 Executor:谁在这一轮执行

Assignment 把 Ticket 绑定到一个 Executor 实例。每个 Ticket 有独立 Worker Session 和目录。一次重试会结束当前 Assignment,并在同一 Ticket、目录、分支和 Pull Request 上创建新的 Assignment。

Worker 报告 progress、waiting、ready、blocked、failed 或 dropped。Pull Request 是否仍开放、是否收到人工后续消息、是否有未读 Input,都会影响 Ticket 是否真正结束。

Subscription:让后续事件回到正确任务

Subscription 是 Ticket 与 Thread 的多对多关系。一个 Ticket 订阅 Issue 和自己创建的 Pull Request 后,后续评论、CI 结果和评审就会作为上下文送回 Worker。

Subscription 不会产生新授权。消息可以提供上下文,但 Worker 仍受原 Mandate 限制。超出 scope 的人类请求会被“交还”给 Router,重新进入 Eval,而不是被当前 Worker 顺手执行。

结束的 Ticket 可以保留 Subscription。相关 Thread 中的人类追问能够恢复任务;机器人消息和 CI 不会自动唤醒已经结束的 Ticket。这让系统既能持续跟进,又不会被自动事件无限复活。

为什么这个模型适合长期 Agent

传统 Agent 常把所有状态放进对话历史:模型记得就继续,压缩或重启后就可能丢失。dsh-superagent 把关键状态放进结构化记录:

  • Source 保存外部读取位置;
  • Trigger 保存原始事件;
  • Decision 保存为什么接受或忽略;
  • Mandate 保存授权边界;
  • Ticket 保存工作生命周期;
  • Assignment 保存每次执行;
  • Subscription 保存后续路由关系。

模型负责语义判断和工作执行,Host 负责幂等、权限和恢复。Super-agent 的“持续性”来自这层结构,而不是依赖无限长上下文。

一条 GitHub Issue 的完整路径

GitHub comment
  → Source records Trigger
  → Thread groups Issue context
  → Gate checks sender and mention
  → Eval produces accept Decision
  → Mandate records scope and Policy version
  → Ticket is created
  → Assignment starts an Executor Session
  → Worker prepares directory and opens PR
  → Ticket subscribes to PR Thread
  → review and CI Triggers return to the same Ticket
  → PR closes and Ticket ends
  → later human follow-up may resume it

这条路径也是源码阅读的最佳顺序:先读 001-domain.md,再看 002-authorization.md 和 003-execution.md,最后进入具体 Source、存储和面板代码。

相关阅读

参考资料