Files

95 lines
3.5 KiB
TypeScript

import { describe, it, expect, vi } from 'vitest'
import { OpenAIProvider } from '../../src/providers/openai'
import { createProvider } from '../../src/providers/factory'
import type { MagpieConfig } from '../../src/config/types'
let lastConstructorOptions: Record<string, unknown> = {}
let lastCreateOptions: Record<string, unknown> = {}
vi.mock('openai', () => ({
default: class MockOpenAI {
chat = {
completions: {
create: vi.fn().mockImplementation((opts: Record<string, unknown>) => {
lastCreateOptions = opts
return Promise.resolve({
choices: [{ message: { content: 'Mock response' } }]
})
})
}
}
constructor(options: Record<string, unknown>) {
lastConstructorOptions = options
}
}
}))
describe('OpenAIProvider', () => {
it('should have correct name', () => {
const provider = new OpenAIProvider({ apiKey: 'test', model: 'gpt-4o' })
expect(provider.name).toBe('openai')
})
it('should call chat and return response', async () => {
const provider = new OpenAIProvider({ apiKey: 'test', model: 'gpt-4o' })
const result = await provider.chat([{ role: 'user', content: 'Hello' }])
expect(result).toBe('Mock response')
})
it('should pass baseURL to SDK when provided', () => {
new OpenAIProvider({ apiKey: 'test', model: 'gpt-4o', baseURL: 'https://my-proxy.example.com/v1' })
expect(lastConstructorOptions.baseURL).toBe('https://my-proxy.example.com/v1')
})
it('should not set baseURL when not provided', () => {
new OpenAIProvider({ apiKey: 'test', model: 'gpt-4o' })
expect(lastConstructorOptions.baseURL).toBeUndefined()
})
})
describe('OpenRouter via OpenAI client', () => {
const baseConfig: MagpieConfig = {
providers: {},
defaults: { max_rounds: 3, output_format: 'markdown' },
reviewers: {},
summarizer: { model: 'openrouter/anthropic/claude-3.5-sonnet', prompt: '' },
analyzer: { model: 'openrouter/anthropic/claude-3.5-sonnet', prompt: '' }
}
it('strips the openrouter/ prefix from the model and defaults baseURL to OpenRouter', async () => {
const config: MagpieConfig = {
...baseConfig,
providers: { openrouter: { api_key: 'or-key' } }
}
const provider = createProvider('openrouter/anthropic/claude-3.5-sonnet', config)
expect(lastConstructorOptions.apiKey).toBe('or-key')
expect(lastConstructorOptions.baseURL).toBe('https://openrouter.ai/api/v1')
// Invoke chat() so the stripped model reaches chat.completions.create
await provider.chat([{ role: 'user', content: 'hi' }])
expect(lastCreateOptions.model).toBe('anthropic/claude-3.5-sonnet')
})
it('honors a custom base_url from config and forwards the stripped model', async () => {
const config: MagpieConfig = {
...baseConfig,
providers: {
openrouter: { api_key: 'or-key', base_url: 'https://my-openrouter-proxy.example.com/v1' }
}
}
const provider = createProvider('openrouter/meta-llama/llama-3-70b-instruct', config)
expect(lastConstructorOptions.baseURL).toBe('https://my-openrouter-proxy.example.com/v1')
await provider.chat([{ role: 'user', content: 'hi' }])
expect(lastCreateOptions.model).toBe('meta-llama/llama-3-70b-instruct')
})
it('throws when the model is just "openrouter/" with no ID after it', () => {
const config: MagpieConfig = {
...baseConfig,
providers: { openrouter: { api_key: 'or-key' } }
}
expect(() => createProvider('openrouter/', config)).toThrow(/must include a model ID/)
})
})