Bug: SessionFormatError "format v4 message requires a producer-owned source kind" - agent turns intermittently fail (core 0.1.7-rc.1) #7800
Replies: 3 comments 1 reply
这条报错是 v4 有意拒绝"已退役的插件来源包装"——而你自己正好跑着一个桌面插件1. 规则在这里,而且注释就写明了意图
function source(message: Readonly<Record<string, unknown>>): void {
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')
}
}同文件第一行的模块注释是整件事的关键:
⇒ 也就是说: 2. 为什么是"写入时"炸,而且会连带标题与投影缓存你贴的调用链 会被检查的行类型(同文件 3. 首要嫌疑:你环境里那个桌面插件你的环境写的是 DSH Desktop 2.0.14( 建议的判别实验(很便宜):
4.
|
|
Resolved: producer was dsh-vision-router, fixed in v2.2.3 Not a core regression: the refusal rule is intentional and unchanged rc.1 → rc.2. In our case the offending rows (source.kind === "plugin") were written by dsh-vision-router@2.2.2 (11 call sites in its bundle). v2.2.3 explicitly recognizes session format v4 — upgrading the plugin fixes it, no settings migration. Interim workaround while a producer is unpatched: reader-side tolerance in assertV4SourceRowAdmission (rewrite kind:"plugin" → a producer-owned kind instead of throwing); it lives in node_modules, so re-apply after each app update. Note: rows already persisted in session files keep failing on every encode even after the offending plugin is disabled — so removing the plugin alone does not recover existing sessions; only this tolerance (or cleaning the rows) fixes them, while upgrading the producer prevents new rows. One genuine core-side improvement this surfaced: the error drops the whole batch without naming the offending event — include seq/row type/plugin so the producer is identifiable and the primary turn error is not masked. |
你的结论与我核到的代码完全一致,而且你那条"核心侧改进"我能给出确切的落点1. 先确认你的三条发现都对得上代码
2. 你提的"核心侧改进"——落点就在那个 switch 上你说错误"丢掉整批却不指名冒犯的那条事件",并建议带上
if (!isSessionFormatJsonObject(row) || !isSessionFormatJsonObject(row['data'])) return // :30
const messages = row['type'] === 'user/message' ? [data] // :32 ← 已经知道 row type
: row['type'] === 'system/message' || row['type'] === 'assistant/message' || row['type'] === 'tool/result' ? [data['message']]
: row['type'] === 'agent/inbox/spliced' ? data['inserted']
: row['type'] === 'session/title-llm-request' ? data['messages'] : []
…
if (isSessionFormatJsonObject(value) && value['kind'] === 'plugin') source(message) // :40⇒ 也就是说:这个函数已经拿到了整行 建议把诉求写成:
这比"请提供更多信息"更容易被采纳——因为它连同"信息已经在该函数作用域内"这一点一起给出了。 3. 你那条临时规避的风险提示请务必保留你写的"reader-side tolerance(把 4. 版本提醒
一条边界我确认的是拒绝规则与 rc.1→rc.2 未变、检查发生在编码时、以及 |
Uh oh!
There was an error while loading. Please reload this page.
Summary
Agent turns intermittently fail with
SessionFormatError: format v4 message requires a producer-owned source kindwhen the session persistence layer encodes an event. The session itself survives (later turns succeed), but the failed turn is lost and automatic title generation + projection cache writes also fail.Environment
session.v4.jsonl.zstd(v4 format, zstd-compressed)Symptom (host log)
Followed by:
Observations
MISSING_CREDENTIAL(user had picked thedeepseek-officialprovider without an API key configured): the failed turn's error-report write then hit the sameSessionFormatError, masking the primary cause.Analysis / hypothesis
The error is raised by
source()indsh-session-format-v3-to-v4/lib/index.js:assertV4SourceRowAdmission(line ~142) only throws for messages whosesource.kind === "plugin"(retired v3 wrapper syntax);assertV4MessageSources(line ~132) requires every durable message to have a non-emptysource.kindthat is not"plugin".So at least one event being encoded contains a message with
source.kind === "plugin"(or an empty/missing source) — most likely the agent-error report message written bydsh-agent-error(or an inbox splice produced by a plugin) which still uses the retired v3{ kind: "plugin", plugin: "…" }shape. Because the failure happens insideencodeEventBatch, the whole batch write fails and the primary turn error is swallowed (the log shows only the SessionFormatError, no earlier[E]).Expected behavior
Notes
SessionFormatError/ "producer-owned source kind".All reactions