Repository navigation
fix(core): inject thinking blocks for DeepSeek anthropic-compatible provider #3788
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
ddaedeb
2212b18
8721b41
487066a
ae1aae5
ec30c1d
51b59d6
106a27a
8f39325
45d394b
07c14ee
fdf2257
4b81d67
0d8b5de
f139e1a
f17fcfc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,6 +39,33 @@ import { | |
|
|
||
| const debugLogger = createDebugLogger('ANTHROPIC'); | ||
|
|
||
| /** | ||
| * DeepSeek's anthropic-compatible API rejects requests in thinking mode that | ||
| * omit a thinking block on prior assistant turns. Detect by base URL hostname | ||
| * or model name so the converter can inject empty thinking blocks where | ||
| * missing. https://github.com/QwenLM/qwen-code/issues/3786 | ||
|
wenshao marked this conversation as resolved.
Outdated
|
||
| */ | ||
| function isDeepSeekAnthropicProvider( | ||
| contentGeneratorConfig: ContentGeneratorConfig, | ||
| ): boolean { | ||
| const baseUrl = contentGeneratorConfig.baseUrl ?? ''; | ||
| if (baseUrl) { | ||
| try { | ||
| const hostname = new URL(baseUrl).hostname.toLowerCase(); | ||
|
wenshao marked this conversation as resolved.
|
||
| if ( | ||
| hostname === 'api.deepseek.com' || | ||
| hostname.endsWith('.api.deepseek.com') | ||
| ) { | ||
| return true; | ||
| } | ||
| } catch { | ||
| // Invalid URL — fall through to model-name detection. | ||
| } | ||
| } | ||
| const model = (contentGeneratorConfig.model ?? '').toLowerCase(); | ||
| return model.includes('deepseek'); | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] 建议使用更精确的匹配(如 — deepseek-v4-pro via Qwen Code /review
wenshao marked this conversation as resolved.
Comment on lines
+46
to
+68
|
||
| } | ||
|
wenshao marked this conversation as resolved.
|
||
|
|
||
| type StreamingBlockState = { | ||
| type: string; | ||
| id?: string; | ||
|
|
@@ -57,6 +84,7 @@ type MessageCreateParamsWithThinking = MessageCreateParamsNonStreaming & { | |
| export class AnthropicContentGenerator implements ContentGenerator { | ||
| private client: Anthropic; | ||
| private converter: AnthropicContentConverter; | ||
| private readonly isDeepSeekProvider: boolean; | ||
|
|
||
| constructor( | ||
| private contentGeneratorConfig: ContentGeneratorConfig, | ||
|
|
@@ -85,6 +113,9 @@ export class AnthropicContentGenerator implements ContentGenerator { | |
| contentGeneratorConfig.schemaCompliance, | ||
| contentGeneratorConfig.enableCacheControl, | ||
| ); | ||
| this.isDeepSeekProvider = isDeepSeekAnthropicProvider( | ||
| contentGeneratorConfig, | ||
| ); | ||
|
wenshao marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| async generateContent( | ||
|
|
@@ -186,17 +217,27 @@ export class AnthropicContentGenerator implements ContentGenerator { | |
| private async buildRequest( | ||
| request: GenerateContentParameters, | ||
| ): Promise<MessageCreateParamsWithThinking> { | ||
| const { system, messages } = | ||
| this.converter.convertGeminiRequestToAnthropic(request); | ||
| const sampling = this.buildSamplingParameters(request); | ||
| const thinking = this.buildThinkingConfig(request); | ||
| const outputConfig = this.buildOutputConfig(); | ||
|
wenshao marked this conversation as resolved.
Outdated
|
||
|
|
||
| // Only ask the converter to inject empty thinking blocks when both the | ||
| // provider needs them AND this request actually enables thinking mode. | ||
| // Otherwise we'd ship thinking blocks without the top-level `thinking` | ||
| // parameter — a protocol violation that DeepSeek rejects with a different | ||
| // 400. Matters for code paths that pass `includeThoughts: false` | ||
| // (suggestionGenerator / ArenaManager / forkedAgent). | ||
| const ensureAssistantThinking = this.isDeepSeekProvider && !!thinking; | ||
|
wenshao marked this conversation as resolved.
Outdated
|
||
|
|
||
| const { system, messages } = this.converter.convertGeminiRequestToAnthropic( | ||
| request, | ||
| { ensureAssistantThinking }, | ||
| ); | ||
|
|
||
| const tools = request.config?.tools | ||
| ? await this.converter.convertGeminiToolsToAnthropic(request.config.tools) | ||
| : undefined; | ||
|
|
||
| const sampling = this.buildSamplingParameters(request); | ||
| const thinking = this.buildThinkingConfig(request); | ||
| const outputConfig = this.buildOutputConfig(); | ||
|
|
||
| return { | ||
| model: this.contentGeneratorConfig.model, | ||
| system, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.