← 返回主页
dsh-superagent 文档

002 授权

002 Authorization
决定谁可以发起工作、这些工作可以包含什么。 GitHub 原文 ↗ 社区中文翻译 · 以原文为准

授权决定谁可以发起工作、以及这些工作可以包含什么。本文档建立在 001 领域模型之上。

由宿主执行允许列表、规则与 Mandate(授权)。消息、评论与被引用的文档只是决定的输入;它们不能改变这些权限。

Trigger 的两条路径

Eval:决定是否开始工作

Source 会记录一条消息是否指向 agent:提到 bot 或 agent 账号记为 mention,直接消息记为 direct。gate(准入)检查发送者与该 Source 的 Policy(策略):

  • 允许列表上的人指向 agent,构成一次 explicit(明确)请求。
  • 人在已有 Ticket(工单)的 Thread(线程)上的后续消息,遵循下文规则。
  • 其他人 messages 按其接收范围的准入表处理。
  • Source 的 bot 列表上的 bot 可以产生 inferred(推断)候选,永远不会构成 explicit 请求。其他 bot 不予准入。

Subscription:延续既有工作

已订阅 Thread 上的每一条消息都会作为上下文到达其订阅中的 Ticket,包括来自 bot 与 CI 的消息。这种送达绕过 gate,也不授予任何新权力。每个 Ticket 仍受其 Mandate 限制。

人的消息落在 Ticket 自己的 Thread 上时,由该 Ticket 的 Executor(执行器)决定。主 Session 把消息附到某个 Ticket 上时同理。在 Executor 拥有这条消息期间,它不走 Eval,也不会产生 Decision(决定)。每个 Executor 要么在其 Ticket 的 scope(范围)内处理该请求,要么把它交还,交由别处路由。

只要 Ticket 还活着,这种归属就一直持续,即使人删除了它的 Subscription。它也覆盖未被人为 stop(停止)、且有消息等待恢复的已结束 Ticket。

主 Session 会收到一条 follow-up(后续)通知。在 Executor 拥有该消息期间,主 Session 只能应人的要求停止工作;accept(接受)、attach(附加)、ignore(忽略)与重新排队都会被拒绝。stop 仍会经过 gate,并带有下文所述的 follow-up 强度。

交还与释放后续消息

当一条消息要求的工作超出 Ticket 的 scope、或属于另一个 Ticket 时,Executor 会把它交还一次。该 Ticket 保留其 Subscription。如果被附加的 Thread 与本 Ticket 无关,Executor 会交还它在那个 Thread 上拥有的消息。

一条消息只有在不再被任何 Ticket 拥有之后,才会进入一次全新的 Eval。其候选信息包含各 Executor 的交还理由。gate 把它当作该 Thread 上的一条普通消息来判定,主 Session 可以接受它、把它附加到别处,或忽略它。交还一条本不归该 Ticket 所有的消息(例如 bot 消息,或人已发给 Eval 的消息)不会排队任何内容。

Ticket 结束时,会释放其 Executor 未读取、未接手的后续消息。这包括从未送达 Executor 的消息,以及在其最后一次 Report(报告)或回合结束之后送达、且 Executor 既未确认、未回答、也未交还的消息。每条被释放的消息,在不再被其他 Ticket 拥有时进入 Eval。stop 只结束被停止的那个 Ticket 自身的工作。

被 stop 的 Ticket 不会再次把它的 stop 消息发给 Eval,除非别的 Ticket 把它交还。执行 stop 的主 Session 可以把该消息的其余部分当作新工作接受。

人可以在面板上把一条被拥有的 follow-up 发给 Eval。如果主 Session 随后把它附加回某个活跃 Ticket,Executor 会再次收到它。当没有任何有效判定覆盖某条消息时,面板也提供重新评估入口。

仅作上下文的订阅

Executor 可以为获取上下文而跟随一个相关 Thread,例如另一个 Issue 或 pull request。这些 Thread 上的消息会到达 Ticket,但不授予任何权力或 follow-up 强度。人在那里的消息不会恢复已结束的 Ticket,除非主 Session 从该 Thread 附加了一条消息。主 Session 关于其他工作的备注同样只是上下文。

没有到达任何 Ticket 的人的消息——包括其 Ticket 已被人 stop 的 Thread 上的——走 Eval 路径。bot 消息独立于「是否送达已订阅 Ticket」同样走这条路径。

强度

强度情形
explicit(明确)列表上的人指向 agent,或在已有 Ticket 的 Thread 上发后续消息;准入表的某个格子设为 explicit request
inferred(推断)不在列表上的人在有 Ticket 的 Thread 上发后续消息(除非其准入表格子为 explicit);准入表格子设为 inferred candidate;bot 列表上的 bot 指向 agent 的消息、或发到 Source 接收全部消息之处
不予准入其他任何 bot 的消息;准入表忽略的一切;accept 模式为 off 期间的所有 inferred 情形

对不在列表上的人,即便在已有 Ticket 的 Thread 上,设为 explicit 的准入格子也优先,且在所有 accept 模式下都有效。否则其后续消息是 inferred,在 off 模式下不予准入。仅为上下文而跟随的 Thread 上的消息使用准入表,而不使用 follow-up 强度。

准入

每个 Source 的 Policy 都有一张准入表。它的每一行是一个接收范围:

  • 飞书:每个已配置的群、bot 收到提及的其他群,以及直接消息。其他群只有在飞书卡片上把 其他群 设为 仅 @ 时才会被接收。
  • GitHub:新 Issue、新 pull request、评论与默认分支的 CI。

每行最多三个格子。每个格子决定一条消息成为 explicit 请求、inferred 候选,还是什么都不是:

格子可选值默认
在列表上,未指向 agentinferred、ignoreinferred
不在列表上,指向 agentexplicit、inferred、ignoreignore
不在列表上,未指向 agentinferred、ignoreignore

针对未指向消息的格子,只在 Source 接收全部消息的地方可用,例如设为 全部消息 的飞书群,或开启了接收全部开关的 GitHub 范围。CI 结果没有发送者,因此它的行只提供最后一个格子。bot 消息使用 bot 列表,而不使用这些格子。

把「不在列表上、指向 agent」的格子设为 explicit,允许该范围内的任何人通过提及 agent 来请求工作。这对专门的支持群可能有用。inferred 候选仍取决于 accept 模式。后续消息通常绕过这张表,唯一的例外是 explicit 格子仍会授予 explicit 强度。

准入表是 Policy 版本的一部分。收紧某个格子不会立即停止依它接受的开放 Ticket,但会在这些 Ticket 恢复前重新校验时撤销其 Mandate。

bot 与自动化审查者

宿主把 GitHub App、以 [bot] 结尾的登录名与飞书 bot 识别为 bot。Source 可以列出 dependabot[bot] 之类的 bot,其消息可以成为 inferred 候选。这些 bot 必须指向 agent,或发在接收全部消息的范围里。它们不能发起 explicit 请求,也不能 stop Ticket。

使用普通账号的自动化审查者,对宿主而言算作人。其评论会到达订阅中的 Ticket 并产生 follow-up 通知。团队 prompt 文本必须把这类账号标识为自动化审查者。

路由候选

主 Session 用 orchestrator_route 路由 explicit 候选。一次调用可以包含多个 accept、attach、stop 或 ignore 决定。每一项独立处理:某一项被拒绝或缺少字段,不妨碍其余项执行。

inferred 候选通常需要完整 assessment(研判)。只有一条捷径:如果它的卡片明显不触及任何启用的规则——例如闲聊或无关讨论——主 Session 可以直接忽略它。Decision 会记录 ignoredFromCard,以区别于规则研判。主 Session 在其 Policy prompt 段落中读取启用的规则。

接受 inferred 候选永远需要研判。直接 accept 会拒绝未被 gate 准入为 explicit 的 Trigger。

Accept 模式与规则

accept 模式是 Policy 的一部分:

模式效果
off任何 inferred 都不成为候选:未指向 agent 的消息、bot 的消息、不在列表上的人的后续消息
observe(默认)inferred 候选会被研判;正面研判记录为标有「will accept(本会接受)」的 ignore,但不接受任何工作
autoinferred 候选的正面研判会直接接受

explicit 请求在所有模式下都有效。从 observe 开始,审阅记录下来的 Decision 后再切换到 auto。每次研判对每条启用的规则恰好判断一次,无论是否匹配。主动接受至少需要一条匹配的规则。

每条规则描述一类主动工作。Ticket 的 Mandate 记录匹配到的规则,其 Executor 会收到这些规则的名称与说明。

对该 Ticket 而言,规则的流程与沟通要求会覆盖默认值。silence 规则可以抑制一条确认消息;review 规则可以指定必需的审查者以及合并前的批准。适用于所有 Ticket 的要求应写入团队 prompt 段落。

Policy 版本

规则、accept 模式与每个 Source 的 Policy 共同构成 Policy 版本。每个 Mandate 都记录它被接受时所依据的版本。

版本变更会丢弃运行中的 Eval 并把其 Trigger 重新排队。它还会向每个受影响的活跃 Ticket 发送一条 policy-changed Input(输入)。该 Input 说明:

  • 某条匹配的规则发生了变化(含新文本),或不再适用;
  • 请求者可能不再被允许发起工作;或
  • 不再接受主动工作,例如模式从 auto 改走了。

不受影响的 Ticket 不会收到通知。变更不会立即撤销活跃 Ticket 的 Mandate。

Source 配置与 Policy 是分开的。它控制什么进入系统:读取哪些群、某个范围接收全部消息还是只接收提及。Mandate 记录其 Source 与接收范围。恢复要求 Source 仍在监听该 Thread,但不要求它仍在那里接收全部消息。

Source 关闭期间,回复会等待。如果 Source 不再监听回复的目的地,回复会被丢弃。

对「Executor 可以对自己的结果做什么」的限制(例如何时可以合并)不决定谁可以授权工作。它属于 agent 的指示,不属于 Policy。

恢复与停止

已结束的 Ticket 保留其 Mandate。人在这类 Ticket 自己的某个 Thread 上的消息可以恢复同一件工作,无需新的 Eval 或 Decision,无论发送者是谁。bot 与 CI 不会唤醒已结束的 Ticket。由 Executor 判断该请求是否符合 scope,不符合就结束这一轮。

只有三种操作会改变 Mandate:accept 创建它;人的 stop 撤回它;重新校验失败撤销它。被人 stop 的 Ticket 保持结束状态,不再接收任何内容。在那里请求的工作需要一次新的 accept。

恢复前的重新校验

Source 必须仍在监听原来的 Thread。其余检查取决于 Mandate 的依据:

  • explicit follow-up 的 Mandate 直接通过。
  • inferred 的 Mandate 需要 auto 模式,且其匹配的规则仍然启用。
  • 由准入表格子准入的 Mandate,在今天的表与发送者成员关系下仍须至少获得其原始强度。因此把发送者移出列表,可以撤销经由「列表发送者」格子接受的 Mandate。
  • bot 的 Mandate 要求该 bot 仍在 Source 的 bot 列表上。inferred 的表格与 bot Mandate 还需要 auto 模式与启用的匹配规则。
  • 其余 Mandate 要求发送者仍在该 Source 的允许列表上。

重新校验失败时,Ticket 保持结束,不接收任何等待中的消息。每条消息都被视为没有到达过任何 Ticket;如果不再被其他 Ticket 拥有,就进入 Eval。主 Session 不会被告知它曾到达过某个 worker。处理暂停之后同样如此。附加到该 Ticket 会被拒绝,进一步的工作需要一次新的 accept。

  • 人在 Thread 里说「stop」是一条普通 Trigger,由 Eval 决定 stop。Executor 不能声明「有人要求它停止」。
  • 面板上的 stop 是命令。它直接作用于 Ticket,并记录为手动停止。
  • 等待条件属于 Source。「N 小时无人认领」这类条件会是一个自己等待并自行复查的 Source;Eval 从不等待。

Eval 未完成时

时限从候选到达主 Session 时开始计算。等待送达的时间不计入;未送达的候选永不过期。

超时的 Eval 把它的 Trigger 重新排队再试一次。连续两次重试后,第三次超时记录为 unavailable。研判失败同样记录 unavailable;之后的 Trigger 可以发起一次新的 Eval。Policy 变更、或依据过期 Policy 做出的决定,会记录 unavailable 并立即按当前版本重新排队该批次。

evals 健康项报告最近一小时未解决的 unavailable Decision。scripts/dsh-superagent status 包含该错误。

面板只在满足以下条件时请求人工关注:unavailable Decision 产生不足 24 小时、仍是其 Thread 上最新的 Decision、未被消除,且该 Thread 既不在队列中也不在研判中。人可以重新评估该 Trigger,或消除该问题。