docs(cli): add Vercel provider to setup and doctor
This commit is contained in:
@@ -145,6 +145,7 @@ If you want a fast mental model of where to start as an AI agent / contributor:
|
|||||||
|----------|--------|
|
|----------|--------|
|
||||||
| Anthropic | `provider: anthropic`, `api_key` or `auth_token` |
|
| Anthropic | `provider: anthropic`, `api_key` or `auth_token` |
|
||||||
| OpenAI | `provider: openai`, `api_key`, optional `endpoint` |
|
| OpenAI | `provider: openai`, `api_key`, optional `endpoint` |
|
||||||
|
| Vercel AI Gateway | `provider: vercel`, `api_key` or `AI_GATEWAY_API_KEY`, optional `endpoint` |
|
||||||
| GitHub Copilot | `provider: github`, auto-login via OAuth device flow |
|
| GitHub Copilot | `provider: github`, auto-login via OAuth device flow |
|
||||||
| Gemini | `provider: gemini`, `api_key` |
|
| Gemini | `provider: gemini`, `api_key` |
|
||||||
| Bedrock | `provider: bedrock`, AWS credentials |
|
| Bedrock | `provider: bedrock`, AWS credentials |
|
||||||
|
|||||||
@@ -331,6 +331,37 @@ models:
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('reports WARN when Vercel AI Gateway has no available API key sources', async () => {
|
||||||
|
const originalKey = process.env.AI_GATEWAY_API_KEY;
|
||||||
|
delete process.env.AI_GATEWAY_API_KEY;
|
||||||
|
|
||||||
|
try {
|
||||||
|
mkdirSync(testDir, { recursive: true });
|
||||||
|
const configPath = join(testDir, 'vercel-missing.yaml');
|
||||||
|
writeFileSync(configPath, `
|
||||||
|
telegram:
|
||||||
|
bot_token: "test-token"
|
||||||
|
allowed_chat_ids: [123]
|
||||||
|
models:
|
||||||
|
default:
|
||||||
|
provider: vercel
|
||||||
|
model: openai/gpt-4.1
|
||||||
|
`);
|
||||||
|
|
||||||
|
const ctx: DoctorContext = { configPath, dataDir: testDir };
|
||||||
|
const results = await runChecks(ctx);
|
||||||
|
const modelCheck = results.find(r => r.label.includes('Model connectivity')) as CheckResult | undefined;
|
||||||
|
expect(modelCheck?.status).toBe('warn');
|
||||||
|
expect(modelCheck?.detail).toContain('AI_GATEWAY_API_KEY');
|
||||||
|
} finally {
|
||||||
|
if (originalKey) {
|
||||||
|
process.env.AI_GATEWAY_API_KEY = originalKey;
|
||||||
|
} else {
|
||||||
|
delete process.env.AI_GATEWAY_API_KEY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('reports FAIL when Anthropic auth_mode=oauth has no available auth token sources', async () => {
|
it('reports FAIL when Anthropic auth_mode=oauth has no available auth token sources', async () => {
|
||||||
const originalHome = process.env.HOME;
|
const originalHome = process.env.HOME;
|
||||||
const originalToken = process.env.ANTHROPIC_AUTH_TOKEN;
|
const originalToken = process.env.ANTHROPIC_AUTH_TOKEN;
|
||||||
|
|||||||
+2
-1
@@ -280,11 +280,12 @@ const checkModelConnectivity: Check = async (ctx) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Providers with API-key style auth (no auth store integration yet)
|
// Providers with API-key style auth (no auth store integration yet)
|
||||||
const needsKey = ['gemini', 'openrouter', 'xai', 'github'];
|
const needsKey = ['gemini', 'openrouter', 'vercel', 'xai', 'github'];
|
||||||
if (needsKey.includes(provider)) {
|
if (needsKey.includes(provider)) {
|
||||||
const envVarMap: Record<string, string> = {
|
const envVarMap: Record<string, string> = {
|
||||||
gemini: 'GEMINI_API_KEY',
|
gemini: 'GEMINI_API_KEY',
|
||||||
openrouter: 'OPENROUTER_API_KEY',
|
openrouter: 'OPENROUTER_API_KEY',
|
||||||
|
vercel: 'AI_GATEWAY_API_KEY',
|
||||||
xai: 'XAI_API_KEY',
|
xai: 'XAI_API_KEY',
|
||||||
github: 'GITHUB_TOKEN',
|
github: 'GITHUB_TOKEN',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -61,4 +61,18 @@ describe('setupProviders', () => {
|
|||||||
expect(config.models.fast).toBeDefined();
|
expect(config.models.fast).toBeDefined();
|
||||||
expect(config.models.fast.provider).toBe('anthropic');
|
expect(config.models.fast.provider).toBe('anthropic');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('configures vercel gateway as default provider (second tier)', async () => {
|
||||||
|
// Pick "More providers..." then pick "Vercel AI Gateway".
|
||||||
|
// Prompts: api key, endpoint, model, then confirm fast tier.
|
||||||
|
const rl = mockReadline(['4', '3', 'sk-vercel-test123', '', '', 'n']);
|
||||||
|
const p = createPrompter(rl);
|
||||||
|
const builder = new ConfigBuilder();
|
||||||
|
await setupProviders(p, builder);
|
||||||
|
const config = builder.build();
|
||||||
|
expect(config.models.default.provider).toBe('vercel');
|
||||||
|
expect(config.models.default.api_key).toBe('sk-vercel-test123');
|
||||||
|
expect(config.models.default.endpoint).toBe('https://ai-gateway.vercel.sh/v1');
|
||||||
|
expect(config.models.default.model).toBe('openai/gpt-4.1');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const TOP_TIER: ProviderDef[] = [
|
|||||||
const SECOND_TIER: ProviderDef[] = [
|
const SECOND_TIER: ProviderDef[] = [
|
||||||
{ name: 'Gemini', provider: 'gemini', defaultModel: 'gemini-2.5-flash', fastModel: 'gemini-2.0-flash-lite', needsApiKey: true, needsEndpoint: false, apiKeyLabel: 'Gemini API key' },
|
{ name: 'Gemini', provider: 'gemini', defaultModel: 'gemini-2.5-flash', fastModel: 'gemini-2.0-flash-lite', needsApiKey: true, needsEndpoint: false, apiKeyLabel: 'Gemini API key' },
|
||||||
{ name: 'OpenRouter', provider: 'openrouter', defaultModel: 'anthropic/claude-sonnet-4', needsApiKey: true, needsEndpoint: false, apiKeyLabel: 'OpenRouter API key' },
|
{ name: 'OpenRouter', provider: 'openrouter', defaultModel: 'anthropic/claude-sonnet-4', needsApiKey: true, needsEndpoint: false, apiKeyLabel: 'OpenRouter API key' },
|
||||||
|
{ name: 'Vercel AI Gateway', provider: 'vercel', defaultModel: 'openai/gpt-4.1', fastModel: 'openai/gpt-4.1-mini', needsApiKey: true, needsEndpoint: true, defaultEndpoint: 'https://ai-gateway.vercel.sh/v1', apiKeyLabel: 'Vercel AI Gateway API key' },
|
||||||
{ name: 'Z.AI (GLM)', provider: 'zhipuai', defaultModel: 'glm-4.7', needsApiKey: true, needsEndpoint: true, defaultEndpoint: 'https://api.z.ai/api/paas/v4', apiKeyLabel: 'Z.AI API key' },
|
{ name: 'Z.AI (GLM)', provider: 'zhipuai', defaultModel: 'glm-4.7', needsApiKey: true, needsEndpoint: true, defaultEndpoint: 'https://api.z.ai/api/paas/v4', apiKeyLabel: 'Z.AI API key' },
|
||||||
{ name: 'xAI (Grok)', provider: 'xai', defaultModel: 'grok-3', fastModel: 'grok-3-mini', needsApiKey: true, needsEndpoint: false, apiKeyLabel: 'xAI API key' },
|
{ name: 'xAI (Grok)', provider: 'xai', defaultModel: 'grok-3', fastModel: 'grok-3-mini', needsApiKey: true, needsEndpoint: false, apiKeyLabel: 'xAI API key' },
|
||||||
{ name: 'Amazon Bedrock', provider: 'bedrock', defaultModel: 'anthropic.claude-sonnet-4-20250514-v1:0', needsApiKey: false, needsEndpoint: false },
|
{ name: 'Amazon Bedrock', provider: 'bedrock', defaultModel: 'anthropic.claude-sonnet-4-20250514-v1:0', needsApiKey: false, needsEndpoint: false },
|
||||||
@@ -33,6 +34,7 @@ const PROVIDER_HELP: Record<string, string> = {
|
|||||||
ollama: 'Ollama runs locally — install from https://ollama.com and run: ollama serve',
|
ollama: 'Ollama runs locally — install from https://ollama.com and run: ollama serve',
|
||||||
gemini: 'Get your API key at https://aistudio.google.com/apikey',
|
gemini: 'Get your API key at https://aistudio.google.com/apikey',
|
||||||
openrouter: 'Get your API key at https://openrouter.ai/keys (supports 200+ models)',
|
openrouter: 'Get your API key at https://openrouter.ai/keys (supports 200+ models)',
|
||||||
|
vercel: 'Vercel AI Gateway uses an API key (AI_GATEWAY_API_KEY) and an OpenAI-compatible base URL (default: https://ai-gateway.vercel.sh/v1)',
|
||||||
zhipuai: 'Get your API key at https://z.ai/manage-apikey/apikey-list (Coding Plan endpoint: https://api.z.ai/api/coding/paas/v4)',
|
zhipuai: 'Get your API key at https://z.ai/manage-apikey/apikey-list (Coding Plan endpoint: https://api.z.ai/api/coding/paas/v4)',
|
||||||
xai: 'Get your API key at https://console.x.ai',
|
xai: 'Get your API key at https://console.x.ai',
|
||||||
bedrock: 'Uses AWS credentials from environment (~/.aws/credentials or IAM role)',
|
bedrock: 'Uses AWS credentials from environment (~/.aws/credentials or IAM role)',
|
||||||
|
|||||||
Reference in New Issue
Block a user