| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- import { describe, it, expect } from "vitest"
- import { resolveToolProtocol } from "../resolveToolProtocol"
- import { TOOL_PROTOCOL, openAiModelInfoSaneDefaults } from "@roo-code/types"
- import type { ProviderSettings, ModelInfo } from "@roo-code/types"
- describe("resolveToolProtocol", () => {
- describe("Precedence Level 1: User Profile Setting", () => {
- it("should use profile toolProtocol when explicitly set to xml", () => {
- const settings: ProviderSettings = {
- toolProtocol: "xml",
- apiProvider: "anthropic",
- }
- const result = resolveToolProtocol(settings)
- expect(result).toBe(TOOL_PROTOCOL.XML)
- })
- it("should use profile toolProtocol when explicitly set to native", () => {
- const settings: ProviderSettings = {
- toolProtocol: "native",
- apiProvider: "anthropic",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 4096,
- contextWindow: 128000,
- supportsPromptCache: false,
- supportsNativeTools: true, // Model supports native tools
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.NATIVE)
- })
- it("should override model default when profile setting is present", () => {
- const settings: ProviderSettings = {
- toolProtocol: "xml",
- apiProvider: "openai-native",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 4096,
- contextWindow: 128000,
- supportsPromptCache: false,
- defaultToolProtocol: "native",
- supportsNativeTools: true,
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.XML) // Profile setting wins
- })
- it("should override model capability when profile setting is present", () => {
- const settings: ProviderSettings = {
- toolProtocol: "xml",
- apiProvider: "openai-native",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 4096,
- contextWindow: 128000,
- supportsPromptCache: false,
- supportsNativeTools: true,
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.XML) // Profile setting wins
- })
- })
- describe("Precedence Level 2: Model Default", () => {
- it("should use model defaultToolProtocol when no profile setting", () => {
- const settings: ProviderSettings = {
- apiProvider: "roo",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 4096,
- contextWindow: 128000,
- supportsPromptCache: false,
- defaultToolProtocol: "native",
- supportsNativeTools: true, // Model must support native tools
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Model default wins when experiment is disabled
- })
- it("should override model capability when model default is present", () => {
- const settings: ProviderSettings = {
- apiProvider: "roo",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 4096,
- contextWindow: 128000,
- supportsPromptCache: false,
- defaultToolProtocol: "xml",
- supportsNativeTools: true,
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.XML) // Model default wins over capability
- })
- })
- describe("Support Validation", () => {
- it("should fall back to XML when model doesn't support native", () => {
- const settings: ProviderSettings = {
- apiProvider: "anthropic",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 4096,
- contextWindow: 128000,
- supportsPromptCache: false,
- supportsNativeTools: false,
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.XML)
- })
- it("should fall back to XML when user prefers native but model doesn't support it", () => {
- const settings: ProviderSettings = {
- toolProtocol: "native", // User wants native
- apiProvider: "anthropic",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 4096,
- contextWindow: 128000,
- supportsPromptCache: false,
- supportsNativeTools: false, // But model doesn't support it
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.XML) // Falls back to XML due to lack of support
- })
- it("should fall back to XML when user prefers native but model support is undefined", () => {
- const settings: ProviderSettings = {
- toolProtocol: "native", // User wants native
- apiProvider: "anthropic",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 4096,
- contextWindow: 128000,
- supportsPromptCache: false,
- // supportsNativeTools is undefined (not specified)
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.XML) // Falls back to XML - undefined treated as unsupported
- })
- })
- describe("Precedence Level 3: Native Fallback", () => {
- it("should use Native fallback when no model default is specified and model supports native", () => {
- 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
- })
- })
- describe("Complete Precedence Chain", () => {
- it("should respect full precedence: Profile > Model Default > Native Fallback", () => {
- // Set up a scenario with all levels defined
- const settings: ProviderSettings = {
- toolProtocol: "native", // Level 1: User profile setting
- apiProvider: "roo",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 4096,
- contextWindow: 128000,
- supportsPromptCache: false,
- defaultToolProtocol: "xml", // Level 2: Model default
- supportsNativeTools: true, // Support check
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Profile setting wins
- })
- it("should skip to model default when profile setting is undefined", () => {
- const settings: ProviderSettings = {
- apiProvider: "openai-native",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 4096,
- contextWindow: 128000,
- supportsPromptCache: false,
- defaultToolProtocol: "xml", // Level 2
- supportsNativeTools: true, // Support check
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.XML) // Model default wins
- })
- it("should skip to Native fallback when profile and model default are undefined", () => {
- const settings: ProviderSettings = {
- apiProvider: "openai-native",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 4096,
- contextWindow: 128000,
- supportsPromptCache: false,
- supportsNativeTools: true,
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Native fallback
- })
- it("should skip to XML fallback when model info is unavailable", () => {
- const settings: ProviderSettings = {
- apiProvider: "anthropic",
- }
- const result = resolveToolProtocol(settings, undefined)
- expect(result).toBe(TOOL_PROTOCOL.XML) // XML fallback (no model info means no native support)
- })
- })
- 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)
- })
- 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)
- })
- it("should fall back to XML when model doesn't support native", () => {
- const settings: ProviderSettings = {
- apiProvider: "roo",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 4096,
- contextWindow: 128000,
- supportsPromptCache: false,
- supportsNativeTools: false, // Model doesn't support native
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.XML) // Falls back to XML due to lack of support
- })
- })
- describe("Real-world Scenarios", () => {
- it("should use Native fallback for models without defaultToolProtocol", () => {
- const settings: ProviderSettings = {
- apiProvider: "openai-native",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 4096,
- contextWindow: 128000,
- supportsPromptCache: false,
- supportsNativeTools: true,
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Native fallback
- })
- it("should use XML for Claude models with Anthropic provider", () => {
- const settings: ProviderSettings = {
- apiProvider: "anthropic",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 8192,
- contextWindow: 200000,
- supportsPromptCache: true,
- supportsNativeTools: false,
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.XML)
- })
- it("should allow user to force XML on native-supporting model", () => {
- const settings: ProviderSettings = {
- toolProtocol: "xml", // User explicitly wants XML
- apiProvider: "openai-native",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 4096,
- contextWindow: 128000,
- supportsPromptCache: false,
- supportsNativeTools: true, // Model supports native but user wants XML
- defaultToolProtocol: "native",
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.XML) // User preference wins
- })
- it("should not allow user to force native when model doesn't support it", () => {
- const settings: ProviderSettings = {
- toolProtocol: "native", // User wants native
- apiProvider: "anthropic",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 4096,
- contextWindow: 128000,
- supportsPromptCache: false,
- supportsNativeTools: false, // Model doesn't support native
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.XML) // Falls back to XML due to lack of support
- })
- it("should use model default when available", () => {
- const settings: ProviderSettings = {
- apiProvider: "roo",
- }
- const modelInfo: ModelInfo = {
- maxTokens: 8192,
- contextWindow: 200000,
- supportsPromptCache: true,
- defaultToolProtocol: "xml",
- supportsNativeTools: true,
- }
- const result = resolveToolProtocol(settings, modelInfo)
- expect(result).toBe(TOOL_PROTOCOL.XML) // Model default wins
- })
- it("should use native tools for OpenAI compatible provider with default model info", () => {
- const settings: ProviderSettings = {
- apiProvider: "openai",
- }
- // Using the actual openAiModelInfoSaneDefaults to verify the fix
- const result = resolveToolProtocol(settings, openAiModelInfoSaneDefaults)
- expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Should use native tools by default
- })
- })
- })
|