Skip to content

feat(core): refine quote and forward reply config schema#780

Closed
PinkElysiaDev wants to merge 2 commits into
ChatLunaLab:v1-devfrom
PinkElysiaDev:v1-dev
Closed

feat(core): refine quote and forward reply config schema#780
PinkElysiaDev wants to merge 2 commits into
ChatLunaLab:v1-devfrom
PinkElysiaDev:v1-dev

Conversation

@PinkElysiaDev
Copy link
Copy Markdown
Contributor

  • isReplyWithAt 从单纯布尔开关改为“开关 + 阈值分支”配置
  • 新增 replyQuoteThreshold,用于按响应耗时决定是否引用原消息
  • isForwardMsg 同样改为“开关 + 阈值分支”配置
  • forwardMsgMinLength 仅在启用合并消息时显示
  • 调整 schema 结构,使两个分支配置分别紧跟各自开关显示
  • 同步更新中英文 locales 文案
  • 优化 includeQuoteReplyreplyQuoteThreshold 的中文描述,使其语义更准确、表达更统一

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 13, 2026

Walkthrough

在聊天链中新增并传播可选的 ChainMiddlewareContext,将上下文透传到消息发送、引用计算和中间件执行路径;同时配置文件新增 replyQuoteThreshold 并将部分布尔配置改为条件化 Schema。其它为符号重命名与导入顺序调整。

Changes

Cohort / File(s) Summary
链式上下文传播
packages/core/src/chains/chain.ts
ChatChainSender 添加可选 context 参数;更新 DefaultChatChainSender.sendsendAsNormalbuildMessageFragmentsendMessagereceiveMessagereceiveCommand 等以透传 ChainMiddlewareContext(包括 requestStartedAt、错误/中止路径)。
配置模式更新
packages/core/src/config.ts
新增可选字段 replyQuoteThreshold?: number;将 isForwardMsgisReplyWithAt 的相关字段迁移到条件化 Schema(仅在对应布尔为 true 时启用附加字段)。
插件符号重命名
packages/service-multimodal/src/plugin.ts
readFiles 的导入别名改为 read_files 并在中间件数组中使用新别名(仅符号重命名,无逻辑变更)。
导入顺序调整
packages/shared-adapter/src/utils.ts
仅调整类型导入的顺序与分组(UsageMetadataChatCompletionTool/ChatCompletionUsage 重新排列),无行为或 API 变更。

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant ChatChain
    participant Middleware
    participant Sender
    participant Downstream

    Client->>ChatChain: receiveMessage/receiveCommand(payload)
    ChatChain->>Middleware: initialize ChainMiddlewareContext (includes requestStartedAt)
    Middleware->>ChatChain: invoke send handlers with context
    ChatChain->>Sender: send(session, messages, context)
    Sender->>Sender: buildMessageFragment(messages, context)
    Sender->>Downstream: forward/send message (includes context)
    Downstream-->>Sender: ack
    Sender-->>ChatChain: resolved
    ChatChain-->>Client: response delivered
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • dingyi222666

Poem

🐰 链上携带着上下文,轻轻跳过时间印记,
请求起点被记录,引用在瞬间判断,
配置悄然分支生长,字段只在需要时启齿,
我在草间跳跃,为这次改动歌唱。

🚥 Pre-merge checks | ✅ 2 | ❌ 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 (2 passed)
Check name Status Explanation
Title check ✅ Passed 标题准确地反映了主要变更:重构引用和转发回复的配置schema,这是PR的核心内容。
Description check ✅ Passed PR描述详细说明了配置schema的具体变更,与代码修改内容相关联,包括新增字段和schema结构调整。

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Tip

CodeRabbit can use Trivy to scan for security misconfigurations and secrets in Infrastructure as Code files.

Add a .trivyignore file to your project to customize which findings Trivy reports.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refines the message handling configuration by introducing more dynamic control over how the bot replies and forwards messages. It moves beyond simple boolean toggles to a more sophisticated system where quoting and forwarding can be conditionally applied based on factors like response time or message length. This enhancement provides greater flexibility and precision in managing bot interactions, ensuring more contextually appropriate responses.

Highlights

  • Refined Reply Quoting Configuration: The isReplyWithAt setting has been enhanced from a simple boolean to a conditional configuration that includes a replyQuoteThreshold. This allows the system to decide whether to quote the original message based on the response time, providing more granular control.
  • Enhanced Message Forwarding Configuration: The isForwardMsg setting has also been upgraded to a conditional configuration. The forwardMsgMinLength option is now only active and displayed when isForwardMsg is enabled, streamlining the configuration interface.
  • Context Propagation in Message Sending: The core message sending mechanism (sendMessage and DefaultChatChainSender.send) has been updated to accept and propagate a ChainMiddlewareContext object. This context now includes requestStartedAt, enabling time-based calculations for features like conditional quoting.
  • Schema Structure Adjustment: The configuration schema (config.ts) has been restructured to logically group related settings. Conditional options like replyQuoteThreshold and forwardMsgMinLength are now displayed immediately after their respective enabling switches (isReplyWithAt and isForwardMsg).
  • Localization Updates: Both English (en-US.schema.yml) and Chinese (zh-CN.schema.yml) localization files have been updated to reflect the new configuration options and their descriptions. The Chinese description for includeQuoteReply was also optimized for better accuracy and consistency.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • packages/core/src/chains/chain.ts
    • Added context parameter to sendMessage and DefaultChatChainSender.send methods and their type definitions.
    • Introduced requestStartedAt to the ChainMiddlewareContext options.
    • Implemented logic in buildMessageFragment to use replyQuoteThreshold and elapsedTime for conditional quoting.
  • packages/core/src/config.ts
    • Added replyQuoteThreshold to the Config interface.
    • Refactored the configuration schema to make forwardMsgMinLength conditional on isForwardMsg and replyQuoteThreshold conditional on isReplyWithAt.
  • packages/core/src/locales/en-US.schema.yml
    • Updated descriptions for isReplyWithAt.
    • Added description for replyQuoteThreshold.
    • Reorganized isForwardMsg and forwardMsgMinLength descriptions.
  • packages/core/src/locales/zh-CN.schema.yml
    • Updated descriptions for isReplyWithAt and includeQuoteReply for improved clarity.
    • Added description for replyQuoteThreshold.
    • Reorganized isForwardMsg and forwardMsgMinLength descriptions.
Activity
  • No specific activity (comments, reviews, progress) has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

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

本次拉取请求主要对引用和转发回复的配置结构进行了优化和功能扩展。通过引入 replyQuoteThreshold,实现了根据响应耗时决定是否引用原消息的逻辑,并对 isReplyWithAtisForwardMsg 配置项进行了更灵活的“开关 + 阈值分支”配置。同时,更新了中英文 locales 文案,使其语义更准确。代码修改清晰,逻辑合理,配置结构也得到了显著改善,提升了用户体验。

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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/chains/chain.ts (1)

356-371: ⚠️ Potential issue | 🟡 Minor

错误/中止消息把 context 丢掉了,引用阈值在失败路径上不会生效。

Line 356 和 Line 371 这里显式传 undefined,所以一旦 replyQuoteThreshold > 0,错误或中止回复就永远命不中新增的耗时引用逻辑。这个 PR 已经把成功路径和 stop 路径都接上了 context,失败路径也应该保持一致。

🔧 建议修改
-                    await this._handleMiddlewareError(
-                        session,
-                        result.middlewareName!,
-                        result.error!
-                    )
+                    await this._handleMiddlewareError(
+                        session,
+                        context,
+                        result.middlewareName!,
+                        result.error!
+                    )
                     return false
                 }
@@
     private async _handleMiddlewareError(
         session: Session,
+        context: ChainMiddlewareContext,
         middlewareName: string,
         error: Error
     ) {
         if (error instanceof ChatLunaError) {
             const message =
                 error.errorCode === ChatLunaErrorCode.ABORTED
                     ? session.text('chatluna.aborted')
                     : error.message
-            await this.sendMessage(session, message, undefined)
+            await this.sendMessage(session, message, context)
             return
         }
@@
         await this.sendMessage(
             session,
             session.text('chatluna.middleware_error', [
                 middlewareName,
                 error.message
             ]),
-            undefined
+            context
         )
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/chains/chain.ts` around lines 356 - 371, The error/abort
paths call this.sendMessage(session, ..., undefined) and thus drop the context
so replyQuoteThreshold logic never triggers; update these calls to forward the
existing context (i.e., pass context instead of undefined) where sendMessage is
invoked in the failure/abort branches so the reply quoting logic
(replyQuoteThreshold) and downstream middleware (middlewareName and the
'chatluna.middleware_error' response) receive the same context as the success
path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/config.ts`:
- Around line 82-97: The schema branch for isForwardMsg===false currently uses
an empty Schema.object({}) which allows forwardMsgMinLength to be omitted,
mismatching the exported Config interface (which requires forwardMsgMinLength).
Update the false-branch object in the Schema.union to include
forwardMsgMinLength with the same numeric constraints but marked hidden (e.g.,
forwardMsgMinLength:
Schema.number().min(0).max(400).step(1).default(0).hidden()) so the field always
exists at runtime while remaining hidden from public validation; keep the
isForwardMsg field handling as-is and ensure the Config type
(forwardMsgMinLength, isForwardMsg) stays consistent with this schema.

---

Outside diff comments:
In `@packages/core/src/chains/chain.ts`:
- Around line 356-371: The error/abort paths call this.sendMessage(session, ...,
undefined) and thus drop the context so replyQuoteThreshold logic never
triggers; update these calls to forward the existing context (i.e., pass context
instead of undefined) where sendMessage is invoked in the failure/abort branches
so the reply quoting logic (replyQuoteThreshold) and downstream middleware
(middlewareName and the 'chatluna.middleware_error' response) receive the same
context as the success path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 237af1b2-18b2-4aed-a32f-f0e1945c1f6b

📥 Commits

Reviewing files that changed from the base of the PR and between 8b2c31a and f88b74e.

⛔ Files ignored due to path filters (2)
  • packages/core/src/locales/en-US.schema.yml is excluded by !**/*.yml
  • packages/core/src/locales/zh-CN.schema.yml is excluded by !**/*.yml
📒 Files selected for processing (2)
  • packages/core/src/chains/chain.ts
  • packages/core/src/config.ts

Comment on lines +82 to +97
Schema.intersect([
Schema.object({
isForwardMsg: Schema.boolean().default(false)
}),
Schema.union([
Schema.object({
isForwardMsg: Schema.const(true).required(),
forwardMsgMinLength: Schema.number()
.min(0)
.max(400)
.step(1)
.default(0)
}),
Schema.object({})
])
]),
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cd packages/core && cat -n src/config.ts | head -120

Repository: ChatLunaLab/chatluna

Length of output: 4493


🏁 Script executed:

cd packages/core && grep -n "forwardMsgMinLength" src/chains/chain.ts | head -20

Repository: ChatLunaLab/chatluna

Length of output: 115


🏁 Script executed:

cd packages/core && sed -n '740,755n' src/chains/chain.ts

Repository: ChatLunaLab/chatluna

Length of output: 46


🏁 Script executed:

cd packages/core && sed -n '740,755p' src/chains/chain.ts

Repository: ChatLunaLab/chatluna

Length of output: 453


🏁 Script executed:

cd packages/core && rg -n "forwardMsgMinLength" --type ts

Repository: ChatLunaLab/chatluna

Length of output: 253


🏁 Script executed:

cd packages/core && rg -B5 -A5 "config.forwardMsgMinLength" --type ts

Repository: ChatLunaLab/chatluna

Length of output: 544


forwardMsgMinLength 的 schema 与导出的 Config 类型不一致

Config 接口(第 9 行)声明 forwardMsgMinLength: number 为必填字段,但第 95 行的空对象分支允许在 isForwardMsg === false 时该字段完全缺失,导致运行时可能返回 undefined。虽然目前在 chains/chain.ts 第 743 行的访问被 isForwardMsg 守卫所保护,但这个类型/运行时契约的不匹配会增加未来维护风险。

建议在 schema 的 false 分支中保留该字段并标记为 .hidden(),保持公共类型签名的一致性:

修复方案
Schema.union([
    Schema.object({
        isForwardMsg: Schema.const(true).required(),
        forwardMsgMinLength: Schema.number()
            .min(0)
            .max(400)
            .step(1)
            .default(0)
    }),
-   Schema.object({})
+   Schema.object({
+       isForwardMsg: Schema.const(false).required(),
+       forwardMsgMinLength: Schema.number()
+           .min(0)
+           .max(400)
+           .step(1)
+           .default(0)
+           .hidden()
+   })
])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Schema.intersect([
Schema.object({
isForwardMsg: Schema.boolean().default(false)
}),
Schema.union([
Schema.object({
isForwardMsg: Schema.const(true).required(),
forwardMsgMinLength: Schema.number()
.min(0)
.max(400)
.step(1)
.default(0)
}),
Schema.object({})
])
]),
Schema.intersect([
Schema.object({
isForwardMsg: Schema.boolean().default(false)
}),
Schema.union([
Schema.object({
isForwardMsg: Schema.const(true).required(),
forwardMsgMinLength: Schema.number()
.min(0)
.max(400)
.step(1)
.default(0)
}),
Schema.object({
isForwardMsg: Schema.const(false).required(),
forwardMsgMinLength: Schema.number()
.min(0)
.max(400)
.step(1)
.default(0)
.hidden()
})
])
]),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/config.ts` around lines 82 - 97, The schema branch for
isForwardMsg===false currently uses an empty Schema.object({}) which allows
forwardMsgMinLength to be omitted, mismatching the exported Config interface
(which requires forwardMsgMinLength). Update the false-branch object in the
Schema.union to include forwardMsgMinLength with the same numeric constraints
but marked hidden (e.g., forwardMsgMinLength:
Schema.number().min(0).max(400).step(1).default(0).hidden()) so the field always
exists at runtime while remaining hidden from public validation; keep the
isForwardMsg field handling as-is and ensure the Config type
(forwardMsgMinLength, isForwardMsg) stays consistent with this schema.

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/service-multimodal/src/plugin.ts (1)

7-22: ⚠️ Potential issue | 🟡 Minor

将导入别名 read_files 改为 camelCase

第 7 行和第 22 行使用的导入别名 read_files 违反 TypeScript 命名规范。变量和函数别名应采用 camelCase,改为 readFiles

修改建议
-import { apply as read_files } from './plugins/read_files' // import end
+import { apply as readFiles } from './plugins/read_files' // import end
@@
-        [audio, image, read_files] // middleware end
+        [audio, image, readFiles] // middleware end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/service-multimodal/src/plugin.ts` around lines 7 - 22, The import
alias read_files violates camelCase; update the import in plugin.ts to use
readFiles and rename all usages accordingly (the import statement and the
middleware array entry inside the plugins function), ensuring the symbol
referenced by the import (from './plugins/read_files') and the middleware array
const middlewares = [audio, image, readFiles] use the new camelCase name so
TypeScript naming conventions are followed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/service-multimodal/src/plugin.ts`:
- Around line 7-22: The import alias read_files violates camelCase; update the
import in plugin.ts to use readFiles and rename all usages accordingly (the
import statement and the middleware array entry inside the plugins function),
ensuring the symbol referenced by the import (from './plugins/read_files') and
the middleware array const middlewares = [audio, image, readFiles] use the new
camelCase name so TypeScript naming conventions are followed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 29e7e16e-ae05-4a62-9704-a2fc496d150e

📥 Commits

Reviewing files that changed from the base of the PR and between f88b74e and 0d130e6.

📒 Files selected for processing (2)
  • packages/service-multimodal/src/plugin.ts
  • packages/shared-adapter/src/utils.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/shared-adapter/src/utils.ts

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.

1 participant