Skip to content

Commit 0329a9c

Browse files
feat(compiler): added openrouter sdk support in compiler (#917)
Co-authored-by: Vaibhav Patil <[email protected]>
1 parent 95c23cc commit 0329a9c

File tree

11 files changed

+112
-1
lines changed

11 files changed

+112
-1
lines changed

.changeset/tidy-drinks-lie.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@lingo.dev/_compiler": minor
3+
"@lingo.dev/_spec": patch
4+
"lingo.dev": patch
5+
---
6+
7+
add openrouter ais support for compiler

packages/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@
128128
"@lingo.dev/_sdk": "workspace:*",
129129
"@lingo.dev/_spec": "workspace:*",
130130
"@modelcontextprotocol/sdk": "^1.5.0",
131+
"@openrouter/ai-sdk-provider": "^0.7.1",
131132
"@paralleldrive/cuid2": "^2.2.2",
132133
"ai": "^4.3.15",
133134
"bitbucket": "^2.12.0",

packages/cli/src/cli/localizer/explicit.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createAnthropic } from "@ai-sdk/anthropic";
22
import { createGoogleGenerativeAI } from "@ai-sdk/google";
33
import { createOpenAI } from "@ai-sdk/openai";
4+
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
45
import { I18nConfig } from "@lingo.dev/_spec";
56
import chalk from "chalk";
67
import dedent from "dedent";
@@ -52,6 +53,15 @@ export default function createExplicitLocalizer(
5253
apiKeyName: "GOOGLE_API_KEY",
5354
baseUrl: provider.baseUrl,
5455
});
56+
case "openrouter":
57+
return createAiSdkLocalizer({
58+
factory: (params) =>
59+
createOpenRouter(params).languageModel(provider.model),
60+
id: provider.id,
61+
prompt: provider.prompt,
62+
apiKeyName: "OPENROUTER_API_KEY",
63+
baseUrl: provider.baseUrl,
64+
});
5565
case "ollama":
5666
return createAiSdkLocalizer({
5767
factory: (_params) => createOllama().languageModel(provider.model),

packages/cli/src/cli/processor/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { createOpenAI } from "@ai-sdk/openai";
88
import { colors } from "../constants";
99
import { createAnthropic } from "@ai-sdk/anthropic";
1010
import { createGoogleGenerativeAI } from "@ai-sdk/google";
11+
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
1112
import { createOllama } from "ollama-ai-provider";
1213

1314
export default function createProcessor(
@@ -81,6 +82,17 @@ function getPureModelProvider(provider: I18nConfig["provider"]) {
8182
apiKey: process.env.GOOGLE_API_KEY,
8283
})(provider.model);
8384
}
85+
case "openrouter": {
86+
if (!process.env.OPENROUTER_API_KEY) {
87+
throw new Error(
88+
createMissingKeyErrorMessage("OpenRouter", "OPENROUTER_API_KEY"),
89+
);
90+
}
91+
return createOpenRouter({
92+
apiKey: process.env.OPENROUTER_API_KEY,
93+
baseURL: provider.baseUrl,
94+
})(provider.model);
95+
}
8496
case "ollama": {
8597
// No API key check needed for Ollama
8698
return createOllama()(provider.model);

packages/cli/src/cli/utils/settings.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export function getSettings(explicitApiKey: string | undefined): CliSettings {
3737
anthropicApiKey: env.ANTHROPIC_API_KEY || systemFile.llm?.anthropicApiKey,
3838
groqApiKey: env.GROQ_API_KEY || systemFile.llm?.groqApiKey,
3939
googleApiKey: env.GOOGLE_API_KEY || systemFile.llm?.googleApiKey,
40+
openrouterApiKey:env.OPENROUTER_API_KEY || systemFile.llm?.openrouterApiKey,
4041
},
4142
};
4243
}
@@ -70,6 +71,7 @@ const SettingsSchema = Z.object({
7071
anthropicApiKey: Z.string().optional(),
7172
groqApiKey: Z.string().optional(),
7273
googleApiKey: Z.string().optional(),
74+
openrouterApiKey: Z.string().optional(),
7375
}),
7476
});
7577

@@ -99,6 +101,7 @@ function _loadEnv() {
99101
ANTHROPIC_API_KEY: Z.string().optional(),
100102
GROQ_API_KEY: Z.string().optional(),
101103
GOOGLE_API_KEY: Z.string().optional(),
104+
OPENROUTER_API_KEY: Z.string().optional(),
102105
})
103106
.passthrough()
104107
.parse(process.env);
@@ -122,6 +125,7 @@ function _loadSystemFile() {
122125
anthropicApiKey: Z.string().optional(),
123126
groqApiKey: Z.string().optional(),
124127
googleApiKey: Z.string().optional(),
128+
openrouterApiKey: Z.string().optional(),
125129
}).optional(),
126130
})
127131
.passthrough()
@@ -192,6 +196,12 @@ function _envVarsInfo() {
192196
`ℹ️ Using GOOGLE_API_KEY env var instead of key from user config`,
193197
);
194198
}
199+
if (env.OPENROUTER_API_KEY && systemFile.llm?.openrouterApiKey) {
200+
console.info(
201+
"\x1b[36m%s\x1b[0m",
202+
`ℹ️ Using OPENROUTER_API_KEY env var instead of key from user config`,
203+
);
204+
}
195205
if (env.LINGODOTDEV_API_URL) {
196206
console.info(
197207
"\x1b[36m%s\x1b[0m",

packages/compiler/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"@babel/parser": "^7.26.7",
4343
"@babel/traverse": "^7.27.4",
4444
"@babel/types": "^7.26.7",
45+
"@openrouter/ai-sdk-provider": "^0.7.1",
4546
"ai": "^4.2.10",
4647
"dedent": "^1.6.0",
4748
"dotenv": "^16.4.5",

packages/compiler/src/lib/lcp/api/index.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { createGroq } from "@ai-sdk/groq";
22
import { createGoogleGenerativeAI } from "@ai-sdk/google";
3+
import { createOpenRouter } from '@openrouter/ai-sdk-provider';
34
import { createOllama } from "ollama-ai-provider";
45
import { generateText } from "ai";
56
import { DictionarySchema } from "../schema";
@@ -13,6 +14,8 @@ import {
1314
getGroqKeyFromEnv,
1415
getGoogleKey,
1516
getGoogleKeyFromEnv,
17+
getOpenRouterKey,
18+
getOpenRouterKeyFromEnv,
1619
} from "../../../utils/llm-api-key";
1720
import dedent from "dedent";
1821
import { isRunningInCIOrDocker } from "../../../utils/env";
@@ -251,6 +254,27 @@ export class LCPAPI {
251254
`Creating Google Generative AI client for ${targetLocale} using model ${modelId}`,
252255
);
253256
return createGoogleGenerativeAI({ apiKey: googleKey })(modelId);
257+
}
258+
case "openrouter": {
259+
// Specific check for CI/CD or Docker missing OpenRouter key
260+
if (isRunningInCIOrDocker()) {
261+
const openRouterFromEnv = getOpenRouterKeyFromEnv();
262+
if (!openRouterFromEnv) {
263+
this._failMissingLLMKeyCi(providerId);
264+
}
265+
}
266+
const openRouterKey = getOpenRouterKey();
267+
if (!openRouterKey) {
268+
throw new Error(
269+
"⚠️ OpenRouter API key not found. Please set OPENROUTER_API_KEY environment variable or configure it user-wide.",
270+
);
271+
}
272+
console.log(
273+
`Creating OpenRouter client for ${targetLocale} using model ${modelId}`,
274+
);
275+
return createOpenRouter({
276+
apiKey: openRouterKey,
277+
})(modelId);
254278
}
255279

256280
case "ollama": {

packages/compiler/src/lib/lcp/api/provider-details.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { openrouter } from "@openrouter/ai-sdk-provider";
2+
13
export const providerDetails: Record<
24
string,
35
{
@@ -22,6 +24,13 @@ export const providerDetails: Record<
2224
getKeyLink: "https://ai.google.dev/",
2325
docsLink: "https://ai.google.dev/gemini-api/docs/troubleshooting",
2426
},
27+
openrouter: {
28+
name: "OpenRouter",
29+
apiKeyEnvVar: "OPENROUTER_API_KEY",
30+
apiKeyConfigKey: "llm.openrouterApiKey",
31+
getKeyLink: "https://openrouter.ai",
32+
docsLink: "https://openrouter.ai/docs",
33+
},
2534
ollama: {
2635
name: "Ollama",
2736
apiKeyEnvVar: undefined, // Ollama doesn't require an API key

packages/compiler/src/utils/llm-api-key.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,13 @@ export function getGoogleKeyFromRc() {
4848
export function getGoogleKeyFromEnv() {
4949
return getKeyFromEnv("GOOGLE_API_KEY");
5050
}
51+
52+
export function getOpenRouterKey() {
53+
return getOpenRouterKeyFromEnv() || getOpenRouterKeyFromRc();
54+
}
55+
export function getOpenRouterKeyFromRc() {
56+
return getKeyFromRc("llm.openrouterApiKey");
57+
}
58+
export function getOpenRouterKeyFromEnv() {
59+
return getKeyFromEnv("OPENROUTER_API_KEY");
60+
}

packages/spec/src/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ export const configV1_4Definition = extendConfigDefinition(
254254
// v1.4 -> v1.5
255255
// Changes: add "provider" field to the config
256256
const providerSchema = Z.object({
257-
id: Z.enum(["openai", "anthropic", "google", "ollama"]),
257+
id: Z.enum(["openai", "anthropic", "google", "ollama", "openrouter"]),
258258
model: Z.string(),
259259
prompt: Z.string(),
260260
baseUrl: Z.string().optional(),

0 commit comments

Comments
 (0)