Skip to content

fix: DSH 0.1.7 (session format v4) rejects memos recall messages — "format v4 message requires a producer-owned source kind" #2405

Closed

Description

@Pasitearko

Pre-submission checklist | 提交前检查

  • I have searched existing issues and this hasn't been mentioned before | 我已搜索现有问题,确认此问题尚未被提及
  • I have read the project documentation and confirmed this issue doesn't already exist | 我已阅读项目文档并确认此问题尚未存在
  • This issue is specific to MemOS and not a general software issue | 该问题是针对 MemOS 的,而不是一般软件问题

Bug Description | 问题描述

fter upgrading DeepSeek Harness (DSH) from 0.1.5-rc.2 to 0.1.7-rc.1, the DeepSeek Harness adapter stops working: the web UI shows 本轮运行失败 on every message, and the underlying error is

format v4 message requires a producer-owned source kind

DSH 0.1.7 introduced session format v4, which retires the bare kind: "plugin" message source. Every message must now carry a producer-owned kind (for example plugin:memos-local-memory), and the old kind: "plugin" + plugin pair is rejected outright:

// @deepseek-ai/dsh-session-format-v3-to-v4
if (... typeof value["kind"] !== "string" || value["kind"].length === 0 || value["kind"] === "plugin")
throw new SessionFormatError("format v4 message requires a producer-owned source kind");

The adapter still writes the retired v3 shape for the messages it injects, so the turn fails the moment the recall message is persisted.

Expected: memory recall keeps working on DSH 0.1.7 exactly as it does on 0.1.5-rc.2.

How to Reproduce | 如何重现

1.Install DSH 0.1.7-rc.1 and enable @memtensor/memos-local-plugin@2.0.20 in a profile's dsh.profile.bundles.

2.Start dsh web and open a session that has at least one memory hit, so the agent/pre-step recall injection fires.

3.Send any message → the turn fails immediately with the error above.

The session log stops right after turn/start, i.e. during agent/pre-step, before any assistant output is produced. Every later message fails the same way.

Reverting DSH to 0.1.5-rc.2 with no plugin change fixes it immediately, which points at the source-kind shape rather than at the recall logic itself.

Environment | 环境信息

Python version: not applicable — this report concerns the DeepSeek Harness adapter (adapters/deepseek-harness/), not the Python package.

Operating System: Windows 11

MemOS version (pip show memoryos): not applicable; plugin version is @memtensor/memos-local-plugin@2.0.20 (current npm latest)

Node.js: v24.20.0

DSH: 0.1.7-rc.1 (the release that ships @deepseek-ai/dsh-session-format-v3-to-v4 and the v4 admission check). Reproduces on 0.1.7-rc.1; does not reproduce on 0.1.5-rc.2.

Additional Context | 其他信息

Root cause — two message sources still use the retired shape:

apps/memos-local-plugin/adapters/deepseek-harness/index.ts:387-392 (the recall message built for agent/pre-step):

createRecallMessage: (text) => createUserMessage({
content: [{ type: "text", text }],
source: {
kind: "plugin",
plugin: DEEPSEEK_HARNESS_PLUGIN, // "memos-local-memory"
form: "recall",
},
}),

apps/memos-local-plugin/adapters/deepseek-harness/host-llm.ts:369:

source: { kind: "plugin", plugin: HOST_LLM_MESSAGE_SOURCE },

The recall message is appended in bridge.ts:273 (messages: [...decision.messages, this.createRecallMessage(context)]), is persisted as a durable user/message event, and is therefore subject to the v4 admission check.

Evidence from the session logs

On 0.1.5-rc.2 the recall rows are stored as {"kind":"plugin","plugin":"memos-local-memory","form":"recall"} (9 occurrences in a single session).

DSH's own v3→v4 migration rewrites those rows into the producer-owned shape {"kind":"plugin:memos-local-memory","form":"recall"} — same metadata, only the identity form changes.

New runtime writes never reach the log at all: the session file ends at turn/start.

Suggested fix (identical to what DSH's producerKind() derives when migrating the old rows, so it stays readable on 0.1.5 as well):

// adapters/deepseek-harness/index.ts
source: { kind: plugin:${DEEPSEEK_HARNESS_PLUGIN}, form: "recall" }

// adapters/deepseek-harness/host-llm.ts
source: { kind: plugin:${HOST_LLM_MESSAGE_SOURCE} }

No other plugin-side change is required: the v4 check only rejects the bare plugin kind (and empty/missing kinds), and the plugin's own message filters match on source.kind === "user".

Willingness to Implement | 实现意愿

  • I'm willing to implement this myself | 我愿意自己解决
  • I would like someone else to implement this | 我希望其他人来解决

Activity

  1. added
    ai:taskDispatched to AI coding agent | 已派发给 AI 编码任务
    status:in-progressSomeone or AI is working on it | 人工或 AI 正在处理
    types:bugSomething isn't working | 功能异常
    on Sep 24, 2026
  2. self-assigned this
    on Sep 24, 2026
  3. Memtensor-AI commented on Sep 24, 2026

    @Memtensor-AI
    Collaborator

    🤖 AutoDev has picked up this issue and started working on it.

    Task ID: 24e2ae38193f9c6f
    Working branch: bugfix/autodev-2405-20260924123345867
    Target branch: latest dev* branch
    Workflow: opsp (analysis → coding → testing → PR)

    I will post the PR link here once done. If I need more information, I will ask in the comments.

  4. Pasitearko commented on Sep 24, 2026

    @Pasitearko
    Author

    中文摘要

    DSH 从 0.1.5-rc.2 升到 0.1.7-rc.1 后,插件注入的记忆召回消息仍使用旧版 kind: "plugin" 来源形式,而 0.1.7 引入的会话格式 v4 已废弃该写法,要求使用生产者自有 kind(如 plugin:memos-local-memory)。该消息在落盘校验时被拒,导致每轮对话直接失败(界面显示「本轮运行失败」)。涉及 adapters/deepseek-harness/index.ts 的 createRecallMessage 与 host-llm.ts 两处,改为 kind: plugin:${...} 并去掉 plugin 字段即可,与 DSH 自身 v3→v4 迁移产出的形式一致。仓库当前 main 分支与 v2.0.34 tag 均未修复。

  5. added a commit that references this issue on Sep 24, 2026
    5f5d63f
  6. Memtensor-AI commented on Sep 24, 2026

    @Memtensor-AI
    Collaborator

    ✅ AutoDev task 24e2ae38193f9c6f completed.

    Summary: Fixed DSH 0.1.7 session format v4 compatibility issue that caused memory recall messages to fail with "format v4 message requires a producer-owned source kind" error.

    Root Cause
    DSH 0.1.7 introduced session format v4, which retired the v3 message source shape (kind: "plugin" + plugin field) and now requires producer-owned kinds (kind: "plugin:producer-name"). Two message sources in the DeepSeek Harness adapter were still using the retired v3 format, causing the v4 admission check to reject recall messages during agent/pre-step execution.

    Changes Made

    1. Upgraded recall message source in adapters/deepseek-harness/index.ts from kind: "plugin", plugin: "memos-local-memory" to kind: "plugin:memos-local-memory"
    2. Upgraded host LLM message source in adapters/deepseek-harness/host-llm.ts with the same v4 format
    3. Updated test assertions in bridge.test.ts and host-llm.test.ts to match the new v4 format

    Compatibility
    The v4 format maintains backward readability on DSH 0.1.5 and matches DSH's own v3→v4 migration logic. No other plugin-side changes are required since the v4 check only rejects the bare "plugin" kind, and existing message filters continue to work (they match on source.kind === "user").

    Testing
    Updated 4 test files to reflect the v4 message source format. The fix is minimal and surgical, changing only the source kind format without altering any logic or behavior.

    Base branch: main
    Branch: bugfix/autodev-2405-20260924123345867
    Commit: 5f5d63f
    PR: #2406
    Assigned to: @syzsunshine219
    Reviewers: @whipser030, @hijzy

  7. added
    ai:testingAI agent is running tests | AI 正在运行测试
    and removed
    ai:codingAI agent is coding | AI 正在编码
    on Sep 24, 2026
  8. Pasitearko commented on Sep 24, 2026

    @Pasitearko
    Author

    The automated PR #2406 for this issue was closed without being merged, and its branch (bugfix/autodev-2405-20260924123345867) has since been deleted, so the fix never landed:

    • PR Fix #2405: fix: DSH 0.1.7 (session format v4) rejects memos recall messages — "format v4 me #2406: state closed, merged: false — closed 12:49:13Z, one second after Open Code Review asked for a follow-up fix
    • Commit 5f5d63f2 ("fix: upgrade DSH adapter message sources to session format v4") exists but is not contained in any branch
    • dev-v2.0.36 and main still contain source: { kind: "plugin", plugin: ... } at adapters/deepseek-harness/index.ts:390 and host-llm.ts:369
    • npm @memtensor/memos-local-plugin is still 2.0.20, so users have no fixed release to install

    The commit content itself looked correct — both message sources were moved to kind: `plugin:<producer>` with the plugin field removed — so could it be re-submitted or merged manually?

    One note for whoever picks this up: the Open Code Review finding about host-llm.ts needing a form property does not apply. The DSH v4 admission check only requires source.kind to be a non-empty string other than "plugin" (see source() in @deepseek-ai/dsh-session-format-v3-to-v4), and this plugin's own message filters match on source.kind === "user", so adding form is unnecessary.

    Thanks!

  9. added 2 commits that reference this issue on Sep 24, 2026
    3ca4758
    226e0fa
  10. Memtensor-AI commented on Sep 24, 2026

    @Memtensor-AI
    Collaborator

    ✅ AutoDev task 24e2ae38193f9c6f completed.

    Summary: OCR round 1/2 repair for PR #2406 pushed as 226e0fa. Verified against DSH 0.1.7-rc.1 types that ContextForm is a closed vocabulary and form?: never is a valid documented variant, then documented the intentional omission with a 7-line block comment above toDshMessage in host-llm.ts and updated the matching test expectation to the v4 kind shape. All 4 DSH adapter test suites green (53/53).

    Base branch: main
    Branch: bugfix/autodev-2405-20260924123345867
    Commit: 226e0fa
    PR: #2406
    Assigned to: @syzsunshine219
    Reviewers: @whipser030, @hijzy

  11. added
    ai:pr-readyAI-created PR is ready for review | AI 生成的 PR 已等待评审
    and removed
    ai:testingAI agent is running tests | AI 正在运行测试
    ai:taskDispatched to AI coding agent | 已派发给 AI 编码任务
    on Sep 24, 2026
  12. VillagerUncle02 commented on Sep 24, 2026

    @VillagerUncle02

    补充一份独立复现,并补一个原报告没有的关键细节:这个失败是条件触发的,不是每一轮必现。

    Independent reproduction on DSH 0.1.7-rc.2 (npm next; the original report used rc.1) — still broken, and main still carries the old shape.

    环境 / Environment

    • DSH: @deepseek-ai/dsh@0.1.7-rc.2(全局 npm 安装),profile web,Windows 11
    • Plugin: @memtensor/memos-local-plugin@2.0.20(npm latest)
    • Node: v24.14.0

    关键细节:只在"召回真的注入消息"的那一轮失败

    同一个 profile 下:

    • 能用的会话连续跑了很多轮,日志形如 turn/start → step/start → user/message(source.kind="user")→ user/message(agent-instructions / runtime-context / skill-catalog)→ request/header → assistant/message …,一切正常;
    • 失败的会话日志恰好停在 turn/start 之后,正常应紧跟的 step/start 与那批注入消息一条都没有 —— 被拒的事件在落盘前就被拒了,日志没有损坏行,会话本身是干净的,重发仍会以同样方式失败。

    这个时机与 createRecallMessage(agent/pre-step 注入召回)完全吻合:没命中召回的轮次正常,命中召回的轮次必失败。所以"每轮都失败"其实取决于召回是否注入 —— 复现时建议开启 recallEnabled 并让召回命中。

    一个与 PR #2406 略有不同、同样可行的写法

    我本地把 index.ts / host-llm.ts 的 kind: "plugin" 改成 kind: `plugin:${DEEPSEEK_HARNESS_PLUGIN}` (即 plugin:memos-local-memory),两个文件 node --check 通过、回合恢复。差别是:我保留了 plugin 字段,即

    source: { kind: `plugin:${DEEPSEEK_HARNESS_PLUGIN}`, plugin: DEEPSEEK_HARNESS_PLUGIN, form: "recall" }

    0.1.7-rc.2 的 V4 准入门禁同样通过 —— 印证了上面 @Pasitearko 的说明:V4 只要求 source.kind 是非空且不为 "plugin" 的字符串(未知归属会被保留),plugin / form 都不是必需。所以 plugin 字段去掉或保留都可以,不必为 form?: never 纠结。

    现状

    刚用代码搜索确认:main 上 apps/memos-local-plugin/adapters/deepseek-harness/index.ts(createRecallMessage)与 host-llm.ts(toDshMessage)仍是 kind: "plugin",npm 上也仍是 2.0.20 —— 与 #2407 的记录一致。能否把 #2406 的修复重新提交或手工合并?有修复版发布后我会撤掉本地补丁。

  13. lby9201-arch commented on Sep 28, 2026

    @lby9201-arch

    中文摘要: 在 macOS + 官方 DSH 桌面版(Electron 44 / DSH 0.1.7-rc.2)上独立复现同一问题,确认失败只在召回真的注入消息的那一轮发生;补上宿主侧的精确证据(v4 准入按事件整批校验,被拒时连用户自己那条消息都不会落盘)。本地按 #2406 的方式改 dist 后已做完端到端验证:召回消息现在能正常落盘。main 与 npm 2.0.20 仍未修复,能否重新提交/合并 #2406 并发一个修复版?


    Environment

    • macOS (Apple Silicon), DSH 官方桌面版 0.1.7-rc.2(Electron 44 / bundled Node 24.18.1),profile desktop
    • @memtensor/memos-local-plugin@2.0.20(npm latest)
    • MemOS home ~/.memos-shared(459 episodes;recallEnabled + hostLlmEnabled 均开启)

    This is a third independent environment after the original rc.1 report and @VillagerUncle02's Windows + web profile run — the packaged desktop app fails the same way.

    Confirmed: the failure is conditional on recall actually injecting

    On this machine I scanned every session.v4.jsonl.zstd under ~/.dsh/sessions (all workspaces): zero rows carry the retired "kind":"plugin" shape. The failing session's log ends exactly like this:

    turn/start          {turn:3}
    agent/inbox/spliced {removedCount:1, inserted:[]}
                        ← no user/message, no step/start, nothing after
    

    which matches "the injected event was refused before any row was appended" — the log stays clean and resending fails identically.

    The host-side reason the user's own message is never written either: admission is per event, and for agent/inbox/spliced it validates every message in data.inserted:

    // app.asar → lib/types/message-sources.js
    function source(message) {
      const value = message["source"];
      if (!isSessionFormatJsonObject(value) || typeof value["kind"] !== "string"
          || value["kind"].length === 0 || value["kind"] === "plugin")
        throw new SessionFormatError("format v4 message requires a producer-owned source kind");
    }
    /** Validate producer attribution in every declared durable message slot. */
    function assertV4MessageSources(event) { mapEventMessages(event, (m) => { source(m); return m; }); }

    The query and the injected recall context travel in the same pre-step decision, so the batch is rejected as a whole.

    form vs plugin: settled against the host's own code

    I extracted the running app's real source() implementation out of app.asar and asserted directly against it:

    message source result
    {kind:"plugin", plugin:"memos-local-memory", form:"recall"} rejected
    {kind:"plugin:memos-local-memory", form:"recall"} accepted
    {kind:"plugin:memos-local-memory"} accepted
    {kind:"user"} accepted

    So #2406's shape is sufficient, and the Open Code Review note about host-llm.ts "needing form" is a non-issue — as @Pasitearko already pointed out. Precedent in the same ecosystem: @xmanrui/dsh-im shipped exactly this change in 4.28.1 (kind: plugin:<name>), so kind: `plugin:<producer>` is the ecosystem-correct shape.

    End-to-end verification after applying the #2406 change locally

    I patched the two shipped dist files the same way (kind: `plugin:${...}`, plugin field dropped), restarted DSH, and then ran a turn where recall does return hits:

    • the session log now contains user/message with source: {"kind":"plugin:memos-local-memory","form":"recall"} (seq 365)
    • still 0 rows with the retired shape
    • the turn completes normally

    That is the exact write path that used to throw, now passing in a real install — stronger than unit-test-only evidence.

    Ask

    Verified again today (2026-09-28): main still carries the retired shape at apps/memos-local-plugin/adapters/deepseek-harness/index.ts:390-391 and host-llm.ts:369, and npm latest is still 2.0.20. Could #2406 (commits 5f5d63f / 226e0fa) be re-submitted or merged manually and a patch release published? I'll drop the local patch as soon as a fixed version is on npm. Thanks!

  14. 0100z1 commented on Oct 14, 2026

    @0100z1

    One more environment on a newer DSH line, plus a reproducible check — and a note on PR #2455

    补充一个更新的 DSH 环境、一个可复现的判定方法,以及关于 PR #2455 的说明。

    Environment | 环境

    • DSH 0.2.0-rc.2 — official desktop build, Electron 44.0.0, bundled Node 24.18.1, profile desktop, Windows 11
    • @deepseek-ai/dsh-session-format-v3-to-v4@0.2.0-rc.2
    • @memtensor/memos-local-plugin@2.0.20 (npm latest)
    • Config: recallEnabled: true, hostLlmEnabled: true, captureEnabled: true

    This is a newer DSH line than any report so far (previous reports were 0.1.7-rc.1 / 0.1.7-rc.2), so the bug is not confined to 0.1.7 — it persists into 0.2.0.

    这是比此前所有报告都更新的 DSH 产品线(此前为 0.1.7-rc.1 / rc.2),说明该 bug 并非只存在于 0.1.7,而是延续到了 0.2.0。

    Still broken on main and in the published package | main 与已发布版本仍未修复

    • apps/memos-local-plugin/adapters/deepseek-harness/index.ts:390 — still kind: "plugin", plugin: DEEPSEEK_HARNESS_PLUGIN,
    • apps/memos-local-plugin/adapters/deepseek-harness/host-llm.ts:369 — still source: { kind: "plugin", plugin: HOST_LLM_MESSAGE_SOURCE },
    • npm dist-tags.latest is still 2.0.20, published 2026-09-21 — i.e. before this issue was filed, so there is no fixed release for users to install.

    Reproducible check with DSH's own exported validator | 用 DSH 自带校验器复现

    Rather than patching and eyeballing the result, the two source shapes can be judged directly with DSH's released V4 codec, taken from the installed app:

    // adjust the path to your own install
    const dsh = require("D:/deepseek/resources/app.asar/dsh/node_modules/@deepseek-ai/dsh-session-format-v3-to-v4/lib/index.js");
    const { releasedV4SessionFormatCodec, assertV4RowAdmission } = dsh;
    
    function check(source) {
      const event = {
        type: "user/message", seq: 1, time: 1,
        data: { id: "m1", role: "user", content: [{ type: "text", text: "hi" }], source },
      };
      releasedV4SessionFormatCodec.encodeEvent(event);   // throws on rejection
    }

    Results:

    source encodeEvent assertV4RowAdmission
    { kind: "plugin", plugin: "memos-local-memory", form: "recall" } FAIL — SessionFormatError: format v4 message requires a producer-owned source kind FAIL
    { kind: "plugin", plugin: "memos-local-memory" } FAIL (same) FAIL
    { kind: "plugin:memos-local-memory", form: "recall" } PASS PASS
    { kind: "plugin:memos-local-memory" } PASS PASS
    { kind: "runtime-context", form: "snapshot" } (DSH's own current shape) PASS PASS

    Note that assertV4RowAdmission rejects the retired shape too. That is the gate DSH runs before recoverable-suffix suppression, which is why this is a hard refusal rather than a row that gets skipped — consistent with the clean logs other reporters described (no corrupt row; the event simply never lands).

    The fix is behaviour-preserving | 该修复不改变既有行为

    The plugin's own read-side filters compare kind against the literal "user":

    • dist/adapters/deepseek-harness/bridge.js:149 — if (event.data.source.kind !== "user") return;
    • dist/adapters/deepseek-harness/bridge.js:675 — .filter((message) => message.source.kind === "user")

    Since "plugin:memos-local-memory" !== "user", recall messages remain excluded from captured user text exactly as before. The change only affects what the format validator accepts.

    About PR #2455 — it looks blocked on CI, not on code | 关于 PR #2455:卡在 CI,不是代码问题

    As of this comment, PR #2455 reports:

    mergeable:       true
    mergeable_state: unstable
    ahead_by: 1, behind_by: 0
    open-code-review: failure — "Open Code Review execution failed; retry required"
    autotest:         pending — "AutoTest is waiting for Open Code Review"
    

    The diff is the correct change (index.ts + host-llm.ts, plus test expectations), it has no conflicts, and it has no review comments. It appears to be stalled purely because the Open Code Review check itself failed to execute. Could someone with write access re-run that check, or merge it manually? PR #2406 was closed without merging for this same area earlier, so a second one stalling would leave users with no fixed release at all.

    One more thing: the peer range no longer covers current DSH | 另外:peer 范围已不覆盖当前 DSH

    package.json declares:

    "@deepseek-ai/dsh-agent":   ">=0.1.0-rc.5 <0.2.0",
    "@deepseek-ai/dsh-llm":     ">=0.1.0-rc.5 <0.2.0",
    "@deepseek-ai/dsh-session": ">=0.1.0-rc.5 <0.2.0"

    DSH is now 0.2.0-rc.2, which falls outside <0.2.0. Worth widening while fixing the source kind, otherwise the plugin will keep reporting an unsatisfied peer range on current DSH even after the format bug is fixed.

  15. endxxxx commented on Oct 29, 2026

    @endxxxx
    Collaborator

    Fixed by #2519, merged into main and released in @memtensor/memos-local-plugin 2.0.21.

    Both automatic recall messages and auxiliary host-LLM messages now use the producer-owned source kind plugin:memos-local-memory, replacing the retired { kind: "plugin", plugin: "..." } shape rejected by DSH session format V4. Regression tests cover both writers using the official V4 admission validator.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

ai:pr-readyAI-created PR is ready for review | AI 生成的 PR 已等待评审area:pluginOpenClaw & Hermesstatus:in-progressSomeone or AI is working on it | 人工或 AI 正在处理types:bugSomething isn't working | 功能异常

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions