mcpField
M
multica-mentioning

multica-mentioning

github.com/multica-aiAgent 工作流54.1k41 次安装今天更新
代码仓库

关于 multica-mentioning

面向 Multica 协作的 Agent 技能,说明评论中的提及链接如何解析、哪些提及会触发 Agent,以及预览和结果的处理规则。

主要功能

  1. 01基于 UUID 的提及语法
  2. 02Agent 与小队的任务触发规则
  3. 03成员和议题链接行为
  4. 04触发预览与抑制规则
  5. 05广播和待处理任务规则

适用场景

  1. 01在评论中指派 Agent 或小队
  2. 02链接成员或议题而不触发任务
  3. 03预览评论将触发的 Agent
  4. 04排查被阻止或合并的提及

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/multica-ai/multica --skill multica-mentioning

安装后在 Claude Code 中输入/multica-mentioning确认已加载。

附带文件references/mentioning-source-map.md

详细介绍

提及与委派

本技能说明提及链接在 Multica 后端中的行为(WHAT),并追溯到源码。是否要提及——避免循环、对确认保持沉默——在你的运行时简报的 Mentions 部分;遵循它,不要在此重复。

以下每一条断言都固定到源码,位于 references/mentioning-source-map.md。如果行为与本文档有任何差异,源码映射表是重新核对它的地方。

提及链接由真实 UUID 构建

后端只通过这种 Markdown 形式识别提及:

[@Label](mention://<type>/<id>)

解析器(server/internal/util/mention.go 中的 util.MentionRe)接受 恰好四个 <type> 值加上 all 哨兵值,而 <id> 组只接受十六进制字符和短横线,或者字面字符串 all:

(member|agent|squad|issue|all)/([0-9a-fA-F-]+|all)

所以链接目标是真实实体 UUID(或 all),绝不是显示名称。方括号之间的标签是自由文本——那是人类可读名称所在的位置。

有一种 mention:// 形式故意位于此解析器之外: [Label](mention://project/<uuid>)。project 不在上面的类型组中, 所以后端永远不会解析它,它也无法入队任何东西——它是一个仅用于渲染的链接,每个客户端都会使其可导航(Web 和桌面端上的 chip,移动端上点击即可打开项目的普通链接)。这正是重点: 项目引用绝不应该能够启动一次运行。可自由使用它来指向 一个项目(参见 multica-projects-and-resources 技能);本文档中的其他一切 都是关于解析器确实识别的四种类型(加上 all)。

步骤 1 —— 用 --output json 查找 UUID

名称不是 UUID。先从匹配的列表命令查找 UUID:

  • 一个人 → multica workspace member list --output json → 使用 user_id
  • 一个 agent → multica agent list --output json → 使用 id
  • 一个 squad → multica squad list --output json → 使用 id

对于一个人,提及 id 是 user_id,而不是成员关系行的 id——后端自己的名册格式化器使用 user_id 来表示成员提及。按显示名称匹配。如果名称有歧义或不存在,不要猜测——在你的评论中说明这一点,而不是发出一个损坏的链接。

第 2 步 — 四种类型以及每种类型究竟会入队什么

格式:[@Name](mention://<type>/<uuid>)。<type> 与 id 来源必须匹配,否则链接会解析到错误的实体(或什么都解析不到)。

要……typeuuid 来自后端会做什么
触发一个 agentagentagent.id为该 agent 入队一次运行(EnqueueTaskForMention)
把工作交给一个 squadsquadsquad.id解析该 squad 的 leader_id,并为 LEADER agent 入队一次运行
链接一个人membermember.user_id渲染一个链接;不会入队任何东西 — 不会运行 agent
引用一个 issueissueissue.id渲染一个链接;不会入队任何东西 — 始终安全

mention 触发集合由 computeMentionedAgentCommentTriggers(server/internal/handler/comment.go)计算;评论路径会把该结果合并进 computeCommentAgentTriggers,并通过 enqueueCommentAgentTriggers 将其入队。它只作用于两种类型:squad 分支解析该 squad 并把它的 leader 加入触发集合;此后所有不是 agent 的都会被跳过(if m.Type != "agent" { continue }),然后 agent 分支加入该 agent。member 或 issue mention 两个分支都进不去,因此不会入队任何任务。

因此,member mention 并不会让某个人“运行”,并且本技能并不声称它会通过 Go 评论处理器投递通知 — 该处理器中并不存在这样的代码路径(见源码映射)。已得到验证的是上述契约:只有 agent 和 squad mention 会入队工作。

预览与按评论抑制

较新的客户端可以在创建或编辑评论之前调用 POST /api/issues/{id}/comments/trigger-preview。预览端点使用与创建和编辑重新触发相同的 computeCommentAgentTriggers 函数,因此显示的 agent 标签来自后端规则,而不是客户端的重新实现。

在预览编辑时,客户端可以发送 editing_comment_id。服务端会验证该评论属于同一工作区和 issue,推导或检查该编辑的父评论上下文,并且只排除 trigger_comment_id 为同一评论的待处理任务。该 issue 上任何其他评论产生的待处理任务仍会对预览去重。

在创建或编辑评论时,客户端可以发送一个可选的 suppress_agent_ids 数组。服务端仍会先计算完整的触发集合,然后作为后置过滤移除那些 agent ID。字段缺失或为空会保留旧行为。一个有效但不在计算出的触发集合中的 UUID 是无操作;格式错误的 UUID 会在请求边界被拒绝。

@all 是广播类型

@all 使用字面量 all,从不使用 UUID:

[@all](mention://all/all)

它面向该 issue 上的所有人。它不会让任何特定 agent 运行。而且它在触发时很特殊:带有 @all mention 的评论会被视为广播,从而抑制 issue 负责人的评论自动触发(以及其他隐式路由回退 — 线程父级 / 会话所有者)。用 @all 来通知,而不是向负责人请求工作。

@all 只会抑制那些隐式路由。同一条评论中显式的 @agent / @squad mention 仍会正常触发(MUL-5411):一条内容为 [@all](mention://all/all) heads up — [@Preflight](mention://agent/<uuid>) please take this 的评论会入队 Preflight,且不会入队其他人。显式 mention 优先于广播;参见 server/internal/handler/comment.go 中的 computeCommentAgentTriggers,其中显式 mention 分支会在 @all 短路之前被求值。

不会发生什么(这样结果就不会让你意外)

这些情况都不会启动一次新的运行,也都不会产生错误响应——但它们是三件不同的事,而响应会告诉你究竟是哪一种。一个从未解析成功的提及是真正静默的空操作。一个解析成功但被拒绝的提及会出现在 trigger_outcomes 中,状态为 status: "blocked",并带有 reason_code。一个目标已经繁忙的提及会返回 coalesced 或 deferred:不会启动第二次运行,但你的评论确实会被并入已经在运行的任务,因此它仍会被读取。发送后请读取那个数组——这是所有这些情况唯一会显现的地方。

  • 在应填 UUID 的位置填了名称。 mention://member/Alice 是无效的。id 分组只接受十六进制字符+连字符或 all;典型名称中的非十六进制字母会使整个模式匹配失败,因此解析器什么也不返回。
  • 一个像十六进制但错误的 UUID。 一个格式看起来正确、但不属于任何实体的 UUID 确实会解析成功,然后在查找时空操作:工作区范围的查询找不到任何 Agent,该提及被报告为受阻,原因为 invocation_not_allowed。该代码是故意含糊的——打错字的 UUID 和真正的权限拒绝被有意设计得看起来完全相同,因为你输入的 id 可能指向另一个工作区中的私有 Agent,而原因绝不能确认它存在。因此,当你看到 invocation_not_allowed 时,请先拿该 UUID 与实时名册核对,再去改动任何可见性或调用设置(MUL-5548);multica squad member list <squad-id> --output json 会返回用于构建该提及的 member_id。一个匹配该模式但根本不是有效 UUID 的 id(mention://agent/-)会被 id 解析器拒绝,并以 target_unavailable 受阻——非 UUID 在任何地方都指代不了任何实体,因此它不隐藏任何东西。这两种情况都绝不会是错误响应。
  • 一个已经待处理的任务。 即使 @agent/@squad 正确,当目标在此 issue 上已有待处理任务时,也不会启动第二次运行(HasPendingTaskForIssueAndAgent)。这是合并,不是丢弃:该评论会合并进那个任务,结果是 coalesced(相同的已审阅 head)或 deferred(不同的 head)——不要把它当作“提及没生效”而重新发送。编辑预览是唯一的例外:editing_comment_id 会忽略正在被编辑的同一条评论产生的待处理任务,因为保存会在重新计算触发器之前取消那些旧任务。它仍然以评论为范围,而不是整个 Agent 范围的绕过。
  • 一个已归档的 Agent,或一个未绑定运行时的 Agent(同样地,一个其 leader 如此的 squad):分别以 target_unavailable 和 runtime_offline 受阻。两者都只在 invoke 门禁之后才检查,因此一个无权调用该目标的调用者永远不会得知其状态。
  • 一个你无法调用的私有 Agent: 受阻——提及路径对 @agent 和 @squad 都依据 canInvokeAgent 进行门禁。那是运行门禁,不是可见门禁:自 MUL-3963 起,一个能在 UI 中打开私有 Agent 的工作区管理员仍然可能无法触发它,因此能够查看该目标并不意味着能够提及它。(canEnqueueSquadLeader 包装器是 squad 分配/提升路径,而非此路径;子任务完成唤醒没有门禁——参见 multica-squads 技能。)

一条跨 issue 的链会保留其人类(MUL-6490)。A2A 门禁评判你链顶端的人类,而该人类会随你写的评论一起传递:评论会记录撰写它的那次运行,因此它所唤醒的运行会继承你的发起者。当你评论的 issue 与你正在其上运行的 issue 不同时,这一点同样成立——即常见的“创建 issue Y,然后在那里协调”流程——因此,在你自己的 issue 上有效的委派,在你刚创建的 issue 上依然有效。它不会反过来成立:任何情况下都不会替换成另一个人类(你的 Agent 的所有者,或目标 issue 的发起者),所以如果你的链顶端没有人类,那么无论你移到哪个 issue,成员范围的允许列表都会保持关闭。 关于自动化(MUL-4857)的一个细节:当一次未归属的 autopilot 运行(schedule/webhook 派发没有人类发起者,因此 A2A 门控没有可依据的人类)在处理该 autopilot 创建的 issue 期间通过 @mention 进行委派时,调用门控会回退到 autopilot 创建者 作为实际调用用户——也就是最初允许首次派发的同一主体。因此,运行中途的 @agent / @squad 委派,只有在 autopilot 创建者能够调用该目标时(owner / public_to 匹配)才会触发,否则保持跳过。这仅涉及授权——入队运行的发起者/归属不变。

该回退绑定到已验证的任务谱系:仅当发起委派的运行自身的任务正是处理该 autopilot issue 的任务时(author == task agent,task.issue_id == 此 issue),它才适用,因此一个在其他地方工作的运行绝不能通过在其 issue 上评论来借用另一个 autopilot 创建者的权限。

同一权限也承载普通的已分配小队队长唤醒(worker 在 autopilot issue 上的结果评论仍可唤醒队长),并且它能在目标繁忙时保留:如果被提及的 agent 已在运行,则该委派会在该运行完成时以同一权限重放,因此绝不会丢失。

编辑被视为一次全新操作——它会从编辑操作重新推导该评论的谱系。只有 agent 作者编辑自己的评论时,才会将该谱系重新标记为编辑任务;任何其他编辑者——包括 workspace owner/admin 编辑 agent 的评论——都会清除它。因此,从无关 issue 编辑一条旧的 autopilot 评论,或 admin 编辑 agent 的评论(管理权限,而非调用权限),会在延迟的 completion-reconcile 阶段失败关闭,而不是复用原始运行的权限。

错误 → 正确

错误:@alice please review → 纯文本,无链接,解析为空,无人被触达。

错误:[@Alice](mention://member/Alice) please review → "Alice" 不是 UUID;id 分组会拒绝非十六进制字母,模式不匹配,链接静默失效。

正确:

  1. multica workspace member list --output json → Alice 的 user_id = 7f3a…
  2. [@Alice](mention://member/7f3a…) please review → 真实 user_id 解析成功;链接会渲染并解析到 Alice。

@all 广播:[@all](mention://all/all) heads up — 会触达所有人,不运行任何特定 agent,并抑制 assignee 自动触发。

这些确切形态由一个 Go 行为测试(TestMentioningSkillTeachesTheParserContract)固定,该测试将它们送入 util.ParseMentions:名称形式解析为空,真实 UUID 形式解析成功,@all 解析为 {all, all},而带有真实 UUID 的错误 type 仍会解析(这就是为什么 type 必须与 id 来源匹配)。

参考资料

references/mentioning-source-map.md — 针对正则、入队分支、@all 抑制以及 CLI id 来源映射的 file:line 证据,并明确注明 Go 评论处理器中不存在成员通知投递路径。

评论

支持 Markdown