Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions src/main/config-health.ts
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,7 @@ const DRIFT_FIELDS: ReadonlyArray<{
label: "ANTHROPIC_API_KEY (.env)",
},
{ source: "env", field: "OPENAI_API_KEY", label: "OPENAI_API_KEY (.env)" },
{ source: "env", field: "EVOLINK_API_KEY", label: "EVOLINK_API_KEY (.env)" },
{
source: "env",
field: "DEEPSEEK_API_KEY",
Expand Down
9 changes: 8 additions & 1 deletion src/main/default-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ const DEFAULT_MODELS: DefaultModel[] = [
baseUrl: "",
},

// ── EvoLink (OpenAI-compatible gateway) ────────────────────────────
{
name: "EvoLink GPT-5.2",
provider: "custom",
model: "gpt-5.2",
baseUrl: "https://direct.evolink.ai/v1",
},

// ── Ollama Cloud ─────────────────────────────────────────────────
{
name: "glm-5.1",
Expand Down Expand Up @@ -93,7 +101,6 @@ const DEFAULT_MODELS: DefaultModel[] = [
model: "Qwen/Qwen3-235B-A22B-Instruct-2507",
baseUrl: "",
},

];

export default DEFAULT_MODELS;
1 change: 1 addition & 0 deletions src/main/hermes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2137,6 +2137,7 @@ function sendMessageViaCli(
"OPENAI_API_KEY",
"OLLAMA_API_KEY",
"AIMLAPI_API_KEY",
"EVOLINK_API_KEY",
"ANTHROPIC_API_KEY",
"GROQ_API_KEY",
"DEEPSEEK_API_KEY",
Expand Down
2 changes: 2 additions & 0 deletions src/main/installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ const PROVIDER_ENV_KEYS: Record<string, string> = {
openai: "OPENAI_API_KEY",
"ollama-cloud": "OLLAMA_API_KEY",
aimlapi: "AIMLAPI_API_KEY",
evolink: "EVOLINK_API_KEY",
google: "GOOGLE_API_KEY",
xai: "XAI_API_KEY",
groq: "GROQ_API_KEY",
Expand Down Expand Up @@ -341,6 +342,7 @@ const URL_TO_ENV_KEY: Array<[RegExp, string]> = [
[/openai\.com/i, "OPENAI_API_KEY"],
[/(^|\/\/|\.)ollama\.com(?=\/|:|$)/i, "OLLAMA_API_KEY"],
[/api\.aimlapi\.com/i, "AIMLAPI_API_KEY"],
[/direct\.evolink\.ai/i, "EVOLINK_API_KEY"],
[/huggingface\.co/i, "HF_TOKEN"],
[/api\.groq\.com/i, "GROQ_API_KEY"],
[/api\.deepseek\.com/i, "DEEPSEEK_API_KEY"],
Expand Down
18 changes: 18 additions & 0 deletions src/renderer/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,18 @@ export const PROVIDERS = {
baseUrl: "https://api.aimlapi.com/v1",
needsKey: true,
},
{
id: "evolink",
name: "EvoLink",
desc: "OpenAI-compatible gateway",
tag: "",
envKey: "EVOLINK_API_KEY",
url: "https://evolink.ai/dashboard/keys",
placeholder: "sk-...",
configProvider: "custom",
baseUrl: "https://direct.evolink.ai/v1",
needsKey: true,
},
{
id: "openai",
name: "constants.openaiName",
Expand Down Expand Up @@ -492,6 +504,12 @@ export const SETTINGS_SECTIONS: SectionDef[] = [
type: "password",
hint: "constants.aimlapiHint",
},
{
key: "EVOLINK_API_KEY",
label: "EvoLink API key",
type: "password",
hint: "https://direct.evolink.ai/v1",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Hint shows API endpoint URL, not key-management URL

The hint field for EVOLINK_API_KEY is set to "https://direct.evolink.ai/v1" — the API base URL rather than a page where users can obtain a key. Every other provider entry either uses an i18n hint key (e.g., "constants.aimlapiHint") or omits the field, none of them point at the service's /v1 endpoint. A user opening the settings panel to find their key will see a URL that navigates to the API gateway, not the key dashboard. The key URL "https://evolink.ai/dashboard/keys" is already in the PROVIDERS.setup entry and would be the more helpful hint value here.

},
{
key: "ANTHROPIC_API_KEY",
label: "constants.anthropicApiKey",
Expand Down
1 change: 1 addition & 0 deletions src/shared/url-key-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const URL_KEY_MAP: ReadonlyArray<UrlKeyMapping> = [
{ pattern: /openai\.com/i, envKey: "OPENAI_API_KEY" },
{ pattern: /ollama\.com/i, envKey: "OLLAMA_API_KEY" },
{ pattern: /api\.aimlapi\.com/i, envKey: "AIMLAPI_API_KEY" },
{ pattern: /direct\.evolink\.ai/i, envKey: "EVOLINK_API_KEY" },
{ pattern: /huggingface\.co/i, envKey: "HF_TOKEN" },
{ pattern: /api\.groq\.com/i, envKey: "GROQ_API_KEY" },
{ pattern: /api\.deepseek\.com/i, envKey: "DEEPSEEK_API_KEY" },
Expand Down
12 changes: 12 additions & 0 deletions tests/constants.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ describe("PROVIDERS", () => {
}
});

it("configures EvoLink through the custom OpenAI-compatible endpoint path", () => {
expect(
PROVIDERS.setup.find((entry) => entry.id === "evolink"),
).toMatchObject({
envKey: "EVOLINK_API_KEY",
configProvider: "custom",
baseUrl: "https://direct.evolink.ai/v1",
needsKey: true,
});
});

it("no duplicate option values", () => {
const values = PROVIDERS.options.map((o) => o.value);
expect(new Set(values).size).toBe(values.length);
Expand Down Expand Up @@ -188,6 +199,7 @@ describe("SETTINGS_SECTIONS", () => {
expect(allKeys).toContain("XAI_API_KEY");
expect(allKeys).toContain("XIAOMI_API_KEY");
expect(allKeys).toContain("AIMLAPI_API_KEY");
expect(allKeys).toContain("EVOLINK_API_KEY");
});

it("includes existing keys (backward compat)", () => {
Expand Down
17 changes: 17 additions & 0 deletions tests/default-models.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { describe, expect, it } from "vitest";
import DEFAULT_MODELS from "../src/main/default-models";

describe("DEFAULT_MODELS", () => {
it("seeds EvoLink through the custom OpenAI-compatible endpoint path", () => {
expect(DEFAULT_MODELS).toEqual(
expect.arrayContaining([
expect.objectContaining({
name: "EvoLink GPT-5.2",
provider: "custom",
model: "gpt-5.2",
baseUrl: "https://direct.evolink.ai/v1",
}),
]),
);
});
});
10 changes: 7 additions & 3 deletions tests/install-gate-providers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ describe("expectedEnvKeyForModel — provider-name lookup", () => {
["openai", "OPENAI_API_KEY"],
["ollama-cloud", "OLLAMA_API_KEY"],
["aimlapi", "AIMLAPI_API_KEY"],
["evolink", "EVOLINK_API_KEY"],
["google", "GOOGLE_API_KEY"],
["xai", "XAI_API_KEY"],
["deepseek", "DEEPSEEK_API_KEY"], // the specific provider from issue #236
Expand Down Expand Up @@ -59,12 +60,15 @@ describe("expectedEnvKeyForModel — URL fallback for custom/auto providers", ()
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://ollama.com/v1")).toBe(
"OLLAMA_API_KEY",
);
expect(expectedEnvKeyForModel("custom", "https://api.aimlapi.com/v1")).toBe(
"AIMLAPI_API_KEY",
);
expect(
expectedEnvKeyForModel("custom", "https://direct.evolink.ai/v1"),
).toBe("EVOLINK_API_KEY");
expect(
expectedEnvKeyForModel("custom", "https://api.xiaomimimo.com/v1"),
).toBe("XIAOMI_API_KEY");
Expand Down
1 change: 1 addition & 0 deletions tests/url-key-map.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe("URL_KEY_MAP", () => {
"https://api.anthropic.com/v1": "ANTHROPIC_API_KEY",
"https://api.openai.com/v1": "OPENAI_API_KEY",
"https://api.aimlapi.com/v1": "AIMLAPI_API_KEY",
"https://direct.evolink.ai/v1": "EVOLINK_API_KEY",
"https://huggingface.co/api": "HF_TOKEN",
"https://api.groq.com/openai/v1": "GROQ_API_KEY",
"https://api.deepseek.com/v1": "DEEPSEEK_API_KEY",
Expand Down