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
34 changes: 12 additions & 22 deletions src/api/providers/__tests__/roo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ vitest.mock("../../providers/fetchers/modelCache", () => ({
supportsPromptCache: true,
inputPrice: 0,
outputPrice: 0,
defaultToolProtocol: "native",
},
"minimax/minimax-m2:free": {
maxTokens: 32_768,
Expand All @@ -110,6 +111,7 @@ vitest.mock("../../providers/fetchers/modelCache", () => ({
supportsNativeTools: true,
inputPrice: 0.15,
outputPrice: 0.6,
defaultToolProtocol: "native",
},
"anthropic/claude-haiku-4.5": {
maxTokens: 8_192,
Expand All @@ -119,6 +121,7 @@ vitest.mock("../../providers/fetchers/modelCache", () => ({
supportsNativeTools: true,
inputPrice: 0.8,
outputPrice: 4,
defaultToolProtocol: "native",
},
}
}
Expand Down Expand Up @@ -425,28 +428,15 @@ describe("RooHandler", () => {
}
})

it("should apply defaultToolProtocol: native for minimax/minimax-m2:free", () => {
const handlerWithMinimax = new RooHandler({
apiModelId: "minimax/minimax-m2:free",
})
const modelInfo = handlerWithMinimax.getModel()
expect(modelInfo.id).toBe("minimax/minimax-m2:free")
expect((modelInfo.info as any).defaultToolProtocol).toBe("native")
// Verify cached model info is preserved
expect(modelInfo.info.maxTokens).toBe(32_768)
expect(modelInfo.info.contextWindow).toBe(1_000_000)
})

it("should apply defaultToolProtocol: native for anthropic/claude-haiku-4.5", () => {
const handlerWithHaiku = new RooHandler({
apiModelId: "anthropic/claude-haiku-4.5",
})
const modelInfo = handlerWithHaiku.getModel()
expect(modelInfo.id).toBe("anthropic/claude-haiku-4.5")
expect((modelInfo.info as any).defaultToolProtocol).toBe("native")
// Verify cached model info is preserved
expect(modelInfo.info.maxTokens).toBe(8_192)
expect(modelInfo.info.contextWindow).toBe(200_000)
it("should have defaultToolProtocol: native for all roo provider models", () => {
// Test that all models have defaultToolProtocol: native
const testModels = ["minimax/minimax-m2:free", "anthropic/claude-haiku-4.5", "xai/grok-code-fast-1"]
for (const modelId of testModels) {
const handlerWithModel = new RooHandler({ apiModelId: modelId })
const modelInfo = handlerWithModel.getModel()
expect(modelInfo.id).toBe(modelId)
expect((modelInfo.info as any).defaultToolProtocol).toBe("native")
}
})

it("should not override existing properties when applying MODEL_DEFAULTS", () => {
Expand Down
34 changes: 21 additions & 13 deletions src/api/providers/fetchers/__tests__/roo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ describe("getRooModels", () => {
description: "Model that requires reasoning",
deprecated: false,
isFree: false,
defaultTemperature: undefined,
defaultToolProtocol: "native",
isStealthModel: undefined,
})
})

Expand Down Expand Up @@ -174,6 +177,9 @@ describe("getRooModels", () => {
description: "Normal model without reasoning",
deprecated: false,
isFree: false,
defaultTemperature: undefined,
defaultToolProtocol: "native",
isStealthModel: undefined,
})
})

Expand Down Expand Up @@ -578,21 +584,21 @@ describe("getRooModels", () => {
expect(models["test/native-tools-model"].defaultToolProtocol).toBe("native")
})

it("should imply supportsNativeTools when default-native-tools tag is present without tool-use tag", async () => {
it("should set defaultToolProtocol to native for all models regardless of tags", async () => {
const mockResponse = {
object: "list",
data: [
{
id: "test/implicit-native-tools",
id: "test/model-without-tool-tags",
object: "model",
created: 1234567890,
owned_by: "test",
name: "Implicit Native Tools Model",
description: "Model with default-native-tools but no tool-use tag",
name: "Model Without Tool Tags",
description: "Model without any tool-related tags",
context_window: 128000,
max_tokens: 8192,
type: "language",
tags: ["default-native-tools"], // Only default-native-tools, no tool-use
tags: [], // No tool-related tags
pricing: {
input: "0.0001",
output: "0.0002",
Expand All @@ -608,21 +614,22 @@ describe("getRooModels", () => {

const models = await getRooModels(baseUrl, apiKey)

expect(models["test/implicit-native-tools"].supportsNativeTools).toBe(true)
expect(models["test/implicit-native-tools"].defaultToolProtocol).toBe("native")
// All Roo provider models now default to native tool protocol
expect(models["test/model-without-tool-tags"].supportsNativeTools).toBe(false)
expect(models["test/model-without-tool-tags"].defaultToolProtocol).toBe("native")
})

it("should not set defaultToolProtocol when default-native-tools tag is not present", async () => {
it("should set supportsNativeTools from tool-use tag and always set defaultToolProtocol to native", async () => {
const mockResponse = {
object: "list",
data: [
{
id: "test/non-native-model",
id: "test/tool-use-model",
object: "model",
created: 1234567890,
owned_by: "test",
name: "Non-Native Tools Model",
description: "Model without native tool calling default",
name: "Tool Use Model",
description: "Model with tool-use tag",
context_window: 128000,
max_tokens: 8192,
type: "language",
Expand All @@ -642,8 +649,9 @@ describe("getRooModels", () => {

const models = await getRooModels(baseUrl, apiKey)

expect(models["test/non-native-model"].supportsNativeTools).toBe(true)
expect(models["test/non-native-model"].defaultToolProtocol).toBeUndefined()
// tool-use tag sets supportsNativeTools, and all models get defaultToolProtocol: native
expect(models["test/tool-use-model"].supportsNativeTools).toBe(true)
expect(models["test/tool-use-model"].defaultToolProtocol).toBe("native")
})

it("should detect stealth mode from tags", async () => {
Expand Down
16 changes: 2 additions & 14 deletions src/api/providers/fetchers/roo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,9 @@ import { DEFAULT_HEADERS } from "../constants"
// Exported so RooHandler.getModel() can also apply these for fallback cases
export const MODEL_DEFAULTS: Record<string, Partial<ModelInfo>> = {
"minimax/minimax-m2:free": {
defaultToolProtocol: "native",
includedTools: ["search_and_replace"],
excludedTools: ["apply_diff"],
},
"anthropic/claude-haiku-4.5": {
defaultToolProtocol: "native",
},
"xai/grok-code-fast-1": {
defaultToolProtocol: "native",
},
}

/**
Expand Down Expand Up @@ -109,13 +102,8 @@ export async function getRooModels(baseUrl: string, apiKey?: string): Promise<Mo
// Determine if the model requires reasoning effort based on tags
const requiredReasoningEffort = tags.includes("reasoning-required")

// Determine if native tool calling should be the default protocol for this model
const hasDefaultNativeTools = tags.includes("default-native-tools")
const defaultToolProtocol = hasDefaultNativeTools ? ("native" as const) : undefined

// Determine if the model supports native tool calling based on tags
// default-native-tools implies tool-use support
const supportsNativeTools = tags.includes("tool-use") || hasDefaultNativeTools
const supportsNativeTools = tags.includes("tool-use")

// Determine if the model should hide vendor/company identity (stealth mode)
const isStealthModel = tags.includes("stealth")
Expand Down Expand Up @@ -143,7 +131,7 @@ export async function getRooModels(baseUrl: string, apiKey?: string): Promise<Mo
deprecated: model.deprecated || false,
isFree: tags.includes("free"),
defaultTemperature: model.default_temperature,
defaultToolProtocol,
defaultToolProtocol: "native" as const,
isStealthModel: isStealthModel || undefined,
}

Expand Down
Loading