Some checks failed
ci/woodpecker/push/ci Pipeline failed
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
143 lines
4.7 KiB
TypeScript
143 lines
4.7 KiB
TypeScript
import { beforeEach, afterEach, describe, expect, it } from 'vitest';
|
|
import { ProviderService } from '../provider.service.js';
|
|
|
|
const ENV_KEYS = [
|
|
'ANTHROPIC_API_KEY',
|
|
'OPENAI_API_KEY',
|
|
'ZAI_API_KEY',
|
|
'OLLAMA_BASE_URL',
|
|
'OLLAMA_HOST',
|
|
'OLLAMA_MODELS',
|
|
'MOSAIC_CUSTOM_PROVIDERS',
|
|
] as const;
|
|
|
|
type EnvKey = (typeof ENV_KEYS)[number];
|
|
|
|
describe('ProviderService', () => {
|
|
const savedEnv = new Map<EnvKey, string | undefined>();
|
|
|
|
beforeEach(() => {
|
|
for (const key of ENV_KEYS) {
|
|
savedEnv.set(key, process.env[key]);
|
|
delete process.env[key];
|
|
}
|
|
});
|
|
|
|
afterEach(() => {
|
|
for (const key of ENV_KEYS) {
|
|
const value = savedEnv.get(key);
|
|
if (value === undefined) {
|
|
delete process.env[key];
|
|
} else {
|
|
process.env[key] = value;
|
|
}
|
|
}
|
|
});
|
|
|
|
it('skips API-key providers when env vars are missing (no models become available)', async () => {
|
|
const service = new ProviderService(null);
|
|
await service.onModuleInit();
|
|
|
|
// Pi's built-in registry may include model definitions for all providers, but
|
|
// without API keys none of them should be available (usable).
|
|
const availableModels = service.listAvailableModels();
|
|
const availableProviderIds = new Set(availableModels.map((m) => m.provider));
|
|
|
|
expect(availableProviderIds).not.toContain('anthropic');
|
|
expect(availableProviderIds).not.toContain('openai');
|
|
expect(availableProviderIds).not.toContain('zai');
|
|
|
|
// Providers list may show built-in providers, but they should not be marked available
|
|
const providers = service.listProviders();
|
|
for (const p of providers.filter((p) => ['anthropic', 'openai', 'zai'].includes(p.id))) {
|
|
expect(p.available).toBe(false);
|
|
}
|
|
});
|
|
|
|
it('registers Anthropic provider with correct models when ANTHROPIC_API_KEY is set', async () => {
|
|
process.env['ANTHROPIC_API_KEY'] = 'test-anthropic';
|
|
|
|
const service = new ProviderService(null);
|
|
await service.onModuleInit();
|
|
|
|
const providers = service.listProviders();
|
|
const anthropic = providers.find((p) => p.id === 'anthropic');
|
|
expect(anthropic).toBeDefined();
|
|
expect(anthropic!.available).toBe(true);
|
|
expect(anthropic!.models.map((m) => m.id)).toEqual([
|
|
'claude-opus-4-6',
|
|
'claude-sonnet-4-6',
|
|
'claude-haiku-4-5',
|
|
]);
|
|
// All Anthropic models have 200k context window
|
|
for (const m of anthropic!.models) {
|
|
expect(m.contextWindow).toBe(200000);
|
|
}
|
|
});
|
|
|
|
it('registers OpenAI provider with correct models when OPENAI_API_KEY is set', async () => {
|
|
process.env['OPENAI_API_KEY'] = 'test-openai';
|
|
|
|
const service = new ProviderService(null);
|
|
await service.onModuleInit();
|
|
|
|
const providers = service.listProviders();
|
|
const openai = providers.find((p) => p.id === 'openai');
|
|
expect(openai).toBeDefined();
|
|
expect(openai!.available).toBe(true);
|
|
expect(openai!.models.map((m) => m.id)).toEqual(['codex-gpt-5-4']);
|
|
});
|
|
|
|
it('registers Z.ai provider with correct models when ZAI_API_KEY is set', async () => {
|
|
process.env['ZAI_API_KEY'] = 'test-zai';
|
|
|
|
const service = new ProviderService(null);
|
|
await service.onModuleInit();
|
|
|
|
const providers = service.listProviders();
|
|
const zai = providers.find((p) => p.id === 'zai');
|
|
expect(zai).toBeDefined();
|
|
expect(zai!.available).toBe(true);
|
|
// Pi's registry may include additional glm variants; verify our registered model is present
|
|
expect(zai!.models.map((m) => m.id)).toContain('glm-5');
|
|
});
|
|
|
|
it('registers all three providers when all keys are set', async () => {
|
|
process.env['ANTHROPIC_API_KEY'] = 'test-anthropic';
|
|
process.env['OPENAI_API_KEY'] = 'test-openai';
|
|
process.env['ZAI_API_KEY'] = 'test-zai';
|
|
|
|
const service = new ProviderService(null);
|
|
await service.onModuleInit();
|
|
|
|
const providerIds = service.listProviders().map((p) => p.id);
|
|
expect(providerIds).toContain('anthropic');
|
|
expect(providerIds).toContain('openai');
|
|
expect(providerIds).toContain('zai');
|
|
});
|
|
|
|
it('can find registered Anthropic models by provider+id', async () => {
|
|
process.env['ANTHROPIC_API_KEY'] = 'test-anthropic';
|
|
|
|
const service = new ProviderService(null);
|
|
await service.onModuleInit();
|
|
|
|
const sonnet = service.findModel('anthropic', 'claude-sonnet-4-6');
|
|
expect(sonnet).toBeDefined();
|
|
expect(sonnet!.provider).toBe('anthropic');
|
|
expect(sonnet!.id).toBe('claude-sonnet-4-6');
|
|
});
|
|
|
|
it('can find registered Z.ai models by provider+id', async () => {
|
|
process.env['ZAI_API_KEY'] = 'test-zai';
|
|
|
|
const service = new ProviderService(null);
|
|
await service.onModuleInit();
|
|
|
|
const glm = service.findModel('zai', 'glm-4.5');
|
|
expect(glm).toBeDefined();
|
|
expect(glm!.provider).toBe('zai');
|
|
expect(glm!.id).toBe('glm-4.5');
|
|
});
|
|
});
|