import { ILlmHandler, IPromptOptions, IPromptGenericConfig, ModuleOptions } from '../../types'; import { libx } from 'libx.js/build/bundles/essentials.js'; export abstract class BaseHandler implements ILlmHandler { protected options: ModuleOptions; constructor(options: ModuleOptions) { this.options = options; } abstract execute(isStream: boolean, options: IPromptOptions): Promise; abstract getConfig(generalConfig: IPromptGenericConfig): any; protected createTransformStream() { return new TransformStream(); } protected handleError(error: any, isPlain?: boolean): ReadableStream { // Better error logging const errorMsg = error?.message || error?.toString() || 'Unknown error'; libx.log.e('Handler error:', errorMsg, error); const { readable, writable } = new TransformStream(); const writer = writable.getWriter(); const encoder = new TextEncoder(); if (isPlain) { writer.write(encoder.encode(`Error: ${errorMsg}`)); } else { const errorMessage = JSON.stringify({ error: errorMsg, type: error?.type || 'handler_error', timestamp: new Date().toISOString() }); writer.write(encoder.encode(`data: ${errorMessage}\n\n`)); } writer.close(); return readable; } protected getApiKey(provider: string): string | undefined { return this.options.apiKeys?.[provider]; } protected normalizeModelName(model: string, provider: string): string { // Strip provider prefix if present (e.g., "groq/model-name" -> "model-name") const prefixes = [`${provider}/`, `${provider}:`]; for (const prefix of prefixes) { if (model.startsWith(prefix)) { return model.slice(prefix.length); } } return model; } protected async writeStreamChunk(writer: WritableStreamDefaultWriter, encoder: TextEncoder, delta: string, isPlain: boolean) { if (isPlain) { await writer.write(encoder.encode(delta)); } else { await writer.write(encoder.encode(`data: ${JSON.stringify({ delta })}\n\n`)); } } protected writeSyncResponse(content: string, metadata: any, isPlain: boolean): ReadableStream { const { readable, writable } = new TransformStream(); const writer = writable.getWriter(); const encoder = new TextEncoder(); if (isPlain) { writer.write(encoder.encode(content)); } else { writer.write(encoder.encode(JSON.stringify({ content, ...metadata }))); } writer.close(); return readable; } }