UNPKG

capsule-ai-cli

Version:

The AI Model Orchestrator - Intelligent multi-model workflows with device-locked licensing

127 lines 4.74 kB
import { BaseProvider } from './base.js'; import { openRouterModelsService } from '../services/openrouter-models.js'; export class ProxyProvider extends BaseProvider { name; models = []; supportsStreaming = true; supportsTools = true; authToken; providerName; constructor(providerName, authToken, baseUrl) { super('proxy', baseUrl || process.env.CAPSULE_API_URL || 'https://api.capsule.dev'); this.providerName = providerName; this.name = providerName; this.authToken = authToken; this.loadProviderCapabilities(); } async loadProviderCapabilities() { await openRouterModelsService.fetchModels(); const models = openRouterModelsService.getModelsByProvider(this.providerName); this.models = models.map(m => m.id); if (this.models.length === 0) { const fallbackModels = { openai: ['openai/gpt-4o', 'openai/gpt-4o-mini'], anthropic: ['anthropic/claude-opus-4', 'anthropic/claude-sonnet-4'], google: ['google/gemini-2.5-pro', 'google/gemini-2.5-flash'], }; this.models = fallbackModels[this.providerName] || []; } } async complete(messages, options) { const response = await fetch(`${this.baseUrl}/api/proxy/complete`, { method: 'POST', headers: { 'Authorization': `Bearer ${this.authToken}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ provider: this.providerName, model: options?.model || this.models[0], messages, options }), }); if (!response.ok) { if (response.status === 402) { const error = await response.json(); throw new Error(`Insufficient RUs: ${error.message || 'Please add more RUs or use your own API keys'}`); } else if (response.status === 401) { throw new Error('Authentication expired. Please run `capsule auth <email>` again.'); } const error = await response.text(); throw new Error(`Proxy request failed: ${error}`); } return response.json(); } async *stream(messages, options) { const response = await fetch(`${this.baseUrl}/api/proxy/stream`, { method: 'POST', headers: { 'Authorization': `Bearer ${this.authToken}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ provider: this.providerName, model: options?.model || this.models[0], messages, options }), }); if (!response.ok) { if (response.status === 402) { const error = await response.json(); throw new Error(`Insufficient RUs: ${error.message || 'Please add more RUs or use your own API keys'}`); } else if (response.status === 401) { throw new Error('Authentication expired. Please run `capsule auth <email>` again.'); } const error = await response.text(); throw new Error(`Proxy request failed: ${error}`); } const reader = response.body?.getReader(); if (!reader) { throw new Error('No response body'); } const decoder = new TextDecoder(); let buffer = ''; try { while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop() || ''; for (const line of lines) { if (line.startsWith('data: ')) { const data = line.slice(6); if (data === '[DONE]') { return; } try { const chunk = JSON.parse(data); yield chunk; } catch (e) { } } } } } finally { reader.releaseLock(); } } calculateCost(_usage, _model) { return { amount: 0, currency: 'RU', breakdown: { prompt: 0, completion: 0 } }; } } //# sourceMappingURL=proxy.js.map