Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/types/src/tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ export const TOOL_PROTOCOL = {
*/
export type ToolProtocol = (typeof TOOL_PROTOCOL)[keyof typeof TOOL_PROTOCOL]

/**
* Default model info properties for native tool support.
* Used to merge with cached model info that may lack these fields.
* Router providers (Requesty, Unbound, LiteLLM) assume all models support native tools.
*/
export const NATIVE_TOOL_DEFAULTS = {
supportsNativeTools: true,
defaultToolProtocol: TOOL_PROTOCOL.NATIVE,
} as const

/**
* Checks if the protocol is native (non-XML).
*
Expand Down
2 changes: 2 additions & 0 deletions src/api/providers/fetchers/requesty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export async function getRequestyModels(baseUrl?: string, apiKey?: string): Prom
supportsImages: rawModel.supports_vision,
supportsReasoningBudget: reasoningBudget,
supportsReasoningEffort: reasoningEffort,
supportsNativeTools: true,
defaultToolProtocol: "native",
inputPrice: parseApiPrice(rawModel.input_price),
outputPrice: parseApiPrice(rawModel.output_price),
description: rawModel.description,
Expand Down
14 changes: 12 additions & 2 deletions src/api/providers/requesty.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { Anthropic } from "@anthropic-ai/sdk"
import OpenAI from "openai"

import { type ModelInfo, requestyDefaultModelId, requestyDefaultModelInfo, TOOL_PROTOCOL } from "@roo-code/types"
import {
type ModelInfo,
requestyDefaultModelId,
requestyDefaultModelInfo,
TOOL_PROTOCOL,
NATIVE_TOOL_DEFAULTS,
} from "@roo-code/types"

import type { ApiHandlerOptions, ModelRecord } from "../../shared/api"
import { resolveToolProtocol } from "../../utils/resolveToolProtocol"
Expand Down Expand Up @@ -79,7 +85,11 @@ export class RequestyHandler extends BaseProvider implements SingleCompletionHan

override getModel() {
const id = this.options.requestyModelId ?? requestyDefaultModelId
let info = this.models[id] ?? requestyDefaultModelInfo
const cachedInfo = this.models[id] ?? requestyDefaultModelInfo

// Merge native tool defaults for cached models that may lack these fields
// The order ensures that cached values (if present) override the defaults
let info: ModelInfo = { ...NATIVE_TOOL_DEFAULTS, ...cachedInfo }

// Apply tool preferences for models accessed through routers (OpenAI, Gemini)
info = applyRouterToolPreferences(id, info)
Expand Down
7 changes: 4 additions & 3 deletions src/api/providers/router-provider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import OpenAI from "openai"

import type { ModelInfo } from "@roo-code/types"
import { type ModelInfo, NATIVE_TOOL_DEFAULTS } from "@roo-code/types"

import { ApiHandlerOptions, RouterName, ModelRecord } from "../../shared/api"

Expand Down Expand Up @@ -64,8 +64,9 @@ export abstract class RouterProvider extends BaseProvider {
const id = this.modelId ?? this.defaultModelId

// First check instance models (populated by fetchModel)
// Merge native tool defaults for cached models that may lack these fields
if (this.models[id]) {
return { id, info: this.models[id] }
return { id, info: { ...NATIVE_TOOL_DEFAULTS, ...this.models[id] } }
}

// Fall back to global cache (synchronous disk/memory cache)
Expand All @@ -74,7 +75,7 @@ export abstract class RouterProvider extends BaseProvider {
if (cachedModels?.[id]) {
// Also populate instance models for future calls
this.models = cachedModels
return { id, info: cachedModels[id] }
return { id, info: { ...NATIVE_TOOL_DEFAULTS, ...cachedModels[id] } }
}

// Last resort: return default model
Expand Down
17 changes: 9 additions & 8 deletions webview-ui/src/components/ui/hooks/useSelectedModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
BEDROCK_1M_CONTEXT_MODEL_IDS,
isDynamicProvider,
getProviderDefaultModelId,
NATIVE_TOOL_DEFAULTS,
} from "@roo-code/types"

import type { ModelRecord, RouterModels } from "@roo/api"
Expand Down Expand Up @@ -157,23 +158,23 @@ function getSelectedModel({
}
case "requesty": {
const id = getValidatedModelId(apiConfiguration.requestyModelId, routerModels.requesty, defaultModelId)
const info = routerModels.requesty?.[id]
const routerInfo = routerModels.requesty?.[id]
// Merge native tool defaults for cached models that may lack these fields
const info = routerInfo ? { ...NATIVE_TOOL_DEFAULTS, ...routerInfo } : undefined
return { id, info }
}
case "unbound": {
const id = getValidatedModelId(apiConfiguration.unboundModelId, routerModels.unbound, defaultModelId)
const info = routerModels.unbound?.[id]
const routerInfo = routerModels.unbound?.[id]
// Merge native tool defaults for cached models that may lack these fields
const info = routerInfo ? { ...NATIVE_TOOL_DEFAULTS, ...routerInfo } : undefined
return { id, info }
}
case "litellm": {
const id = getValidatedModelId(apiConfiguration.litellmModelId, routerModels.litellm, defaultModelId)
const routerInfo = routerModels.litellm?.[id]
// Only merge native tool call defaults, not prices or other model-specific info
const nativeToolDefaults = {
supportsNativeTools: litellmDefaultModelInfo.supportsNativeTools,
defaultToolProtocol: litellmDefaultModelInfo.defaultToolProtocol,
}
const info = routerInfo ? { ...nativeToolDefaults, ...routerInfo } : litellmDefaultModelInfo
// Merge native tool defaults for cached models that may lack these fields
const info = routerInfo ? { ...NATIVE_TOOL_DEFAULTS, ...routerInfo } : litellmDefaultModelInfo
return { id, info }
}
case "xai": {
Expand Down
Loading