diff options
Diffstat (limited to 'packages/opencode/test/provider/transform.test.ts')
| -rw-r--r-- | packages/opencode/test/provider/transform.test.ts | 569 |
1 files changed, 569 insertions, 0 deletions
diff --git a/packages/opencode/test/provider/transform.test.ts b/packages/opencode/test/provider/transform.test.ts index 78bd296c9..59041b09f 100644 --- a/packages/opencode/test/provider/transform.test.ts +++ b/packages/opencode/test/provider/transform.test.ts @@ -409,3 +409,572 @@ describe("ProviderTransform.message - empty image handling", () => { }) }) }) + +describe("ProviderTransform.variants", () => { + const createMockModel = (overrides: Partial<any> = {}): any => ({ + id: "test/test-model", + providerID: "test", + api: { + id: "test-model", + url: "https://api.test.com", + npm: "@ai-sdk/openai", + }, + name: "Test Model", + capabilities: { + temperature: true, + reasoning: true, + attachment: true, + toolcall: true, + input: { text: true, audio: false, image: true, video: false, pdf: false }, + output: { text: true, audio: false, image: false, video: false, pdf: false }, + interleaved: false, + }, + cost: { + input: 0.001, + output: 0.002, + cache: { read: 0.0001, write: 0.0002 }, + }, + limit: { + context: 128000, + output: 8192, + }, + status: "active", + options: {}, + headers: {}, + release_date: "2024-01-01", + ...overrides, + }) + + test("returns empty object when model has no reasoning capabilities", () => { + const model = createMockModel({ + capabilities: { reasoning: false }, + }) + const result = ProviderTransform.variants(model) + expect(result).toEqual({}) + }) + + test("deepseek returns empty object", () => { + const model = createMockModel({ + id: "deepseek/deepseek-chat", + providerID: "deepseek", + api: { + id: "deepseek-chat", + url: "https://api.deepseek.com", + npm: "@ai-sdk/openai-compatible", + }, + }) + const result = ProviderTransform.variants(model) + expect(result).toEqual({}) + }) + + test("minimax returns empty object", () => { + const model = createMockModel({ + id: "minimax/minimax-model", + providerID: "minimax", + api: { + id: "minimax-model", + url: "https://api.minimax.com", + npm: "@ai-sdk/openai-compatible", + }, + }) + const result = ProviderTransform.variants(model) + expect(result).toEqual({}) + }) + + test("glm returns empty object", () => { + const model = createMockModel({ + id: "glm/glm-4", + providerID: "glm", + api: { + id: "glm-4", + url: "https://api.glm.com", + npm: "@ai-sdk/openai-compatible", + }, + }) + const result = ProviderTransform.variants(model) + expect(result).toEqual({}) + }) + + test("mistral returns empty object", () => { + const model = createMockModel({ + id: "mistral/mistral-large", + providerID: "mistral", + api: { + id: "mistral-large-latest", + url: "https://api.mistral.com", + npm: "@ai-sdk/mistral", + }, + }) + const result = ProviderTransform.variants(model) + expect(result).toEqual({}) + }) + + describe("@openrouter/ai-sdk-provider", () => { + test("returns empty object for non-qualifying models", () => { + const model = createMockModel({ + id: "openrouter/test-model", + providerID: "openrouter", + api: { + id: "test-model", + url: "https://openrouter.ai", + npm: "@openrouter/ai-sdk-provider", + }, + }) + const result = ProviderTransform.variants(model) + expect(result).toEqual({}) + }) + + test("gpt models return OPENAI_EFFORTS with reasoning", () => { + const model = createMockModel({ + id: "openrouter/gpt-4", + providerID: "openrouter", + api: { + id: "gpt-4", + url: "https://openrouter.ai", + npm: "@openrouter/ai-sdk-provider", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["none", "minimal", "low", "medium", "high", "xhigh"]) + expect(result.low).toEqual({ reasoning: { effort: "low" } }) + expect(result.high).toEqual({ reasoning: { effort: "high" } }) + }) + + test("gemini-3 returns OPENAI_EFFORTS with reasoning", () => { + const model = createMockModel({ + id: "openrouter/gemini-3-5-pro", + providerID: "openrouter", + api: { + id: "gemini-3-5-pro", + url: "https://openrouter.ai", + npm: "@openrouter/ai-sdk-provider", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["none", "minimal", "low", "medium", "high", "xhigh"]) + }) + + test("grok-4 returns OPENAI_EFFORTS with reasoning", () => { + const model = createMockModel({ + id: "openrouter/grok-4", + providerID: "openrouter", + api: { + id: "grok-4", + url: "https://openrouter.ai", + npm: "@openrouter/ai-sdk-provider", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["none", "minimal", "low", "medium", "high", "xhigh"]) + }) + }) + + describe("@ai-sdk/gateway", () => { + test("returns OPENAI_EFFORTS with reasoningEffort", () => { + const model = createMockModel({ + id: "gateway/gateway-model", + providerID: "gateway", + api: { + id: "gateway-model", + url: "https://gateway.ai", + npm: "@ai-sdk/gateway", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["none", "minimal", "low", "medium", "high", "xhigh"]) + expect(result.low).toEqual({ reasoningEffort: "low" }) + expect(result.high).toEqual({ reasoningEffort: "high" }) + }) + }) + + describe("@ai-sdk/cerebras", () => { + test("returns WIDELY_SUPPORTED_EFFORTS with reasoningEffort", () => { + const model = createMockModel({ + id: "cerebras/llama-4", + providerID: "cerebras", + api: { + id: "llama-4-sc", + url: "https://api.cerebras.ai", + npm: "@ai-sdk/cerebras", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["low", "medium", "high"]) + expect(result.low).toEqual({ reasoningEffort: "low" }) + expect(result.high).toEqual({ reasoningEffort: "high" }) + }) + }) + + describe("@ai-sdk/togetherai", () => { + test("returns WIDELY_SUPPORTED_EFFORTS with reasoningEffort", () => { + const model = createMockModel({ + id: "togetherai/llama-4", + providerID: "togetherai", + api: { + id: "llama-4-sc", + url: "https://api.togetherai.com", + npm: "@ai-sdk/togetherai", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["low", "medium", "high"]) + expect(result.low).toEqual({ reasoningEffort: "low" }) + expect(result.high).toEqual({ reasoningEffort: "high" }) + }) + }) + + describe("@ai-sdk/xai", () => { + test("returns WIDELY_SUPPORTED_EFFORTS with reasoningEffort", () => { + const model = createMockModel({ + id: "xai/grok-3", + providerID: "xai", + api: { + id: "grok-3", + url: "https://api.x.ai", + npm: "@ai-sdk/xai", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["low", "medium", "high"]) + expect(result.low).toEqual({ reasoningEffort: "low" }) + expect(result.high).toEqual({ reasoningEffort: "high" }) + }) + }) + + describe("@ai-sdk/deepinfra", () => { + test("returns WIDELY_SUPPORTED_EFFORTS with reasoningEffort", () => { + const model = createMockModel({ + id: "deepinfra/llama-4", + providerID: "deepinfra", + api: { + id: "llama-4-sc", + url: "https://api.deepinfra.com", + npm: "@ai-sdk/deepinfra", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["low", "medium", "high"]) + expect(result.low).toEqual({ reasoningEffort: "low" }) + expect(result.high).toEqual({ reasoningEffort: "high" }) + }) + }) + + describe("@ai-sdk/openai-compatible", () => { + test("returns WIDELY_SUPPORTED_EFFORTS with reasoningEffort", () => { + const model = createMockModel({ + id: "custom-provider/custom-model", + providerID: "custom-provider", + api: { + id: "custom-model", + url: "https://api.custom.com", + npm: "@ai-sdk/openai-compatible", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["low", "medium", "high"]) + expect(result.low).toEqual({ reasoningEffort: "low" }) + expect(result.high).toEqual({ reasoningEffort: "high" }) + }) + }) + + describe("@ai-sdk/azure", () => { + test("o1-mini returns empty object", () => { + const model = createMockModel({ + id: "o1-mini", + providerID: "azure", + api: { + id: "o1-mini", + url: "https://azure.com", + npm: "@ai-sdk/azure", + }, + }) + const result = ProviderTransform.variants(model) + expect(result).toEqual({}) + }) + + test("standard azure models return custom efforts with reasoningSummary", () => { + const model = createMockModel({ + id: "azure/gpt-4o", + providerID: "azure", + api: { + id: "gpt-4o", + url: "https://azure.com", + npm: "@ai-sdk/azure", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["low", "medium", "high"]) + expect(result.low).toEqual({ + reasoningEffort: "low", + reasoningSummary: "auto", + include: ["reasoning.encrypted_content"], + }) + }) + + test("gpt-5 adds minimal effort", () => { + const model = createMockModel({ + id: "azure/gpt-5", + providerID: "azure", + api: { + id: "gpt-5", + url: "https://azure.com", + npm: "@ai-sdk/azure", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["minimal", "low", "medium", "high"]) + }) + }) + + describe("@ai-sdk/openai", () => { + test("gpt-5-pro returns empty object", () => { + const model = createMockModel({ + id: "gpt-5-pro", + providerID: "openai", + api: { + id: "gpt-5-pro", + url: "https://api.openai.com", + npm: "@ai-sdk/openai", + }, + }) + const result = ProviderTransform.variants(model) + expect(result).toEqual({}) + }) + + test("standard openai models return custom efforts with reasoningSummary", () => { + const model = createMockModel({ + id: "openai/gpt-4o", + providerID: "openai", + api: { + id: "gpt-4o", + url: "https://api.openai.com", + npm: "@ai-sdk/openai", + }, + release_date: "2024-06-01", + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["minimal", "low", "medium", "high"]) + expect(result.low).toEqual({ + reasoningEffort: "low", + reasoningSummary: "auto", + include: ["reasoning.encrypted_content"], + }) + }) + + test("models after 2025-11-13 include 'none' effort", () => { + const model = createMockModel({ + id: "openai/gpt-4.5", + providerID: "openai", + api: { + id: "gpt-4.5", + url: "https://api.openai.com", + npm: "@ai-sdk/openai", + }, + release_date: "2025-11-14", + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["none", "minimal", "low", "medium", "high"]) + }) + + test("models after 2025-12-04 include 'xhigh' effort", () => { + const model = createMockModel({ + id: "openai/gpt-5-chat", + providerID: "openai", + api: { + id: "gpt-5-chat", + url: "https://api.openai.com", + npm: "@ai-sdk/openai", + }, + release_date: "2025-12-05", + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["none", "minimal", "low", "medium", "high", "xhigh"]) + }) + }) + + describe("@ai-sdk/anthropic", () => { + test("returns high and max with thinking config", () => { + const model = createMockModel({ + id: "anthropic/claude-4", + providerID: "anthropic", + api: { + id: "claude-4", + url: "https://api.anthropic.com", + npm: "@ai-sdk/anthropic", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["high", "max"]) + expect(result.high).toEqual({ + thinking: { + type: "enabled", + budgetTokens: 16000, + }, + }) + expect(result.max).toEqual({ + thinking: { + type: "enabled", + budgetTokens: 31999, + }, + }) + }) + }) + + describe("@ai-sdk/amazon-bedrock", () => { + test("returns WIDELY_SUPPORTED_EFFORTS with reasoningConfig", () => { + const model = createMockModel({ + id: "bedrock/llama-4", + providerID: "bedrock", + api: { + id: "llama-4-sc", + url: "https://bedrock.amazonaws.com", + npm: "@ai-sdk/amazon-bedrock", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["low", "medium", "high"]) + expect(result.low).toEqual({ + reasoningConfig: { + type: "enabled", + maxReasoningEffort: "low", + }, + }) + }) + }) + + describe("@ai-sdk/google", () => { + test("gemini-2.5 returns high and max with thinkingConfig and thinkingBudget", () => { + const model = createMockModel({ + id: "google/gemini-2.5-pro", + providerID: "google", + api: { + id: "gemini-2.5-pro", + url: "https://generativelanguage.googleapis.com", + npm: "@ai-sdk/google", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["high", "max"]) + expect(result.high).toEqual({ + thinkingConfig: { + includeThoughts: true, + thinkingBudget: 16000, + }, + }) + expect(result.max).toEqual({ + thinkingConfig: { + includeThoughts: true, + thinkingBudget: 24576, + }, + }) + }) + + test("other gemini models return low and high with thinkingLevel", () => { + const model = createMockModel({ + id: "google/gemini-2.0-pro", + providerID: "google", + api: { + id: "gemini-2.0-pro", + url: "https://generativelanguage.googleapis.com", + npm: "@ai-sdk/google", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["low", "high"]) + expect(result.low).toEqual({ + includeThoughts: true, + thinkingLevel: "low", + }) + expect(result.high).toEqual({ + includeThoughts: true, + thinkingLevel: "high", + }) + }) + }) + + describe("@ai-sdk/google-vertex", () => { + test("gemini-2.5 returns high and max with thinkingConfig and thinkingBudget", () => { + const model = createMockModel({ + id: "google-vertex/gemini-2.5-pro", + providerID: "google-vertex", + api: { + id: "gemini-2.5-pro", + url: "https://vertexai.googleapis.com", + npm: "@ai-sdk/google-vertex", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["high", "max"]) + }) + + test("other vertex models return low and high with thinkingLevel", () => { + const model = createMockModel({ + id: "google-vertex/gemini-2.0-pro", + providerID: "google-vertex", + api: { + id: "gemini-2.0-pro", + url: "https://vertexai.googleapis.com", + npm: "@ai-sdk/google-vertex", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["low", "high"]) + }) + }) + + describe("@ai-sdk/cohere", () => { + test("returns empty object", () => { + const model = createMockModel({ + id: "cohere/command-r", + providerID: "cohere", + api: { + id: "command-r", + url: "https://api.cohere.com", + npm: "@ai-sdk/cohere", + }, + }) + const result = ProviderTransform.variants(model) + expect(result).toEqual({}) + }) + }) + + describe("@ai-sdk/groq", () => { + test("returns none and WIDELY_SUPPORTED_EFFORTS with thinkingLevel", () => { + const model = createMockModel({ + id: "groq/llama-4", + providerID: "groq", + api: { + id: "llama-4-sc", + url: "https://api.groq.com", + npm: "@ai-sdk/groq", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["none", "low", "medium", "high"]) + expect(result.none).toEqual({ + includeThoughts: true, + thinkingLevel: "none", + }) + expect(result.low).toEqual({ + includeThoughts: true, + thinkingLevel: "low", + }) + }) + }) + + describe("@ai-sdk/perplexity", () => { + test("returns empty object", () => { + const model = createMockModel({ + id: "perplexity/sonar-plus", + providerID: "perplexity", + api: { + id: "sonar-plus", + url: "https://api.perplexity.ai", + npm: "@ai-sdk/perplexity", + }, + }) + const result = ProviderTransform.variants(model) + expect(result).toEqual({}) + }) + }) +}) |
