Skip to content

[Fix] 修复 1.4 alpha conversation 回归#886

Merged
dingyi222666 merged 3 commits into
ChatLunaLab:v1-devfrom
liuwanwan1:fix/alpha-conversation-regressions
May 28, 2026
Merged

[Fix] 修复 1.4 alpha conversation 回归#886
dingyi222666 merged 3 commits into
ChatLunaLab:v1-devfrom
liuwanwan1:fix/alpha-conversation-regressions

Conversation

@liuwanwan1
Copy link
Copy Markdown
Contributor

@liuwanwan1 liuwanwan1 commented May 27, 2026

关联

背景

继续测试 1.4 alpha 时,packages/core 的 conversation 相关用例暴露了几处回归和测试夹具失配。该 PR 针对这些问题做集中修复。

问题

  • 旧消息的 content 可能为 null,导出 Markdown 时会继续调用 gzipDecode(null) 并失败。
  • preset lane 列出会话时先按 bindingKey 排序,导致 seq 展示和数字切换顺序不稳定。
  • rollback_chat / stop_chat 已有完整 conversation resolution 时仍会重复解析。
  • 显式指定 targetConversation 时,不能复用当前预解析会话,否则会忽略用户指定的目标会话。
  • core 测试夹具缺少 database.set、默认 plugin chat chain,并仍引用已移除的 extension-agent cli service 文件。

修复

  • exportMarkdown 格式化消息时允许 message.content 为空,并回退使用 message.text
  • listConversations 跨 route / preset lane 排序时优先使用 conversation.seq,仅在 seq 相同且合并多 binding 时再比较 bindingKey
  • rollback_chat / stop_chat 在没有显式 targetConversation 且现有解析结果完整时复用 context.options.conversation
  • 为显式目标覆盖预解析会话的场景补充 rollback_chatstop_chat 回归测试。
  • 补齐测试夹具能力,并更新 lifecycle 事件断言以覆盖 chatluna/after-binding-update

验证

本地已验证:

yarn test                         # 96 passing
yarn fast-build shared-prompt-renderer
yarn fast-build core
yarn lint                         # 0 errors, 7 existing max-len warnings

GitHub Actions 已通过:

  • prepare
  • lint
  • build
  • CodeFactor
  • CodeRabbit

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 27, 2026

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 74c38bf3-b80b-425f-bd6a-5e7815964ac1

📥 Commits

Reviewing files that changed from the base of the PR and between cc29b32 and 459cf01.

📒 Files selected for processing (8)
  • packages/core/src/middlewares/chat/rollback_chat.ts
  • packages/core/src/middlewares/chat/stop_chat.ts
  • packages/core/src/services/conversation.ts
  • packages/core/tests/conversation-runtime.spec.ts
  • packages/core/tests/conversation-service.spec.ts
  • packages/core/tests/conversation-source.spec.ts
  • packages/core/tests/helpers.ts
  • packages/core/tests/rollback-chat.spec.ts

Walkthrough

中间件在有显式 target 时调用解析器、无 target 时复用预解析会话;调整会话排序与消息内容空值保护;测试 helpers 新增 DB.set 与 plugin 注册;增加 rollback/stop 回归用例验证解析优先级。

Changes

Core conversation resolution and service improvements

Layer / File(s) Summary
Middleware conversation resolution fast-path
packages/core/src/middlewares/chat/rollback_chat.ts, packages/core/src/middlewares/chat/stop_chat.ts
rollback_chatstop_chat 在构建 resolved 时:当 targetConversation == null 直接复用 context.options.conversation,否则调用 ctx.chatluna.conversation.resolveConversation 并调整传参(移除基于 conversationId 的传入,简化 useRoutePresetLane 条件为 context.options.presetLane == null)。
Conversation service sorting and message formatting
packages/core/src/services/conversation.ts
listConversations 现在以 seq 为主键排序;仅当 seq 相等且 merged 为真时按 bindingKey 次级排序。formatMessagemessage.content 增加空值保护,避免对空值执行 gzip 解码与 JSON.parse。

Test infrastructure and assertion updates

Layer / File(s) Summary
Test helper infrastructure
packages/core/tests/helpers.ts
FakeDatabase 新增 set()createMemoryService 在初始化后注册 plugin 聊天链。
Test assertions and configuration updates
packages/core/tests/conversation-runtime.spec.ts, packages/core/tests/conversation-service.spec.ts, packages/core/tests/conversation-source.spec.ts, packages/core/tests/rollback-chat.spec.ts
为 ConversationRuntime 添加 resolveCallbacks;在生命周期事件断言数组中插入 chatluna/after-binding-update;移除 conversation-source 测试中的一个目标文件;新增 rollback/stop 回归用例,验证显式 targetConversation 在存在预解析 conversation 时仍会传入 resolveConversation 并被优先使用。

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • ChatLunaLab/chatluna#825: 修改中间件解析/复用逻辑,与本次对 rollback_chat/stop_chat 的更改相关。
  • ChatLunaLab/chatluna#831: 对 conversation 服务排序调整的相关变更,与本次 listConversations 修改存在重叠。
  • ChatLunaLab/chatluna#828: 同样改动了中间件的 target-resolution 逻辑,与本次变更语义相关。

Suggested reviewers

  • dingyi222666

Poem

🐰 我在提交林间跳一跳,
预解析会话静静不烦恼,
显式 target 走到前排坐好,
测试与 helpers 把路都铺好,
小兔一拍手,合并走得巧。

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 标题清晰准确地总结了主要变更:修复 1.4 alpha 版本中 conversation 相关的多处回归问题。
Description check ✅ Passed 描述详细阐述了背景、问题、修复方案和验证步骤,与变更集完全相关,提供了充分的上下文信息。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces optimizations and bug fixes to conversation resolution, sorting, and message formatting. Specifically, it bypasses redundant conversation resolution in rollback_chat and stop_chat middlewares when a valid active conversation is already present in the context options. It also refactors the sorting logic in ConversationService to prioritize sequence numbers, handles potential null values when formatting messages, and updates corresponding tests and helpers.

However, two critical issues were identified in the rollback_chat and stop_chat middlewares: when a user explicitly specifies a target conversation, the code incorrectly bypasses resolution and reuses the current active conversation. This can be resolved by ensuring the existing conversation is only reused when no target conversation is specified.

Comment thread packages/core/src/middlewares/chat/rollback_chat.ts Outdated
Comment thread packages/core/src/middlewares/chat/stop_chat.ts Outdated
@liuwanwan1 liuwanwan1 changed the title 修复 1.4 alpha conversation 回归 [Fix] 修复 1.4 alpha conversation 回归 May 27, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/core/tests/rollback-chat.spec.ts (2)

465-470: 💤 Low value

建议使用更精确的断言验证调用行为。

当前使用 some() 只验证至少有一次调用包含正确的 targetConversation,但根据测试场景(提供了显式 target 和完整 pre-resolved conversation),理论上应该只调用一次 resolveConversation。更精确的断言能更早发现意外的重复调用。

♻️ 建议的改进
-        assert.equal(
-            resolveOpts.some(
-                (opts) => (opts as any).targetConversation === target.id
-            ),
-            true
-        )
+        assert.equal(resolveOpts.length, 1)
+        assert.equal((resolveOpts[0] as any).targetConversation, target.id)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/tests/rollback-chat.spec.ts` around lines 465 - 470, The test
currently asserts that at least one call to resolveConversation included the
correct targetConversation by checking resolveOpts.some(...), but given the
scenario (explicit target + pre-resolved conversation) you should assert that
resolveConversation was called exactly once and that its single call had
targetConversation === target.id; change the assertion to check
resolveOpts.length === 1 and that resolveOpts[0].targetConversation (or
(resolveOpts[0] as any).targetConversation) equals target.id to catch unexpected
duplicate calls to resolveConversation.

837-842: 💤 Low value

建议使用更精确的断言验证调用行为。

与 rollback_chat 测试类似,使用精确断言能更好地验证 resolveConversation 只被调用一次且参数正确。

♻️ 建议的改进
-        assert.equal(
-            resolveOpts.some(
-                (opts) => (opts as any).targetConversation === target.id
-            ),
-            true
-        )
+        assert.equal(resolveOpts.length, 1)
+        assert.equal((resolveOpts[0] as any).targetConversation, target.id)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/tests/rollback-chat.spec.ts` around lines 837 - 842, Replace
the loose truthy check on resolveOpts with a precise call assertion: stub/spy
resolveConversation and assert it was called exactly once with the expected
argument where the targetConversation equals target.id (i.e., use
resolveConversation.calledOnce or sinon.assert.calledOnce and calledWithExactly
/ strict equality against target.id), referencing resolveOpts,
resolveConversation and target.id to locate and verify the correct call rather
than using assert.equal(...some(...), true).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/core/tests/rollback-chat.spec.ts`:
- Around line 465-470: The test currently asserts that at least one call to
resolveConversation included the correct targetConversation by checking
resolveOpts.some(...), but given the scenario (explicit target + pre-resolved
conversation) you should assert that resolveConversation was called exactly once
and that its single call had targetConversation === target.id; change the
assertion to check resolveOpts.length === 1 and that
resolveOpts[0].targetConversation (or (resolveOpts[0] as
any).targetConversation) equals target.id to catch unexpected duplicate calls to
resolveConversation.
- Around line 837-842: Replace the loose truthy check on resolveOpts with a
precise call assertion: stub/spy resolveConversation and assert it was called
exactly once with the expected argument where the targetConversation equals
target.id (i.e., use resolveConversation.calledOnce or sinon.assert.calledOnce
and calledWithExactly / strict equality against target.id), referencing
resolveOpts, resolveConversation and target.id to locate and verify the correct
call rather than using assert.equal(...some(...), true).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 98c0d0c7-5785-408a-b2fd-fe7dbca651e7

📥 Commits

Reviewing files that changed from the base of the PR and between e82a2eb and c774602.

📒 Files selected for processing (3)
  • packages/core/src/middlewares/chat/rollback_chat.ts
  • packages/core/src/middlewares/chat/stop_chat.ts
  • packages/core/tests/rollback-chat.spec.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core/src/middlewares/chat/stop_chat.ts
  • packages/core/src/middlewares/chat/rollback_chat.ts

@dingyi222666
Copy link
Copy Markdown
Member

一样的问题,A conversation must be resolved before this pull request can be merged.
Commits must have verified signatures. 你让 codex 给你配个 git 签名,重新 rebase 全部签名,push -f

liuwanwan1 and others added 3 commits May 28, 2026 18:15
…lewares

When targetConversation is null, resolve_conversation middleware has
already populated context.options.conversation — reuse it directly
instead of re-resolving with redundant null checks.
@dingyi222666 dingyi222666 force-pushed the fix/alpha-conversation-regressions branch from cc29b32 to 459cf01 Compare May 28, 2026 10:15
@dingyi222666 dingyi222666 merged commit dd19726 into ChatLunaLab:v1-dev May 28, 2026
2 of 3 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.

2 participants