From 6ea83b6fbafb31d98f5d78fcac21c39b2c489b97 Mon Sep 17 00:00:00 2001 From: David Lo Dico Date: Wed, 18 Feb 2026 12:48:16 +0100 Subject: [PATCH] feat: add EUrouter as AI provider Add EUrouter (eurouter.ai) as an OpenAI-compatible AI provider for EU-based GDPR-compliant model routing. Uses the existing createOpenAICompatible pattern from @ai-sdk/openai-compatible. Co-Authored-By: Claude Opus 4.6 --- examples/09-ai/02-playground/src/data/aimodels.ts | 3 +++ packages/xl-ai-server/.env.example | 3 ++- .../xl-ai-server/src/routes/model-playground/index.ts | 6 ++++++ packages/xl-ai/src/testUtil/testAIModels.ts | 9 ++++++++- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/examples/09-ai/02-playground/src/data/aimodels.ts b/examples/09-ai/02-playground/src/data/aimodels.ts index 329805d1b2..caa69eb6a7 100644 --- a/examples/09-ai/02-playground/src/data/aimodels.ts +++ b/examples/09-ai/02-playground/src/data/aimodels.ts @@ -20,4 +20,7 @@ export const AI_MODELS = [ "google.generative-ai/gemini-1.5-flash", "google.generative-ai/gemini-2.5-pro", "google.generative-ai/gemini-2.5-flash", + "eurouter.chat/openai/gpt-4o", + "eurouter.chat/anthropic/claude-sonnet-4-5", + "eurouter.chat/google/gemini-2.5-pro", ]; diff --git a/packages/xl-ai-server/.env.example b/packages/xl-ai-server/.env.example index 531ac8a8ef..e92e8cf2a6 100644 --- a/packages/xl-ai-server/.env.example +++ b/packages/xl-ai-server/.env.example @@ -4,4 +4,5 @@ GROQ_API_KEY= ANTHROPIC_API_KEY= MISTRAL_API_KEY= ALBERT_ETALAB_API_KEY= -GOOGLE_API_KEY= \ No newline at end of file +GOOGLE_API_KEY= +EUROUTER_API_KEY= \ No newline at end of file diff --git a/packages/xl-ai-server/src/routes/model-playground/index.ts b/packages/xl-ai-server/src/routes/model-playground/index.ts index e113660614..b3eaf13a3a 100644 --- a/packages/xl-ai-server/src/routes/model-playground/index.ts +++ b/packages/xl-ai-server/src/routes/model-playground/index.ts @@ -73,6 +73,12 @@ function getModel(aiModelString: string) { baseURL: "https://albert.api.etalab.gouv.fr/v1", apiKey: providerKey, })(modelName); + } else if (provider === "eurouter.chat") { + return createOpenAICompatible({ + name: "eurouter", + baseURL: "https://eurouter.ai/api/v1", + apiKey: providerKey, + })(modelName); } else if (provider === "mistral.chat") { return createMistral({ apiKey: providerKey, diff --git a/packages/xl-ai/src/testUtil/testAIModels.ts b/packages/xl-ai/src/testUtil/testAIModels.ts index c6ed3a2b8a..953dae5bf5 100644 --- a/packages/xl-ai/src/testUtil/testAIModels.ts +++ b/packages/xl-ai/src/testUtil/testAIModels.ts @@ -22,12 +22,19 @@ const albert = createOpenAICompatible({ apiKey: process.env.ALBERT_API_KEY || "not-available-in-ci", })("albert-etalab.chat/albert-large"); +const eurouter = createOpenAICompatible({ + name: "eurouter", + baseURL: "https://eurouter.ai/api/v1", + apiKey: process.env.EUROUTER_API_KEY || "not-available-in-ci", +})("openai/gpt-4o"); + export const testAIModels: Record< - "groq" | "openai" | "albert" | "anthropic", + "groq" | "openai" | "albert" | "anthropic" | "eurouter", Exclude > = { groq, openai, albert, anthropic, + eurouter, };