Apache Maka WorkHub 协调会话架构完全指南:一个 Session 如何管好所有工作
【免费下载链接】makaApache Maka (Incubating) is a high-performance agent workspace that keeps a complete record of everything it did.项目地址: https://gitcode.com/GitHub_Trending/mak/maka
Apache Maka(Incubating)的 WorkHub 是所有普通 Session 的统一入口,而支撑它的核心是WorkHub 协调会话(Coordination Session)架构:它没有为这个"总调度台"新建任何数据库或事件存储,只是给一个既有 Session 穿上了workhub_coordination特殊角色。本文从使用场景出发,拆解这套架构的路由处置模型、确定性 Action Gate、委派链接的原子提交,以及纠正、停止、恢复等破坏性操作的崩溃恢复契约。
一、先看现场:WorkHub 到底在解决什么问题
从界面看,WorkHub 就是"一个入口 + 一张工作卡片列表 + 一个对话区":你在这里提问、澄清、创建新工作、继续旧工作,左侧的 Rail 实时展示每个工作项的归属 Session 与状态(活跃、进行中、等待用户、已停止)。
但界面背后藏着一个工程难题:这个协调者必须是持久的。用户今天说"继续昨天那个支付幂等性的活",明天应用重启后再来,它仍然要记得上下文、记得自己把活派给了谁。要拿到这种可延续的会话连续性,最顺手的做法是再建一套 WorkHub 专用的数据库、事件存储、转录基座和生命周期权威——这正是 Maka 架构决策记录(ADR)明确拒绝的路线。用一句话概括那条铁律:
绝不产生第二个 WorkHub 数据库、事件存储、转录基座,或与 Session 并行的生命周期权威。
可以把它想象成一家公司的调度室:调度台有自己的通话记录本,但每个项目的真正台账都在各部门手里。调度台不复制各部门的账本,只记"谁跟谁谈过、活儿交接给了谁"。WorkHub 协调会话扮演的就是这个调度台。关于领域术语与责任划分,可参考 docs/workhub-domain-language.md。
二、核心决策:不是新实体,而是一个"特殊角色"
整个方案的支点是一个看似平淡的决定:协调会话就是既有 Session 的一个特殊角色,不是新的持久实体类型。
这个角色在 packages/core/src/session.ts 中被显式定义为保留角色与保留 ID:
WORKHUB_COORDINATION_SESSION_ROLE = 'workhub_coordination'WORKHUB_COORDINATION_SESSION_ID = 'maka_workhub_coordination'- 判定函数
isWorkHubCoordinationSessionId
SessionHeader结构上的role?: SessionRole字段缺省即普通 Session;注释特意写明"特殊角色仍然驻留在同一 Session 基座上"。Session 工具配置文件里也多了workhub-coordination-v1与workhub-coordination-v2两套协调工具面——换句话说,协调会话复用的是现有 Session 的执行通道,只是换了一层工具面板。
围绕这个角色,有几条生命周期契约值得逐条理解:
- 惰性创建:WorkHub 首次需要时才预置协调会话,平时它不存在、不占资源。
- 按 Host 隔离:一个协调会话只协调同一个 Runtime Host 下的普通 Session。切换 Host 就会落到另一个 Host 自己的协调会话上;不存在全局协调会话,跨 Host 协调在第一个里程碑里不做。
- 重启可解析:应用或 Host 重启后,查找逻辑必须解析回同一个 Session,保证"同一个调度台"的体验。
- 对普通视图隐身:协调会话不出现在普通 Session 列表里,也被排除在所有路由候选集之外。
第 4 点是结构性约束:即使 Action Gate 里再有一层自我路由拒绝的校验,那也只是纵深防御,不能替代"从候选集里结构性排除"这一层。
三、责任划分:谁对哪类事实说了算
理解这套架构的关键,是接受一张"权威归属表"。三个关注点各归其主:
| 关注点 | 持久化权威 |
|---|---|
| 用户在 WorkHub 发出的消息、普通问答、澄清、协调决策、有界委派引用、协调摘要 | 当前 Runtime Host 的协调会话 |
| 具体执行、项目与文件系统范围、模型与权限模式、根 Turn 准入、工具、工件、恢复、归档/删除、权威执行转录 | 目标普通 Session |
| WorkHub 卡片、过滤器、状态摘要、导航辅助 | 无持久化权威——全部是从 Session 事实可重建的投影 |
从这张表能推出两条必须背下来的原则:
- 协调会话只对协调对话有权威,它永远拿不到对普通 Session 执行或生命周期的权威。
- 意图(intent)只描述用户想要什么,不选择权威。真正选择权威的是确定性的准入机制——Action Gate。
这个划法直接决定了后文所有机制的样子:凡是"执行状态",一律从目标 Session 只读派生;凡是"协调事实",一律只落在协调转录里。
四、一句话进来,会被送到哪里去:路由处置与链接操作
每条普通路由输入,最终都收敛为恰好一个提议的路由处置:
answer_here:协调会话直接回答,不动任何普通 Session。delegate_existing:把具体工作交给某个有界、有效的既有普通 Session。create_new:先创建一个普通 Session,再把工作委派给它。clarify:继续在协调会话里澄清,不猜目标、不建 Session。
除了这四条"去路",还有一组链接操作——它们不选去路,而是作用于既有持久委派之上:
- 纠正(correction):换掉之前委派出去的目标,替换目标仍受限于
delegate_existing或显式create_new准入。 - 停止(stop)与恢复(resume):沿着"委派 → Session → Turn"的持久谱系找到目标,而不是去匹配名字相似的 Session。
整条决策链长这样:
用户输入 → 意图分析 → Session Resolver / 链接目标解析 → 协调策略(建议性提案) → 确定性 Action Gate → 归属的 Host / Session链条上每一环的权力都被刻意压低:Session Resolver 只返回有界的既有 Session 证据,从不创建 Session;链接目标解析从 WorkHub 持有的有界委派出发,沿持久的 Message、Turn 与延续谱系推进,一旦链接缺失、过期或歧义,就直接失败关闭,绝不退回去做名称相似匹配;协调策略产出的提案是建议性的——所有模型输出和路由输出都只是建议。
真正能授权写入的只有Action Gate。它对 packages/runtime-host/src/server/workhub-coordination-action-gate.ts 中的WorkHubCoordinationActionGate强制校验:Runtime Host 与目标有效性、归档与等待状态、自我路由排除、显式create_new、既有工具与权限上限。对替换类操作还有附加门槛:可信用户文本里必须有显式纠正证据、按协调转录顺序声明源委派,且拒绝任何后来的竞争性替换意图。
Gate 的act方法还实现了一套基于动作指纹的幂等重放:同一个actionId携带不同请求指纹,直接以action_conflict拒绝;指纹相同则返回缓存的重放结果。效果是"重试同一个动作绝不会执行两次"——这对崩溃后用户连点两次"重试"的场景至关重要。
可以这么类比:模型是起草文书的人,Gate 是签字柜台。再好的草稿,没到柜台盖章就不能落账;同一份文书被重复审一次,柜台只认指纹,不会盖两次章。
五、可选组件:两阶段模型路由适配器的"视线隔离"
除了确定性的协调策略,架构还留了一个可选安装的模型路由适配器。它把模型调用拆成两阶段,核心设计是严格隔离两个模型"能看到什么":
- Intent 模型:复用协调会话保存的连接、模型与思考设置,只看到当前请求和至多 8 条有界用户/助手消息,看不到任何候选 Session。系统提示明确"Intent 不得选择 Session"——它只负责理解用户要什么。
- Recall 模型:仅在
execute与普通continue场景被第二次调用,看到至多 32 个候选,每个候选只含请求作用域内的不透明引用、有界名称、状态与新旧分桶。它拿不到稳定的 Session 身份、路径、文件内容、工具或能力信息。
候选上限在 packages/core/src/workhub-routing.ts 中以常量固化:WORKHUB_ROUTING_MAX_CANDIDATES = 32。
确定性的applyWorkHubRoutingPolicy负责把模型评估映射为最终处置或链接操作。以下几类情况一律失败关闭到clarify,任何情况下都不隐含create_new:
- 模型输出无效;
- 提供方(provider)失败;
- 候选不可用;
- 召回为空;
- 结果歧义。
边界设计上还有一道双保险:Intent 输出不含目标,Session Resolver 输出只含有界不透明候选引用,不能返回创建或处置;链接目标证据同样是建议性的,不能证明所有权。模型排序、工具选择,单独都不能授权任何工作——每个提案仍要带着原始可信用户请求,过一遍 Host 拥有的 Gate。
当适配器在组合时显式安装后,其结果会挂在根 Turn 准入上并被恢复流程复用;每个新根(含排队的跟进与待处理消息恢复)都会拿到自己的决策。想改生产默认值?ADR 要求走仓库既有的maka evalExperiment/Cell/Attempt/Result 路径做对比评估,并分别报告 Intent 准确率、召回类型准确率、Recall@K、MRR、结果准确率、不安全绑定、隐式创建、不必要澄清、延迟、Token 用量与成本——刻意不为 WorkHub 另起一套评估框架。
六、委派链接:开"回执",而不是"抄送"
一次委派落盘时,协调转录与执行转录之间只持久化一个有界链接,而不是把目标的工作内容抄送过来:
delegationId coordinationTurnId targetSessionId targetMessageId targetTurnId disposition关键原则有三条:
- 不镜像执行生命周期。目标的接受、运行、等待、完成、失败、中止与恢复状态,始终是普通 Session 的事实;WorkHub 以只读投影派生,绝不把它们作为协调会话的独立真相落盘。
- 链接状态归协调会话所有。链接纠正记录
active/superseded/aborted三种链接状态,其中aborted表示源链接已退役但替换准入没完成(所选目标被归档、消失或开始等待用户输入)。 - 不复制转录。渲染器从完整协调转录重建活动链接,保持持久转录顺序而非墙钟顺序;普通 Session 记录自己的请求、工具、副作用与权威结果,WorkHub 最多显示有界投影或协调摘要,绝不把完整转录搬进协调会话。分配投影保留
create_new标记,让可见卡片诚实地说"WorkHub 创建了新工作项",而不是含糊地暗示"既有条目接受了请求"。
原子提交是这套链接的心脏。委派使用协调转录里一条闭合的、类型化的delegation_assigned记录;在协调会话与目标 Session 的准入权威之下,一次runtime.sqlite事务同时提交该记录与目标的待处理消息准入——对create_new,目标 Session 元数据也进同一事务。记录携带确切用户文本、已解析目标、目标 Message/Turn 身份、创建上下文与稳定显示名,其动作指纹拒绝动作身份的冲突复用。
事务本身就是用户可见的分配边界:提交前,两个 Session 都看不到这项工作的影子;提交后,WorkHub 链接与目标输入同时存在。唤醒内存执行器只发生在提交之后。如果 Host 恰好在"提交之后、唤醒之前"崩溃,接管的是普通待处理消息的既有恢复机制——WorkHub 不拥有第二个恢复状态机,也没有补偿链。而delegation_assigned记录本身就投影出一条可见的 WorkHub Turn,渲染器不再追加第二条摘要。
这些消息类型的持久 schema 定义在 packages/core/src/session.ts(WorkHubDelegationAssignedMessage、WorkHubCoordinationMessageEnvelope与WorkHubDelegationCreateSpec),协议层的workhub.coordination.actFromTurn、workhub.coordination.selectAndDelegate等操作规范见 packages/runtime-host/src/protocol/workhub-coordination.ts。
混合第一响应契约
WorkHub 对委派的第一响应是"混合"的,兼顾了即时性与准确性:
- 原子的
delegation_assigned记录就是即时的持久确认——WorkHub 不用等目标跑起来就能告诉用户"收到,已交办"。 - 目标 Message 是稳定的委派身份;
targetTurnId只记录它的准入位置。 - 状态怎么显示?WorkHub 向目标 Message 的权威查询"哪个 Turn 持久消费或准入了这个 Message",再联合已解析 Turn 记录的寿命周期与目标 Session 的确切活跃 Turn 成员关系,投影出
running、waiting_for_user、completed、failed、aborted。
这套投影在几个容易翻车的边缘场景里依然正确:未消费的转向消息(steering Message)被折叠进后继 Turn 时照常解析;恢复把多个待处理 Message 聚合到一个新 Turn 之下时不丢状态;持久的取消墓碑可以把撤回的排队 Message 解析为aborted;若目标权威暂时不可读,WorkHub 投影为recovering,不虚构任何终结结果。这些执行状态从不作为可变的协调记录被追加;Session 变更通知会让投影失效,重启后打开 WorkHub,投影从同一链接与目标事实重建。
渲染器一侧同样克制:确认之前只持久化一个 Host 作用域的动作 id;Composer 草稿文本走独立存储键与生命周期。于是重载保留幂等性——不会冻结旧文本,也不会把草稿编辑耦合进 Host 权威。而waiting_for_user仍是本地可重试结果,因为此时还没有任何分配被提交。
七、撤销已发生的事:破坏性操作的崩溃恢复契约
真正考验架构的不是"派活",而是"改派、叫停、续上"。这三类破坏性操作各自有一套持久化契约。
纠正:两段式退役
任何破坏性退役之前,先持久化一条对源委派身份唯一的delegation_replacement_requested记录。随后目标 Session 的普通 Message 权威二选一:要么取消那条确切的、仍待处理的委派 Message,要么解析它如何进入了执行 Turn:
- 若根 Turn 是由该 Message 创建的——可以停;
- 若既有用户 Turn 只是把它当作转向消息消费了——那是共享权威,必须保持运行。
替换分配与旧链接的delegation_superseded证明原子提交。重试同一动作能恢复"退役/停止之后、替换分配之前"这个崩溃接缝。替换指纹绑定的是已解析的稳定目标 Session id,而非临时候选引用——所以元数据刷新不会改变动作身份,重试也不会选错 Session。若目标在破坏性退役边界之后变成归档、不可用或等待状态,协调会话追加一条delegation_replacement_aborted终结事实:已退役源从活动链接移除,后续重试返回同样的终结结果,而不是挂着一个"已停止却未超期"的僵尸链接。
直接停止:第一索赔胜出
直接停止先通过共享 Session Resolver 解析目标,然后先向 Host 问一句"该 Session 的哪些委派仍持有可停止的工作",再回答用户或提出任何提案。约束清单很严:
- WorkHub 投影是可重建的,窗口打开时可能为空,绝不从投影给出破坏性回答。
- 提案只携带解析产物:不透明委派身份及其所属 Session。显示名只是提案侧的检索证据,永不进入准入;提案不声称拥有自己的证明——Host 从持久状态制作证明。
- Action Gate 在任何效果之前立即重验:分配仍存在、仍属于被提议的 Session、该 Session 上没有其他委派仍持有可停止的工作。
- 可见性只为被停的那一个委派证明——因为不存在"Session 被删了就退役委派"的路径,若对全部活动集证明,一个已删除的 Session 会阻塞所有停止。于是过期解析失败关闭,而解析与准入之间的重命名则正确地无关紧要。
- 可信用户文本必须携带直接停止命令;
user_stop确认保持在策略输出之外——模型输出或显示名都不能替用户选停止对象。
持久化形式:停止前落一条delegation_stop_requested声明,停止后落一条delegation_stop_resolved观察。待处理取消墓碑保留破坏性动作身份,使两条协调记录之间发生崩溃时状态仍保持cancelled_pending。其根 Turn 的停止在确切目标 Turn 上使用动作派生的中止源,恢复流程因此不会把普通 Session 停止误认成 WorkHub 投递。准入时同时持有协调会话与每个活动目标 Session 通道,并重读活动链接——并发分配必须先在"唯一委派证明"之前落定、等到停止声明之后,否则准入直接失败关闭。只有已确认的直接停止才记录该溯源:退休同一根的路由纠正携带自己的取消声明但保持中性停止源,重放不会把纠正读成已投递的停止。
全局动作声明
上面两条契约共享一个底层机制:每条持久 WorkHub 记录都按"它关于什么"为键——分配按动作键控,停止或替换按委派键控——因此没有任何单条记录能看到"动作身份移动到第二个委派或第二个处置"。一个在相同协调准入下、在任何效果之前单独取得的持久动作声明,就是那个全局所有者:
- 精确重放收敛于它;任何对该身份的复用——包括已拒绝或仍在恢复的尝试之后、跨 Host 重启——都在效果之前失败关闭。
- 声明不携带Session 外键,因为已提交的破坏性声明必须比目标更长寿:目标 Session 消失时,允许停止走到终结解析的是它的移除墓碑,而不是消失的 Message 证明,更不是"目标不可读"。
恢复
命名恢复走普通 Session 的延续准入,报告resume_started或already_running,不另建协调恢复账本。暂停与基于代词的停止控制被明确列为后续工作。
协议层的提案类型(delegate_existing/create_new/correct/stop/resume及其前置条件结构)完整定义在 packages/runtime-host/src/protocol/workhub-coordination.ts,持久消息 schema(含停止结果枚举cancelled_pending/stop_delivered/already_terminal/not_owned)在 packages/core/src/session.ts。
八、让用户亲手选:select_and_delegate 交互能力
目标选择是一个交互能力,独立于第五节那个可选的前准入模型路由策略。默认协调模型在候选发现之后可以调用tasks.select_and_delegate:Host 用既有交互权威发布一个持久 Form,用户点选一个确切的不透明选项,Host 把绑定的 Session/工作区传给既有 Action Gate。全程不引入额外 Session 生命周期,也不碰 WorkHub 数据库。
时序与恢复语义是这么约定的:
- 协调 Turn 在等待期间已被准入;只有后续 Gate 与目标准入才能启动委派执行。
- 操作在等待结束后重读活动 Run 权威,保留原始已准入的用户内容,永不重写既有的路由决策。
- 绑定的实验性 Turn 必须遵循其已准入的决策;想改它,得走后续协调决策。
- 渲染器重载会重新查询待处理交互;取消/停止会关闭它;Host 恢复关闭孤儿延续。过期提案不能悄悄选中另一项工作,成功分配的重放使用持久动作身份。
- 旧的
answer -> targetSelection -> answer前准入协议与渲染器 Promise 已被移除而非保留——不留第二套选择实现。
协议层对应用户可见的workhub.coordination.selectAndDelegate操作,输入包含turnId、actionId、candidateSetId、candidateRefs与delegationText,并支持candidate_set_stale错误。候选集 id 必须匹配sha256:[a-f0-9]{64}格式,候选数量上限为 32(WORKHUB_COORDINATION_CANDIDATE_MAX_ITEMS)——与第五节的 Recall 候选上限对齐。
九、代价、实现现状,以及什么时候该推翻这个设计
收益是明确的:WorkHub 在没有第二套持久权威、数据库、事件存储、生命周期或转录副本的前提下拿到持久会话连续性;协调与执行在共享 Session 基座内各自持有独立权威。
成本与限制同样写进了 ADR:
- 按 Host 的边界会在用户切换 Runtime Host 时割裂 WorkHub 连续性——每个 Host 有独立协调转录,无法协调另一 Host 的 Session。
- 特殊 Session 角色即使刻意复用现有基座,也带来预置、查找、恢复、保留与 UI 一整套义务。
- 每个被委派的协调 Turn 多一条类型化分配记录(它同时也是可见时间线的来源)。
- Work 与 Session 是 1:1、1:N 还是独立持久实体,至今未决;跨 Runtime Host 协调被推迟。
实现状态(2026-09,对照main验证):协调会话的角色表示、惰性创建、持久查找、恢复、按 Host 的 UI 解析、持久转录、闭合处置与 Action Gate 均已实现;持久委派链接编码在转录中;目标生命周期投影与混合第一响应契约以可重建读取实现;链接纠正、目标拥有的待处理取消/Turn 停止、原子超期、基于重试的替换恢复与直接停止都已落地,直接停止使用持久的delegation_stop_requested/delegation_stop_resolved事实、精确 Message 所有权与"第一索赔胜出"仲裁。相关实现集中在 packages/runtime-host/src/server/workhub-coordination-coordinator.ts、packages/runtime-host/src/server/workhub-coordination-action-gate.ts 与 packages/core/src/workhub-routing.ts。需要说明的是:ADR 提到的 Resolver "临时精确名称基线"从未实现——今天的协调是模型驱动的,协调模型发现候选 Session,准入重新验证不透明身份与预期状态,停止/恢复提案携带显式持久目标而非任何显示名。
再评估触发条件也有明确判据:若受支持的工作流需要一次 WorkHub 对话跨多个 Runtime Host 协调普通 Session,或 Host 切换造成可重建投影无法解决的用户可见连续性损失,就重新评估按 Host 的决策;若实现这个特殊 Session 角色必须引入第二个持久权威,或普通 Session 基座无法安全强制某条例外,就重新评估特殊角色方案。
附:四条被否决的路线
ADR 完整记录了被拒绝的备选方案,读它们能快速把握这套设计划在哪条线上:
- 第二个 WorkHub 数据库、事件存储、转录基座或生命周期权威——与第一约束直接冲突。
- 跨 Runtime Host 的全局协调会话——违反按 Host 隔离,推迟。
- 把普通 Session 的完整转录复制进 WorkHub——违反"链接而非复制",只保留有界投影。
- 允许模型或路由输出绕过确定性 Action Gate 直接授权写入——所有写入必须经 Gate 准入。
回看全文,这套架构反复在做同一件事:把每个"想要新系统"的冲动,翻译成对既有基座的一次角色叠加、一次原子事务或一条可重建投影。协调会话拿到了持久的对话连续性,而代价被精确控制在一张责任表、一个 Gate 和几类类型化记录之内——这对任何想在通用执行子系统之上叠一个持久协调层的产品,都是相当有参考价值的工程样本。
【免费下载链接】makaApache Maka (Incubating) is a high-performance agent workspace that keeps a complete record of everything it did.项目地址: https://gitcode.com/GitHub_Trending/mak/maka
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考