diff --git a/src/config/schema.test.ts b/src/config/schema.test.ts index 4fb5791..021a6d8 100644 --- a/src/config/schema.test.ts +++ b/src/config/schema.test.ts @@ -169,6 +169,16 @@ describe('configSchema — models auth_mode', () => { }); }).toThrow(/auth_mode/i); }); + + it('accepts vercel provider id', () => { + const result = configSchema.parse({ + ...minimalConfig, + models: { + default: { provider: 'vercel', model: 'openai/gpt-4.1', endpoint: 'https://ai-gateway.vercel.sh/v1', api_key: 'test-key' }, + }, + }); + expect(result.models.default.provider).toBe('vercel'); + }); }); describe('configSchema — skills watcher', () => { diff --git a/src/config/schema.ts b/src/config/schema.ts index c0b1efb..04695ef 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -39,7 +39,7 @@ const serverSchema = z.object({ }); /** All supported model provider identifiers. Used by the config schema and TUI autocompletion. */ -export const MODEL_PROVIDERS = ['anthropic', 'openai', 'gemini', 'ollama', 'llamacpp', 'openrouter', 'bedrock', 'github', 'zhipuai', 'xai', 'synthetic'] as const; +export const MODEL_PROVIDERS = ['anthropic', 'openai', 'gemini', 'ollama', 'llamacpp', 'openrouter', 'vercel', 'bedrock', 'github', 'zhipuai', 'xai', 'synthetic'] as const; export type ModelProvider = (typeof MODEL_PROVIDERS)[number]; diff --git a/src/daemon/clientFactory.test.ts b/src/daemon/clientFactory.test.ts index f290d67..e4013b2 100644 --- a/src/daemon/clientFactory.test.ts +++ b/src/daemon/clientFactory.test.ts @@ -103,6 +103,27 @@ describe('createClientFromConfig', () => { expect(client.constructor.name).toBe('OpenAIClient'); }); + it('creates OpenAIClient for vercel provider', async () => { + const prev = process.env.AI_GATEWAY_API_KEY; + process.env.AI_GATEWAY_API_KEY = 'test-key'; + + try { + const { createClientFromConfig } = await loadFactory(); + const client = createClientFromConfig({ + provider: 'vercel', + model: 'openai/gpt-4.1', + endpoint: 'https://ai-gateway.vercel.sh/v1', + }); + expect(client.constructor.name).toBe('OpenAIClient'); + } finally { + if (prev === undefined) { + delete process.env.AI_GATEWAY_API_KEY; + } else { + process.env.AI_GATEWAY_API_KEY = prev; + } + } + }); + it('creates OpenAIClient with Zhipu AI baseURL for zhipuai provider', async () => { const { createClientFromConfig } = await loadFactory(); const client = createClientFromConfig({ diff --git a/src/daemon/models.ts b/src/daemon/models.ts index 4b94b21..a636761 100644 --- a/src/daemon/models.ts +++ b/src/daemon/models.ts @@ -190,6 +190,12 @@ export function createClientFromConfig(cfg: ModelConfig): ModelClient { apiKey: requireApiKey(cfg, 'OPENROUTER_API_KEY'), baseURL: cfg.endpoint ?? 'https://openrouter.ai/api/v1', }); + case 'vercel': + return new OpenAIClient({ + model: cfg.model, + apiKey: requireApiKey(cfg, 'AI_GATEWAY_API_KEY'), + baseURL: cfg.endpoint ?? 'https://ai-gateway.vercel.sh/v1', + }); case 'zhipuai': if (cfg.use_oauth) { const apiKey = getZaiApiKey();