|
1 | | -import { getApiProtocol } from "../provider-settings.js" |
| 1 | +import { ANTHROPIC_API_PROTOCOL, getApiProtocol, OPENAI_API_PROTOCOL, providerIdentifiers } from "../index.js" |
2 | 2 |
|
3 | 3 | describe("getApiProtocol", () => { |
4 | | - describe("Anthropic-style providers", () => { |
5 | | - it("should return 'anthropic' for anthropic provider", () => { |
6 | | - expect(getApiProtocol("anthropic")).toBe("anthropic") |
7 | | - expect(getApiProtocol("anthropic", "gpt-4")).toBe("anthropic") |
8 | | - }) |
| 4 | + it("preserves API protocol wire values", () => { |
| 5 | + expect(ANTHROPIC_API_PROTOCOL).toBe("anthropic") |
| 6 | + expect(OPENAI_API_PROTOCOL).toBe("openai") |
| 7 | + }) |
9 | 8 |
|
10 | | - it("should return 'anthropic' for bedrock provider", () => { |
11 | | - expect(getApiProtocol("bedrock")).toBe("anthropic") |
12 | | - expect(getApiProtocol("bedrock", "gpt-4")).toBe("anthropic") |
13 | | - expect(getApiProtocol("bedrock", "claude-3-opus")).toBe("anthropic") |
14 | | - }) |
| 9 | + describe("Anthropic-style providers", () => { |
| 10 | + it.each([providerIdentifiers.anthropic, providerIdentifiers.bedrock, providerIdentifiers.minimax])( |
| 11 | + "should return 'anthropic' for %s provider", |
| 12 | + (provider) => { |
| 13 | + expect(getApiProtocol(provider)).toBe(ANTHROPIC_API_PROTOCOL) |
| 14 | + expect(getApiProtocol(provider, "gpt-4")).toBe(ANTHROPIC_API_PROTOCOL) |
| 15 | + }, |
| 16 | + ) |
15 | 17 | }) |
16 | 18 |
|
17 | 19 | describe("Vertex provider with Claude models", () => { |
18 | 20 | it("should return 'anthropic' for vertex provider with claude models", () => { |
19 | | - expect(getApiProtocol("vertex", "claude-3-opus")).toBe("anthropic") |
20 | | - expect(getApiProtocol("vertex", "Claude-3-Sonnet")).toBe("anthropic") |
21 | | - expect(getApiProtocol("vertex", "CLAUDE-instant")).toBe("anthropic") |
22 | | - expect(getApiProtocol("vertex", "anthropic/claude-3-haiku")).toBe("anthropic") |
| 21 | + expect(getApiProtocol(providerIdentifiers.vertex, "claude-3-opus")).toBe(ANTHROPIC_API_PROTOCOL) |
| 22 | + expect(getApiProtocol(providerIdentifiers.vertex, "Claude-3-Sonnet")).toBe(ANTHROPIC_API_PROTOCOL) |
| 23 | + expect(getApiProtocol(providerIdentifiers.vertex, "CLAUDE-instant")).toBe(ANTHROPIC_API_PROTOCOL) |
| 24 | + expect(getApiProtocol(providerIdentifiers.vertex, "anthropic/claude-3-haiku")).toBe(ANTHROPIC_API_PROTOCOL) |
23 | 25 | }) |
24 | 26 |
|
25 | 27 | it("should return 'openai' for vertex provider with non-claude models", () => { |
26 | | - expect(getApiProtocol("vertex", "gpt-4")).toBe("openai") |
27 | | - expect(getApiProtocol("vertex", "gemini-pro")).toBe("openai") |
28 | | - expect(getApiProtocol("vertex", "llama-2")).toBe("openai") |
| 28 | + expect(getApiProtocol(providerIdentifiers.vertex, "gpt-4")).toBe(OPENAI_API_PROTOCOL) |
| 29 | + expect(getApiProtocol(providerIdentifiers.vertex, "gemini-pro")).toBe(OPENAI_API_PROTOCOL) |
| 30 | + expect(getApiProtocol(providerIdentifiers.vertex, "llama-2")).toBe(OPENAI_API_PROTOCOL) |
29 | 31 | }) |
30 | 32 |
|
31 | 33 | it("should return 'openai' for vertex provider without model", () => { |
32 | | - expect(getApiProtocol("vertex")).toBe("openai") |
| 34 | + expect(getApiProtocol(providerIdentifiers.vertex)).toBe(OPENAI_API_PROTOCOL) |
33 | 35 | }) |
34 | 36 | }) |
35 | 37 |
|
36 | | - describe("Vercel AI Gateway provider", () => { |
| 38 | + describe("Gateway providers", () => { |
| 39 | + it("uses the canonical Zoo Gateway identifier for Anthropic model protocol selection", () => { |
| 40 | + expect(getApiProtocol(providerIdentifiers.zooGateway, "anthropic/claude-3-opus")).toBe( |
| 41 | + ANTHROPIC_API_PROTOCOL, |
| 42 | + ) |
| 43 | + }) |
| 44 | + |
37 | 45 | it("should return 'anthropic' for vercel-ai-gateway provider with anthropic models", () => { |
38 | | - expect(getApiProtocol("vercel-ai-gateway", "anthropic/claude-3-opus")).toBe("anthropic") |
39 | | - expect(getApiProtocol("vercel-ai-gateway", "anthropic/claude-3.5-sonnet")).toBe("anthropic") |
40 | | - expect(getApiProtocol("vercel-ai-gateway", "ANTHROPIC/claude-sonnet-4")).toBe("anthropic") |
41 | | - expect(getApiProtocol("vercel-ai-gateway", "anthropic/claude-opus-4.1")).toBe("anthropic") |
| 46 | + expect(getApiProtocol(providerIdentifiers.vercelAiGateway, "anthropic/claude-3-opus")).toBe( |
| 47 | + ANTHROPIC_API_PROTOCOL, |
| 48 | + ) |
| 49 | + expect(getApiProtocol(providerIdentifiers.vercelAiGateway, "anthropic/claude-3.5-sonnet")).toBe( |
| 50 | + ANTHROPIC_API_PROTOCOL, |
| 51 | + ) |
| 52 | + expect(getApiProtocol(providerIdentifiers.vercelAiGateway, "ANTHROPIC/claude-sonnet-4")).toBe( |
| 53 | + ANTHROPIC_API_PROTOCOL, |
| 54 | + ) |
| 55 | + expect(getApiProtocol(providerIdentifiers.vercelAiGateway, "anthropic/claude-opus-4.1")).toBe( |
| 56 | + ANTHROPIC_API_PROTOCOL, |
| 57 | + ) |
42 | 58 | }) |
43 | 59 |
|
44 | 60 | it("should return 'openai' for vercel-ai-gateway provider with non-anthropic models", () => { |
45 | | - expect(getApiProtocol("vercel-ai-gateway", "openai/gpt-4")).toBe("openai") |
46 | | - expect(getApiProtocol("vercel-ai-gateway", "google/gemini-pro")).toBe("openai") |
47 | | - expect(getApiProtocol("vercel-ai-gateway", "meta/llama-3")).toBe("openai") |
48 | | - expect(getApiProtocol("vercel-ai-gateway", "mistral/mixtral")).toBe("openai") |
| 61 | + expect(getApiProtocol(providerIdentifiers.vercelAiGateway, "openai/gpt-4")).toBe(OPENAI_API_PROTOCOL) |
| 62 | + expect(getApiProtocol(providerIdentifiers.vercelAiGateway, "google/gemini-pro")).toBe(OPENAI_API_PROTOCOL) |
| 63 | + expect(getApiProtocol(providerIdentifiers.vercelAiGateway, "meta/llama-3")).toBe(OPENAI_API_PROTOCOL) |
| 64 | + expect(getApiProtocol(providerIdentifiers.vercelAiGateway, "mistral/mixtral")).toBe(OPENAI_API_PROTOCOL) |
49 | 65 | }) |
50 | 66 |
|
51 | 67 | it("should return 'openai' for vercel-ai-gateway provider without model", () => { |
52 | | - expect(getApiProtocol("vercel-ai-gateway")).toBe("openai") |
| 68 | + expect(getApiProtocol(providerIdentifiers.vercelAiGateway)).toBe(OPENAI_API_PROTOCOL) |
53 | 69 | }) |
54 | 70 | }) |
55 | 71 |
|
56 | 72 | describe("Opencode Go provider", () => { |
57 | 73 | it("should return 'anthropic' for opencode-go Anthropic-format models (Qwen/MiniMax)", () => { |
58 | | - expect(getApiProtocol("opencode-go", "qwen3.7-max")).toBe("anthropic") |
59 | | - expect(getApiProtocol("opencode-go", "qwen3.7-plus")).toBe("anthropic") |
60 | | - expect(getApiProtocol("opencode-go", "qwen3.6-plus")).toBe("anthropic") |
61 | | - expect(getApiProtocol("opencode-go", "minimax-m3")).toBe("anthropic") |
62 | | - expect(getApiProtocol("opencode-go", "minimax-m2.7")).toBe("anthropic") |
63 | | - expect(getApiProtocol("opencode-go", "minimax-m2.5")).toBe("anthropic") |
| 74 | + expect(getApiProtocol(providerIdentifiers.opencodeGo, "qwen3.7-max")).toBe(ANTHROPIC_API_PROTOCOL) |
| 75 | + expect(getApiProtocol(providerIdentifiers.opencodeGo, "qwen3.7-plus")).toBe(ANTHROPIC_API_PROTOCOL) |
| 76 | + expect(getApiProtocol(providerIdentifiers.opencodeGo, "qwen3.6-plus")).toBe(ANTHROPIC_API_PROTOCOL) |
| 77 | + expect(getApiProtocol(providerIdentifiers.opencodeGo, "minimax-m3")).toBe(ANTHROPIC_API_PROTOCOL) |
| 78 | + expect(getApiProtocol(providerIdentifiers.opencodeGo, "minimax-m2.7")).toBe(ANTHROPIC_API_PROTOCOL) |
| 79 | + expect(getApiProtocol(providerIdentifiers.opencodeGo, "minimax-m2.5")).toBe(ANTHROPIC_API_PROTOCOL) |
64 | 80 | }) |
65 | 81 |
|
66 | 82 | it("should return 'openai' for opencode-go OpenAI-format models (GLM/DeepSeek/etc.)", () => { |
67 | | - expect(getApiProtocol("opencode-go", "glm-5.2")).toBe("openai") |
68 | | - expect(getApiProtocol("opencode-go", "deepseek-v4-pro")).toBe("openai") |
69 | | - expect(getApiProtocol("opencode-go", "kimi-k2.5")).toBe("openai") |
70 | | - expect(getApiProtocol("opencode-go", "mimo-v2.5")).toBe("openai") |
| 83 | + expect(getApiProtocol(providerIdentifiers.opencodeGo, "glm-5.2")).toBe(OPENAI_API_PROTOCOL) |
| 84 | + expect(getApiProtocol(providerIdentifiers.opencodeGo, "deepseek-v4-pro")).toBe(OPENAI_API_PROTOCOL) |
| 85 | + expect(getApiProtocol(providerIdentifiers.opencodeGo, "kimi-k2.5")).toBe(OPENAI_API_PROTOCOL) |
| 86 | + expect(getApiProtocol(providerIdentifiers.opencodeGo, "mimo-v2.5")).toBe(OPENAI_API_PROTOCOL) |
71 | 87 | }) |
72 | 88 |
|
73 | 89 | it("should return 'openai' for opencode-go without a model", () => { |
74 | | - expect(getApiProtocol("opencode-go")).toBe("openai") |
| 90 | + expect(getApiProtocol(providerIdentifiers.opencodeGo)).toBe(OPENAI_API_PROTOCOL) |
75 | 91 | }) |
76 | 92 |
|
77 | 93 | it("should return 'openai' for opencode-go with an unknown model id", () => { |
78 | | - expect(getApiProtocol("opencode-go", "some-future-model")).toBe("openai") |
| 94 | + expect(getApiProtocol(providerIdentifiers.opencodeGo, "some-future-model")).toBe(OPENAI_API_PROTOCOL) |
79 | 95 | }) |
80 | 96 | }) |
81 | 97 |
|
82 | 98 | describe("Other providers", () => { |
83 | 99 | it("should return 'openai' for non-anthropic providers regardless of model", () => { |
84 | | - expect(getApiProtocol("openrouter", "claude-3-opus")).toBe("openai") |
85 | | - expect(getApiProtocol("openai", "claude-3-sonnet")).toBe("openai") |
86 | | - expect(getApiProtocol("litellm", "claude-instant")).toBe("openai") |
87 | | - expect(getApiProtocol("ollama", "claude-model")).toBe("openai") |
| 100 | + expect(getApiProtocol(providerIdentifiers.openrouter, "claude-3-opus")).toBe(OPENAI_API_PROTOCOL) |
| 101 | + expect(getApiProtocol(providerIdentifiers.openai, "claude-3-sonnet")).toBe(OPENAI_API_PROTOCOL) |
| 102 | + expect(getApiProtocol(providerIdentifiers.litellm, "claude-instant")).toBe(OPENAI_API_PROTOCOL) |
| 103 | + expect(getApiProtocol(providerIdentifiers.ollama, "claude-model")).toBe(OPENAI_API_PROTOCOL) |
88 | 104 | }) |
89 | 105 | }) |
90 | 106 |
|
91 | 107 | describe("Edge cases", () => { |
92 | 108 | it("should return 'openai' when provider is undefined", () => { |
93 | | - expect(getApiProtocol(undefined)).toBe("openai") |
94 | | - expect(getApiProtocol(undefined, "claude-3-opus")).toBe("openai") |
| 109 | + expect(getApiProtocol(undefined)).toBe(OPENAI_API_PROTOCOL) |
| 110 | + expect(getApiProtocol(undefined, "claude-3-opus")).toBe(OPENAI_API_PROTOCOL) |
95 | 111 | }) |
96 | 112 |
|
97 | 113 | it("should handle empty strings", () => { |
98 | | - expect(getApiProtocol("vertex", "")).toBe("openai") |
| 114 | + expect(getApiProtocol(providerIdentifiers.vertex, "")).toBe(OPENAI_API_PROTOCOL) |
99 | 115 | }) |
100 | 116 |
|
101 | 117 | it("should be case-insensitive for claude detection", () => { |
102 | | - expect(getApiProtocol("vertex", "CLAUDE-3-OPUS")).toBe("anthropic") |
103 | | - expect(getApiProtocol("vertex", "claude-3-opus")).toBe("anthropic") |
104 | | - expect(getApiProtocol("vertex", "ClAuDe-InStAnT")).toBe("anthropic") |
| 118 | + expect(getApiProtocol(providerIdentifiers.vertex, "CLAUDE-3-OPUS")).toBe(ANTHROPIC_API_PROTOCOL) |
| 119 | + expect(getApiProtocol(providerIdentifiers.vertex, "claude-3-opus")).toBe(ANTHROPIC_API_PROTOCOL) |
| 120 | + expect(getApiProtocol(providerIdentifiers.vertex, "ClAuDe-InStAnT")).toBe(ANTHROPIC_API_PROTOCOL) |
105 | 121 | }) |
106 | 122 | }) |
107 | 123 | }) |
0 commit comments