Repository navigation
Open
Description
概要
两个可用性问题,都是「面板/文档说了,代码里没有」:
- OpenCode 系模型路由下,后台 LLM 调用必然 400:总结提炼(
summarize)、记忆巩固(dream)、实体抽取(entityExtract)都不传sessionId,而 pi-ai 的 opencode / opencode-go 适配器只在options.sessionId存在时才注入x-opencode-session头,于是被网关拒绝。表现是「记忆 → 状态」页全是失败。 kbEnabled没有任何 UI 入口:键在 config schema 与 settings 白名单里,但 v0.13.0 的FEATURE_GROUPS不含它;而知识库空态文案仍写着「打开 设置 → 记忆(mneme) → 功能 → 知识库」,用户照做找不到,只能调 HTTP 接口才能开。
环境
- DeepSeek Harness 桌面客户端 0.2.2-rc.1(Windows 11)
@modusensus/dsh-mneme0.13.0- 模型路由:
opencode-go / deepseek-v4.1-flash(pi-ai 的 opencode-go provider) - 未配置
dreamProvider/summarizeProvider/entityExtractionProvider,走 agent 默认模型
问题一:后台 LLM 全部 400 MissingSessionID
现象
「记忆 → 状态」里「总结提炼」「记忆巩固」每条都是失败,点开错误是 llm stream error 或完整 400。
证据
llm_audit_logs(截取):
| id | trigger_source | operation_type | model_id | status | error_message |
|---|---|---|---|---|---|
| 283 | autoSummarize | summarize_compress | opencode-go:deepseek-v4.1-flash | error | llm stream error |
| 282 | autoSummarize | summarize_compress | 同上 | error | llm stream error |
| 281 | autoSummarize | summarize_compress | 同上 | error | llm stream error |
| 280 | autoDream | dream_consolidate | 同上 | error | llm stream aborted or errored (INVALID_REQUEST: 400: {"type":"MissingSessionID",...}) |
| 279 | entityExtract | entity_extract | 同上 | error | INVALID_REQUEST: 400: {"type":"MissingSessionID","message":"Request is missing x-opencode-session ..."} |
distill_runs 里同一条错误原文:
INVALID_REQUEST: 400: {"type":"MissingSessionID","message":"Request is missing x-opencode-session and cannot be routed efficiently. Please see https://opencode.ai/v2/docs/console/go/#where-can-i-use-it"}
根因
pi-ai 的 opencode-go 适配器 dist/providers/opencode-headers.js:
const OPENCODE_SESSION_HEADER = "x-opencode-session";
function withSessionHeader(options) {
if (!options?.sessionId || hasHeader(options.headers, OPENCODE_SESSION_HEADER)) return options;
return { ...options, headers: { ...options.headers, [OPENCODE_SESSION_HEADER]: options.sessionId } };
}即只有 options.sessionId 存在才注入该头。
- 主对话正常:
@deepseek-ai/dsh-agent-loop在请求里带sessionId: this.session.id(lib/index.js:1090)。 - 插件后台调用失败:mneme 的 6 处
ctx.llm.stream(...)都没有传sessionId:lib/dream.js:291lib/dream/sleep.js:87lib/summarize.js:967lib/index.js:152(实体抽取)lib/pre-inject-gate.js:239lib/api.js:830
建议
后台调用传一个稳定标识,例如 sessionId: "dsh-mneme"(或按 run id 派生)。它只用于网关路由,不参与会话归属,和现在「LLM 审计行 session_key 恒 NULL」的语义一致。
另一条路是宿主侧兜底(见下方「临时绕过」),但那需要用户自己装插件,不该是默认体验。
问题二:kbEnabled 没有 UI 入口
lib/config.js:1181定义了kbEnabled: z.boolean().default(false)lib/settings.js的FEATURE_FLAG_BOOLEANS白名单包含kbEnabled- 但
lib/client.js的FEATURE_GROUPS、FEATURE_ADVANCED_BOOLS、FEATURE_STRINGS都不含它 → 设置页永远不会渲染这一项 - 空态文案
kb.empty.disabled(lib/client.js:372)却写着「打开 设置 → 记忆(mneme) → 功能 → 知识库,打开开关后重启 DSH 生效」
对比:M.O. 那组下架时 client.js:4197 留了注释说明「随时可恢复」,知识库没有。
建议
二选一:
- 把
kbEnabled加回FEATURE_GROUPS(比照chorographyEnabled放在 enhance 组),恢复 UI 开关; - 或把空态文案改成实际可操作的说法,例如「在
PUT /api/dsh-mneme/features里置kbEnabled: true后重启」。
临时绕过(供其他用户参考)
补头(宿主侧插件,参加 llm-pi-ai/request-headers waterfall):
ctx.on('llm-pi-ai/request-headers', (request, headers, next) => {
if (request?.provider === 'opencode-go' && !headers.has('x-opencode-session')) {
headers.set('x-opencode-session', String(request.sessionId ?? 'dsh-background'))
}
return next()
})开知识库:
curl -X PUT http://127.0.0.1:<port>/api/dsh-mneme/features \
-H 'content-type: application/json' \
-d '{"kbEnabled":true}'
# 然后重启 DSH;GET /api/dsh-mneme/kb/collections 返回 200 即生效验证补头是否成功,可用 POST /api/dsh-mneme/test-model {} —— 它走的正是后台无会话调用路径,修复前 400,修复后返回 {"ok":true,...,"reply":"ok"}。
Metadata
Metadata
Assignees
Labels
No labels
Activity
modusensus commentedon Nov 12, 2026
两半都看了,结论分开说。
一、
x-opencode-session缺头:属实,已修(PR #670)你说得对,而且原因比标题更宽一点:不是某个调用点漏了,是七处后台调用全都没传
sessionId。src/dream.js/src/dream/sleep.js的本地streamText(覆盖全部 7 个 dream/sleep 相位)src/summarize.js(蒸馏)src/index.js(实体抽取流)src/pre-inject-gate.js(注入门控)src/api.js(连通性探测)src/image-describe.js(图像描述)pi-ai 的
dist/providers/opencode-headers.js里withSessionHeader只在options.sessionId存在时才注入x-opencode-session,没有就直接 400——所以这条在多数网关上完全无声,只有 OpenCode 这类严格网关会炸出来。修法:新增
src/llm-session.js,BACKGROUND_SESSION_ID = "dsh-mneme"+withBackgroundSession(options),七处统一包一层。两个刻意选择:sessionId时不覆盖——注入链路上可能带真实用户会话过来,那时换掉 id 等于伪造来源。PR:#670 (测试与五轮变异自证在正文里)
二、
kbEnabled没有 UI 入口:只对 0.13.0 成立,beta 起已修我核了 tag 差异:
v0.13.0的lib/client.js只有group.basic / core / enhance / dream / scope五组,确实没有扩展组的入口。v0.14.0-beta.1起的提交97317871(#607「三个扩展子系统的总闸提到设置页首屏」)新增了group.ext: ["chorographyEnabled", "kbEnabled", "diaryEnabled"],beta.1 / beta.2 / beta.3 都带着它。所以这条升级到 0.14.0-beta.3 就好,不用改代码。顺带说明一句:这个版本整体是预发布,
npm i dsh-mneme装的还是 0.13.0,需要显式装 beta。一点补充
本机库里
MissingSessionID记录是 0 条——因为当前走的是 xdpool/workbuddy,不受这个头影响。也就是说 #670 修的是你换到 OpenCode 或其它严格网关时的硬失败,不是现在就能观测到的回归。这个边界我写进 PR 的「已知边界」了,免得以后有人以为是修了一个线上正在发生的故障。