mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-05 08:10:14 +00:00
fix: handle empty response with reasoning in OpenRouter provider
This commit is contained in:
parent
caf6142201
commit
f80136f66f
1 changed files with 19 additions and 0 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import OpenAI from "openai"
|
||||
import { z } from "zod"
|
||||
import { t } from "i18next"
|
||||
|
||||
import {
|
||||
openRouterDefaultModelId,
|
||||
|
|
@ -374,6 +375,12 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
|
|||
}
|
||||
>()
|
||||
|
||||
// Track whether we received actual content vs just reasoning
|
||||
// This prevents "Empty assistant response" errors when models output
|
||||
// reasoning but no text/tool content (e.g., malformed tool calls in thinking)
|
||||
let hasContent = false
|
||||
let hasReasoning = false
|
||||
|
||||
for await (const chunk of stream) {
|
||||
// OpenRouter returns an error object instead of the OpenAI SDK throwing an error.
|
||||
if ("error" in chunk) {
|
||||
|
|
@ -445,17 +452,20 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
|
|||
// Note: reasoning.encrypted types are intentionally skipped as they contain redacted content
|
||||
|
||||
if (reasoningText) {
|
||||
hasReasoning = true
|
||||
yield { type: "reasoning", text: reasoningText }
|
||||
}
|
||||
}
|
||||
} else if ("reasoning" in delta && delta.reasoning && typeof delta.reasoning === "string") {
|
||||
// Handle legacy reasoning format - only if reasoning_details is not present
|
||||
// See: https://openrouter.ai/docs/use-cases/reasoning-tokens
|
||||
hasReasoning = true
|
||||
yield { type: "reasoning", text: delta.reasoning }
|
||||
}
|
||||
|
||||
// Emit raw tool call chunks - NativeToolCallParser handles state management
|
||||
if ("tool_calls" in delta && Array.isArray(delta.tool_calls)) {
|
||||
hasContent = true
|
||||
for (const toolCall of delta.tool_calls) {
|
||||
yield {
|
||||
type: "tool_call_partial",
|
||||
|
|
@ -468,6 +478,7 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
|
|||
}
|
||||
|
||||
if (delta.content) {
|
||||
hasContent = true
|
||||
yield { type: "text", text: delta.content }
|
||||
}
|
||||
}
|
||||
|
|
@ -491,6 +502,14 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
|
|||
this.currentReasoningDetails = Array.from(reasoningDetailsAccumulator.values())
|
||||
}
|
||||
|
||||
// If we had reasoning but no content, emit a placeholder text to prevent
|
||||
// "Empty assistant response" errors. This typically happens when some models
|
||||
// output malformed tool calls in their thinking content (e.g., <tool_call> tags)
|
||||
// instead of using proper tool calling mechanisms.
|
||||
if (hasReasoning && !hasContent) {
|
||||
yield { type: "text", text: t("common:errors.gemini.thinking_complete_no_output") }
|
||||
}
|
||||
|
||||
if (lastUsage) {
|
||||
yield {
|
||||
type: "usage",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue