109 lines
4.4 KiB
TypeScript
109 lines
4.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { expectedEnvKeyForModel } from "../src/main/installer";
|
|
|
|
// Regression tests for #236: the install gate's .env check hard-coded
|
|
// only OPENROUTER_API_KEY / ANTHROPIC_API_KEY / OPENAI_API_KEY, so users
|
|
// configured for DeepSeek, Groq, Mistral, etc. saw the "set AI provider"
|
|
// first-run screen every restart, even with a valid key in .env.
|
|
//
|
|
// The new `expectedEnvKeyForModel(provider, baseUrl)` returns the
|
|
// canonical env var name the gateway expects per provider, falling back
|
|
// to URL-pattern matching for `custom` / `auto` providers pointed at a
|
|
// known endpoint, then to null for unrecognized configurations (where
|
|
// the caller does a permissive `*_API_KEY` scan).
|
|
|
|
describe("expectedEnvKeyForModel — provider-name lookup", () => {
|
|
it.each([
|
|
["openrouter", "OPENROUTER_API_KEY"],
|
|
["anthropic", "ANTHROPIC_API_KEY"],
|
|
["openai", "OPENAI_API_KEY"],
|
|
["ollama-cloud", "OLLAMA_API_KEY"],
|
|
["aimlapi", "AIMLAPI_API_KEY"],
|
|
["google", "GOOGLE_API_KEY"],
|
|
["xai", "XAI_API_KEY"],
|
|
["deepseek", "DEEPSEEK_API_KEY"], // the specific provider from issue #236
|
|
["groq", "GROQ_API_KEY"],
|
|
["mistral", "MISTRAL_API_KEY"],
|
|
["together", "TOGETHER_API_KEY"],
|
|
["fireworks", "FIREWORKS_API_KEY"],
|
|
["cerebras", "CEREBRAS_API_KEY"],
|
|
["perplexity", "PERPLEXITY_API_KEY"],
|
|
["huggingface", "HF_TOKEN"], // exception to the *_API_KEY convention
|
|
["alibaba", "DASHSCOPE_API_KEY"],
|
|
// The agent's DashScope aliases — `qwen` is what pre-#825 desktop
|
|
// configs stored, so it must keep resolving to a real key check.
|
|
["dashscope", "DASHSCOPE_API_KEY"],
|
|
["qwen", "DASHSCOPE_API_KEY"],
|
|
["aliyun", "DASHSCOPE_API_KEY"],
|
|
["alibaba-cloud", "DASHSCOPE_API_KEY"],
|
|
["qwen-oauth", "QWEN_API_KEY"],
|
|
["minimax", "MINIMAX_API_KEY"],
|
|
["glm", "GLM_API_KEY"],
|
|
["kimi", "KIMI_API_KEY"],
|
|
["xiaomi", "XIAOMI_API_KEY"],
|
|
])("maps provider %s → %s", (provider, expected) => {
|
|
expect(expectedEnvKeyForModel(provider, "")).toBe(expected);
|
|
});
|
|
|
|
it("is case-insensitive on the provider name", () => {
|
|
expect(expectedEnvKeyForModel("DeepSeek", "")).toBe("DEEPSEEK_API_KEY");
|
|
expect(expectedEnvKeyForModel("ANTHROPIC", "")).toBe("ANTHROPIC_API_KEY");
|
|
});
|
|
|
|
it("trims surrounding whitespace from the provider name", () => {
|
|
expect(expectedEnvKeyForModel(" groq ", "")).toBe("GROQ_API_KEY");
|
|
});
|
|
});
|
|
|
|
describe("expectedEnvKeyForModel — URL fallback for custom/auto providers", () => {
|
|
it("recognizes a known endpoint when provider is 'custom'", () => {
|
|
expect(
|
|
expectedEnvKeyForModel("custom", "https://api.deepseek.com/v1"),
|
|
).toBe("DEEPSEEK_API_KEY");
|
|
expect(
|
|
expectedEnvKeyForModel("custom", "https://api.groq.com/openai/v1"),
|
|
).toBe("GROQ_API_KEY");
|
|
expect(
|
|
expectedEnvKeyForModel("custom", "https://openrouter.ai/api/v1"),
|
|
).toBe("OPENROUTER_API_KEY");
|
|
expect(expectedEnvKeyForModel("custom", "https://ollama.com/v1")).toBe(
|
|
"OLLAMA_API_KEY",
|
|
);
|
|
expect(expectedEnvKeyForModel("custom", "https://api.aimlapi.com/v1")).toBe(
|
|
"AIMLAPI_API_KEY",
|
|
);
|
|
expect(
|
|
expectedEnvKeyForModel("custom", "https://api.xiaomimimo.com/v1"),
|
|
).toBe("XIAOMI_API_KEY");
|
|
});
|
|
|
|
it("recognizes a known endpoint when provider is 'auto'", () => {
|
|
expect(expectedEnvKeyForModel("auto", "https://api.mistral.ai/v1")).toBe(
|
|
"MISTRAL_API_KEY",
|
|
);
|
|
});
|
|
|
|
it("returns null for unknown provider with unknown URL", () => {
|
|
expect(
|
|
expectedEnvKeyForModel("custom", "http://localhost:1234/v1"),
|
|
).toBeNull();
|
|
expect(expectedEnvKeyForModel("custom", "")).toBeNull();
|
|
expect(expectedEnvKeyForModel("", "")).toBeNull();
|
|
});
|
|
|
|
it("provider-name match wins over URL fallback when both are present", () => {
|
|
// If somehow provider is "anthropic" but baseUrl points at deepseek
|
|
// (configuration error), trust the provider name — the gateway
|
|
// dispatches by provider, not URL.
|
|
expect(
|
|
expectedEnvKeyForModel("anthropic", "https://api.deepseek.com/v1"),
|
|
).toBe("ANTHROPIC_API_KEY");
|
|
});
|
|
});
|
|
|
|
// The actual install-gate behavior is exercised end-to-end by importing
|
|
// the module under a per-test HERMES_HOME — same pattern as the other
|
|
// installer tests. Skipped here because the existing tests already cover
|
|
// the file-existence half; the gap was provider awareness, which the
|
|
// pure-function tests above pin down.
|