feat(amsg-server): onBeforeFire skip 出口 + GET /messages 投影 charId/clientTaskId#28
Conversation
宿主在 fire 时刻就能判断消息已多余时,onBeforeFire 返回 { skip: true }
作废本次触发:算一次零推送成功(status: 'skipped'),一次性任务照删、
循环任务照推进到下次,不调 LLM、不耗 token。返回 null 的老语义不变。
Claude-Session: https://claude.ai/code/session_017mfb5T9eZU4iHpFbCEmeqR
There was a problem hiding this comment.
Code Review
This pull request introduces a new { skip: true } return option for the onBeforeFire hook, allowing the host to cancel a scheduled message fire before the first LLM call is made, resulting in a zero-push success. The feedback suggests improving code cohesion by centralizing the validation of { skip: true } inside normalizeBeforeFireResult to avoid inconsistencies with its updated error message, and simplifying the redundant type check typeof before === 'object' in runAgenticFire since before is already verified to be non-null.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| } | ||
| throw new TypeError( | ||
| 'AGENTIC_BAD_BEFORE_FIRE: onBeforeFire must return ChatMessage[] | { messages, maxToolIterations?, totalTimeoutMs? } | null' | ||
| 'AGENTIC_BAD_BEFORE_FIRE: onBeforeFire must return ChatMessage[] | { messages, maxToolIterations?, totalTimeoutMs? } | { skip: true } | null' |
There was a problem hiding this comment.
| // conversation moved on after the task was scheduled). Shaped exactly like | ||
| // the post-LLM 'skipped' result, so run-tick's success handling (delete | ||
| // once-off / advance recurrence) applies unchanged — and zero tokens spent. | ||
| if (typeof before === 'object' && before.skip === true) { |
There was a problem hiding this comment.
由于在第 183 行已经进行了 before == null 的空值检查,此时 before 已经确保不为 null 或 undefined。在 JavaScript 中,对任何非空原始类型(如字符串、数字、布尔值等)访问属性都是安全的(会返回 undefined 而不会报错)。因此,这里的 typeof before === 'object' 判断是多余的,可以直接简化为 before.skip === true,使代码更加简洁和地道。
| if (typeof before === 'object' && before.skip === true) { | |
| if (before.skip === true) { |
每条任务额外返回 charId / clientTaskId(取自任务 metadata 的 charId / amsgClientTaskId,缺省 null),供宿主按角色归属筛选任务。metadata 其余 字段与凭据类字段照旧不回传。 Claude-Session: https://claude.ai/code/session_017mfb5T9eZU4iHpFbCEmeqR
本 PR 含两项上游改动,同属一次发版(下游 SullyOS amsg2 多任务改造依赖这两项)。均只动
@rei-standard/amsg-server,各带 changeset(minor),未发版。1. onBeforeFire 支持
{ skip: true }生成前跳过onBeforeFirehook 新增第三条出口:返回{ skip: true },让宿主在第一次 LLM 调用之前作废本次定时触发。原来只有两条路——返回 messages(fire 时刻现场组装 prompt),或返回
null(回退排程时冻结的 completePrompt 老链路)。现在多一条:{ skip: true }直接把本次 fire 当成一次零推送的成功投递结束(status: 'skipped'),一次性任务照删、循环任务照推进到下次,不调用 LLM、不消耗 token。用途:宿主在 fire 时刻就能判断这条消息已经多余(比如排程之后对话又有了新进展)时作废它。返回
null的既有语义不变。server/src/server/lib/agentic-fire.jsbefore == null判断后新增{ skip: true }分支,返回形状与既有 skip-push 一致(iterations: 0);同步更新文件头流程注释、@returnsJSDoc、AGENTIC_BAD_BEFORE_FIRE文案server/src/server/lib/message-processor.jsserver/examples/cloudflare-single-user/README.md{ skip: true }一行2.
GET /messages投影 charId / clientTaskIdGET /messages每条任务额外返回charId/clientTaskId(取自任务 metadata 的charId/amsgClientTaskId,缺省null),供宿主按角色归属筛选任务——contactName会在不同角色间重名,不可靠。边界:只投影这两个字段,不回传整个 metadata(其余可能是宿主自定义数据);凭据类字段照旧不回传;老任务无这俩字段返回
null不报错;响应照旧整体加密。分页未动。server/src/server/handlers/messages.jsdecryptedTasks投影加charId/clientTaskId(?? null兜底)验证
packages/rei-standard-amsg/server全量测试 185 passed / 0 failed。https://claude.ai/code/session_017mfb5T9eZU4iHpFbCEmeqR