fix: expose sf-scoped providers

This commit is contained in:
Mikael Hugo 2026-05-05 16:42:36 +02:00
parent ab6cad4c84
commit aeea733cd6
12 changed files with 138 additions and 5 deletions

View file

@ -38,4 +38,22 @@ describe("getEnvApiKey", () => {
else process.env.GOOGLE_GENERATIVE_AI_API_KEY = savedGoogleGenerative;
}
});
it("uses the OpenCode Go subscription key before the Zen key", () => {
const savedZen = process.env.OPENCODE_API_KEY;
const savedGo = process.env.OPENCODE_GO_API_KEY;
process.env.OPENCODE_API_KEY = "zen-key";
process.env.OPENCODE_GO_API_KEY = "go-key";
try {
assert.equal(getEnvApiKey("opencode"), "zen-key");
assert.equal(getEnvApiKey("opencode-go"), "go-key");
} finally {
if (savedZen === undefined) delete process.env.OPENCODE_API_KEY;
else process.env.OPENCODE_API_KEY = savedZen;
if (savedGo === undefined) delete process.env.OPENCODE_GO_API_KEY;
else process.env.OPENCODE_GO_API_KEY = savedGo;
}
});
});

View file

@ -166,7 +166,7 @@ export function getEnvApiKey(provider: any): string | undefined {
"minimax-cn": "MINIMAX_CN_API_KEY",
huggingface: "HF_TOKEN",
opencode: "OPENCODE_API_KEY",
"opencode-go": "OPENCODE_API_KEY",
"opencode-go": ["OPENCODE_GO_API_KEY", "OPENCODE_API_KEY"],
"kimi-coding": "KIMI_API_KEY",
xiaomi: "XIAOMI_API_KEY",
"xiaomi-token-plan-ams": "XIAOMI_API_KEY",

View file

@ -101,7 +101,7 @@ export function getEnvApiKey(provider: string): string | undefined {
"minimax-cn": "MINIMAX_CN_API_KEY",
huggingface: "HF_TOKEN",
opencode: "OPENCODE_API_KEY",
"opencode-go": "OPENCODE_API_KEY",
"opencode-go": ["OPENCODE_GO_API_KEY", "OPENCODE_API_KEY"],
"kimi-coding": "KIMI_API_KEY",
xiaomi: "XIAOMI_API_KEY",
"xiaomi-token-plan-ams": "XIAOMI_API_KEY",

View file

@ -352,7 +352,8 @@ ${chalk.bold("Environment Variables:")}
MISTRAL_API_KEY - Mistral API key
OLLAMA_API_KEY - Ollama Cloud API key
MINIMAX_API_KEY - MiniMax API key
OPENCODE_API_KEY - OpenCode Zen/OpenCode Go API key
OPENCODE_API_KEY - OpenCode Zen API key
OPENCODE_GO_API_KEY - OpenCode Go API key
KIMI_API_KEY - Kimi For Coding API key
AWS_PROFILE - AWS profile for Amazon Bedrock
AWS_ACCESS_KEY_ID - AWS access key for Amazon Bedrock

View file

@ -208,6 +208,26 @@ describe("ModelRegistry.getModelsForProxy — basic", () => {
);
});
it("hides Grok models even when they arrive through aggregators", () => {
const registry = createRegistry(() => true);
const available = registry.getAvailable();
assert.ok(
!available.some(
(m) =>
m.provider === "xai" ||
m.id.toLowerCase().includes("grok") ||
m.id.toLowerCase().startsWith("x-ai/"),
),
"Grok/xAI models should not be visible through direct or aggregate providers",
);
assert.equal(
registry.find("openrouter", "x-ai/grok-4:free"),
undefined,
"direct lookup should also block OpenRouter Grok SKUs",
);
});
it("hides Claude Code because it is not part of the managed provider pool", () => {
const registry = createRegistry(() => true);
const available = registry.getAvailable();

View file

@ -311,6 +311,9 @@ function isModelAllowedByBuiltInProviderPolicy(
if (HIDDEN_MODEL_PROVIDERS.has(provider)) {
return false;
}
if (modelKey.includes("grok") || modelKey.startsWith("x-ai/")) {
return false;
}
if (provider === "mistral") {
return isMistralSelectionModel(model.id);
}

View file

@ -71,8 +71,11 @@ const LLM_PROVIDER_IDS = [
"google-gemini-cli",
"groq",
"openrouter",
"zai",
"mistral",
"xiaomi",
"opencode",
"opencode-go",
"ollama",
"ollama-cloud",
"custom-openai",
@ -91,12 +94,23 @@ const OTHER_PROVIDERS = [
label: "OpenRouter",
hint: "200+ models — openrouter.ai/keys",
},
{ value: "zai", label: "ZAI", hint: "ZAI GLM — bigmodel.cn" },
{ value: "mistral", label: "Mistral", hint: "console.mistral.ai/api-keys" },
{
value: "xiaomi",
label: "Xiaomi MiMo",
hint: "token-plan-ams.xiaomimimo.com",
},
{
value: "opencode",
label: "OpenCode Zen",
hint: "free Zen models — OPENCODE_API_KEY",
},
{
value: "opencode-go",
label: "OpenCode Go",
hint: "subscription — OPENCODE_GO_API_KEY",
},
{ value: "ollama-cloud", label: "Ollama Cloud" },
{
value: "custom-openai",

View file

@ -60,6 +60,13 @@ export const PROVIDER_REGISTRY = [
envVar: "MISTRAL_API_KEY",
dashboardUrl: "console.mistral.ai",
},
{
id: "zai",
label: "ZAI",
category: "llm",
envVar: "ZAI_API_KEY",
dashboardUrl: "bigmodel.cn",
},
{
id: "xiaomi",
label: "Xiaomi MiMo",
@ -75,7 +82,7 @@ export const PROVIDER_REGISTRY = [
},
{
id: "opencode",
label: "OpenCode",
label: "OpenCode Zen",
category: "llm",
envVar: "OPENCODE_API_KEY",
dashboardUrl: "opencode.ai/zen",
@ -84,7 +91,7 @@ export const PROVIDER_REGISTRY = [
id: "opencode-go",
label: "OpenCode Go",
category: "llm",
envVar: "OPENCODE_API_KEY",
envVar: "OPENCODE_GO_API_KEY",
dashboardUrl: "opencode.ai/zen",
},
{

View file

@ -99,6 +99,9 @@ function isModelAllowedByBuiltInProviderPolicy(provider, modelId, model) {
if (HIDDEN_MODEL_PROVIDERS.has(providerKey)) {
return false;
}
if (modelKey.includes("grok") || modelKey.startsWith("x-ai/")) {
return false;
}
if (providerKey === "mistral") {
return isMistralSelectionModel(modelId);
}

View file

@ -57,6 +57,7 @@ const SANITIZED_PROVIDER_ENV_KEYS = [
"MINIMAX_CN_API_KEY",
"HF_TOKEN",
"OPENCODE_API_KEY",
"OPENCODE_GO_API_KEY",
"KIMI_API_KEY",
"ALIBABA_API_KEY",
"COPILOT_GITHUB_TOKEN",

View file

@ -42,6 +42,7 @@ const ONBOARDING_ENV_KEYS = [
"MINIMAX_CN_API_KEY",
"HF_TOKEN",
"OPENCODE_API_KEY",
"OPENCODE_GO_API_KEY",
"KIMI_API_KEY",
"ALIBABA_API_KEY",
"AWS_PROFILE",
@ -396,6 +397,11 @@ test("boot and onboarding routes expose locked required state plus explicitly sk
"groq",
"openrouter",
"mistral",
"zai",
"xiaomi",
"opencode",
"opencode-go",
"ollama-cloud",
]);
const anthropicProvider = bootPayload.onboarding.required.providers.find(
(provider: any) => provider.id === "anthropic",

View file

@ -199,6 +199,31 @@ const REQUIRED_PROVIDER_CATALOG: RequiredProviderCatalogEntry[] = [
supportsApiKey: true,
supportsOAuth: false,
},
{ id: "zai", label: "ZAI", supportsApiKey: true, supportsOAuth: false },
{
id: "xiaomi",
label: "Xiaomi MiMo",
supportsApiKey: true,
supportsOAuth: false,
},
{
id: "opencode",
label: "OpenCode Zen",
supportsApiKey: true,
supportsOAuth: false,
},
{
id: "opencode-go",
label: "OpenCode Go",
supportsApiKey: true,
supportsOAuth: false,
},
{
id: "ollama-cloud",
label: "Ollama Cloud",
supportsApiKey: true,
supportsOAuth: false,
},
];
const OPTIONAL_SECTION_CATALOG: OptionalSectionCatalogEntry[] = [
@ -460,6 +485,41 @@ async function defaultValidateApiKey(
"https://api.mistral.ai/v1/models",
apiKey,
);
case "zai":
return await validateBearerRequest(
fetchImpl,
providerId,
"https://open.bigmodel.cn/api/paas/v4/models",
apiKey,
);
case "xiaomi":
return await validateBearerRequest(
fetchImpl,
providerId,
"https://token-plan-ams.xiaomimimo.com/anthropic/v1/models",
apiKey,
);
case "opencode":
return await validateBearerRequest(
fetchImpl,
providerId,
"https://opencode.ai/zen/v1/models",
apiKey,
);
case "opencode-go":
return await validateBearerRequest(
fetchImpl,
providerId,
"https://opencode.ai/zen/go/v1/models",
apiKey,
);
case "ollama-cloud":
return await validateBearerRequest(
fetchImpl,
providerId,
"https://ollama.com/api/tags",
apiKey,
);
default:
return {
ok: false,