Skip to content

feat(adapter-claude): support interleaved thinking with streaming#783

Merged
dingyi222666 merged 7 commits into
v1-devfrom
fix/adapter-interleaved-thinking
Mar 15, 2026
Merged

feat(adapter-claude): support interleaved thinking with streaming#783
dingyi222666 merged 7 commits into
v1-devfrom
fix/adapter-interleaved-thinking

Conversation

@dingyi222666
Copy link
Copy Markdown
Member

Summary

This PR adds comprehensive support for interleaved thinking in Claude models with streaming capabilities.

New Features

  • Interleaved Thinking Support: Added interleaved-thinking-2025-05-14 beta support for compatible Claude models (claude-3-7-, claude-sonnet-4, claude-opus-4-, claude-haiku-4)
  • Streaming Thinking Extraction: Properly extract and process thinking content from SSE stream events including:
    • content_block_start events for thinking blocks
    • content_block_delta events for incremental thinking updates
    • signature_delta events for thinking signatures
  • Reasoning Blocks: Track and manage reasoning blocks with thinking content and signatures for response reconstruction
  • Beta Header Management: Automatic beta header construction based on model version and thinking configuration
  • Usage Metadata: Calculate and propagate token usage metadata from streaming responses, including cache read/creation tokens
  • Enhanced Message Processing: Support for tool results within reasoning blocks and interleaved content

Bug Fixes

  • Fixed typo: CluadeToolClaudeTool throughout adapter codebase
  • Fixed handling of empty/null chunks in stream processing
  • Improved message content block handling for AI messages with reasoning
  • Fixed image processing for newer Claude models
  • Added proper validation for API response assertions

Other Changes

  • Refactored Request Building: Consolidated request parameter handling using deepAssign utility
  • Improved Type Definitions: Enhanced and exported comprehensive type definitions for:
    • ClaudeThinkingConfig
    • ClaudeToolChoice
    • ClaudeReasoningBlockParam
    • ClaudeServerToolUseBlockParam
    • ClaudeStreamContentBlockParam
    • ClaudeContentBlockDelta
  • Better Message Handling: Refactored message content processing to handle tool messages, AI messages with reasoning, and complex content blocks
  • File Support: Added support for file content processing via fetchFileLikeUrl utility for PDF and text documents
  • Header Improvements: Added Authorization header alongside x-api-key for improved compatibility
  • Code Quality: Removed unnecessary comments and improved code organization

Files Changed

  • packages/adapter-claude/src/requester.ts: Enhanced streaming and thinking support
  • packages/adapter-claude/src/types.ts: Comprehensive type definitions for new features
  • packages/adapter-claude/src/utils.ts: Improved message processing and tool handling
  • packages/adapter-hunyuan/src/*: Adapter consolidation for shared patterns
  • packages/adapter-wenxin/src/*: Adapter consolidation for shared patterns
  • packages/adapter-zhipu/src/*: Adapter consolidation for shared patterns
  • packages/shared-adapter/src/utils.ts: Minor shared utility updates

Consolidate duplicated message conversion, tool formatting, and stream
response handling logic across hunyuan, wenxin, and zhipu adapters into
shared-adapter utilities. Remove 1000+ lines of duplicate code by
leveraging buildChatCompletionParams, processStreamResponse, and other
shared utilities. Adapters now focus on adapter-specific configuration
and request/response translation.
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 13, 2026

Warning

Rate limit exceeded

@dingyi222666 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 6 minutes and 40 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a7d73c8e-e889-44fd-a306-7c7eb31bdb24

📥 Commits

Reviewing files that changed from the base of the PR and between 409fe42 and 789b57a.

⛔ 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 (6)
  • packages/adapter-claude/src/requester.ts
  • packages/adapter-claude/src/types.ts
  • packages/adapter-hunyuan/src/requester.ts
  • packages/adapter-hunyuan/src/types.ts
  • packages/adapter-wenxin/src/requester.ts
  • packages/adapter-wenxin/src/types.ts

Walkthrough

统一重构多个适配器的请求与流处理(Claude、Hunyuan、Wenxin、Zhipu),扩展 Claude 类型与推理块支持,迁移到共享适配器工具链(buildChatCompletionParams、processStreamResponse 等),并为若干适配器新增 embeddings 路径与头部/用量元数据透传。

Changes

Cohort / File(s) Summary
Claude — 请求与流
packages/adapter-claude/src/requester.ts
构建集中 ClaudeRequest;聚合并传递 anthropic-beta 头;按模型条件注入 interleaved-thinking;改用 SSE 统一流处理,解析并发出 usage_metadata、reasoning_blocks、signature_delta;增强错误映射与 Authorization/x-api-key 头处理。
Claude — 类型扩展
packages/adapter-claude/src/types.ts
大量导出并细化内容块/消息/delta/响应类型(新增 ClaudeThinkingConfig、ClaudeToolChoice、ClaudeReasoningBlockParam 等),将响应模型重构为细粒度 block 类型并扩展公共类型表面。
Claude — 工具/消息处理
packages/adapter-claude/src/utils.ts
消息转换签名新增 plugin 与可选 model;加入 image/file_url 处理;重写 delta→消息映射以支持新 delta 变体;工具格式化改用新 ClaudeTool 类型与 schema 清理。
Hunyuan — 请求与流重构
packages/adapter-hunyuan/src/requester.ts
用 buildChatCompletionParams 构建请求并通过 processStreamResponse 处理流;新增 validateHunyuanStream 与集中错误/安全检查;移除内联 SSE 解析;新增 public embeddings 方法。
Hunyuan — 类型与 utils 委托
packages/adapter-hunyuan/src/types.ts, packages/adapter-hunyuan/src/utils.ts
将若干类型重导出自共享模块;消息/工具与 delta 转换委托到共享适配器(OpenAI 相关实现),移除本地映射实现。
Wenxin — 请求/流与工具标准化
packages/adapter-wenxin/src/requester.ts, packages/adapter-wenxin/src/utils.ts
迁移到共享构建与流处理,公开 buildHeaders/concatUrl,delta 与工具映射委托共享实现,消息映射逻辑简化并引入 CONTINUE_PROMPT。
Zhipu — 统一流与 embeddings
packages/adapter-zhipu/src/requester.ts, packages/adapter-zhipu/src/utils.ts
采用共享请求构建与 processStreamResponse,支持 image/tool 特性分支,新增 concatUrl/buildHeaders,实现 EmbeddingsRequester,工具与 delta 映射委托共享实现。
共享适配器 — 思考处理通用化
packages/shared-adapter/src/utils.ts
将 processDeepSeekThinkMessages 重命名为 processInterleavedThinkMessages 并统一调用站点,移除 DeepSeek 专用分支,统一应用交错思考处理。
Claude 客户端 — 文件处理能力
packages/adapter-claude/src/client.ts, packages/adapter-claude/src/index.ts
新增并公开 FileHandlingConfig,向模型构建注入 fileHandlingConfig;扩展默认 modelCapabilities 包含 FileInput。

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Adapter as Requester
    participant Shared as SharedAdapter
    participant API as ExternalAPI
    participant Consumer

    Client->>Adapter: 发起 completion / embeddings 请求
    Adapter->>Shared: buildChatCompletionParams(request)
    Shared-->>Adapter: 返回 requestPayload 与 requestContext
    Adapter->>API: POST 请求 (含 headers 与 anthropic-beta)
    API-->>Adapter: 返回 SSE / 流响应
    Adapter->>Shared: processStreamResponse(iterable)
    Shared-->>Adapter: 标准化 stream chunk (delta, usage, thinking)
    Adapter->>Consumer: emit ChatGenerationChunk (包含 usage_metadata、reasoning_blocks、signature_delta)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 我是爱码的兔子,敲键合并又跳跃,
把适配器串成桥,流与头都排成列。
推理块与用量记,embeddings 路也接,
小改动,大合流,代码花园开新叶。

🚥 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 标题准确概括了 PR 的主要功能:在 Claude 适配器中添加支持交错思考(interleaved thinking)与流式处理,与文件摘要和目标完全一致。
Description check ✅ Passed 描述详细说明了新功能、bug 修复和其他改动,与文件摘要中的实际变更内容完全相关并高度匹配。

✏️ 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
  • Commit unit tests in branch fix/adapter-interleaved-thinking
📝 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.

@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 enhances the Claude adapter by introducing comprehensive support for interleaved thinking with streaming. It refactors the request and response processing to accurately capture and reconstruct reasoning blocks and usage metadata from streaming events. Furthermore, it consolidates common functionalities across other adapters (Hunyuan, Wenxin, Zhipu) into shared utilities, leading to a more robust and maintainable codebase. These changes improve the fidelity of model interactions, especially for advanced features like thinking processes and tool usage, while also streamlining development for future adapter integrations.

Highlights

  • Interleaved Thinking Support: Added beta support for 'interleaved-thinking-2025-05-14' in compatible Claude models (claude-3-7-, claude-sonnet-4, claude-opus-4-, claude-haiku-4) with streaming capabilities.
  • Streaming Thinking Extraction: Implemented proper extraction and processing of thinking content from SSE stream events, including content_block_start, content_block_delta, and signature_delta.
  • Reasoning Blocks Management: Introduced tracking and management of reasoning blocks with thinking content and signatures for accurate response reconstruction.
  • Unified Request Building: Refactored request parameter handling across adapters using a deepAssign utility for consistency and flexibility.
  • Enhanced Type Definitions: Expanded and exported comprehensive type definitions for Claude thinking configurations, tool choices, reasoning blocks, server tool use, and stream content blocks.
  • Improved Message Processing: Refactored message content processing to better handle tool messages, AI messages with reasoning, complex content blocks, and added support for file content (PDF, text) via URLs.
  • Adapter Consolidation: Standardized stream processing, request building, and tool formatting across Hunyuan, Wenxin, and Zhipu adapters by leveraging shared utilities.
  • Bug Fixes: Corrected a typo from CluadeTool to ClaudeTool, improved handling of empty stream chunks, and fixed image processing for newer Claude models.

🧠 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/adapter-claude/src/requester.ts
    • Refactored request building using deepAssign and added support for overrideRequestParams.
    • Implemented automatic anthropic-beta header construction, specifically for interleaved-thinking-2025-05-14 on compatible Claude models.
    • Enhanced stream processing to extract and manage usage metadata from message_start and message_delta events.
    • Added logic to handle content_block_start events for 'thinking' and 'redacted_thinking' blocks, and content_block_delta for 'thinking_delta' and 'signature_delta'.
    • Updated reasoning state to track and output reasoning_signature and reasoning_blocks in the final ChatGenerationChunk.
    • Added Authorization header to API requests for improved compatibility.
  • packages/adapter-claude/src/types.ts
    • Introduced and exported new types: ClaudeThinkingConfig, ClaudeToolChoice, ClaudeReasoningBlockParam, ClaudeServerToolUseBlockParam, ClaudeStreamContentBlockParam, and ClaudeContentBlockDelta.
    • Updated ClaudeRequest interface to include system, tool_choice, metadata, and service_tier fields.
    • Corrected typo CluadeTool to ClaudeTool.
  • packages/adapter-claude/src/utils.ts
    • Refactored langchainMessageToClaudeMessage to process images and file-like URLs more effectively, supporting PDF and text documents.
    • Enhanced AI message processing to incorporate reasoning_blocks, reasoning_content, and reasoning_signature from additional_kwargs.
    • Updated formatToolToClaudeTool to use removeAdditionalProperties for tool schema cleanup.
    • Revised convertDeltaToMessageChunk to explicitly handle various content_block_start and content_block_delta types, including thinking and signature deltas.
  • packages/adapter-hunyuan/src/requester.ts
    • Refactored completionStreamInternal to utilize shared adapter utilities for request building and stream processing.
    • Implemented validateHunyuanStream to perform specific error checking for 'IllegalDetected' content from Hunyuan API responses.
    • Standardized embeddings creation using the shared createEmbeddings utility.
  • packages/adapter-hunyuan/src/types.ts
    • Replaced local type definitions with exports from @chatluna/v1-shared-adapter for consistency and reduced duplication.
  • packages/adapter-hunyuan/src/utils.ts
    • Migrated message and tool formatting utilities to use shared adapter functions (formatToolToOpenAITool, langchainMessageToOpenAIMessage, convertOpenAIDeltaToMessageChunk).
    • Adjusted langchainMessageToHunyuanMessage to apply Hunyuan-specific system message handling and continuation prompts.
  • packages/adapter-wenxin/src/requester.ts
    • Refactored completionStreamInternal to use shared adapter utilities for request building and stream processing.
    • Standardized embeddings creation using the shared createEmbeddings utility.
    • Removed redundant _post and _buildHeaders methods, relying on the base ModelRequester implementation.
  • packages/adapter-wenxin/src/utils.ts
    • Migrated message and tool formatting utilities to use shared adapter functions (formatToolToOpenAITool, langchainMessageToOpenAIMessage, convertOpenAIDeltaToMessageChunk).
    • Adjusted langchainMessageToWenXinMessage to apply Wenxin-specific system message handling and continuation prompts.
  • packages/adapter-zhipu/src/requester.ts
    • Refactored completionStreamInternal to use shared adapter utilities for request building and stream processing.
    • Standardized embeddings creation using the shared createEmbeddings utility.
    • Removed jsonwebtoken dependency and related token generation logic, simplifying API key handling.
    • Removed redundant _post, init, and dispose methods, relying on the base ModelRequester implementation.
  • packages/adapter-zhipu/src/utils.ts
    • Migrated message and tool formatting utilities to use shared adapter functions (formatToolToOpenAITool, langchainMessageToOpenAIMessage, convertOpenAIDeltaToMessageChunk).
    • Adjusted langchainMessageToZhipuMessage to apply Zhipu-specific system message handling, continuation prompts, and special content handling for glm-4v-flash and tools models.
  • packages/shared-adapter/src/utils.ts
    • Generalized processDeepSeekThinkMessages to processInterleavedThinkMessages to support broader interleaved thinking patterns.
    • Removed specific deepseek-reasoner model checks, making the message processing logic more generic.
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

This pull request introduces comprehensive support for interleaved thinking with streaming for Claude models, which is a significant feature addition. The implementation across the Claude adapter's requester, types, and utilities appears thorough and well-executed. A major part of this PR is also the large-scale refactoring of the Hunyuan, Wenxin, and Zhipu adapters to leverage a new shared adapter library. This refactoring greatly enhances code reuse and maintainability across the project. Overall, the code quality is high. I have identified one critical error handling issue in the Hunyuan adapter and one medium-severity maintainability concern in the Claude adapter that should be addressed.

Comment thread packages/adapter-hunyuan/src/requester.ts
Comment thread packages/adapter-claude/src/requester.ts
@dingyi222666 dingyi222666 force-pushed the fix/adapter-interleaved-thinking branch 2 times, most recently from 41282ac to d4127b7 Compare March 13, 2026 22:10
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: 5

Caution

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

⚠️ Outside diff range comments (2)
packages/adapter-zhipu/src/utils.ts (1)

139-149: ⚠️ Potential issue | 🟠 Major

逻辑错误:web_search 工具被添加后立即移除

第 140-146 行添加了 web_search 工具,但第 148 行立即将其过滤掉。这使得整个代码块无效。

请确认预期行为:

  1. 如果应该添加 web_search,删除第 148 行
  2. 如果不应该添加 web_search,删除整个 if 块
🔧 如果应该添加 web_search
     if (clientConfig.webSearch && model.includes('tools')) {
         result.push({
             type: 'web_search',
             web_search: {
                 enable: true,
                 search_engine: 'search_std'
             }
         } satisfies ChatCompletionTool)
-
-        result = result.filter((tool) => tool.type !== 'web_search')
     }
🔧 如果不应该添加 web_search
-    if (clientConfig.webSearch && model.includes('tools')) {
-        result.push({
-            type: 'web_search',
-            web_search: {
-                enable: true,
-                search_engine: 'search_std'
-            }
-        } satisfies ChatCompletionTool)
-
-        result = result.filter((tool) => tool.type !== 'web_search')
-    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-zhipu/src/utils.ts` around lines 139 - 149, The if block
that checks clientConfig.webSearch && model.includes('tools') (in
packages/adapter-zhipu/src/utils.ts) adds a web_search tool to result and then
immediately removes it with result = result.filter((tool) => tool.type !==
'web_search'), so the addition is a no-op; decide the intended behavior and
apply one of two fixes: if web_search should be added, remove the filter line
that removes 'web_search' (the filter expression); if web_search should not be
added, remove the entire if block that pushes the web_search object (including
the push of the ChatCompletionTool-like object) to result.
packages/adapter-wenxin/src/requester.ts (1)

155-161: ⚠️ Potential issue | 🟡 Minor

删除 buildHeaders() 中的空 appid 字段

appid 字段被硬编码为空字符串,且 Config 类型中不存在相应的配置字段。由于文心 API 使用 Bearer Token 认证,该字段应该被移除。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-wenxin/src/requester.ts` around lines 155 - 161, Remove the
hard-coded empty appid property from the buildHeaders() return object in the
requester (function buildHeaders), since Config has no appid and the Wenxin API
uses Bearer token auth; update buildHeaders() to only return Content-Type and
Authorization: `Bearer ${this._config.value.apiKey}` (keep Authorization intact)
and run a quick compile/type-check to ensure no references to appid remain.
🧹 Nitpick comments (4)
packages/adapter-wenxin/src/utils.ts (1)

60-65: 冗余检查:第 60-65 行的逻辑永远不会执行

第 33-38 行已经处理了第一条消息是 assistant 的情况,会在其前面添加 user 消息。因此第 60 行的检查 result[0]?.role === 'assistant' 永远不会为真。

🔧 建议删除冗余代码
     if (result[result.length - 1]?.role === 'assistant') {
         result.push({
             role: 'user',
             content: CONTINUE_PROMPT
         })
     }

-    if (result[0]?.role === 'assistant') {
-        result.unshift({
-            role: 'user',
-            content: CONTINUE_PROMPT
-        })
-    }
-
     return result
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-wenxin/src/utils.ts` around lines 60 - 65, Remove the
redundant branch that checks result[0]?.role === 'assistant' and unshifts a user
message with CONTINUE_PROMPT into result; that case is already handled earlier
when the first message is assistant (the logic that prepends a user
CONTINUE_PROMPT when the first message is assistant), so delete the duplicate
block referencing result and CONTINUE_PROMPT to avoid unreachable code.
packages/adapter-zhipu/src/requester.ts (1)

90-90: 格式问题:不必要的括号

静态分析工具标记了第 90 行的不必要括号。

🔧 建议修复
-        request.user = isToolModel ? undefined : (params.user ?? 'user')
+        request.user = isToolModel ? undefined : params.user ?? 'user'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-zhipu/src/requester.ts` at line 90, Line uses unnecessary
parentheses around (params.user ?? 'user'); update the assignment in
requester.ts so request.user is set without extra parens: use the ternary
expression with the nullish coalescing directly (i.e., request.user =
isToolModel ? undefined : params.user ?? 'user'), targeting the expression that
sets request.user and referencing isToolModel and params.user.
packages/shared-adapter/src/utils.ts (1)

260-261: 注释与函数名不一致

函数已重命名为 processInterleavedThinkMessages 以支持通用的交织思考处理,但注释仍然引用 "DeepSeek docs"。建议更新注释以反映通用用途。

🔧 建议修复
     // Find the start of the last turn by locating the last user message
-    // According to DeepSeek docs: a turn starts with a user message
+    // A turn starts with a user message
     let lastTurnStartIndex = -1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/shared-adapter/src/utils.ts` around lines 260 - 261, 更新
processInterleavedThinkMessages 上方的注释以反映函数通用用途:删除对 "DeepSeek docs"
的引用并改为描述该函数用于处理通用的交织(interleaved)思考消息流,说明其行为——通过定位最后一个用户消息来确定最后一轮的起点(即把一轮视为以用户消息开始的消息序列),并简要列出输入/输出预期(例如接受混合的
system/assistant/user 消息数组并返回切分后的最后一轮消息)。保证注释和函数名一致且不包含特定实现来源引用。
packages/adapter-hunyuan/src/requester.ts (1)

97-101: JSON 解析错误被静默忽略

JSON.parse 失败且异常不是 ChatLunaError 时,错误被静默忽略。这可能会隐藏流处理中的问题。考虑添加日志记录以便调试。

🔧 建议添加日志记录
         } catch (e) {
             if (e instanceof ChatLunaError) {
                 throw e
             }
+            // JSON parse failed for non-data chunk, continue processing
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-hunyuan/src/requester.ts` around lines 97 - 101, The catch
block in packages/adapter-hunyuan/src/requester.ts currently swallows
non-ChatLunaError exceptions (e.g., JSON.parse failures) which hides parsing
issues; update the catch around the JSON.parse call so that if the thrown error
is not an instance of ChatLunaError you log the full error and relevant context
(response body or raw text) using the project logger (or console.error if no
logger is available) and then rethrow the error so callers can handle it;
reference the ChatLunaError type and the JSON.parse usage in the same try/catch
when making this change.
🤖 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/adapter-claude/src/requester.ts`:
- Around line 127-132: The code currently only pushes reasoning blocks into
reasoningState.blocks and emits text/tool_use blocks separately, which loses the
original interleaved order; update the logic around reasoningState (the
reasoningState object and its .blocks array, and any code that emits blocks in
the requester flow) to store the entire sequence of blocks with their original
index/position (keep full block objects including type, content, and an index)
instead of extracting only reasoning blocks, and then use that preserved ordered
array when constructing reasoning_blocks for replay; apply the same change to
the other similar sections referenced (the blocks handling around the other
occurrences) so interleaved sequences like thinking->text->tool_use->thinking
are reconstructed in original order when sending messages back to Claude.
- Around line 48-80: The merged request currently allows callers to override
stream behavior which breaks completionStreamInternal/sseIterable; after
deepAssign into request (the ClaudeRequest built with deepAssign and
params.overrideRequestParams), forcibly set request.stream = true (or remove any
stream property from override) so the request variable used by
completionStreamInternal and sseIterable always remains streaming; update the
logic around deepAssign/ClaudeRequest in requester.ts (the request construction)
to enforce this invariant and reference the request variable, deepAssign,
ClaudeRequest, and params.overrideRequestParams when making the change.

In `@packages/adapter-claude/src/utils.ts`:
- Around line 91-105: The ToolMessage branch currently rebuilds
tool_result.content from rawMessage.content and calls processMessageContent
again, which discards the multimodal content (images) assembled earlier; instead
reuse the already-constructed result.content (the merged rawMessage.content +
additional_kwargs.images) when creating the tool_result entry so
images/attachments are preserved, keep setting tool_use_id to
rawMessage.tool_call_id, and remove the redundant processing call to
processMessageContent in the ToolMessage handling block.
- Around line 270-275: The warn log currently outputs the raw message.file_url
via the rawUrl variable which may contain signed object-storage URLs or
sensitive local paths; change the catch block (where rawUrl and logger.warn are
used) to never log the full URL — instead log a fixed/descriptive message or a
safely redacted identifier (e.g., "file_url present" or a hashed/partial token)
and/or the message ID or filename only; remove rawUrl from logger.warn and
replace it with the sanitized or constant text to avoid credential/path leakage.

In `@packages/adapter-zhipu/src/utils.ts`:
- Around line 46-67: In the glm-4v-flash special-case branch (the if (model ===
'glm-4v-flash') block) the code assumes msg.content.find(item => item.type ===
'text') always returns an object and reads .text, which can throw; change the
assignment to safely handle missing matches by first storing the result of
msg.content.find(...) into a variable, check it is truthy before reading .text,
and fall back to a safe value (e.g., empty string or leave msg.content
unchanged) so no runtime error occurs when no {type: 'text'} item exists.

---

Outside diff comments:
In `@packages/adapter-wenxin/src/requester.ts`:
- Around line 155-161: Remove the hard-coded empty appid property from the
buildHeaders() return object in the requester (function buildHeaders), since
Config has no appid and the Wenxin API uses Bearer token auth; update
buildHeaders() to only return Content-Type and Authorization: `Bearer
${this._config.value.apiKey}` (keep Authorization intact) and run a quick
compile/type-check to ensure no references to appid remain.

In `@packages/adapter-zhipu/src/utils.ts`:
- Around line 139-149: The if block that checks clientConfig.webSearch &&
model.includes('tools') (in packages/adapter-zhipu/src/utils.ts) adds a
web_search tool to result and then immediately removes it with result =
result.filter((tool) => tool.type !== 'web_search'), so the addition is a no-op;
decide the intended behavior and apply one of two fixes: if web_search should be
added, remove the filter line that removes 'web_search' (the filter expression);
if web_search should not be added, remove the entire if block that pushes the
web_search object (including the push of the ChatCompletionTool-like object) to
result.

---

Nitpick comments:
In `@packages/adapter-hunyuan/src/requester.ts`:
- Around line 97-101: The catch block in
packages/adapter-hunyuan/src/requester.ts currently swallows non-ChatLunaError
exceptions (e.g., JSON.parse failures) which hides parsing issues; update the
catch around the JSON.parse call so that if the thrown error is not an instance
of ChatLunaError you log the full error and relevant context (response body or
raw text) using the project logger (or console.error if no logger is available)
and then rethrow the error so callers can handle it; reference the ChatLunaError
type and the JSON.parse usage in the same try/catch when making this change.

In `@packages/adapter-wenxin/src/utils.ts`:
- Around line 60-65: Remove the redundant branch that checks result[0]?.role ===
'assistant' and unshifts a user message with CONTINUE_PROMPT into result; that
case is already handled earlier when the first message is assistant (the logic
that prepends a user CONTINUE_PROMPT when the first message is assistant), so
delete the duplicate block referencing result and CONTINUE_PROMPT to avoid
unreachable code.

In `@packages/adapter-zhipu/src/requester.ts`:
- Line 90: Line uses unnecessary parentheses around (params.user ?? 'user');
update the assignment in requester.ts so request.user is set without extra
parens: use the ternary expression with the nullish coalescing directly (i.e.,
request.user = isToolModel ? undefined : params.user ?? 'user'), targeting the
expression that sets request.user and referencing isToolModel and params.user.

In `@packages/shared-adapter/src/utils.ts`:
- Around line 260-261: 更新 processInterleavedThinkMessages 上方的注释以反映函数通用用途:删除对
"DeepSeek docs"
的引用并改为描述该函数用于处理通用的交织(interleaved)思考消息流,说明其行为——通过定位最后一个用户消息来确定最后一轮的起点(即把一轮视为以用户消息开始的消息序列),并简要列出输入/输出预期(例如接受混合的
system/assistant/user 消息数组并返回切分后的最后一轮消息)。保证注释和函数名一致且不包含特定实现来源引用。
🪄 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: 430eb48a-2e09-4586-9cd0-fe484d5d1b3f

📥 Commits

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

📒 Files selected for processing (11)
  • packages/adapter-claude/src/requester.ts
  • packages/adapter-claude/src/types.ts
  • packages/adapter-claude/src/utils.ts
  • packages/adapter-hunyuan/src/requester.ts
  • packages/adapter-hunyuan/src/types.ts
  • packages/adapter-hunyuan/src/utils.ts
  • packages/adapter-wenxin/src/requester.ts
  • packages/adapter-wenxin/src/utils.ts
  • packages/adapter-zhipu/src/requester.ts
  • packages/adapter-zhipu/src/utils.ts
  • packages/shared-adapter/src/utils.ts

Comment thread packages/adapter-claude/src/requester.ts
Comment thread packages/adapter-claude/src/requester.ts
Comment thread packages/adapter-claude/src/utils.ts
Comment thread packages/adapter-claude/src/utils.ts
Comment thread packages/adapter-zhipu/src/utils.ts
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/adapter-claude/src/utils.ts (1)

217-224: ⚠️ Potential issue | 🟡 Minor

图片 URL 也不应输出到日志。

processFileContent 类似,image_url 也可能包含签名 URL 或敏感数据。建议统一处理,避免泄露。

🛡️ 建议修改
     } catch (e) {
-        const rawUrl =
-            typeof message.image_url === 'string'
-                ? message.image_url
-                : message.image_url.url
-        logger.warn(`Failed to fetch image url: ${rawUrl}`, e)
+        logger.warn('Failed to fetch image content', e)
         return null
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-claude/src/utils.ts` around lines 217 - 224, The catch block
logs the raw image URL which may contain sensitive/signed data; update the error
handling in the try/catch around fetching images (the block that accesses
message.image_url) to avoid emitting the URL itself—use a redacted placeholder
or omit the URL and include only contextual info (e.g., "Failed to fetch image
url for message id/attachment") and the error object in the logger.warn call;
follow the same redaction approach used in processFileContent to ensure
consistent handling.
♻️ Duplicate comments (3)
packages/adapter-claude/src/utils.ts (2)

91-105: ⚠️ Potential issue | 🟠 Major

ToolMessage 分支丢弃了前面处理好的多模态内容。

Lines 49-84 已经将 rawMessage.contentadditional_kwargs.images 合并处理到 content 变量中。但这里又从 rawMessage.content 重新生成 tool_result.content,会丢弃图片附件。应直接复用前面组装好的 content

🐛 建议修改
             if (rawMessage instanceof ToolMessage) {
                 result.content = [
                     {
                         type: 'tool_result',
-                        content:
-                            typeof rawMessage.content === 'string'
-                                ? rawMessage.content
-                                : await processMessageContent(
-                                      plugin,
-                                      rawMessage.content
-                                  ),
+                        content,
                         tool_use_id: rawMessage.tool_call_id
                     }
                 ]
                 return result
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-claude/src/utils.ts` around lines 91 - 105, The ToolMessage
branch in the function handling messages currently rebuilds tool_result.content
from rawMessage.content (and calls processMessageContent) which discards
previously merged multimodal data (the local variable content assembled earlier
from rawMessage.content and additional_kwargs.images); update the ToolMessage
branch to reuse that assembled content variable for tool_result.content (keep
tool_use_id set from rawMessage.tool_call_id) instead of reprocessing
rawMessage.content so attached images and multimodal parts are preserved (check
code around ToolMessage, processMessageContent, tool_call_id and the local
content variable).

270-276: ⚠️ Potential issue | 🟠 Major

不要将原始 file_url 输出到日志。

file_url 可能包含签名的对象存储 URL 或敏感路径。在 warn 日志中原样输出会泄露凭证或文件位置。建议只记录固定文案或脱敏后的标识。

🛡️ 建议修改
     } catch (e) {
-        const rawUrl =
-            typeof message.file_url === 'string'
-                ? message.file_url
-                : message.file_url.url
-        logger.warn(`Failed to fetch file url: ${rawUrl}`, e)
+        logger.warn('Failed to fetch Claude file content', e)
         return null
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-claude/src/utils.ts` around lines 270 - 276, The catch block
currently logs the raw file_url (see message.file_url and rawUrl) which can leak
signed URLs or sensitive paths; change the logger.warn call in that catch block
to avoid emitting the full URL—either log a fixed message like "Failed to fetch
file URL (redacted)" or log a non-sensitive identifier (e.g. derive and log only
a masked/hashed token or the filename without query params), and include the
error object for debugging (keep using logger.warn but remove rawUrl from the
message and replace with the redacted identifier).
packages/adapter-claude/src/requester.ts (1)

48-80: ⚠️ Potential issue | 🟠 Major

overrideRequestParams 可能覆盖 stream: true 导致 SSE 解析失败。

deepAssign 会将 params.overrideRequestParams 合并到请求中。如果调用方传入 { stream: false },后续的 sseIterable(response) 会将普通 JSON 响应当作 SSE 流处理,导致解析错误。应在合并后强制设置 request.stream = true

🐛 建议修改
         const request = deepAssign(
             {},
             {
                 model,
                 max_tokens: maxTokens,
                 // ... other fields
             } satisfies ClaudeRequest,
             params.overrideRequestParams ?? {}
         ) as ClaudeRequest
+        request.stream = true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-claude/src/requester.ts` around lines 48 - 80, deepAssign
merges params.overrideRequestParams into the ClaudeRequest which allows callers
to set stream:false and break SSE parsing; after building the request (the
deepAssign call that produces the request variable typed ClaudeRequest in
requester.ts), explicitly set request.stream = true to ensure SSE remains
enabled regardless of overrides (keep the rest of override merging intact), and
similarly ensure any downstream uses (e.g., sseIterable(response)) can rely on
request.stream always being true.
🧹 Nitpick comments (1)
packages/adapter-claude/src/utils.ts (1)

368-395: content_block_start 中的 thinking 类型未被处理。

delta.content_block.typethinkingredacted_thinking 时,函数会返回 undefined。虽然 requester.ts 中单独处理了这些类型,但建议在此处添加显式 case 或注释说明,避免将来维护时产生困惑。

💡 可选:添加显式处理或注释
         if (delta.content_block.type === 'text') {
             const content = delta.content_block.text
             if (content !== undefined) {
                 return new AIMessageChunk({
                     content,
                     additional_kwargs: {}
                 })
             }
         }
 
+        // thinking and redacted_thinking blocks are handled separately in requester.ts
         return
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-claude/src/utils.ts` around lines 368 - 395, The handler for
content_block_start in packages/adapter-claude/src/utils.ts currently only
handles 'tool_use' and 'text' but silently returns undefined for 'thinking' and
'redacted_thinking'; update the delta.content_block.type switch in the function
(the block that constructs AIMessageChunk) to explicitly handle 'thinking' and
'redacted_thinking'—either by adding a clear case that returns undefined with a
comment pointing to requester.ts for actual processing, or by returning an
explicit AIMessageChunk shape if needed—so future readers see intended behavior
for these types (refer to delta.content_block.type, AIMessageChunk, and the
content_block_start handling).
🤖 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/adapter-claude/src/utils.ts`:
- Around line 334-342: The function formatToolsToClaudeTools currently declares
a return type of ClaudeTool[] but returns undefined when tools.length < 1;
change the behavior to return an empty array instead of undefined (or
alternatively widen the return type to ClaudeTool[] | undefined) so the declared
signature matches actual return values; update the early-return branch in
formatToolsToClaudeTools and ensure callers expecting an array still work
(formatToolToClaudeTool remains used for mapping).

---

Outside diff comments:
In `@packages/adapter-claude/src/utils.ts`:
- Around line 217-224: The catch block logs the raw image URL which may contain
sensitive/signed data; update the error handling in the try/catch around
fetching images (the block that accesses message.image_url) to avoid emitting
the URL itself—use a redacted placeholder or omit the URL and include only
contextual info (e.g., "Failed to fetch image url for message id/attachment")
and the error object in the logger.warn call; follow the same redaction approach
used in processFileContent to ensure consistent handling.

---

Duplicate comments:
In `@packages/adapter-claude/src/requester.ts`:
- Around line 48-80: deepAssign merges params.overrideRequestParams into the
ClaudeRequest which allows callers to set stream:false and break SSE parsing;
after building the request (the deepAssign call that produces the request
variable typed ClaudeRequest in requester.ts), explicitly set request.stream =
true to ensure SSE remains enabled regardless of overrides (keep the rest of
override merging intact), and similarly ensure any downstream uses (e.g.,
sseIterable(response)) can rely on request.stream always being true.

In `@packages/adapter-claude/src/utils.ts`:
- Around line 91-105: The ToolMessage branch in the function handling messages
currently rebuilds tool_result.content from rawMessage.content (and calls
processMessageContent) which discards previously merged multimodal data (the
local variable content assembled earlier from rawMessage.content and
additional_kwargs.images); update the ToolMessage branch to reuse that assembled
content variable for tool_result.content (keep tool_use_id set from
rawMessage.tool_call_id) instead of reprocessing rawMessage.content so attached
images and multimodal parts are preserved (check code around ToolMessage,
processMessageContent, tool_call_id and the local content variable).
- Around line 270-276: The catch block currently logs the raw file_url (see
message.file_url and rawUrl) which can leak signed URLs or sensitive paths;
change the logger.warn call in that catch block to avoid emitting the full
URL—either log a fixed message like "Failed to fetch file URL (redacted)" or log
a non-sensitive identifier (e.g. derive and log only a masked/hashed token or
the filename without query params), and include the error object for debugging
(keep using logger.warn but remove rawUrl from the message and replace with the
redacted identifier).

---

Nitpick comments:
In `@packages/adapter-claude/src/utils.ts`:
- Around line 368-395: The handler for content_block_start in
packages/adapter-claude/src/utils.ts currently only handles 'tool_use' and
'text' but silently returns undefined for 'thinking' and 'redacted_thinking';
update the delta.content_block.type switch in the function (the block that
constructs AIMessageChunk) to explicitly handle 'thinking' and
'redacted_thinking'—either by adding a clear case that returns undefined with a
comment pointing to requester.ts for actual processing, or by returning an
explicit AIMessageChunk shape if needed—so future readers see intended behavior
for these types (refer to delta.content_block.type, AIMessageChunk, and the
content_block_start handling).
🪄 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: 1d6683b6-f783-49ba-b573-6e8f1550c14a

📥 Commits

Reviewing files that changed from the base of the PR and between f9897a6 and d4127b7.

📒 Files selected for processing (3)
  • packages/adapter-claude/src/requester.ts
  • packages/adapter-claude/src/types.ts
  • packages/adapter-claude/src/utils.ts

Comment thread packages/adapter-claude/src/utils.ts
Add interleaved-thinking-2025-05-14 beta support for Claude models with:
- Streaming thinking content extraction from SSE events
- Reasoning blocks with thinking content and signatures
- Proper message content handling for tool results
- Beta header management with model detection
@dingyi222666 dingyi222666 force-pushed the fix/adapter-interleaved-thinking branch from d4127b7 to 569777c Compare March 13, 2026 22:20
- Enable streaming in Claude requester by setting stream=true
- Simplify tool result content handling with proper type casting
- Fix formatToolsToClaudeTools to return empty array instead of undefined
- Add missing ClaudeToolResultContentBlockParam import for type safety
…nto constants

Extract hardcoded model checks into INTERLEAVED_THINKING_SUPPORTED_MODELS and
INTERLEAVED_THINKING_EXCLUDED_MODELS constants for improved maintainability
and reusability.
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/adapter-claude/src/utils.ts (1)

213-221: ⚠️ Potential issue | 🟠 Major

不要把原始 image_url 写进日志。

image_url 可能是签名对象存储地址,甚至是内联 data: URL。这里失败时把完整值打到 warn,会把凭证或大段二进制内容泄露到日志系统。

建议修改
     } catch (e) {
-        const rawUrl =
-            typeof message.image_url === 'string'
-                ? message.image_url
-                : message.image_url.url
-        logger.warn(`Failed to fetch image url: ${rawUrl}`, e)
+        logger.warn('Failed to fetch Claude image content', e)
         return null
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-claude/src/utils.ts` around lines 213 - 221, The current
catch block in the image fetching flow (around fetchImageUrl and logger.warn)
logs the raw message.image_url (variable rawUrl), which can leak credentials or
large data URLs; change the warning to avoid printing the full image_url —
instead log a safe redaction or metadata (e.g., indicate whether image_url is a
string/object, its length or the scheme like "data:" vs "https", or simply
"image_url omitted for security"), and include the error object; update the
logger.warn call in the catch for fetchImageUrl to use the redacted/metadata
value rather than rawUrl.
♻️ Duplicate comments (2)
packages/adapter-claude/src/utils.ts (1)

268-274: ⚠️ Potential issue | 🟠 Major

不要把原始 file_url 写进日志。

file_url 很可能是签名 URL 或本地敏感路径。这里会把完整地址写进 warn,失败一次就会把凭证或路径泄露到日志系统。

建议修改
     } catch (e) {
-        const rawUrl =
-            typeof message.file_url === 'string'
-                ? message.file_url
-                : message.file_url.url
-        logger.warn(`Failed to fetch file url: ${rawUrl}`, e)
+        logger.warn('Failed to fetch Claude file content', e)
         return null
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-claude/src/utils.ts` around lines 268 - 274, The catch block
currently logs the full rawUrl derived from message.file_url which may expose
signed URLs or local sensitive paths; update the logger.warn in that catch to
avoid emitting the full URL (reference the variable message.file_url and the
logger.warn call) by either logging a redacted/obfuscated form (e.g., mask query
string or show only hostname) or logging a generic message like "Failed to fetch
file url" with no raw URL and optionally include a non-sensitive identifier
(e.g., message.id); leave the return null behavior unchanged.
packages/adapter-claude/src/requester.ts (1)

138-143: ⚠️ Potential issue | 🟠 Major

reasoning_blocks 仍然没有保住 interleaved 的原始顺序。

reasoningState.blocks 的元素类型还是 ClaudeReasoningBlockParam[],后面也只把这些块写回 additional_kwargs.reasoning_blocks。只要流里出现 thinking -> text/tool_use -> thinking,中间的 text/tool_use 就不会进入这个序列;下一轮在 packages/adapter-claude/src/utils.tslangchainMessageToClaudeMessage() 里只能把 reasoning 全部前置,原始顺序会被重排。

Also applies to: 202-250, 278-305

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-claude/src/requester.ts` around lines 138 - 143, The current
implementation only stores ClaudeReasoningBlockParam objects in
reasoningState.blocks and writes them back to
additional_kwargs.reasoning_blocks, which loses the original interleaved order
when non-reasoning events (text/tool_use) occur between thinking blocks; update
the logic so reasoningState.blocks records ordering information (e.g., make it
an array of discriminated union entries or include an index/timestamp and
message kind) instead of only ClaudeReasoningBlockParam, and when emitting
additional_kwargs.reasoning_blocks or when langchainMessageToClaudeMessage()
reconstructs the stream, merge/restore blocks according to that recorded order
so thinking and text/tool_use elements remain in original interleaved sequence;
reference reasoningState.blocks, ClaudeReasoningBlockParam,
additional_kwargs.reasoning_blocks and langchainMessageToClaudeMessage() when
changing types and reconstruction logic.
🤖 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/adapter-claude/src/utils.ts`:
- Around line 59-85: The image-handling branch uses model?.includes('claude-4')
which misses variants like claude-sonnet-4 / claude-opus-4* / claude-haiku-4 and
thus silently drops additional_kwargs.images; update the condition in the block
that builds mappedImages/nextContent (the model check wrapping images processing
inside packages/adapter-claude/src/utils.ts) to match the same Claude 4
detection used in packages/adapter-claude/src/requester.ts (e.g., reuse the
shared helper or change the check to a regex/pattern that matches all claude-*4
variants such as /^claude.*-?4/ or the existing isClaude4Model function), so
images are processed by processImageContent and merged into content
(mappedImages, nextContent) for all Claude 4 variants.

---

Outside diff comments:
In `@packages/adapter-claude/src/utils.ts`:
- Around line 213-221: The current catch block in the image fetching flow
(around fetchImageUrl and logger.warn) logs the raw message.image_url (variable
rawUrl), which can leak credentials or large data URLs; change the warning to
avoid printing the full image_url — instead log a safe redaction or metadata
(e.g., indicate whether image_url is a string/object, its length or the scheme
like "data:" vs "https", or simply "image_url omitted for security"), and
include the error object; update the logger.warn call in the catch for
fetchImageUrl to use the redacted/metadata value rather than rawUrl.

---

Duplicate comments:
In `@packages/adapter-claude/src/requester.ts`:
- Around line 138-143: The current implementation only stores
ClaudeReasoningBlockParam objects in reasoningState.blocks and writes them back
to additional_kwargs.reasoning_blocks, which loses the original interleaved
order when non-reasoning events (text/tool_use) occur between thinking blocks;
update the logic so reasoningState.blocks records ordering information (e.g.,
make it an array of discriminated union entries or include an index/timestamp
and message kind) instead of only ClaudeReasoningBlockParam, and when emitting
additional_kwargs.reasoning_blocks or when langchainMessageToClaudeMessage()
reconstructs the stream, merge/restore blocks according to that recorded order
so thinking and text/tool_use elements remain in original interleaved sequence;
reference reasoningState.blocks, ClaudeReasoningBlockParam,
additional_kwargs.reasoning_blocks and langchainMessageToClaudeMessage() when
changing types and reconstruction logic.

In `@packages/adapter-claude/src/utils.ts`:
- Around line 268-274: The catch block currently logs the full rawUrl derived
from message.file_url which may expose signed URLs or local sensitive paths;
update the logger.warn in that catch to avoid emitting the full URL (reference
the variable message.file_url and the logger.warn call) by either logging a
redacted/obfuscated form (e.g., mask query string or show only hostname) or
logging a generic message like "Failed to fetch file url" with no raw URL and
optionally include a non-sensitive identifier (e.g., message.id); leave the
return null behavior unchanged.
🪄 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: ceaae035-d048-40c6-b6bf-2c66da317539

📥 Commits

Reviewing files that changed from the base of the PR and between d4127b7 and ac4b124.

📒 Files selected for processing (3)
  • packages/adapter-claude/src/requester.ts
  • packages/adapter-claude/src/types.ts
  • packages/adapter-claude/src/utils.ts

Comment thread packages/adapter-claude/src/utils.ts
Let Claude models accept read_files inline documents and images so native Anthropic file blocks are used instead of dropping supported inputs.
Move Claude shared content and interleaved-thinking definitions into its types module, and centralize Hunyuan and Wenxin request shapes so requester implementations can reuse the same adapter types.
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.

♻️ Duplicate comments (2)
packages/adapter-claude/src/utils.ts (2)

277-283: ⚠️ Potential issue | 🟠 Major

敏感 URL 不应直接记录到日志。

file_url 可能包含带签名的对象存储 URL 或敏感本地路径。将其原样输出到 warn 日志会泄露凭证或文件位置。

建议修改
     } catch (e) {
-        const rawUrl =
-            typeof message.file_url === 'string'
-                ? message.file_url
-                : message.file_url.url
-        logger.warn(`Failed to fetch file url: ${rawUrl}`, e)
+        logger.warn('Failed to fetch Claude file content', e)
         return null
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-claude/src/utils.ts` around lines 277 - 283, The catch block
in packages/adapter-claude/src/utils.ts currently builds rawUrl from
message.file_url and logs it via logger.warn (see variable rawUrl and the
logger.warn call); change this to avoid printing sensitive URLs/paths
directly—either redact or replace the URL with a fixed placeholder (e.g.,
"<REDACTED_FILE_URL>"), or log a deterministic hash/UUID of the URL instead, and
include minimal context like the message ID or error without the raw path;
ensure the logger.warn invocation uses the sanitized placeholder/hash and still
logs the caught error object e for diagnostics.

68-70: ⚠️ Potential issue | 🟠 Major

Claude 4 模型变体的图片处理会被静默跳过。

model?.includes('claude-4') 无法匹配 claude-sonnet-4claude-opus-4*claude-haiku-4 等变体(参考 client.ts 中的 fallbackModels 列表)。这些模型名称中包含的是 sonnet-4opus-4 而非 claude-4,导致 additional_kwargs.images 会被丢弃。

建议修改
             if (
-                (model?.includes('claude-3') || model?.includes('claude-4')) &&
-                images != null
+                images != null &&
+                (model?.includes('claude-3') ||
+                    model?.includes('claude-sonnet-4') ||
+                    model?.includes('claude-opus-4') ||
+                    model?.includes('claude-haiku-4'))
             ) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-claude/src/utils.ts` around lines 68 - 70, The check in
utils.ts that uses model?.includes('claude-4') misses Claude v4 variants (e.g.,
claude-sonnet-4, claude-opus-4, claude-haiku-4) so images get dropped; update
the conditional around model (the if that gates additional_kwargs.images) to
detect any Claude v4 variant instead of only the literal "claude-4" (for example
use a regex that matches "claude" with any suffix ending in "-4" or reuse the
fallbackModels logic from client.ts), then ensure additional_kwargs.images is
preserved when that updated match succeeds; touch the condition that references
model and additional_kwargs.images in utils.ts only.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/adapter-claude/src/utils.ts`:
- Around line 277-283: The catch block in packages/adapter-claude/src/utils.ts
currently builds rawUrl from message.file_url and logs it via logger.warn (see
variable rawUrl and the logger.warn call); change this to avoid printing
sensitive URLs/paths directly—either redact or replace the URL with a fixed
placeholder (e.g., "<REDACTED_FILE_URL>"), or log a deterministic hash/UUID of
the URL instead, and include minimal context like the message ID or error
without the raw path; ensure the logger.warn invocation uses the sanitized
placeholder/hash and still logs the caught error object e for diagnostics.
- Around line 68-70: The check in utils.ts that uses model?.includes('claude-4')
misses Claude v4 variants (e.g., claude-sonnet-4, claude-opus-4, claude-haiku-4)
so images get dropped; update the conditional around model (the if that gates
additional_kwargs.images) to detect any Claude v4 variant instead of only the
literal "claude-4" (for example use a regex that matches "claude" with any
suffix ending in "-4" or reuse the fallbackModels logic from client.ts), then
ensure additional_kwargs.images is preserved when that updated match succeeds;
touch the condition that references model and additional_kwargs.images in
utils.ts only.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: cafd61f6-bcae-4455-991f-4b56a3051e0d

📥 Commits

Reviewing files that changed from the base of the PR and between ac4b124 and 409fe42.

📒 Files selected for processing (3)
  • packages/adapter-claude/src/client.ts
  • packages/adapter-claude/src/index.ts
  • packages/adapter-claude/src/utils.ts

Update adapter package dependencies to use @chatluna/v1-shared-adapter 1.0.30 and bump affected package versions so the release metadata stays aligned.
@dingyi222666 dingyi222666 merged commit 87d4151 into v1-dev Mar 15, 2026
5 checks passed
@dingyi222666 dingyi222666 deleted the fix/adapter-interleaved-thinking branch March 15, 2026 20:07
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