Skip to content

Commit 2eae321

Browse files
authored
Default to using native tools when supported on openrouter (#9878)
1 parent 4a5cbcb commit 2eae321

File tree

2 files changed

+57
-1
lines changed

2 files changed

+57
-1
lines changed

src/api/providers/fetchers/__tests__/openrouter.spec.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ describe("OpenRouter API", () => {
3030
supportsReasoningEffort: false,
3131
supportsNativeTools: true,
3232
supportedParameters: ["max_tokens", "temperature", "reasoning", "include_reasoning"],
33+
defaultToolProtocol: "native",
3334
})
3435

3536
expect(models["anthropic/claude-3.7-sonnet:thinking"]).toEqual({
@@ -47,6 +48,7 @@ describe("OpenRouter API", () => {
4748
supportsReasoningEffort: true,
4849
supportsNativeTools: true,
4950
supportedParameters: ["max_tokens", "temperature", "reasoning", "include_reasoning"],
51+
defaultToolProtocol: "native",
5052
})
5153

5254
expect(models["google/gemini-2.5-flash-preview-05-20"].maxTokens).toEqual(65535)
@@ -390,5 +392,55 @@ describe("OpenRouter API", () => {
390392
expect(textResult.maxTokens).toBe(64000)
391393
expect(imageResult.maxTokens).toBe(64000)
392394
})
395+
396+
it("sets defaultToolProtocol to native when model supports native tools", () => {
397+
const mockModel = {
398+
name: "Tools Model",
399+
description: "Model with native tool support",
400+
context_length: 128000,
401+
max_completion_tokens: 8192,
402+
pricing: {
403+
prompt: "0.000003",
404+
completion: "0.000015",
405+
},
406+
}
407+
408+
const resultWithTools = parseOpenRouterModel({
409+
id: "test/tools-model",
410+
model: mockModel,
411+
inputModality: ["text"],
412+
outputModality: ["text"],
413+
maxTokens: 8192,
414+
supportedParameters: ["tools", "max_tokens", "temperature"],
415+
})
416+
417+
expect(resultWithTools.supportsNativeTools).toBe(true)
418+
expect(resultWithTools.defaultToolProtocol).toBe("native")
419+
})
420+
421+
it("does not set defaultToolProtocol when model does not support native tools", () => {
422+
const mockModel = {
423+
name: "No Tools Model",
424+
description: "Model without native tool support",
425+
context_length: 128000,
426+
max_completion_tokens: 8192,
427+
pricing: {
428+
prompt: "0.000003",
429+
completion: "0.000015",
430+
},
431+
}
432+
433+
const resultWithoutTools = parseOpenRouterModel({
434+
id: "test/no-tools-model",
435+
model: mockModel,
436+
inputModality: ["text"],
437+
outputModality: ["text"],
438+
maxTokens: 8192,
439+
supportedParameters: ["max_tokens", "temperature"],
440+
})
441+
442+
expect(resultWithoutTools.supportsNativeTools).toBe(false)
443+
expect(resultWithoutTools.defaultToolProtocol).toBeUndefined()
444+
})
393445
})
394446
})

src/api/providers/fetchers/openrouter.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ export const parseOpenRouterModel = ({
207207

208208
const supportsPromptCache = typeof cacheReadsPrice !== "undefined" // some models support caching but don't charge a cacheWritesPrice, e.g. GPT-5
209209

210+
const supportsNativeTools = supportedParameters ? supportedParameters.includes("tools") : undefined
211+
210212
const modelInfo: ModelInfo = {
211213
maxTokens: maxTokens || Math.ceil(model.context_length * 0.2),
212214
contextWindow: model.context_length,
@@ -218,8 +220,10 @@ export const parseOpenRouterModel = ({
218220
cacheReadsPrice,
219221
description: model.description,
220222
supportsReasoningEffort: supportedParameters ? supportedParameters.includes("reasoning") : undefined,
221-
supportsNativeTools: supportedParameters ? supportedParameters.includes("tools") : undefined,
223+
supportsNativeTools,
222224
supportedParameters: supportedParameters ? supportedParameters.filter(isModelParameter) : undefined,
225+
// Default to native tool protocol when native tools are supported
226+
defaultToolProtocol: supportsNativeTools ? ("native" as const) : undefined,
223227
}
224228

225229
if (OPEN_ROUTER_REASONING_BUDGET_MODELS.has(id)) {

0 commit comments

Comments
 (0)