Repository navigation
fix(llm): 消息补 source 字段——严格 provider 下不再于序列化阶段抛 TypeError(#189) - #190
Conversation
) dsh-llm 的消息契约要求每条消息带 source(lib/types/message.d.ts:119-129, 「Required source fields supplied by the producer」)。mneme 手拼的 13 处 LLM 消息缺该字段,遇到会读 message.source.kind 的 provider 适配器 (如 dsh-commandcode-provider 的 messagesToCC)时,请求在序列化阶段同步抛 TypeError —— 0–8ms 失败且不发出任何网络请求。内置 dsh-llm-deepseek 从不读 该字段,所以这个契约违背长期潜伏,只在更换 provider 时一次性暴露。 按契约补 source: { kind: "plugin", plugin: "dsh-mneme" },不改 content 形状、 不新增 import(peer 0.1.0-rc.8 未导出 createSystemMessage,用字面量才能同时 兼容 rc.6 / rc.8 / 2.0.x)。 覆盖 13 处:dream.js ×2(consolidation / dream summary)、dream/sleep.js ×2 (conflict / pattern)、entities/extractor.js、summarize.js(system 消息 + createUserMessage 调用)、api.js(连接探测用的 system 消息)。 新增 test/llm-message-source.test.js:4 个用例以严格桩驱动真实管线 (dream / summarize / sleep / entity extraction),逐条断言 message.source.kind === "plugin"。
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (11)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthrough本次修改为 dsh-mneme 各条 LLM 调用管线的消息增加插件来源元数据,并新增回归测试验证 dream、summarize、sleep 和实体抽取流程。 ChangesLLM 消息来源标记
Priority: ➖ Normal Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix · Severity of issue fixed: Medium Suggested reviewers: Merge Risk: ⚪ Minimal · up to The affected LLM request paths now provide the required source metadata, with regression coverage for the primary pipelines. No actionable merge risk remains. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
modusensus
left a comment
There was a problem hiding this comment.
复验通过,逐项核对:
契约与根因:@deepseek-ai/dsh-llm 的 lib/types/message.d.ts 对 Message.source 的注释原文确为 "Required source fields supplied by the producer"(必填);dsh-llm-deepseek 不读该字段所以官方路由长期不显现,第三方适配器一读就炸——报告的机制判断准确。
改动面:13 处手拼消息(dream ×4、sleep ×4、entity extraction ×2、summarize ×2、连接探测 ×1)全部补上 source: { kind: "plugin", plugin: "dsh-mneme" },src/lib 双侧同步,无 content 形状变化、无新增 import,兼容取舍(不引 createSystemMessage 以兼容 rc.6/rc.8)合理。
测试:test/llm-message-source.test.js 用严格桩驱动四条真实管线(dream / summarize / sleep / entity extraction)并逐消息断言 source.kind === "plugin"——不是空转测试,任何新增消息漏了 source 都会红。本地全量跑过:新用例 4/4,整体 1 034 pass + 1 环境跳过、0 fail,与 CI 矩阵一致。
A/B 数据:修前 0–8 ms 序列化阶段 TypeError vs 修后 summarize/dream 全 success、applied=51——指纹(毫秒级失败 = 请求根本没发出去)抓得很准。
后续两点记下了:@mars-sea/dsh-commandcode-provider 侧的可选链加固由报告者知会其作者(不在本仓范围);dsh-llm 的 forAdapter 裸读点属于宿主侧,我们会在宿主反馈线里提。感谢 @heptaspirit —— 报告、修复、回归测试、A/B 一条龙,这正是我们想要的贡献形态。
实测 0.1.6-alpha.1 上 test-model 返回 502「INVALID_REQUEST: messages: at least one message is required」:新适配器把 system 消息抽成顶层 参数后,探测此前发送的 system-only 单条消息成了零条对话,官方 API 整单拒绝。同一探测在 0.1.2-rc.1 时代(system 进 messages)一直正常。 探测改为一条 user 消息(保留 #189 的 source 标注)——user 在任何 适配器/校验下都是合法对话,不怕 host 侧继续演进。回归断言锁定 role=user + source.kind=plugin。 主链路无恙:dream/summarize/实体抽取本就发送 system+user,alpha 上 实测 dream_consolidate success(53.8s 真实运行)。 (叠在 #190 之上,先合 #190 再合本 PR。)
实测 0.1.6-alpha.1 上 test-model 返回 502「INVALID_REQUEST: messages: at least one message is required」:新适配器把 system 消息抽成顶层 参数后,探测此前发送的 system-only 单条消息成了零条对话,官方 API 整单拒绝。同一探测在 0.1.2-rc.1 时代(system 进 messages)一直正常。 探测改为一条 user 消息(保留 #189 的 source 标注)——user 在任何 适配器/校验下都是合法对话,不怕 host 侧继续演进。回归断言锁定 role=user + source.kind=plugin。 主链路无恙:dream/summarize/实体抽取本就发送 system+user,alpha 上 实测 dream_consolidate success(53.8s 真实运行)。 (叠在 #190 之上,先合 #190 再合本 PR。)
Closes #189
问题
dsh-llm 的消息契约要求每条消息带
source(lib/types/message.d.ts:119-129,注释原文「Required source fields supplied by the producer」)。mneme 手拼的 13 处 LLM 消息缺该字段;遇到会读message.source.kind的 provider 适配器(本机是@mars-sea/[email protected]的messagesToCC)时,请求在序列化阶段同步抛TypeError—— 0–8 ms 失败,且不发出任何网络请求。内置dsh-llm-deepseek从不读该字段,所以这个契约违背长期潜伏,只在更换 provider 时一次性暴露。改动
按契约给这 13 处补
source: { kind: "plugin", plugin: "dsh-mneme" },不改content形状、不新增 import(peer0.1.0-rc.8未导出createSystemMessage,用字面量才能同时兼容 rc.6 / rc.8 / 2.0.x):dream.js×2(consolidation / dream summary)dream/sleep.js×2(conflict / pattern)entities/extractor.js×1summarize.js×2(system 消息 +createUserMessage调用)api.js×1(连接探测用的 system 消息)system 消息也一并补上:当前只有 user 角色会被读取(commandcode 会跳过 role system,避免与
options.system重复),但契约对所有消息生效,补上不留同类缺口。验证
test/llm-message-source.test.js:4 个用例以严格桩驱动真实管线(dream / summarize / sleep / entity extraction),逐条断言message.source.kind === "plugin"。node --test --test-isolation=none test/*.test.js:全量 1 033/1 035(唯一失败是受限沙箱下的spawn EPERM环境限制,与本改动无关)。npm run sync后scripts/check-sync.js逐字节一致(37 文件)。TypeError;修后 summarize success 8 450 / 14 240 / 11 337 ms,dream_consolidatesuccess 90 104 ms +dream_summarizesuccess 4 571 ms,dream_runs由failed, applied=0变为ok, applied=51,期间 121 条记忆被实际更新。遗留
@mars-sea/dsh-commandcode-provider那四处读法加可选链(message.source?.kind)即可挡下这类消息;该插件归其作者维护,不在本仓库范围。Summary by CodeRabbit
改进
测试