Skip to content

Conversation

@dingyi222666
Copy link
Member

This PR adds support for DeepSeek's reasoning mode and refactors message transformation utilities.

New Features

  • Add processDeepSeekThinkMessages function to preserve reasoning_content for DeepSeek reasoner models during multi-turn tool calling
  • Support reasoning_content field in message transformations

Bug Fixes

  • Fix bug in removeSystemMessage logic that was iterating over empty array

Other Changes

  • Extract transformSystemMessages function for better code organization
  • Optimize image service plugin detection to avoid repeated lookups
  • Bump shared-adapter to v1.0.18 and update all adapter dependencies

…ctor message transformations

- Add processDeepSeekThinkMessages function to handle reasoning_content for DeepSeek reasoner models
- Extract transformSystemMessages function from langchainMessageToOpenAIMessage for better code organization
- Support reasoning_content in ChatCompletionResponseMessage type
- Fix bug in removeSystemMessage logic (was iterating over empty array)
- Optimize image service plugin detection to avoid repeated lookups in read_chat_message
- Bump shared-adapter version to 1.0.18 and update all adapter package dependencies

The reasoning_content feature enables DeepSeek models to maintain their thinking process
across multi-turn tool calling conversations by preserving reasoning_content from the last
turn (starting from the last non-tool-call AI message).
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 1, 2025

Caution

Review failed

The pull request is closed.

演练

本PR在两个关键模块中引入条件逻辑优化。第一处为图像处理模块添加了插件可用性缓存标志,以优化重复检查。第二处为DeepSeek推理模型扩展了消息变换能力,包括系统消息过滤和推理内容合并功能。

变更

组件 / 文件 变更摘要
图像处理缓存优化
packages/core/src/middlewares/chat/read_chat_message.ts
引入 isInstalledImageService 本地标志以缓存图像服务插件的存在状态;将图像处理路径中的直接检查替换为该标志;扩展 oldImageRead 函数签名以接收并传递此标志;更新所有调用点以传递该标志参数
DeepSeek推理模型支持
packages/shared-adapter/src/utils.ts
新增 transformSystemMessages() 函数用于过滤系统消息并确保对话从用户消息开始;新增 processDeepSeekThinkMessages() 函数用于将推理内容从原始消息合并到转换后的消息;为名称包含"deepseek-reasoner"的模型添加专门处理路径,支持系统消息移除和推理内容增强

代码审查工作量估计

🎯 3 (中等) | ⏱️ ~25 分钟

需要特别关注的领域:

  • packages/shared-adapter/src/utils.ts 中的 processDeepSeekThinkMessages() 函数逻辑,特别是最后一个AI回合的索引计算和推理内容的合并逻辑
  • 确认 transformSystemMessages() 中对话开头/结尾的用户消息插入逻辑是否处理了所有边界情况
  • isInstalledImageService 标志在所有调用链路中的正确传递,确保不存在遗漏的调用点

可能相关的PR

🐰 缓存标志来优化,
图像检查更迅速;
DeepSeek深思被记忆,
推理内容妥妥地,
流转在消息里漫舞。✨

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/deepseek-toolcall

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3f233ef and bb9a40c.

⛔ Files ignored due to path filters (15)
  • 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/shared-adapter/package.json is excluded by !**/*.json
📒 Files selected for processing (2)
  • packages/core/src/middlewares/chat/read_chat_message.ts (5 hunks)
  • packages/shared-adapter/src/utils.ts (2 hunks)

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.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @dingyi222666, 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 introduces comprehensive support for DeepSeek's reasoning mode, enabling the system to correctly process and retain reasoning_content during complex multi-turn interactions. It also includes significant refactoring of message transformation utilities, improving code structure and fixing a bug related to system message handling. Furthermore, the detection of the image service plugin has been optimized for efficiency, and various adapter dependencies have been updated to their latest versions.

Highlights

  • DeepSeek Reasoning Content Support: Added new functionality to support DeepSeek's reasoning_content field, specifically for DeepSeek reasoner models during multi-turn tool calling, ensuring this crucial information is preserved.
  • Message Transformation Refactoring: The utility functions for message transformation have been refactored. The logic for handling system messages has been extracted into a dedicated transformSystemMessages function, improving code organization and maintainability.
  • Image Service Plugin Optimization: Optimized the detection mechanism for the image-service plugin within the read_chat_message.ts middleware. This change avoids repeated lookups and streamlines the process of warning users about unsupported image types like GIFs.
  • Dependency Updates: The @chatluna/v1-shared-adapter package has been bumped to v1.0.18 across all adapter packages, ensuring consistency and incorporating the latest shared functionalities.
  • System Message Removal Bug Fix: Fixed a bug in the removeSystemMessage logic that previously iterated over an empty array, leading to incorrect behavior. The refactored transformSystemMessages now correctly handles system message removal and conversation flow.
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.

@dingyi222666 dingyi222666 merged commit f7f3072 into v1-dev Dec 1, 2025
2 of 3 checks passed
Copy link
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 is well-executed. It successfully adds support for DeepSeek's reasoning content, fixes a significant bug in the removeSystemMessage logic by refactoring it into transformSystemMessages, and introduces a sensible optimization for detecting the image service plugin. The dependency updates across the packages are also correctly handled. I have a couple of suggestions for the new utility functions in packages/shared-adapter/src/utils.ts to make them even more concise and idiomatic using modern array methods. Overall, great work on improving functionality and code quality.

Comment on lines +160 to +171
let lastTurnStartIndex = -1
for (let i = originalMessages.length - 1; i >= 0; i--) {
const message = originalMessages[i]
if (message.getType() === 'ai') {
const aiMessage = message as AIMessage
// Check if it's a non-tool-call AI message
if (!aiMessage.tool_calls || aiMessage.tool_calls.length === 0) {
lastTurnStartIndex = i
break
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The for loop to find the index of the last AI message can be simplified by using the Array.prototype.findLastIndex() method. This makes the intent of the code clearer and more declarative.

    const lastTurnStartIndex = originalMessages.findLastIndex((message) => {
        if (message.getType() !== 'ai') {
            return false;
        }
        const aiMessage = message as AIMessage;
        // Check if it's a non-tool-call AI message
        return !aiMessage.tool_calls || aiMessage.tool_calls.length === 0;
    });

Comment on lines +197 to 233
export function transformSystemMessages(
messages: ChatCompletionResponseMessage[]
): ChatCompletionResponseMessage[] {
const mappedMessage: ChatCompletionResponseMessage[] = []

if (mappedMessage[0].role === 'assistant') {
mappedMessage.unshift({
role: 'user',
content:
'Continue what I said to you last time. Follow these instructions.'
})
for (let i = 0; i < messages.length; i++) {
const message = messages[i]

if (message.role !== 'system') {
mappedMessage.push(message)
continue
}

return mappedMessage
// Skip system messages (remove them)
continue
}

return result
// Ensure the conversation doesn't end with an assistant message
if (mappedMessage[mappedMessage.length - 1]?.role === 'assistant') {
mappedMessage.push({
role: 'user',
content:
'Continue what I said to you last message. Follow these instructions.'
})
}

// Ensure the conversation doesn't start with an assistant message
if (mappedMessage[0]?.role === 'assistant') {
mappedMessage.unshift({
role: 'user',
content:
'Continue what I said to you last time. Follow these instructions.'
})
}

return mappedMessage
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This function can be made more concise and readable by using the Array.prototype.filter() method to remove system messages, instead of a for loop. This is a more idiomatic way to handle array filtering in TypeScript. I've also added a guard for an empty array after filtering and removed the now-unnecessary optional chaining.

export function transformSystemMessages(
    messages: ChatCompletionResponseMessage[]
): ChatCompletionResponseMessage[] {
    const mappedMessage = messages.filter(
        (message) => message.role !== 'system'
    );

    if (mappedMessage.length === 0) {
        return mappedMessage;
    }

    // Ensure the conversation doesn't end with an assistant message
    if (mappedMessage[mappedMessage.length - 1].role === 'assistant') {
        mappedMessage.push({
            role: 'user',
            content:
                'Continue what I said to you last message. Follow these instructions.'
        });
    }

    // Ensure the conversation doesn't start with an assistant message
    if (mappedMessage[0].role === 'assistant') {
        mappedMessage.unshift({
            role: 'user',
            content:
                'Continue what I said to you last time. Follow these instructions.'
        });
    }

    return mappedMessage;
}

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