cf403250e0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
52 lines
1.6 KiB
TypeScript
52 lines
1.6 KiB
TypeScript
import type { LlmConfig } from '../config/llmConfig.js';
|
|
import type { RenderedPrompt } from './promptTemplate.js';
|
|
|
|
const OPENROUTER_URL = 'https://openrouter.ai/api/v1/chat/completions';
|
|
|
|
export interface CompletionRequest extends RenderedPrompt {
|
|
maxTokens?: number;
|
|
temperature?: number;
|
|
}
|
|
|
|
export interface OpenRouterClient {
|
|
complete(request: CompletionRequest): Promise<string | null>;
|
|
}
|
|
|
|
export function createOpenRouterClient(config: LlmConfig): OpenRouterClient {
|
|
return {
|
|
async complete(request: CompletionRequest): Promise<string | null> {
|
|
try {
|
|
const response = await fetch(OPENROUTER_URL, {
|
|
method: 'POST',
|
|
signal: AbortSignal.timeout(config.timeoutMs),
|
|
headers: {
|
|
'Authorization': `Bearer ${config.apiKey}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
model: config.model,
|
|
max_tokens: request.maxTokens ?? config.maxTokens,
|
|
temperature: request.temperature ?? config.temperature,
|
|
messages: [
|
|
{ role: 'system', content: request.system },
|
|
{ role: 'user', content: request.user },
|
|
],
|
|
}),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
console.warn(`OpenRouter API error: ${response.status} ${response.statusText}`);
|
|
return null;
|
|
}
|
|
|
|
const data = await response.json();
|
|
const content = data?.choices?.[0]?.message?.content;
|
|
return content ?? null;
|
|
} catch (error) {
|
|
console.warn('OpenRouter request failed:', (error as Error).message);
|
|
return null;
|
|
}
|
|
},
|
|
};
|
|
}
|