// Copyright (C) 2026 Rob Colbert // Licensed under the Apache License, Version 2.0 export type AiSdkType = "ollama" | "openai"; export interface IAiProvider { _id: string; name: string; sdk: AiSdkType; baseUrl: string; apiKey: string; defaultModelId?: string; } export interface IAiModelConfig { provider: IAiProvider; modelId: string; params: { reasoning: boolean | "high" | "medium" | "low"; temperature: number; topP: number; topK: number; }; } export interface IAiInferenceStats { tokenCounts: { input: number; thinking: number; response: number; }; duration: { seconds: number; text: string; }; } export interface IAiGenerateOptions { prompt: string; systemPrompt?: string; } export interface IAiGenerateResponse { response: string; thinking?: string; stats: IAiInferenceStats; done: boolean; doneReason?: string; } export interface IContextChatMessage { createdAt: Date; role: string; content: string; user?: { _id: string; username: string; displayName: string; }; } export interface IAiChatOptions { systemPrompt?: string; userPrompt?: string; context?: IContextChatMessage[]; } export interface IToolCall { call_id: string; function: { name: string; arguments: string; }; } export interface IAiChatResponse { response: string; thinking?: string; stats: IAiInferenceStats; done: boolean; doneReason?: string; tool_calls?: IToolCall[]; } export interface IAiStreamChunk { data: string; } export type IAiResponseStreamFn = (chunk: IAiStreamChunk) => Promise; export interface IAiLogger { debug(message: string, metadata?: unknown): Promise | void; info(message: string, metadata?: unknown): Promise | void; warn(message: string, metadata?: unknown): Promise | void; error(message: string, metadata?: unknown): Promise | void; } const noOpLogger: IAiLogger = { debug: () => {}, info: () => {}, warn: () => {}, error: () => {}, }; export function defaultLogger(): IAiLogger { return noOpLogger; } export abstract class AiApi { protected provider: IAiProvider; protected log: IAiLogger; constructor(provider: IAiProvider, logger?: IAiLogger) { this.provider = provider; this.log = logger ?? defaultLogger(); } abstract listModels(): Promise; abstract probeModel(modelId: string): Promise; abstract generate( model: IAiModelConfig, options: IAiGenerateOptions, streamCallback?: IAiResponseStreamFn, ): Promise; abstract chat( model: IAiModelConfig, options: IAiChatOptions, streamCallback?: IAiResponseStreamFn, ): Promise; }