Skip to content

fix: prevent DeepSeek v4 reasoning chain from leaking as analysis result#193

Merged
AmintaCCCP merged 7 commits into
mainfrom
fix/deepseek-reasoning-content-leak
Jun 6, 2026
Merged

fix: prevent DeepSeek v4 reasoning chain from leaking as analysis result#193
AmintaCCCP merged 7 commits into
mainfrom
fix/deepseek-reasoning-content-leak

Conversation

@AmintaCCCP

@AmintaCCCP AmintaCCCP commented Jun 4, 2026

Copy link
Copy Markdown
Owner

问题

用户反馈使用 deepseek-v4-flashdeepseek-v4-pro 模型分析仓库时,模型的思维链(reasoning chain)被当作分析结果展示,而非实际的 JSON 分析内容。

相关讨论:#192

根因分析

问题1:token 耗尽

DeepSeek v4 模型默认开启 thinking mode。max_tokens 包含 reasoning_tokens,当设置 max_tokens: 700 时,所有 700 个 token 被思维链消耗,content 为空。

问题2:reasoning_content 回退

requestText() 的响应解析逻辑无条件回退到 reasoning_content,将思维链当作最终结果返回。

问题3:特殊参数混在通用路径中

DeepSeek/MiMo 特有参数(thinkingreasoning_content)散落在 openai/openai-compatible 代码路径中,通过模型名字符串匹配,可能误伤第三方中转站。

修复内容

1. 独立 DeepSeek 官方渠道(deepseek API 类型)

  • 官方渠道:apiType = 'deepseek',自动处理 thinking/reasoning_content
  • 第三方中转:apiType = 'openai-compatible',通用行为
  • 默认 baseUrl:https://api.deepseek.com

2. 独立 MiMo 官方渠道(mimo API 类型)

MiMo 有两种官方渠道,接入点不同:

渠道 Base URL API Key 前缀
API(按量付费) api.xiaomimimo.com/v1 sk-
Token Plan(订阅制) token-plan-cn.xiaomimimo.com/v1 tp-

用户选择 MiMo 后,需进一步选择渠道,baseUrl 自动切换。thinking:disabled 仅对官方渠道注入。

3. 禁用 DeepSeek/MiMo 的 thinking

对非 reasoner 的 DeepSeek 模型和 MiMo 模型显式发送 { thinking: { type: 'disabled' } }

4. reasoning_content 回退限制

仅对 deepseek-reasoner 模型使用 reasoning_content 回退。

5. 增大 maxTokens

分析请求的 maxTokens 从 700 增至 1000。

6. 修复截断 <think> 标签

parseAIResponse() 增加对截断 <think> 标签的处理。

影响范围

模型 是否受影响
deepseek-reasoner 不受影响
deepseek-v4-flash/pro 修复
MiMo(官方渠道) 修复
OpenAI / Claude / Gemini 不受影响
第三方中转站 不受影响

参考

Summary by CodeRabbit

  • New Features

    • Added DeepSeek as an AI API option and MiMo plan selection in settings; MiMo plan is persisted with AI configs and included in import/sync.
  • Bug Fixes

    • Prevented automatic injection of a reasoning payload for the DeepSeek Reasoner model.
    • Improved response parsing to remove embedded thinking markers and handle missing final text.
  • Improvements

    • Broader DeepSeek/MiMo detection, clearer endpoint guidance, and increased tokens for repository analysis.

…sis result

- Only fall back to reasoning_content for deepseek-reasoner model, not
  deepseek-v4-flash/v4-pro which also return this field
- Extend isDeepSeekReasonerModel() to cover openai-compatible API type
- Strip <think> tags in parseAIResponse() to handle models that embed
  thinking in the content field
- Skip reasoning parameter injection in proxy for deepseek-reasoner

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds DeepSeek and MiMo AI provider support across types, DB schema, config routes, sync, settings UI, proxy reasoning injection rules, and AIService model detection, request shaping, response parsing (think-tag stripping), and analysis token limit.

Changes

DeepSeek / MiMo Integration

Layer / File(s) Summary
Types and schema contracts
src/types/index.ts, server/src/types/api.ts, server/src/db/schema.ts
Add deepseek/mimo to AIApiType, MiMoPlan and AIConfig.mimoPlan; add mimo_plan column to ai_configs and migration step; expose mimo_plan on server row type.
Config routes and sync persistence
server/src/routes/configs.ts, server/src/routes/sync.ts
Include mimoPlan in GET/POST/PUT/bulk config APIs and persist mimo_plan; sync import upsert maps mimo_plan from camelCase or snake_case.
Settings panel provider and MiMo plan wiring
src/components/settings/AIConfigPanel.tsx
Expose DeepSeek and MiMo in API selector, add mimoPlan form state and plan→endpoint mapping, auto-update baseUrl on MiMo plan changes, and persist mimoPlan for create/edit flows.
Proxy reasoning gating
server/src/routes/proxy.ts, src/utils/apiUrlBuilder.ts
OpenAI-like proxy branch now includes DeepSeek and MiMo for target URL/auth; skip injecting reasoning when model is deepseek-reasoner; add comment about DeepSeek endpoint parity.
AIService model detection and request flags
src/services/aiService.ts
Add DeepSeek detection helpers, detect deepseek-reasoner vs other DeepSeek models, treat apiType === 'mimo' for MiMo, include DeepSeek/MiMo in OpenAI-style request branch, and disable thinking for MiMo or DeepSeek-thinking models; conditionally include temperature/reasoning fields.
AIService response parsing and token budget
src/services/aiService.ts
Return reasoning_content only for deepseek-reasoner, fallback to content and warn on inconsistent fields; strip <think>...</think> fragments before JSON parsing; raise analyzeRepository maxTokens to 1000.

Sequence Diagram

sequenceDiagram
  participant Client
  participant ProxyRoute
  participant ExternalAPI
  participant AIService
  Client->>ProxyRoute: Send AI proxy request (apiType, model, reasoningEffort)
  ProxyRoute->>ProxyRoute: Resolve targetUrl and Authorization for openai/deepseek/mimo
  alt model is deepseek-reasoner
    ProxyRoute->>ProxyRoute: Skip injecting reasoning field
  else other model
    ProxyRoute->>ProxyRoute: Inject reasoning derived from reasoningEffort
  end
  ProxyRoute->>ExternalAPI: Forward proxied request
  ExternalAPI-->>ProxyRoute: Return response payload
  ProxyRoute->>AIService: Forward response for parsing
  AIService->>AIService: Strip <think> blocks and extract final content/reasoning
  AIService-->>Client: Return parsed content
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐇 I packed new paths in a tiny sack,
DeepSeek hopped in on the OpenAI track.
MiMo chose its plan, the endpoint aligned,
I trimmed stray tags and cleared the mind.
More tokens now — I hop off, well-defined.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main fix: preventing DeepSeek v4 reasoning content from being returned as the analysis result instead of the expected JSON content.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/deepseek-reasoning-content-leak

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.

@AmintaCCCP AmintaCCCP changed the title fix: DeepSeek v4 模型思维链泄漏为分析结果 fix: prevent DeepSeek v4 reasoning chain from leaking as analysis result Jun 4, 2026
@cyb233

cyb233 commented Jun 4, 2026

Copy link
Copy Markdown

看起来思考过程还是没有处理好

image
{
  "id": "da10db8f-8981-4fcf-8df4-1ee3c96eec98",
  "object": "chat.completion",
  "created": 1780582943,
  "model": "deepseek-v4-pro",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "",
        "reasoning_content": "我们被要求输出合法JSON,分析仓库。仓库名称:Sitoi/dailycheckin,描述:基于Docker/青龙面板/群晖的每日签到脚本(支持多账号),签到列表包括多个平台。编程语言Python,星数8635,主题标签包括acfun, aliyundrive, baidu, bilibili, chatgpt, checkin, dailycheckin, docker, imaotai, iqiyi, kgqq, mimotion, pypi, python, qinglong, signin, smzdm, tieba, v2ex, youdaonote。README内容有特性,支持多个平台部署,多个平台签到,支持多账号和通知。显然是一个自动化签到工具。总结:一个支持多平台每日签到的自动化脚本,可部署于Docker、青龙面板等。标签:效率工具(自动化签到提升效率),开发工具(脚本),也可以考虑教育学习?不,主要是签到。可用分类中有:Web应用, 移动应用, 桌面应用, 数据库, AI/机器学习, 开发工具, 安全工具, 游戏, 设计工具, 效率工具, 教育学习, 社交网络, 数据分析。最适合的应该是效率工具和开发工具。另外,它支持多个平台签到,可能也可以归类为“工具”类。所以tags:[\"效率工具\", \"开发工具\", \"自动化\"]?但是自动化不在列表中,只能用列表中的。那就“效率工具”和“开发工具”两个,还需要3-5个,可以加上“桌面应用”?不,它是脚本,可以在各种平台运行。但它支持Docker、青龙面板,也提供PyPI包,本质是命令行脚本,可以使用cli平台。平台线索:支持Docker,有docker标签,所以docker平台;支持本地、青龙面板(基于web?),主要部署在服务器或本地,所以可能包括linux, docker, cli。另外也支持群晖(NAS,基于Linux)。所以平台可以包括:docker, cli, linux, mac? 可能也支持mac/windows但主要是通过Python环境。根据README,特性有“支持多个平台部署”,但没有明确指定。我们看主题标签有docker,描述中提到基于Docker/青龙面板/群晖,所以docker是明确的。另外从pypi包安装,可以在任何有Python的环境运行,所以cli是肯定的。那可以加上linux(因为docker通常运行在linux上,群晖也是linux),也可能支持mac和windows,但无法确定,所以不填。Platforms: [\"docker\",\"cli\",\"linux\"] 还可以有web?青龙面板是一个web面板,所以可能通过web访问,但签到脚本本身不是web应用,是后台脚本。所以不添加web。因此platforms: [\"docker\", \"cli\", \"linux\"]。tags:效率工具(因为自动化签到节省时间),开发工具(Python脚本,面向开发者和技术用户),可能再加一个“自动化”?但自动化不在列表中,只能用给定的。那从给定列表中选择:效率工具, 开发工具, 安全工具? 不是安全。教育学习?不。社交网络?签到的是社交网络平台,但工具本身不是社交。所以“效率工具”和“开发工具”就够了,还可以加“命令行”但不是标签。可以给3个标签:效率工具,"
      },
      "logprobs": null,
      "finish_reason": "length"
    }
  ],
  "usage": {
    "prompt_tokens": 1181,
    "completion_tokens": 700,
    "total_tokens": 1881,
    "prompt_tokens_details": { "cached_tokens": 1152 },
    "completion_tokens_details": { "reasoning_tokens": 700 },
    "prompt_cache_hit_tokens": 1152,
    "prompt_cache_miss_tokens": 29
  },
  "system_fingerprint": "fp_9954b31ca7_prod0820_fp8_kvcache_20260402"
}

@AmintaCCCP

Copy link
Copy Markdown
Owner Author

看起来思考过程还是没有处理好

image
{

  "id": "da10db8f-8981-4fcf-8df4-1ee3c96eec98",

  "object": "chat.completion",

  "created": 1780582943,

  "model": "deepseek-v4-pro",

  "choices": [

    {

      "index": 0,

      "message": {

        "role": "assistant",

        "content": "",

        "reasoning_content": "我们被要求输出合法JSON,分析仓库。仓库名称:Sitoi/dailycheckin,描述:基于Docker/青龙面板/群晖的每日签到脚本(支持多账号),签到列表包括多个平台。编程语言Python,星数8635,主题标签包括acfun, aliyundrive, baidu, bilibili, chatgpt, checkin, dailycheckin, docker, imaotai, iqiyi, kgqq, mimotion, pypi, python, qinglong, signin, smzdm, tieba, v2ex, youdaonote。README内容有特性,支持多个平台部署,多个平台签到,支持多账号和通知。显然是一个自动化签到工具。总结:一个支持多平台每日签到的自动化脚本,可部署于Docker、青龙面板等。标签:效率工具(自动化签到提升效率),开发工具(脚本),也可以考虑教育学习?不,主要是签到。可用分类中有:Web应用, 移动应用, 桌面应用, 数据库, AI/机器学习, 开发工具, 安全工具, 游戏, 设计工具, 效率工具, 教育学习, 社交网络, 数据分析。最适合的应该是效率工具和开发工具。另外,它支持多个平台签到,可能也可以归类为“工具”类。所以tags:[\"效率工具\", \"开发工具\", \"自动化\"]?但是自动化不在列表中,只能用列表中的。那就“效率工具”和“开发工具”两个,还需要3-5个,可以加上“桌面应用”?不,它是脚本,可以在各种平台运行。但它支持Docker、青龙面板,也提供PyPI包,本质是命令行脚本,可以使用cli平台。平台线索:支持Docker,有docker标签,所以docker平台;支持本地、青龙面板(基于web?),主要部署在服务器或本地,所以可能包括linux, docker, cli。另外也支持群晖(NAS,基于Linux)。所以平台可以包括:docker, cli, linux, mac? 可能也支持mac/windows但主要是通过Python环境。根据README,特性有“支持多个平台部署”,但没有明确指定。我们看主题标签有docker,描述中提到基于Docker/青龙面板/群晖,所以docker是明确的。另外从pypi包安装,可以在任何有Python的环境运行,所以cli是肯定的。那可以加上linux(因为docker通常运行在linux上,群晖也是linux),也可能支持mac和windows,但无法确定,所以不填。Platforms: [\"docker\",\"cli\",\"linux\"] 还可以有web?青龙面板是一个web面板,所以可能通过web访问,但签到脚本本身不是web应用,是后台脚本。所以不添加web。因此platforms: [\"docker\", \"cli\", \"linux\"]。tags:效率工具(因为自动化签到节省时间),开发工具(Python脚本,面向开发者和技术用户),可能再加一个“自动化”?但自动化不在列表中,只能用给定的。那从给定列表中选择:效率工具, 开发工具, 安全工具? 不是安全。教育学习?不。社交网络?签到的是社交网络平台,但工具本身不是社交。所以“效率工具”和“开发工具”就够了,还可以加“命令行”但不是标签。可以给3个标签:效率工具,"

      },

      "logprobs": null,

      "finish_reason": "length"

    }

  ],

  "usage": {

    "prompt_tokens": 1181,

    "completion_tokens": 700,

    "total_tokens": 1881,

    "prompt_tokens_details": { "cached_tokens": 1152 },

    "completion_tokens_details": { "reasoning_tokens": 700 },

    "prompt_cache_hit_tokens": 1152,

    "prompt_cache_miss_tokens": 29

  },

  "system_fingerprint": "fp_9954b31ca7_prod0820_fp8_kvcache_20260402"

}

明天好好看看 deepseek 文档再搞下

@cyb233

cyb233 commented Jun 5, 2026

Copy link
Copy Markdown

明天好好看看 deepseek 文档再搞下

https://api-docs.deepseek.com/zh-cn/guides/thinking_mode

DeepSeek v4-pro/v4-flash models have thinking enabled by default. With
max_tokens=700, all tokens are consumed by reasoning (700 reasoning_tokens),
leaving 0 tokens for content output. This causes empty content and the
thinking chain leaks as the analysis result.

- Add isDeepSeekThinkingModel() to detect DeepSeek models with default thinking
- Explicitly disable thinking with { thinking: { type: 'disabled' } } for these models
- Increase maxTokens from 700 to 1000 for analysis requests

Ref: https://api-docs.deepseek.com/zh-cn/guides/thinking_mode

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

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.

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)
src/services/aiService.ts (1)

611-617: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle truncated <think> blocks too.

This only removes balanced <think>...</think> pairs. The failure mode here was token exhaustion, so a cut-off payload like <think>... is still plausible; in that case cleaned keeps the reasoning text and the fallback summary path leaks it again. Strip a dangling opening tag through end-of-string as well.

🩹 Minimal fix
       const cleaned = content
         .trim()
         .replace(/<think>[\s\S]*?<\/think>/gi, '')
+        .replace(/<think>[\s\S]*$/gi, '')
         .replace(/^```(?:json)?\s*/i, '')
         .replace(/\s*```$/i, '')
         .trim();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/aiService.ts` around lines 611 - 617, The current cleaning logic
building the variable cleaned only strips balanced <think>...</think> pairs, so
a truncated dangling "<think>" remains; update the regex used in the .replace
that targets think blocks (the one currently using /<think>[\s\S]*?<\/think>/gi)
so it also matches an opening <think> through end-of-string (e.g. make it accept
either </think> or end-of-input) and keep the rest of the chaining
(.replace(...).replace(...).trim()) unchanged to ensure dangling think blocks
are removed before further processing.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/services/aiService.ts`:
- Around line 132-136: The current isDeepSeekThinkingModel() marks any model
starting with "deepseek-" (except "deepseek-reasoner") as DeepSeek for both
'openai' and 'openai-compatible' APIs; restrict this by making an explicit
allowlist of DeepSeek models (e.g., ['deepseek-xyz', 'deepseek-abc', ...]) and
only enable the thinking injection when getApiType() === 'openai' OR
(getApiType() === 'openai-compatible' AND model is in that allowlist) so unknown
OpenAI-compatible backends won't receive the unknown thinking field; also update
parseAIResponse() to defensively strip any unbalanced or truncated <think> and
</think> tags (not just balanced pairs) from the raw response before attempting
JSON parse or falling back to summary to prevent leaked tags in fallback text.

---

Outside diff comments:
In `@src/services/aiService.ts`:
- Around line 611-617: The current cleaning logic building the variable cleaned
only strips balanced <think>...</think> pairs, so a truncated dangling "<think>"
remains; update the regex used in the .replace that targets think blocks (the
one currently using /<think>[\s\S]*?<\/think>/gi) so it also matches an opening
<think> through end-of-string (e.g. make it accept either </think> or
end-of-input) and keep the rest of the chaining
(.replace(...).replace(...).trim()) unchanged to ensure dangling think blocks
are removed before further processing.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 96e64e43-f5ee-4110-ab25-faddcffe22c1

📥 Commits

Reviewing files that changed from the base of the PR and between 7540f57 and d3cc53f.

📒 Files selected for processing (1)
  • src/services/aiService.ts

Comment thread src/services/aiService.ts Outdated
…nnels

Separate DeepSeek official API from generic openai-compatible to avoid
sending DeepSeek-specific parameters (thinking, reasoning_content) to
third-party proxies.

- Add 'deepseek' to AIApiType union
- Add DeepSeek option in API Format dropdown with default endpoint
- Refactor isDeepSeek*Model() to use apiType === 'deepseek'
- Include 'deepseek' in proxy routing and reasoning injection
- Fix truncated <think> tag stripping in parseAIResponse()
- openai-compatible remains generic, no DeepSeek-specific behavior

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (2)
src/components/settings/AIConfigPanel.tsx (2)

422-441: 💤 Low value

Consider extracting help text logic to improve readability.

Similar to the placeholder, the nested ternary for help text is getting complex. While functionally correct, extracting this to a helper would improve maintainability.

♻️ Example refactor approach
const getApiEndpointHelp = (apiType: AIApiType, t: (zh: string, en: string) => string) => {
  switch (apiType) {
    case 'openai-compatible':
      return t('填写完整的API调用地址,包含完整路径', 'Enter the full API endpoint URL including the complete path');
    case 'gemini':
      return t('只填到 v1beta 即可,路径会自动生成', 'Only include the version prefix v1beta, the path will be generated automatically');
    case 'deepseek':
      return t('填写到域名即可,路径会自动生成', 'Only include the domain, the path will be generated automatically');
    default:
      return t('只填到版本号即可(如 .../v1 或 .../v1beta),不要包含 /chat/completions、/responses、/messages', 'Only include the version prefix (e.g. .../v1 or .../v1beta). Do not include /chat/completions, /responses, or /messages.');
  }
};

// Then in the JSX:
<p className="text-xs text-gray-500 dark:text-text-tertiary mt-1">
  {getApiEndpointHelp(form.apiType, t)}
</p>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/settings/AIConfigPanel.tsx` around lines 422 - 441, The nested
ternary used to render the API endpoint help text in AIConfigPanel (based on
form.apiType and t) should be extracted into a small helper (e.g.,
getApiEndpointHelp(apiType: AIApiType, t)) that returns the localized string for
each case ('openai-compatible', 'gemini', 'deepseek', default). Add that helper
near the top of the component (or export from a nearby util) and replace the
ternary in the <p> with a single call to getApiEndpointHelp(form.apiType, t) to
improve readability and maintainability.

410-420: 💤 Low value

Consider extracting placeholder logic to improve readability.

The nested ternary now has multiple branches and is becoming harder to maintain. Consider extracting this to a helper function or object lookup.

♻️ Example refactor using object lookup
const PLACEHOLDER_BY_API_TYPE: Record<AIApiType, string> = {
  'openai': 'https://api.openai.com/v1',
  'openai-responses': 'https://api.openai.com/v1',
  'claude': 'https://api.anthropic.com/v1',
  'gemini': 'https://generativelanguage.googleapis.com/v1beta',
  'deepseek': 'https://api.deepseek.com',
  'openai-compatible': 'https://integrate.api.nvidia.com/v1/chat/completions',
};

// Then in the JSX:
placeholder={PLACEHOLDER_BY_API_TYPE[form.apiType]}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/settings/AIConfigPanel.tsx` around lines 410 - 420, Extract
the nested ternary that computes the input placeholder (currently based on
form.apiType) into a simple lookup or helper to improve readability and
maintainability: create a constant like PLACEHOLDER_BY_API_TYPE:
Record<AIApiType, string> (or a function getPlaceholderForApiType(apiType:
AIApiType): string) and replace the inline ternary in AIConfigPanel.tsx with
placeholder={PLACEHOLDER_BY_API_TYPE[form.apiType]} (or
placeholder={getPlaceholderForApiType(form.apiType)}), making sure to include
all handled api types (openai, openai-responses, claude, deepseek,
openai-compatible, gemini) and a sensible default.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/components/settings/AIConfigPanel.tsx`:
- Around line 422-441: The nested ternary used to render the API endpoint help
text in AIConfigPanel (based on form.apiType and t) should be extracted into a
small helper (e.g., getApiEndpointHelp(apiType: AIApiType, t)) that returns the
localized string for each case ('openai-compatible', 'gemini', 'deepseek',
default). Add that helper near the top of the component (or export from a nearby
util) and replace the ternary in the <p> with a single call to
getApiEndpointHelp(form.apiType, t) to improve readability and maintainability.
- Around line 410-420: Extract the nested ternary that computes the input
placeholder (currently based on form.apiType) into a simple lookup or helper to
improve readability and maintainability: create a constant like
PLACEHOLDER_BY_API_TYPE: Record<AIApiType, string> (or a function
getPlaceholderForApiType(apiType: AIApiType): string) and replace the inline
ternary in AIConfigPanel.tsx with
placeholder={PLACEHOLDER_BY_API_TYPE[form.apiType]} (or
placeholder={getPlaceholderForApiType(form.apiType)}), making sure to include
all handled api types (openai, openai-responses, claude, deepseek,
openai-compatible, gemini) and a sensible default.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: afc08939-ed67-43b9-84e9-f86bd7ac8a7f

📥 Commits

Reviewing files that changed from the base of the PR and between d3cc53f and d42b789.

📒 Files selected for processing (5)
  • server/src/routes/proxy.ts
  • src/components/settings/AIConfigPanel.tsx
  • src/services/aiService.ts
  • src/types/index.ts
  • src/utils/apiUrlBuilder.ts
✅ Files skipped from review due to trivial changes (1)
  • src/utils/apiUrlBuilder.ts

@AmintaCCCP

Copy link
Copy Markdown
Owner Author

明天好好看看 deepseek 文档再搞下

https://api-docs.deepseek.com/zh-cn/guides/thinking_mode

为了节约token,设置了最大回复token的值。deepseek思考的太用力,把max token耗光了,造成了实际content里没有字了。
根据文档,需要传个参禁止思考。
小米也有这种禁止思考的传参。
之前通过模型名称判断,但是考虑到有用户使用三方中转,这个传参并不是openai-compatible标准的传参,属于额外加戏。
所以准备把deepseek还有小米的官方渠道独立出来。

MiMo models have two official channels with different base URLs:
- API (按量付费): api.xiaomimimo.com, key prefix sk-
- Token Plan (订阅制): token-plan-cn.xiaomimimo.com, key prefix tp-

Add 'mimo' to AIApiType with a mimoPlan sub-option so users can select
their billing channel. The thinking:disabled parameter is now only sent
for the official mimo API type, not for openai-compatible with 'mimo'
in the model name.

- Add MiMoPlan type and mimoPlan field to AIConfig
- Add MiMo option in API Format dropdown with plan sub-selector
- Auto-switch baseUrl based on selected plan
- Add mimo_plan column to ai_configs DB table with migration
- Map mimo_plan in all CRUD and sync routes

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (1)
src/components/settings/AIConfigPanel.tsx (1)

123-141: 💤 Low value

Reset prevMimoPlanRef alongside prevApiTypeRef in resetForm.

The function resets prevApiTypeRef at line 140 but doesn't reset prevMimoPlanRef. After editing a MiMo config with token-plan, then canceling, the ref retains 'token-plan' while the form resets to 'api'. This state inconsistency breaks the invariant that refs track previous form values.

🔧 Proposed fix
     prevApiTypeRef.current = 'openai';
+    prevMimoPlanRef.current = 'api';
   };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/settings/AIConfigPanel.tsx` around lines 123 - 141, The
resetForm function resets the form state but only resets prevApiTypeRef.current;
also reset prevMimoPlanRef.current to match the cleared form's mimoPlan ('api')
to avoid stale ref state. Update resetForm (same function name) to set
prevMimoPlanRef.current = 'api' (or to the new form.mimoPlan value) alongside
prevApiTypeRef.current so refs remain consistent with the reset form.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/components/settings/AIConfigPanel.tsx`:
- Around line 123-141: The resetForm function resets the form state but only
resets prevApiTypeRef.current; also reset prevMimoPlanRef.current to match the
cleared form's mimoPlan ('api') to avoid stale ref state. Update resetForm (same
function name) to set prevMimoPlanRef.current = 'api' (or to the new
form.mimoPlan value) alongside prevApiTypeRef.current so refs remain consistent
with the reset form.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 326711be-d328-4b9f-9a94-efccbe274238

📥 Commits

Reviewing files that changed from the base of the PR and between d42b789 and 10b4a3d.

📒 Files selected for processing (8)
  • server/src/db/schema.ts
  • server/src/routes/configs.ts
  • server/src/routes/proxy.ts
  • server/src/routes/sync.ts
  • server/src/types/api.ts
  • src/components/settings/AIConfigPanel.tsx
  • src/services/aiService.ts
  • src/types/index.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • server/src/routes/proxy.ts
  • src/services/aiService.ts

- Reset prevMimoPlanRef in resetForm to avoid stale ref state
- Extract endpoint placeholder and help text from nested ternaries
  into getEndpointPlaceholder() and getEndpointHelpText() helpers
- Truncated <think> tag fix was already in place from prior commit

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/settings/AIConfigPanel.tsx`:
- Around line 66-68: The help text for the 'deepseek' and 'mimo' cases in
AIConfigPanel.tsx is incorrect: it currently says to provide only the domain but
the code/defaults expect a path (e.g., "/v1"). Update the return string for the
switch cases 'deepseek' and 'mimo' (the case handling in AIConfigPanel.tsx) to
instruct users to include the domain and the path (for example: include "/v1" or
the full base path), so the displayed guidance matches the actual endpoint
format used elsewhere.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: a026b2e2-946e-447c-a411-af50779deb75

📥 Commits

Reviewing files that changed from the base of the PR and between 10b4a3d and 8c2e29a.

📒 Files selected for processing (1)
  • src/components/settings/AIConfigPanel.tsx

Comment thread src/components/settings/AIConfigPanel.tsx Outdated
DeepSeek default has no /v1 (auto-appended), MiMo default includes /v1.
Help text now reflects the expected format for each.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AmintaCCCP

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (2)
server/src/types/api.ts (1)

119-133: 💤 Low value

Consider adding mimoPlan to SyncAIConfigsRequest for type completeness.

The AIConfigRow now includes mimo_plan, but SyncAIConfigsRequest (used for the bulk sync API contract) does not include mimoPlan. While the actual route handler in configs.ts does accept mimoPlan, the request type definition here is incomplete, which could cause type-checking gaps if this interface is used for validation.

Proposed fix
 export interface SyncAIConfigsRequest {
   configs: Array<{
     id: string;
     name: string;
     apiType?: string;
     baseUrl: string;
     apiKey: string;
     model: string;
     isActive: boolean;
     customPrompt?: string;
     useCustomPrompt?: boolean;
     concurrency?: number;
     reasoningEffort?: string;
+    mimoPlan?: string;
   }>;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/types/api.ts` around lines 119 - 133, SyncAIConfigsRequest is
missing the mimoPlan field present on AIConfigRow and accepted by the configs.ts
handler; update the SyncAIConfigsRequest interface to include an optional
mimoPlan?: string (matching the server's naming convention mapping from
mimo_plan) on each config object so the bulk sync contract aligns with
AIConfigRow and the route handler.
src/services/aiService.ts (1)

188-196: 💤 Low value

Consider excluding reasoning for DeepSeek/MiMo API types.

The reasoning: { effort } parameter on line 195 is OpenAI-specific (for o1/o3 models). For apiType === 'deepseek' or apiType === 'mimo', this parameter will be ignored by the API but is semantically misplaced. DeepSeek uses the thinking parameter which you correctly handle on line 196.

The current logic is harmless since DeepSeek/MiMo APIs ignore unknown parameters, but you could refine the condition to exclude reasoning for these API types:

-...(!isDeepSeekReasoner && reasoning && apiType !== 'openai-compatible' ? { reasoning } : {}),
+...(!isDeepSeekReasoner && reasoning && apiType !== 'openai-compatible' && apiType !== 'deepseek' && apiType !== 'mimo' ? { reasoning } : {}),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/aiService.ts` around lines 188 - 196, The request builder is
adding the OpenAI-specific reasoning parameter even for DeepSeek/MiMo API types;
update the spread that adds reasoning (currently gated by !isDeepSeekReasoner &&
reasoning && apiType !== 'openai-compatible') to also exclude apiType values for
'deepseek' and 'mimo' (or use the existing flags isDeepSeekReasoner/isMiMoModel)
so that reasoning is only sent for true OpenAI-style endpoints; adjust the
conditional around the reasoning spread in the function that constructs the
request (look for usages of reasoning, isDeepSeekReasoner, isMiMoModel, apiType,
thinking) so DeepSeek/MiMo requests receive only thinking and not reasoning.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@server/src/types/api.ts`:
- Around line 119-133: SyncAIConfigsRequest is missing the mimoPlan field
present on AIConfigRow and accepted by the configs.ts handler; update the
SyncAIConfigsRequest interface to include an optional mimoPlan?: string
(matching the server's naming convention mapping from mimo_plan) on each config
object so the bulk sync contract aligns with AIConfigRow and the route handler.

In `@src/services/aiService.ts`:
- Around line 188-196: The request builder is adding the OpenAI-specific
reasoning parameter even for DeepSeek/MiMo API types; update the spread that
adds reasoning (currently gated by !isDeepSeekReasoner && reasoning && apiType
!== 'openai-compatible') to also exclude apiType values for 'deepseek' and
'mimo' (or use the existing flags isDeepSeekReasoner/isMiMoModel) so that
reasoning is only sent for true OpenAI-style endpoints; adjust the conditional
around the reasoning spread in the function that constructs the request (look
for usages of reasoning, isDeepSeekReasoner, isMiMoModel, apiType, thinking) so
DeepSeek/MiMo requests receive only thinking and not reasoning.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 060adc94-44bf-4c1f-88ac-bf3ceb074564

📥 Commits

Reviewing files that changed from the base of the PR and between 6546318 and 6ce1ee4.

📒 Files selected for processing (9)
  • server/src/db/schema.ts
  • server/src/routes/configs.ts
  • server/src/routes/proxy.ts
  • server/src/routes/sync.ts
  • server/src/types/api.ts
  • src/components/settings/AIConfigPanel.tsx
  • src/services/aiService.ts
  • src/types/index.ts
  • src/utils/apiUrlBuilder.ts

…ncAIConfigsRequest

- reasoning: { effort } is OpenAI-specific, should not be sent to
  DeepSeek or MiMo APIs (they use thinking parameter instead)
- Add mimoPlan to SyncAIConfigsRequest for type completeness

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AmintaCCCP

Copy link
Copy Markdown
Owner Author

@cyb233 佬友测下,我这边测试都过了。用新的deepseek独立渠道。

@cyb233

cyb233 commented Jun 5, 2026

Copy link
Copy Markdown

使用了 https://github.com/AmintaCCCP/GithubStarsManager/actions/runs/27006772870 的编译
看起来似乎没有什么问题

正好看到有人新提了个 #194 ,或许可以一并考虑看看

@AmintaCCCP AmintaCCCP merged commit 4353206 into main Jun 6, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants