Skip to content

Commit afee778

Browse files
committed
feat: add @ai-sdk/gateway dependency and integrate VercelLLMAdapter for AI service
1 parent ca2b14f commit afee778

3 files changed

Lines changed: 49 additions & 2 deletions

File tree

packages/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"topicSeparator": " "
4040
},
4141
"dependencies": {
42+
"@ai-sdk/gateway": "^3.0.84",
4243
"@objectstack/core": "workspace:*",
4344
"@objectstack/driver-memory": "workspace:^",
4445
"@objectstack/objectql": "workspace:^",

packages/cli/src/commands/serve.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,51 @@ export default class Serve extends Command {
328328
if (!hasAIPlugin) {
329329
try {
330330
const aiPkg = '@objectstack/service-ai';
331-
const { AIServicePlugin } = await import(/* webpackIgnore: true */ aiPkg);
332-
await kernel.use(new AIServicePlugin());
331+
const { AIServicePlugin, VercelLLMAdapter } = await import(/* webpackIgnore: true */ aiPkg);
332+
333+
// Auto-detect LLM provider from environment variables.
334+
// Priority: 1) Vercel AI Gateway 2) Direct provider SDKs 3) MemoryLLMAdapter (echo)
335+
let adapter: any = undefined;
336+
337+
// 1. Vercel AI Gateway — works with any provider via gateway('provider/model')
338+
// Uses OIDC on Vercel, VERCEL_API_KEY locally.
339+
const gatewayModel = process.env.AI_GATEWAY_MODEL; // e.g. 'anthropic/claude-sonnet-4.6'
340+
if (gatewayModel) {
341+
try {
342+
const gatewayPkg = '@ai-sdk/gateway';
343+
const { gateway } = await import(/* webpackIgnore: true */ gatewayPkg);
344+
adapter = new VercelLLMAdapter({ model: gateway(gatewayModel) });
345+
} catch {
346+
// @ai-sdk/gateway not installed
347+
}
348+
}
349+
350+
// 2. Direct provider SDKs
351+
if (!adapter) {
352+
const providerConfigs: Array<{ envKey: string; pkg: string; factory: string; defaultModel: string }> = [
353+
{ envKey: 'OPENAI_API_KEY', pkg: '@ai-sdk/openai', factory: 'openai', defaultModel: 'gpt-4o' },
354+
{ envKey: 'ANTHROPIC_API_KEY', pkg: '@ai-sdk/anthropic', factory: 'anthropic', defaultModel: 'claude-sonnet-4-20250514' },
355+
{ envKey: 'GOOGLE_GENERATIVE_AI_API_KEY', pkg: '@ai-sdk/google', factory: 'google', defaultModel: 'gemini-2.0-flash' },
356+
];
357+
358+
for (const { envKey, pkg, factory, defaultModel } of providerConfigs) {
359+
if (process.env[envKey]) {
360+
try {
361+
const mod = await import(/* webpackIgnore: true */ pkg);
362+
const createModel = mod[factory] ?? mod.default;
363+
if (typeof createModel === 'function') {
364+
const modelId = process.env.AI_MODEL ?? defaultModel;
365+
adapter = new VercelLLMAdapter({ model: createModel(modelId) });
366+
break;
367+
}
368+
} catch {
369+
// Provider SDK not installed — skip
370+
}
371+
}
372+
}
373+
}
374+
375+
await kernel.use(new AIServicePlugin(adapter ? { adapter } : undefined));
333376
trackPlugin('AIService');
334377
} catch {
335378
// @objectstack/service-ai not installed — AI features unavailable

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)