hive 前端触发器系统清理指南:Colony 生命周期简化与 missed-trigger 追补握手
2026/9/24 9:11:22 网站建设 项目流程
  • 人工智能
  • AI Agent
  • 多智能体
  • MCP 服务
  • 工具调用
  • 浏览器控制

【免费下载链接】hive

Multi-Agent Harness for Production AI

项目地址:https://gitcode.com/gh_mirrors/hive48/hive
点击查看免费下载

本文档是 hive(Multi-Agent Harness for Production AI)前端在触发器(Trigger)系统大幅简化后的清理与迁移指南。后端已经彻底塌缩了 colony-lifecycle(Colony 生命周期)这一层:加载一个 colony 的会话(session)即视为"激活",关闭即视为"停用",不再存在独立的激活/停用状态机。随之而来的是一批前端 UI 变为死代码需要删除、一个事件被重命名,同时新增了一个"错过触发器握手(missed-trigger handshake)"的小型交互组件,用于在会话加载时追补会话关闭期间错过的定时触发。阅读完本文,你将掌握:哪些端点/事件/字段/组件必须从现有前端代码中移除,哪些触发器能力保持不变,以及如何从零实现并接入missed_triggers事件与POST /colony/resolve_missed追补接口。

全文按照原文档的Remove(删除)→ Keep(保留)→ Add(新增)→ Migration checklist(迁移清单)骨架组织,并逐节结合当前仓库的后端实现(core/framework/server/routes_sessions.py、core/framework/tools/queen_lifecycle_tools.py、core/framework/host/triggers.py、core/framework/host/event_bus.py)与测试用例(core/tests/test_missed_triggers.py、core/tests/test_missed_triggers_http_e2e.py)给出源码级佐证。


背景:为什么这次简化会发生

简化的本质是一个状态模型的收敛。旧前端需要在四个状态之间做对账:

状态来源含义
loadedsession 是否已加载
metadata.active磁盘上写死的激活标记
per-triggeractive每个触发器自己的激活标记
is_executing会话当前是否正在执行

这四个状态塌缩成了一个用户真正关心的问题——"该 colony 的会话是否已加载?"——外加一个面向高级用户的、每个触发器独立的enabled配置开关。其余全部是人为分层:加载 colony 本身就是激活,关闭 colony 本身就是停用,没有"已暂停但已加载(paused but loaded)"这种中间态。

由此得到触发系统的核心不变量,也是全文所有改动的前提:

触发器仅在 colony 的会话已加载、且该触发器的enabled为 true 时才会触发。不存在额外的生命周期开关。


Remove:必须删除的前端代码

已消失的端点(全部返回 404)

以下三个端点已从后端路由注册表中移除。在 routes_sessions.py 的路由注册区段中已搜索不到任何colony/statecolony/activatecolony/deactivate注册项,前端凡是还在请求这些 URL 的代码都会收到 404,必须一并删除。

Endpoint状态
GET /api/sessions/{id}/colony/state404
POST /api/sessions/{id}/colony/activate404
POST /api/sessions/{id}/colony/deactivate404

这些端点暴露的信息(loaded / active / busy)要么与现有 session 信号冗余,要么是人为构造的,没有独立存在的必要。

已消失的事件

事件类型状态
colony_activated不再发出
colony_deactivated不再发出
activation_missed_triggers更名为missed_triggers

需要取消订阅并删除前两个事件的全部 handler;第三个事件则按新名字missed_triggers重新订阅(细节见下文 Add 部分)。在 core/framework/host/event_bus.py 的事件类型定义中,当前保留的触发器事件族为trigger_availabletrigger_activatedtrigger_deactivatedtrigger_firedtrigger_removedtrigger_updated(event_bus.py),而missed_triggers作为新增事件独立存在(event_bus.py)——colony_activated/colony_deactivated/activation_missed_triggers均不在其中。

已消失的 tool 响应字段

queen 的set_trigger工具不再在响应中返回colony_active,也不再返回"queued_for_next_activation"状态字符串;trigger_activated事件负载同样去掉了colony_active字段。

当前set_trigger的响应已经统一为{ "status": "activated", ... }——触发器已注册,并且(因为 queen 能调用该工具时会话必然已加载)正在触发中。源码可以佐证这一契约:queen_lifecycle_tools.py 中 timer 分支返回的负载只有statustrigger_idtrigger_typetrigger_config;webhook 分支也只是追加了webhook_url(queen_lifecycle_tools.py)。同时 routes_sessions.py 广播的TRIGGER_ACTIVATED事件数据仅包含trigger_idtrigger_typetrigger_confignameentry_node等字段,PATCH 后的TRIGGER_UPDATED同样不含colony_active

必须删除的 UI 组件

  • colony 头部的 Activate / Deactivate 切换开关。加载 colony 视图本身就是激活,关闭它本身就是停用。该开关只是在重复已有的打开/关闭 colony 交互。
  • metadata.last_active_at驱动的 "Active since …" 徽章。该字段已不再落盘。如果确实需要一个"会话开始于"的时间戳,现有 session 响应中的loaded_at即可覆盖。
  • queen 对话记录中的 "Queued for next activation" 指示卡片。不再存在"排队"中间态:一个触发器要么已配置(会话打开期间运行),要么已禁用/被移除。
  • 侧边栏上区分 "loaded" 与 "active" 的圆点。收敛为单一圆点:仅表示该 session 当前是否已加载。

已消失的metadata.json字段

metadata.activemetadata.last_active_at不再由后端写入。任何在前端读取它们的逻辑都应删除——它们已不属于契约的一部分。


Keep:触发器系统本身不变

触发器系统本身完全未变,以下能力照旧工作:

  • 触发器 CRUD UI:通过 queen 的set_trigger/remove_trigger/list_triggers工具,以及现有的每触发器 HTTP 路由(/triggers/{id}/activate/triggers/{id}/deactivate/triggers/{id}/runPATCH /triggers/{id})。这些路由在 routes_sessions.py 中完整注册,分别对应handle_list_triggers(L1154)、handle_create_trigger(L1173)、handle_update_trigger_task(L1304)、handle_run_trigger(L1450)、handle_activate_trigger(L1551)与handle_deactivate_trigger(L1628)。
  • trigger_fired事件:只要配置的触发器触发(或resolve_missed注入追补事件)就会发出,前端照旧渲染即可。源码侧由_emit_trigger_fired负责广播(参见 routes_sessions.py 与 queen_lifecycle_tools.py)。
  • trigger_availabletrigger_activatedtrigger_deactivatedtrigger_removedtrigger_updated:触发器 CRUD 时仍然发出,数据形状不变,仅去掉上文提及的colony_active字段。
  • triggers.json中每个触发器的字段idnametrigger_typetrigger_configtaskenabledlast_fired_atnext_due_at。注意字段名是enabled(旧的每触发器active字段名已废弃)。源码中set_trigger激活后即设置tdef.enabled = True(queen_lifecycle_tools.py),与此一致。

另外,触发器列表的权威读取入口是GET /api/sessions/{session_id}/triggers,它通过 core/framework/host/triggers.py 的build_trigger_view把持久化的triggers.json定义与运行时状态(enabled、下次触发倒计时、触发统计)合并成 UI 就绪的视图,SSE 的trigger_*事件只负责在其上叠加实时增量。


Add:新增的 missed-trigger 握手

会话关闭期间,定时触发器不会触发。当会话重新加载时,后端会计算这段时间错过的触发(missed ticks),并在 SSE 流上推送一个新事件,前端用一个弹窗让用户决定每个错过的触发器如何处理,最后把决定 POST 回去。

订阅missed_triggers事件

在会话加载时,如果任一启用的 timer 触发器存在过期的last_fired_at(即 cron / interval 的 tick 本应在会话关闭期间触发),会话的 SSE 流上就会落下一个missed_triggers事件:

{ "type": "missed_triggers", "stream_id": "queen", "data": { "colony_id": "...", "missed": [ { "trigger_id": "daily_outreach", "trigger_type": "timer", "count": 3, "ticks": [ "2026-05-19T09:00:00+00:00", "2026-05-20T09:00:00+00:00", "2026-05-21T09:00:00+00:00" ], "next_due_at": "2026-05-22T09:00:00+00:00" } ] } }

字段语义与渲染注意事项:

  • count是错过 tick 的真实总数,必须忠实展示。
  • ticks列表最多截断到 100 条——展示总数时如实呈现count,但如果逐条展示时间戳,列表需要截断。
  • next_due_at是用户不做任何操作时下一次未来触发的时间。
  • webhook 触发器永远不会被报告(事件驱动型,没有可重建的调度)。
  • 所有时间戳都是带显式+00:00/Z后缀的 UTC ISO 8601。渲染时用new Date(iso).toLocaleString()转换为本地时间,不要直接展示原始 UTC 字符串。

源码与测试佐证:

  • 计算逻辑位于 core/framework/host/triggers.py 的compute_missed:只考虑enabled=true的条目;非timer类型(webhook)直接跳过;没有last_fired_at(注册后从未触发过)的触发器贡献 0 个 missed tick(不会为注册之前的时段追溯触发);cron 与interval_minutes两种调度各自计算countticksnext_due_at。函数是纯函数、无副作用。
  • 事件类型在 event_bus.py 中有明确注释说明:会话加载时若某触发器的last_fired_at早于调度期望,即会话在若干次调度触发期间处于关闭状态,UI 弹出逐触发器的握手(fire 一次追补 / skip / reschedule),并把决定 POST 到/api/sessions/{id}/colony/resolve_missed
  • test_missed_triggers.py 验证了截断行为:cron 每 6 秒一次、缺口 1 天时count == 14400,而len(ticks) == 100(截断生效);另有针对禁用触发器、webhook 触发器、从未触发触发器、非法 cron 的各种跳过用例(test_missed_triggers.py)。

展示 "Catch up?" 弹窗

推荐形态:

  • 标题:Catch up while you were away?(离开期间要追补吗?)
  • 副标题:简要说明 colony 关闭期间触发器不会触发。
  • missed数组的每一行:
    • 触发器名称、错过次数、"next due at <本地时间>"。
    • 三个按钮:Fire latest(触发最新一次)/Skip(跳过)/Reschedule(重新排期)。
  • 一个Apply按钮,把收集到的全部决定一次性 POST 出去。

前端侧已经预留了实现锚点:在 core/frontend/src/pages/colony-chat.tsx 中有一段明确注释,说明后端会在会话加载后立刻发出missed_triggersSSE 事件,弹窗打开后用户为每个触发器选择fire_latest/skip/reschedule,随后前端 POST/colony/resolve_missed

POST 到/colony/resolve_missed

POST /api/sessions/{session_id}/colony/resolve_missed Body: { "decisions": { "<trigger_id>": "fire_latest" | "skip" | "reschedule", ... } }

每个触发器的决策语义:

  • fire_latest— 向 queen 注入一次追补触发器事件(负载带catch_up: true,queen 据此压缩工作量),并把last_fired_at推进到当前时间。
  • skip— 不触发,仅把last_fired_at推进到当前时间。
  • reschedule— 把last_fired_at推进到当前时间,并从当前时刻重新计算next_due_at到下一个未来 tick。不触发。

响应 200:

{ "results": { "daily_outreach": "fired", "hourly_check": "skipped", "ghost": "unknown_trigger", "bad": "invalid_decision:explode" } }

注意:handler 永远不会因为某一行的坏数据而让整个请求失败——前端应展示"部分成功"而非整体中止。

状态码:

状态码含义
200请求已处理(逐触发器读取results
400decisions不是对象
404未知 session
409session 未绑定 colony

源码级实现证据:

  • 路由注册位于 routes_sessions.py,处理函数为handle_resolve_missed_triggers(L1509)。其中:session 解析失败返回对应错误(未知 session → 404);session.colony_id is None返回409(L1523-L1524);JSON 解析失败返回 400(L1528-L1529);decisions非 dict 返回 400(L1531-L1536);内部异常返回 500 并记录日志(L1542-L1547)。
  • 核心决策执行位于 queen_lifecycle_tools.py 的resolve_missed:决策白名单为{"fire_latest", "skip", "reschedule"}(L671);未知决策返回invalid_decision:<value>、未知触发器返回unknown_triggerfire_latest会调用_inject_catch_up(L696-L721)构造一个带catch_up: True负载的TriggerEvent注入 queen 节点,并广播TRIGGER_FIREDreschedule通过_next_due_from(L674-L693)用 croniter(cron 表达式)或interval_minutes加法重新计算next_due_at
  • HTTP 层行为有端到端测试覆盖:test_missed_triggers_http_e2e.py 验证了 200(skip / fire_latest / 逐触发器标记)、400(decisions非 dict)、404(未知 session)、409(session 无 colony)全部分支;单测 test_missed_triggers.py 验证fire_latest注入追补(inject_trigger被调用一次)、skip不触发、reschedule设置未来next_due_atunknown_triggerinvalid_decision的标记返回。

Migration checklist(迁移清单)

  • 删除所有对/api/sessions/{id}/colony/state/activate/deactivate的调用。
  • 取消订阅colony_activatedcolony_deactivatedactivation_missed_triggers
  • 订阅missed_triggers(注意事件已重命名)。
  • 删除 Activate/Deactivate 切换开关组件。
  • 删除 "Active since…" 徽章。
  • 删除 queen 对话记录中的 "queued for next activation" 卡片;queen 工具不再返回该状态字符串。
  • 停止读取metadata.active/metadata.last_active_at
  • 停止从trigger_activatedset_trigger响应中读取colony_active
  • 侧边栏圆点简化成单一状态(session 已加载 vs 未加载),不再有每 colony 生命周期。
  • 新增 missed-trigger 握手弹窗,并接入POST /colony/resolve_missed

为什么移除它

一句话总结:旧前端需要调和四个状态(loadedmetadata.active、每触发器activeis_executing),如今它们塌缩为一个面向用户的单一问题——"该 colony 的会话是否已加载?"——外加一个面向高级用户的每触发器enabled配置开关,其余都是人为分层。加载 colony 本身就是激活,关闭它就是停用。

触发器的触发条件只有两个:colony 的会话已加载触发器的enabled为 true。没有额外的生命周期开关,也没有"已暂停但已加载"的状态。

对前端开发者而言,本次清理的收益是状态机的整体瘦身:删除四个组件/字段来源的冗余逻辑之后,触发器 UI 只剩下"CRUD + 实时状态 + 错过追补"三块,而后两块都已有清晰的后端契约(SSE 事件 + 单一 POST 接口)与测试兜底,可放心重构。


相关源码与测试索引

  • 前端握手实现锚点:core/frontend/src/pages/colony-chat.tsx
  • HTTP 路由与处理函数:core/framework/server/routes_sessions.py、路由注册 L3060-L3093
  • 决策执行与追补注入:core/framework/tools/queen_lifecycle_tools.py、L696-L721
  • 错过计算:core/framework/host/triggers.py
  • 事件类型定义:core/framework/host/event_bus.py
  • 单元测试:core/tests/test_missed_triggers.py
  • HTTP 端到端测试:core/tests/test_missed_triggers_http_e2e.py、core/tests/test_missed_triggers_routes_registered.py
  • 人工智能
  • AI Agent
  • 多智能体
  • MCP 服务
  • 工具调用
  • 浏览器控制

【免费下载链接】hive

Multi-Agent Harness for Production AI

项目地址:https://gitcode.com/gh_mirrors/hive48/hive
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询