mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-05 08:10:14 +00:00
Merge 583488145f into 7adbfec2a4
This commit is contained in:
commit
353065e56a
2 changed files with 83 additions and 9 deletions
|
|
@ -525,6 +525,65 @@ describe("OpenRouterHandler", () => {
|
|||
expect(endChunks).toHaveLength(1)
|
||||
expect(endChunks[0].id).toBe("call_openrouter_test")
|
||||
})
|
||||
|
||||
it("always includes require_parameters for tools in provider config", async () => {
|
||||
const handler = new OpenRouterHandler(mockOptions)
|
||||
|
||||
const mockStream = {
|
||||
async *[Symbol.asyncIterator]() {
|
||||
yield {
|
||||
id: "test-id",
|
||||
choices: [{ delta: { content: "test" } }],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const mockCreate = vitest.fn().mockResolvedValue(mockStream)
|
||||
;(OpenAI as any).prototype.chat = {
|
||||
completions: { create: mockCreate },
|
||||
} as any
|
||||
|
||||
const generator = handler.createMessage("test system", [{ role: "user", content: "test" }])
|
||||
await generator.next()
|
||||
|
||||
const callArgs = mockCreate.mock.calls[0][0]
|
||||
expect(callArgs.provider).toBeDefined()
|
||||
expect(callArgs.provider.require_parameters).toEqual(["tools", "tool_choice"])
|
||||
// Should NOT have routing fields when no specific provider
|
||||
expect(callArgs.provider.order).toBeUndefined()
|
||||
expect(callArgs.provider.only).toBeUndefined()
|
||||
})
|
||||
|
||||
it("merges require_parameters with specific provider routing config", async () => {
|
||||
const handler = new OpenRouterHandler({
|
||||
...mockOptions,
|
||||
openRouterSpecificProvider: "anthropic",
|
||||
})
|
||||
|
||||
const mockStream = {
|
||||
async *[Symbol.asyncIterator]() {
|
||||
yield {
|
||||
id: "test-id",
|
||||
choices: [{ delta: { content: "test" } }],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const mockCreate = vitest.fn().mockResolvedValue(mockStream)
|
||||
;(OpenAI as any).prototype.chat = {
|
||||
completions: { create: mockCreate },
|
||||
} as any
|
||||
|
||||
const generator = handler.createMessage("test system", [{ role: "user", content: "test" }])
|
||||
await generator.next()
|
||||
|
||||
const callArgs = mockCreate.mock.calls[0][0]
|
||||
expect(callArgs.provider).toBeDefined()
|
||||
expect(callArgs.provider.require_parameters).toEqual(["tools", "tool_choice"])
|
||||
expect(callArgs.provider.order).toEqual(["anthropic"])
|
||||
expect(callArgs.provider.only).toEqual(["anthropic"])
|
||||
expect(callArgs.provider.allow_fallbacks).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("completePrompt", () => {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ type OpenRouterChatCompletionParams = OpenAI.Chat.ChatCompletionCreateParams & {
|
|||
include_reasoning?: boolean
|
||||
// https://openrouter.ai/docs/use-cases/reasoning-tokens
|
||||
reasoning?: OpenRouterReasoningParams
|
||||
// https://openrouter.ai/docs/features/provider-routing
|
||||
provider?: Record<string, unknown>
|
||||
}
|
||||
|
||||
// Zod schema for OpenRouter error response structure (for caught exceptions)
|
||||
|
|
@ -308,6 +310,27 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
|
|||
}
|
||||
}
|
||||
|
||||
// Build the provider configuration.
|
||||
// Always include require_parameters to ensure OpenRouter passes tool-calling
|
||||
// parameters through to the model, even when the model's metadata doesn't
|
||||
// list "tools" in supported_parameters. Without this, OpenRouter may strip
|
||||
// tool parameters or apply prompt-based transforms that produce poor results
|
||||
// for models that actually support native tool calling (e.g. Nemotron 3 Super).
|
||||
// See: https://github.com/RooCodeInc/Roo-Code/issues/11968
|
||||
const providerConfig: Record<string, unknown> = {
|
||||
require_parameters: ["tools", "tool_choice"],
|
||||
}
|
||||
|
||||
// Add specific provider routing if configured.
|
||||
if (
|
||||
this.options.openRouterSpecificProvider &&
|
||||
this.options.openRouterSpecificProvider !== OPENROUTER_DEFAULT_PROVIDER_NAME
|
||||
) {
|
||||
providerConfig.order = [this.options.openRouterSpecificProvider]
|
||||
providerConfig.only = [this.options.openRouterSpecificProvider]
|
||||
providerConfig.allow_fallbacks = false
|
||||
}
|
||||
|
||||
// https://openrouter.ai/docs/transforms
|
||||
const completionParams: OpenRouterChatCompletionParams = {
|
||||
model: modelId,
|
||||
|
|
@ -317,15 +340,7 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
|
|||
messages: openAiMessages,
|
||||
stream: true,
|
||||
stream_options: { include_usage: true },
|
||||
// Only include provider if openRouterSpecificProvider is not "[default]".
|
||||
...(this.options.openRouterSpecificProvider &&
|
||||
this.options.openRouterSpecificProvider !== OPENROUTER_DEFAULT_PROVIDER_NAME && {
|
||||
provider: {
|
||||
order: [this.options.openRouterSpecificProvider],
|
||||
only: [this.options.openRouterSpecificProvider],
|
||||
allow_fallbacks: false,
|
||||
},
|
||||
}),
|
||||
provider: providerConfig,
|
||||
...(reasoning && { reasoning }),
|
||||
tools: this.convertToolsForOpenAI(metadata?.tools),
|
||||
tool_choice: metadata?.tool_choice,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue