Skip to content

fix: 修复 #285 的 memo 非法消息窗口与 provider 错误包装#287

Merged
phantom5099 merged 4 commits into
1024XEngineer:mainfrom
wynxing:refix_br
Apr 14, 2026
Merged

fix: 修复 #285 的 memo 非法消息窗口与 provider 错误包装#287
phantom5099 merged 4 commits into
1024XEngineer:mainfrom
wynxing:refix_br

Conversation

@wynxing

@wynxing wynxing commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator

背景

issue #285 当前问题 3、4 分别表现为:

  • memo 自动提取最近消息时,可能把不完整的 assistant tool_calls 片段直接发给 provider,触发非法消息序列。
  • provider.GenerateText 在非流式 HTTP 错误场景下,可能额外包装成 message_done missing,导致最终错误信息失真。

修改

  • internal/context 提炼共享消息投影能力:
    • 新增 ProjectToolMessagesForModel,统一复用主链路的 tool 消息投影规则。
    • 新增 BuildRecentMessagesForModel,从会话尾部构造 provider-safe 的 recent window。
  • 调整 memo recent window 规则:
    • 只保留完整的 assistant tool_calls + tool span。
    • 丢弃缺少 tool 响应的 assistant span。
    • 丢弃孤立 tool 消息。
    • 丢弃已被 micro compact 清空内容的旧 tool 结果。
  • internal/memo/llm_extractor.go 改为复用上述共享 helper,避免继续发送非法消息窗口。
  • 调整 internal/provider/generate.go 的错误优先级:
    • Generate(...) 直接返回 provider 错误时,优先返回上游错误。
    • 仅在 Generate(...) == nil 且流正常结束却缺少 message_done 时,才返回流式中断错误。
    • 若同时存在真实流处理错误,仍保留组合错误。
  • 同步更新 docs/runtime-provider-event-flow.md,补充 recent window 合法性约束和错误语义说明。

测试

已新增/更新以下回归测试:

  • internal/memo/llm_extractor_test.go
  • internal/provider/generate_test.go
  • internal/context/builder_test.go
  • internal/app/bootstrap_test.go

本地验证:

go test ./...

@codecov

codecov Bot commented Apr 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.66234% with 19 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/context/projection.go 85.92% 10 Missing and 9 partials ⚠️

📢 Thoughts on this report? Let us know!

fennoai[bot]

This comment was marked as outdated.

@wynxing

wynxing commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator Author

/simplify

@fennoai

fennoai Bot commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

完成情况

已按触发指令完成以下工作并推送到当前 PR 分支 Yumiue:refix_br(commit: f1b233e):

  • 读取评论日志并评估未解决 review 评论;
  • 认定两条评论均值得修复,并完成实现:
    • BuildRecentMessagesForModel 增加 recent window 总消息数硬预算,避免 tool span 导致窗口失控;
    • 对 memo recent window 中的 projected tool 内容做摘要化截断,降低原始输出暴露面;
  • 按要求调用了代码简化代理(在 projection.go 提炼了公共标记逻辑);
  • 新增/更新回归测试:internal/context/projection_test.go
  • 执行验证:go test ./... 全量通过;
  • 已提交并推送到 PR 分支。

未执行项

  • 未新增其他 PR;本次为现有 PR 分支直接推送。

View job run

…ayload

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: Yumiue <188874804+Yumiue@users.noreply.github.com>
@wynxing

wynxing commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator Author

/review

fennoai[bot]

This comment was marked as outdated.

@wynxing

wynxing commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator Author

/simplify

@fennoai

fennoai Bot commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

完成情况

已按触发指令完成处理,并推送到当前 PR 分支 Yumiue:refix_br(commit: d443271)。

本次完成内容:

  • 读取历史评论并评估未解决 review comments;
  • 修复 internal/context/projection.go
    • matchedToolCallSpan 仅接受可投影的 tool 响应(要求可注入且含 ToolMetadata),避免将非投影 raw tool 内容带入 memo 提取窗口;
    • 增加 raw tool 文本兜底摘要化(content_excerpt + 600 rune 截断标记);
  • 使用子代理执行 code-simplifier 审阅并合并可安全简化:
    • matchedToolCallSpan 改为单次扫描收集索引后拼接 span;
    • TestBuildRecentMessagesForModelBoundaries 改为表驱动;
  • 补充/更新文档 docs/runtime-provider-event-flow.md,明确 recent window 硬预算 min(limit*2, 24) 与 tool 文本 600 rune 收敛约束;
  • 更新回归测试覆盖上述变更;
  • 本地验证通过:go test ./...

未完成项:

  • 未新建 PR(本任务在现有 PR 分支直接推送)。

View job run

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: Yumiue <188874804+Yumiue@users.noreply.github.com>
@phantom5099

Copy link
Copy Markdown
Collaborator

/review -codex

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

整体实现方向正确,测试也比较完整。我这里保留 3 个仍建议修正的问题(1 个安全边界、2 个文档准确性)。

return nil
}

return sanitizeRecentWindowToolMessages(ProjectToolMessagesForModel(cloneContextMessages(selected)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BuildRecentMessagesForModel 把 tool 消息投影后直接送入 memo 提取链路。当前 FormatToolMessageForModel 会保留 meta.path/root/workdir,并附带 content_excerpt(最多 600 rune)。这会把本地路径和工具输出片段跨边界发送到提取模型,数据最小化仍不够。建议在 memo 场景增加专用投影(仅保留必要字段,如 tool_name/status + 更强摘要),默认去掉 meta.* 路径类字段。

- 调度时会绑定当次 provider/model 快照,后台任务不会重新读取全局当前配置,避免把历史会话消息发送到后续切换后的 provider。
- 自动提取失败只记日志,不额外发出 TUI 事件,也不影响主链路完成。
- `memo` 的最近消息窗口会复用 `internal/context` 的只读投影规则,只保留 provider-safe 的消息序列。
- assistant 含 `tool_calls` 时,只有在窗口内能同时保留对应 `tool` 响应时才会注入;缺响应、空内容或已被 micro compact 清空的 assistant/tool 片段会整组丢弃,保留项会先投影为模型可消费的结构化文本。

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里的描述少了一个实现条件:tool 消息还需要满足“可投影”(ToolMetadata 非空)才会保留。当前文案只写了“缺响应/空内容/cleared”会丢弃,和 matchedToolCallSpan 的真实过滤条件不完全一致。建议补一句,避免读者误解。

- runtime 将累积过程映射成 `RuntimeEvent`
- TUI 使用 Bubble Tea `Cmd` 监听事件,并在处理完成后继续订阅
- `provider.GenerateText` 只在上游 `Generate` 成功返回时,才把缺失 `message_done` 视为流式中断。
- 如果 provider 在真正开始流式输出前直接返回 HTTP/ProviderError,则优先保留原始错误,不再额外包装成 `message_done` 缺失。

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这句把错误优先级限定为“真正开始流式前直接返回 ProviderError”。但实现更宽:只要 Generate(...) 返回错误,且流侧唯一问题是 message_done 缺失,就会优先返回原始 provider 错误(包括已有部分 text_delta 的情况)。建议把表述改成与 internal/provider/generate.go 当前逻辑一致。

@phantom5099 phantom5099 merged commit 9d86044 into 1024XEngineer:main Apr 14, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants