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
1 change: 0 additions & 1 deletion src/core/task/__tests__/Task.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,6 @@ describe("Cline", () => {
getState: vi.fn().mockResolvedValue({
apiConfiguration: mockApiConfig,
}),
getMcpHub: vi.fn().mockReturnValue(undefined),
say: vi.fn(),
postStateToWebview: vi.fn().mockResolvedValue(undefined),
postMessageToWebview: vi.fn().mockResolvedValue(undefined),
Expand Down
30 changes: 12 additions & 18 deletions src/utils/__tests__/resolveToolProtocol.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,24 +139,18 @@ describe("resolveToolProtocol", () => {
})
})

describe("Precedence Level 3: Native Fallback", () => {
it("should use Native fallback when no model default is specified and model supports native", () => {
describe("Precedence Level 3: XML Fallback", () => {
it("should use XML fallback when no model default is specified", () => {
const settings: ProviderSettings = {
apiProvider: "anthropic",
}
const modelInfo: ModelInfo = {
maxTokens: 4096,
contextWindow: 128000,
supportsPromptCache: false,
supportsNativeTools: true,
}
const result = resolveToolProtocol(settings, modelInfo)
expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Native fallback
const result = resolveToolProtocol(settings, undefined)
expect(result).toBe(TOOL_PROTOCOL.XML) // XML fallback
})
})

describe("Complete Precedence Chain", () => {
it("should respect full precedence: Profile > Model Default > Native Fallback", () => {
it("should respect full precedence: Profile > Model Default > XML Fallback", () => {
// Set up a scenario with all levels defined
const settings: ProviderSettings = {
toolProtocol: "native", // Level 1: User profile setting
Expand Down Expand Up @@ -192,7 +186,7 @@ describe("resolveToolProtocol", () => {
expect(result).toBe(TOOL_PROTOCOL.XML) // Model default wins
})

it("should skip to Native fallback when profile and model default are undefined", () => {
it("should skip to XML fallback when profile and model default are undefined", () => {
const settings: ProviderSettings = {
apiProvider: "openai-native",
}
Expand All @@ -205,7 +199,7 @@ describe("resolveToolProtocol", () => {
}

const result = resolveToolProtocol(settings, modelInfo)
expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Native fallback
expect(result).toBe(TOOL_PROTOCOL.XML) // XML fallback
})

it("should skip to XML fallback when model info is unavailable", () => {
Expand All @@ -214,23 +208,23 @@ describe("resolveToolProtocol", () => {
}

const result = resolveToolProtocol(settings, undefined)
expect(result).toBe(TOOL_PROTOCOL.XML) // XML fallback (no model info means no native support)
expect(result).toBe(TOOL_PROTOCOL.XML) // XML fallback
})
})

describe("Edge Cases", () => {
it("should handle missing provider name gracefully", () => {
const settings: ProviderSettings = {}
const result = resolveToolProtocol(settings)
expect(result).toBe(TOOL_PROTOCOL.XML) // Falls back to XML (no model info)
expect(result).toBe(TOOL_PROTOCOL.XML) // Falls back to global
})

it("should handle undefined model info gracefully", () => {
const settings: ProviderSettings = {
apiProvider: "openai-native",
}
const result = resolveToolProtocol(settings, undefined)
expect(result).toBe(TOOL_PROTOCOL.XML) // XML fallback (no model info)
expect(result).toBe(TOOL_PROTOCOL.XML) // XML fallback
})

it("should fall back to XML when model doesn't support native", () => {
Expand All @@ -249,7 +243,7 @@ describe("resolveToolProtocol", () => {
})

describe("Real-world Scenarios", () => {
it("should use Native fallback for models without defaultToolProtocol", () => {
it("should use XML fallback for models without defaultToolProtocol", () => {
const settings: ProviderSettings = {
apiProvider: "openai-native",
}
Expand All @@ -260,7 +254,7 @@ describe("resolveToolProtocol", () => {
supportsNativeTools: true,
}
const result = resolveToolProtocol(settings, modelInfo)
expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Native fallback
expect(result).toBe(TOOL_PROTOCOL.XML) // XML fallback
})

it("should use XML for Claude models with Anthropic provider", () => {
Expand Down
6 changes: 3 additions & 3 deletions src/utils/resolveToolProtocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { ProviderSettings, ModelInfo } from "@roo-code/types"
*
* 1. User Preference - Per-Profile (explicit profile setting)
* 2. Model Default (defaultToolProtocol in ModelInfo)
* 3. Native Fallback (final fallback)
* 3. XML Fallback (final fallback)
*
* Then check support: if protocol is "native" but model doesn't support it, use XML.
*
Expand All @@ -31,6 +31,6 @@ export function resolveToolProtocol(providerSettings: ProviderSettings, modelInf
return modelInfo.defaultToolProtocol
}

// 3. Native Fallback
return TOOL_PROTOCOL.NATIVE
// 3. XML Fallback
return TOOL_PROTOCOL.XML
}
4 changes: 2 additions & 2 deletions webview-ui/src/components/settings/ApiOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,8 @@ const ApiOptions = ({
// Mirrors the simplified logic in resolveToolProtocol.ts:
// 1. User preference (toolProtocol) - handled by the select value binding
// 2. Model default - use if available
// 3. Native fallback
const defaultProtocol = selectedModelInfo?.defaultToolProtocol || TOOL_PROTOCOL.NATIVE
// 3. XML fallback
const defaultProtocol = selectedModelInfo?.defaultToolProtocol || TOOL_PROTOCOL.XML

// Show the tool protocol selector when model supports native tools
const showToolProtocolSelector = selectedModelInfo?.supportsNativeTools === true
Expand Down
Loading