Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
11 changes: 8 additions & 3 deletions packages/types/src/__tests__/provider-settings.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getApiProtocol } from "../provider-settings.js"
import { getApiProtocol, providerIdentifiers } from "../index.js"

describe("getApiProtocol", () => {
describe("Anthropic-style providers", () => {
Expand All @@ -16,7 +16,7 @@ describe("getApiProtocol", () => {

describe("Vertex provider with Claude models", () => {
it("should return 'anthropic' for vertex provider with claude models", () => {
expect(getApiProtocol("vertex", "claude-3-opus")).toBe("anthropic")
expect(getApiProtocol(providerIdentifiers.vertex, "claude-3-opus")).toBe("anthropic")
Comment thread
WebMad marked this conversation as resolved.
Outdated
expect(getApiProtocol("vertex", "Claude-3-Sonnet")).toBe("anthropic")
expect(getApiProtocol("vertex", "CLAUDE-instant")).toBe("anthropic")
expect(getApiProtocol("vertex", "anthropic/claude-3-haiku")).toBe("anthropic")
Expand All @@ -34,6 +34,11 @@ describe("getApiProtocol", () => {
})

describe("Vercel AI Gateway provider", () => {
it("uses canonical gateway identifiers for Anthropic model protocol selection", () => {
expect(getApiProtocol(providerIdentifiers.vercelAiGateway, "anthropic/claude-3-opus")).toBe("anthropic")
Comment thread
WebMad marked this conversation as resolved.
Outdated
expect(getApiProtocol(providerIdentifiers.zooGateway, "anthropic/claude-3-opus")).toBe("anthropic")
})

it("should return 'anthropic' for vercel-ai-gateway provider with anthropic models", () => {
expect(getApiProtocol("vercel-ai-gateway", "anthropic/claude-3-opus")).toBe("anthropic")
expect(getApiProtocol("vercel-ai-gateway", "anthropic/claude-3.5-sonnet")).toBe("anthropic")
Expand All @@ -55,7 +60,7 @@ describe("getApiProtocol", () => {

describe("Opencode Go provider", () => {
it("should return 'anthropic' for opencode-go Anthropic-format models (Qwen/MiniMax)", () => {
expect(getApiProtocol("opencode-go", "qwen3.7-max")).toBe("anthropic")
expect(getApiProtocol(providerIdentifiers.opencodeGo, "qwen3.7-max")).toBe("anthropic")
expect(getApiProtocol("opencode-go", "qwen3.7-plus")).toBe("anthropic")
Comment thread
WebMad marked this conversation as resolved.
Outdated
expect(getApiProtocol("opencode-go", "qwen3.6-plus")).toBe("anthropic")
expect(getApiProtocol("opencode-go", "minimax-m3")).toBe("anthropic")
Expand Down
31 changes: 26 additions & 5 deletions packages/types/src/provider-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -581,23 +581,39 @@ export const modelIdKeysByProvider: Record<TypicalProvider, ModelIdKey> = {
*/

// Providers that use Anthropic-style API protocol.
export const ANTHROPIC_STYLE_PROVIDERS: ProviderName[] = ["anthropic", "bedrock", "minimax"]
export const ANTHROPIC_STYLE_PROVIDERS: ProviderName[] = [
providerIdentifiers.anthropic,
providerIdentifiers.bedrock,
providerIdentifiers.minimax,
]

const CLAUDE_MODEL_ID_FRAGMENT = "claude"
const ANTHROPIC_MODEL_ID_PREFIX = "anthropic/"
const ANTHROPIC_MODEL_GATEWAY_PROVIDERS: ProviderName[] = [
providerIdentifiers.vercelAiGateway,
providerIdentifiers.zooGateway,
]

export const getApiProtocol = (provider: ProviderName | undefined, modelId?: string): "anthropic" | "openai" => {
if (provider && ANTHROPIC_STYLE_PROVIDERS.includes(provider)) {
return "anthropic"
}

if (provider && provider === "vertex" && modelId && modelId.toLowerCase().includes("claude")) {
if (
provider &&
provider === providerIdentifiers.vertex &&
modelId &&
modelId.toLowerCase().includes(CLAUDE_MODEL_ID_FRAGMENT)
) {
return "anthropic"
Comment thread
WebMad marked this conversation as resolved.
Outdated
}

// Vercel AI Gateway and Zoo Gateway use the anthropic protocol for anthropic models.
if (
provider &&
["vercel-ai-gateway", "zoo-gateway"].includes(provider) &&
ANTHROPIC_MODEL_GATEWAY_PROVIDERS.includes(provider) &&
modelId &&
modelId.toLowerCase().startsWith("anthropic/")
modelId.toLowerCase().startsWith(ANTHROPIC_MODEL_ID_PREFIX)
) {
return "anthropic"
Comment thread
WebMad marked this conversation as resolved.
Outdated
}
Expand All @@ -609,7 +625,12 @@ export const getApiProtocol = (provider: ProviderName | undefined, modelId?: str
// models must use the anthropic protocol so token/cost aggregation adds the
// cache tokens back into the input total — otherwise the cached prefix is
// dropped from `contextTokens`, undercounting context-window usage.
if (provider && provider === "opencode-go" && modelId && isOpencodeGoAnthropicFormatModel(modelId)) {
if (
provider &&
provider === providerIdentifiers.opencodeGo &&
modelId &&
isOpencodeGoAnthropicFormatModel(modelId)
) {
return "anthropic"
}

Expand Down
14 changes: 13 additions & 1 deletion src/shared/__tests__/checkExistApiConfig.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// npx vitest run src/shared/__tests__/checkExistApiConfig.spec.ts

import type { ProviderSettings } from "@roo-code/types"
import { providerIdentifiers, type ProviderSettings } from "@roo-code/types"

import { checkExistKey } from "../checkExistApiConfig"

Expand Down Expand Up @@ -66,6 +66,10 @@ describe("checkExistKey", () => {
expect(checkExistKey(config)).toBe(true)
})

it("recognizes keyless providers through their canonical identifiers", () => {
expect(checkExistKey({ apiProvider: providerIdentifiers.fakeAi })).toBe(true)
})

Comment thread
coderabbitai[bot] marked this conversation as resolved.
it("should return true for openai-codex provider without API key", () => {
const config: ProviderSettings = {
apiProvider: "openai-codex",
Expand Down Expand Up @@ -95,6 +99,10 @@ describe("checkExistKey", () => {
expect(checkExistKey(config)).toBe(true)
})

it("recognizes OAuth authentication through the canonical Kimi Code identifier", () => {
expect(checkExistKey({ apiProvider: providerIdentifiers.kimiCode, kimiCodeAuthMethod: "oauth" })).toBe(true)
})

it("should return true for kimi-code provider without auth method (defaults to OAuth)", () => {
const config: ProviderSettings = {
apiProvider: "kimi-code",
Expand Down Expand Up @@ -128,6 +136,10 @@ describe("checkExistKey", () => {
expect(checkExistKey(config, false)).toBe(false)
})

it("recognizes session authentication through the canonical Zoo Gateway identifier", () => {
expect(checkExistKey({ apiProvider: providerIdentifiers.zooGateway }, true)).toBe(true)
})

it("should return true for zoo-gateway when profile has zooSessionToken", () => {
const config: ProviderSettings = {
apiProvider: "zoo-gateway",
Expand Down
13 changes: 9 additions & 4 deletions src/shared/checkExistApiConfig.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SECRET_STATE_KEYS, GLOBAL_SECRET_KEYS, ProviderSettings } from "@roo-code/types"
import { SECRET_STATE_KEYS, GLOBAL_SECRET_KEYS, providerIdentifiers, ProviderSettings } from "@roo-code/types"

/**
* Returns whether a provider profile is sufficiently configured to leave the
Expand All @@ -14,17 +14,22 @@ export function checkExistKey(config: ProviderSettings | undefined, zooCodeIsAut
}

// Special case for fake-ai, openai-codex, and qwen-code providers which don't need any configuration.
if (config.apiProvider && ["fake-ai", "openai-codex", "qwen-code"].includes(config.apiProvider)) {
const configurationFreeProviders: ProviderSettings["apiProvider"][] = [
providerIdentifiers.fakeAi,
providerIdentifiers.openaiCodex,
providerIdentifiers.qwenCode,
]
if (config.apiProvider && configurationFreeProviders.includes(config.apiProvider)) {
return true
}

if (config.apiProvider === "kimi-code" && (config.kimiCodeAuthMethod ?? "oauth") === "oauth") {
if (config.apiProvider === providerIdentifiers.kimiCode && (config.kimiCodeAuthMethod ?? "oauth") === "oauth") {
return true
}

// Zoo Gateway uses session auth (profile token and/or global Zoo Code login),
// not a traditional API key listed in SECRET_STATE_KEYS.
if (config.apiProvider === "zoo-gateway") {
if (config.apiProvider === providerIdentifiers.zooGateway) {
return Boolean(config.zooSessionToken) || Boolean(zooCodeIsAuthenticated)
}

Expand Down
Loading