import AIClient from 'ai.libx.js'; import { IConvMessage, IPromptConfig } from './FeedoxAI'; /** * Client for ai.libx.js - unified API bridge for AI models */ export class AiLibxClient { private client: AIClient; constructor(public options?: Partial) { this.options = { ...new AiLibxClientOptions(), ...options }; // Initialize ai.libx.js client with API keys this.client = new AIClient({ apiKeys: { openai: this.options.openaiApiKey, anthropic: this.options.anthropicApiKey, google: this.options.googleApiKey, groq: this.options.groqApiKey, mistral: this.options.mistralApiKey, cohere: this.options.cohereApiKey, xai: this.options.xaiApiKey, deepseek: this.options.deepseekApiKey, ai21: this.options.ai21ApiKey, openrouter: this.options.openrouterApiKey, cloudflare: this.options.cloudflareApiKey, }, cloudflareAccountId: this.options.cloudflareAccountId, enableLogging: this.options.enableLogging, }); } /** * Stream a prompt through ai.libx.js */ public async streamPrompt( workspaceId: string, promptId: string, variables: any, messages: IConvMessage[], config?: IPromptConfig ): Promise { const model = this.buildModelString(config); const result = await this.client.chat({ model, messages: this.convertMessages(messages, config), temperature: config?.temperature, maxTokens: config?.maxTokens, topP: config?.topP, frequencyPenalty: config?.frequencyPenalty, presencePenalty: config?.presencePenalty, stream: true, }) as AsyncIterable; // Convert ai.libx.js stream to ReadableStream const readable = new ReadableStream({ async start(controller) { try { for await (const chunk of result) { const encoder = new TextEncoder(); controller.enqueue(encoder.encode(chunk.content || '')); } controller.close(); } catch (error) { controller.error(error); } } }); return readable; } /** * Run a prompt without streaming (sync mode) */ public async runPrompt( workspaceId: string, promptId: string, variables: any, messages: IConvMessage[], config?: IPromptConfig ): Promise { const model = this.buildModelString(config); const response = await this.client.chat({ model, messages: this.convertMessages(messages, config), temperature: config?.temperature, maxTokens: config?.maxTokens, topP: config?.topP, frequencyPenalty: config?.frequencyPenalty, presencePenalty: config?.presencePenalty, stream: false, }) as any; return response.content || ''; } /** * Build model string in format "provider/model" */ private buildModelString(config?: IPromptConfig): string { const provider = config?.provider || this.options.defaultProvider; const model = config?.model || this.options.defaultModel; return `${provider}/${model}`; } /** * Convert messages to ai.libx.js format, including system prompt */ private convertMessages(messages: IConvMessage[], config?: IPromptConfig) { const converted = [...messages]; // Add system prompt as first message if provided if (config?.systemPrompt) { converted.unshift({ role: 'system', content: config.systemPrompt }); } return converted; } /** * Get stats from ai.libx.js logger */ public getStats() { return this.client.getStats(); } } /** * Configuration options for the AiLibxClient */ export class AiLibxClientOptions { /** Default provider to use if not specified */ defaultProvider = process.env.DEFAULT_PROVIDER || 'openai'; /** Default model to use if not specified */ defaultModel = process.env.DEFAULT_MODEL || 'gpt-4o-mini'; /** Enable request logging in ai.libx.js */ enableLogging = process.env.AILBX_ENABLE_LOGGING === 'true'; /** API keys for various providers */ openaiApiKey = process.env.OPENAI_API_KEY; anthropicApiKey = process.env.ANTHROPIC_API_KEY; googleApiKey = process.env.GOOGLE_AI_API_KEY; groqApiKey = process.env.GROQ_API_KEY; mistralApiKey = process.env.MISTRAL_API_KEY; cohereApiKey = process.env.COHERE_API_KEY; xaiApiKey = process.env.XAI_API_KEY; deepseekApiKey = process.env.DEEPSEEK_API_KEY; ai21ApiKey = process.env.AI21_API_KEY; openrouterApiKey = process.env.OPENROUTER_API_KEY; cloudflareApiKey = process.env.CLOUDFLARE_API_KEY; cloudflareAccountId = process.env.CLOUDFLARE_ACCOUNT_ID; }