Skip to content

[Fix] validate routing and stabilize skill reloads#859

Merged
dingyi222666 merged 5 commits into
v1-devfrom
fix/qwen-adapter
May 15, 2026
Merged

[Fix] validate routing and stabilize skill reloads#859
dingyi222666 merged 5 commits into
v1-devfrom
fix/qwen-adapter

Conversation

@dingyi222666
Copy link
Copy Markdown
Member

@dingyi222666 dingyi222666 commented May 12, 2026

This pr fixes conversation chat mode validation, trigger conversation routing, empty tool-call IDs, and bundled skill reload behavior so invalid configuration fails clearly and skill updates avoid unnecessary reload loops.

Fixes #858
Fixes #860

New Features

None

Bug fixes

  • Validate chat modes when creating conversations, updating conversations, and updating route constraints.
  • Add localized user-facing messages for invalid conversation chat modes.
  • Preserve trigger binding keys when building wakeup tasks.
  • Reset trigger conversation IDs when the binding key changes.
  • Only create a fresh trigger conversation when newConversation is true and no conversation ID is already provided.
  • Treat empty streaming tool-call IDs as missing IDs instead of passing empty strings through.
  • Sync bundled skill files only when file contents changed, while preserving existing config.json files.
  • Avoid overlapping skill hot reloads by queuing a pending reload while one is already running.

Other Changes

None

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 12, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d3092af5-be80-4135-813b-86a4a1d78ef5

📥 Commits

Reviewing files that changed from the base of the PR and between c7eb7d8 and a4d3536.

⛔ Files ignored due to path filters (17)
  • packages/adapter-azure-openai/package.json is excluded by !**/*.json
  • packages/adapter-claude/package.json is excluded by !**/*.json
  • packages/adapter-deepseek/package.json is excluded by !**/*.json
  • packages/adapter-doubao/package.json is excluded by !**/*.json
  • packages/adapter-gemini/package.json is excluded by !**/*.json
  • packages/adapter-hunyuan/package.json is excluded by !**/*.json
  • packages/adapter-ollama/package.json is excluded by !**/*.json
  • packages/adapter-openai-like/package.json is excluded by !**/*.json
  • packages/adapter-openai/package.json is excluded by !**/*.json
  • packages/adapter-qwen/package.json is excluded by !**/*.json
  • packages/adapter-rwkv/package.json is excluded by !**/*.json
  • packages/adapter-spark/package.json is excluded by !**/*.json
  • packages/adapter-wenxin/package.json is excluded by !**/*.json
  • packages/adapter-zhipu/package.json is excluded by !**/*.json
  • packages/extension-agent/package.json is excluded by !**/*.json
  • packages/extension-tools/package.json is excluded by !**/*.json
  • packages/shared-adapter/package.json is excluded by !**/*.json
📒 Files selected for processing (2)
  • packages/extension-agent/src/skills/watch.ts
  • packages/extension-agent/src/utils/runtime_sync.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/extension-agent/src/skills/watch.ts

Walkthrough

该 PR 添加 chatMode 验证并映射对应错误,修正代理触发器的 bindingKey 与 conversationId 合并/路由逻辑,增量化内置技能同步并改进热重载调度,规范化空工具调用 ID,为运行时同步日志添加条件输出。

变更

聊天模式验证系统

层 / 文件(s) 摘要
聊天模式验证助手和集成点
packages/core/src/services/conversation.ts
新增私有 checkChatMode 并在 createConversationupdateConversationUsageupdateManagedConstraint 中调用以验证指定的 chatMode 是否存在。
聊天模式错误消息处理
packages/core/src/middlewares/system/conversation_manage.ts
扩展 formatConversationError 中间件以识别 Chat mode <mode> not found. 错误并返回本地化的 invalid_chat_mode 消息(含匹配的模式值)。

代理触发器对话和绑定路由

层 / 文件(s) 摘要
绑定键分配和对话 ID 补丁处理
packages/extension-agent/src/service/trigger.ts
在构建唤醒动作时显式使用 override?.bindingKey ?? task.bindingKey,并在 _prepareTaskPatch 中根据 bindingKey 变更或补丁显式设置来有条件清除或设置 conversationId
新对话解析逻辑
packages/extension-agent/src/trigger/executor.ts
调整 wakeup() 的 resolved 计算:仅当 action.newConversation === trueaction.conversationId 缺失/为 null 时才走“新会话”路径,保留显式提供的 conversationId。

工具调用 ID 规范化

层 / 文件(s) 摘要
空工具调用 ID 规范化
packages/shared-adapter/src/utils.ts
convertDeltaToMessageChunk 中将 rawToolCall.id === '' 归一化为 undefined,避免将空字符串下传。

内置技能增量同步与热重载

层 / 文件(s) 摘要
增量复制/刷新技能目录实现
packages/extension-agent/src/skills/builtin.ts
引入 syncSkillDircollectFiles,按文件差异复制、删除多余目的文件,force 模式下保留目标 config.json,并将 FS 操作用法改为 copyFile
热重载调度与重入控制
packages/extension-agent/src/skills/watch.ts
将简单定时去抖改为带重载状态的调度:维护 reloading/pending,在重载进行时标记 pending 并在完成后按需再次触发重载(仍保留 100ms 延迟)。
运行时同步日志条件
packages/extension-agent/src/utils/runtime_sync.ts
collectSyncFiles 仅在存在远程文件或待同步文件时才输出对应的 debug 日志,移除无意义的 “none” 回退显示。

估计代码审查工作量

🎯 4 (Complex) | ⏱️ ~45 分钟

可能相关的 PR

  • ChatLunaLab/chatluna#828:与本 PR 在 packages/core/src/middlewares/system/conversation_manage.ts 的错误映射更改存在重叠。
  • ChatLunaLab/chatluna#847:与本 PR 在 syncBundledSkills 的行为和 config.json 保留/刷新逻辑上相关。
  • ChatLunaLab/chatluna#825:与会话管理流程(会话解析/列举)在代码层面有可能重叠的更改。

诗歌

🐰 我是小兔子来祝贺,
聊天模式检验更严谨,
绑定键与对话更稳健,
空 ID 变为无惊喜,
技能刷新更聪明又欢喜。

🚥 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 标题清晰准确地总结了PR的主要内容:验证路由和稳定技能重新加载,直接反映了代码变更的核心目标。
Description check ✅ Passed 描述与PR变更内容高度相关,详细列举了所有修复项和功能改进,包括聊天模式验证、触发器路由、工具调用ID处理和技能重新加载等。
Linked Issues check ✅ Passed PR代码变更完整实现了两个关联问题的要求:[#858]处理空工具调用ID,[#860]修复技能同步竞态条件和防止无限重新加载循环。
Out of Scope Changes check ✅ Passed 所有代码变更均与关联问题的要求紧密相关,无发现范围外的改动。调试日志优化[runtime_sync.ts]是对同步机制的合理改进。

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/qwen-adapter

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

@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 (1)
packages/core/src/services/conversation.ts (1)

1756-1765: ⚡ Quick win

建议内联此验证逻辑以遵循编码规范。

根据编码规范,简短逻辑(1-5行)不应提取为独立函数。虽然此方法被调用了4次,但验证逻辑非常简单(仅一个条件检查和抛出错误),应该在每个调用点直接内联。这样可以减少抽象层次,使代码更加直接。

♻️ 建议的内联重构

删除 checkChatMode 方法,在每个调用点内联验证:

createConversation (608行附近):

-        this.checkChatMode(options.chatMode)
+        if (
+            options.chatMode != null &&
+            !this.ctx.chatluna.platform.chatChains.value.some(
+                (chain) => chain.name === options.chatMode
+            )
+        ) {
+            throw new Error(`Chat mode ${options.chatMode} not found.`)
+        }

updateConversationUsage (1566行附近):

-        this.checkChatMode(options.chatMode)
+        if (
+            options.chatMode != null &&
+            !this.ctx.chatluna.platform.chatChains.value.some(
+                (chain) => chain.name === options.chatMode
+            )
+        ) {
+            throw new Error(`Chat mode ${options.chatMode} not found.`)
+        }

updateManagedConstraint (1697行附近):

-        this.checkChatMode(patch.defaultChatMode)
-        this.checkChatMode(patch.fixedChatMode)
+        if (
+            patch.defaultChatMode != null &&
+            !this.ctx.chatluna.platform.chatChains.value.some(
+                (chain) => chain.name === patch.defaultChatMode
+            )
+        ) {
+            throw new Error(`Chat mode ${patch.defaultChatMode} not found.`)
+        }
+        if (
+            patch.fixedChatMode != null &&
+            !this.ctx.chatluna.platform.chatChains.value.some(
+                (chain) => chain.name === patch.fixedChatMode
+            )
+        ) {
+            throw new Error(`Chat mode ${patch.fixedChatMode} not found.`)
+        }

然后删除 checkChatMode 方法定义(1756-1765行)。

编码规范规定:"如果函数体只有1-5行,请在调用点内联它,而不是提取成独立函数"以及"编写最简单的代码,减少抽象、函数和变量"。

🤖 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/src/services/conversation.ts` around lines 1756 - 1765, The
short validation in checkChatMode should be inlined at each call site instead of
kept as a separate method: replace calls to checkChatMode(mode) in
createConversation, updateConversationUsage, and updateManagedConstraint with
the equivalent inline guard (if mode != null &&
!this.ctx.chatluna.platform.chatChains.value.some(chain => chain.name === mode)
throw new Error(`Chat mode ${mode} not found.`)); after inlining at all call
sites, remove the private checkChatMode method definition entirely.
🤖 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/src/services/conversation.ts`:
- Around line 1756-1765: The short validation in checkChatMode should be inlined
at each call site instead of kept as a separate method: replace calls to
checkChatMode(mode) in createConversation, updateConversationUsage, and
updateManagedConstraint with the equivalent inline guard (if mode != null &&
!this.ctx.chatluna.platform.chatChains.value.some(chain => chain.name === mode)
throw new Error(`Chat mode ${mode} not found.`)); after inlining at all call
sites, remove the private checkChatMode method definition entirely.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 379d8269-ddca-4cf4-b740-5286655c6885

📥 Commits

Reviewing files that changed from the base of the PR and between a59c916 and 307a205.

⛔ Files ignored due to path filters (2)
  • packages/core/src/locales/en-US.yml is excluded by !**/*.yml
  • packages/core/src/locales/zh-CN.yml is excluded by !**/*.yml
📒 Files selected for processing (5)
  • packages/core/src/middlewares/system/conversation_manage.ts
  • packages/core/src/services/conversation.ts
  • packages/extension-agent/src/service/trigger.ts
  • packages/extension-agent/src/trigger/executor.ts
  • packages/shared-adapter/src/utils.ts

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 chat mode validation across the conversation services, including localized error messages for invalid modes. It also refines the conversation trigger logic to handle binding key changes and resets conversation IDs appropriately. Additionally, it ensures that empty tool call IDs are treated as undefined in the shared adapter. Feedback was provided to improve the explicitness of property checks when updating conversation IDs in the trigger service.

Comment thread packages/extension-agent/src/service/trigger.ts
@dingyi222666 dingyi222666 changed the title [Fix] validate chat modes and trigger routing [Fix] validate routing and stabilize skill reloads May 13, 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 (1)
packages/extension-agent/src/skills/watch.ts (1)

39-42: 💤 Low value

冗余的 reloading 二次判断可移除。

外层 schedule()(Lines 32-35)已在 reloading 为 true 时直接返回,不会再注册新的定时器;而 reloading = true 只在这同一个定时器回调里被设置(Line 44),因此当定时器真正触发时 reloading 一定为 false。这里的二次检查属于防御性死代码。

♻️ 建议移除冗余分支
         timer = setTimeout(async () => {
             timer = undefined
-            if (reloading) {
-                pending = true
-                return
-            }
-
             reloading = true
             try {
                 await reload()
As per coding guidelines: "Do not add type guards, null checks, or fallback values unless there is concrete evidence that the value can actually be null/undefined/wrong-type".
🤖 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/extension-agent/src/skills/watch.ts` around lines 39 - 42, The inner
defensive check that tests the module-level reloading flag inside the timer
callback is redundant; remove the block that checks reloading and sets pending
(the if (reloading) { pending = true; return } inside the schedule/timer
callback) since schedule() already returns early when reloading is true and
reloading is only set within the same timer callback; update the
schedule()/timer callback in watch.ts to drop that branch and rely on the
existing outer guard, leaving pending handling only where actually needed.
🤖 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/extension-agent/src/skills/watch.ts`:
- Around line 39-42: The inner defensive check that tests the module-level
reloading flag inside the timer callback is redundant; remove the block that
checks reloading and sets pending (the if (reloading) { pending = true; return }
inside the schedule/timer callback) since schedule() already returns early when
reloading is true and reloading is only set within the same timer callback;
update the schedule()/timer callback in watch.ts to drop that branch and rely on
the existing outer guard, leaving pending handling only where actually needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 71b04d57-dd08-466f-a2a3-52f95591da9d

📥 Commits

Reviewing files that changed from the base of the PR and between 307a205 and c7eb7d8.

📒 Files selected for processing (2)
  • packages/extension-agent/src/skills/builtin.ts
  • packages/extension-agent/src/skills/watch.ts

@dingyi222666 dingyi222666 merged commit a88113f into v1-dev May 15, 2026
5 checks passed
@dingyi222666 dingyi222666 deleted the fix/qwen-adapter branch May 15, 2026 16:10
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.

[Bug] syncBundledSkills 在 Windows 上触发无限循环与 EEXIST 错误 [Bug] 由于上游问题导致通义千问系列模型无法调用工具

1 participant