type ModelState = 'idle' | 'loading' | 'ready' | 'inferring' | 'unloading' | 'error' | 'disposed'; interface WebGpuCapability { readonly supported: boolean; readonly adapter: { readonly vendor: string; readonly architecture: string; readonly device: string; readonly description: string; } | null; readonly limits: { readonly maxBufferSize: number; readonly maxStorageBufferBindingSize: number; } | null; readonly isFallback: boolean; } interface WasmCapability { readonly supported: boolean; readonly simd: boolean; readonly threads: boolean; } interface CapabilityReport { readonly webgpu: WebGpuCapability; readonly wasm: WasmCapability; readonly sharedWorker: boolean; readonly broadcastChannel: boolean; readonly webLocks: boolean; readonly hardwareConcurrency: number; } type Device = 'webgpu' | 'wasm'; interface LoadProgressEvent { readonly phase: string; readonly loaded: number; readonly total: number; } interface InferenceOptions { readonly signal?: AbortSignal; readonly priority?: 'high' | 'normal' | 'low'; } interface PoolConfig { /** Adapter factory for the AI runtime. Required. */ readonly adapter: ModelAdapterFactory; /** * URL to the pre-built dedicated worker file. * Default: resolves `inferis/worker` relative to import.meta.url if available. */ readonly workerUrl?: URL | string; /** Maximum number of dedicated workers. Default: hardwareConcurrency - 1, min 1. */ readonly maxWorkers?: number; /** Maximum combined memory budget in MB. Default: 2048. */ readonly maxMemoryMB?: number; /** Default inference device. 'auto' tries WebGPU first, falls back to WASM. Default: 'auto'. */ readonly defaultDevice?: Device | 'auto'; /** Enable cross-tab model deduplication. Default: false. */ readonly crossTab?: boolean; /** Per-task timeout in milliseconds. Default: 120_000. */ readonly taskTimeout?: number; } interface ModelLoadConfig { /** Model identifier (e.g. HuggingFace model ID or URL). */ readonly model: string; /** Estimated memory usage in MB. Used for pre-eviction budgeting. */ readonly estimatedMemoryMB?: number; /** Progress callback for download and load phases. */ readonly onProgress?: (event: LoadProgressEvent) => void; /** Additional adapter-specific config. */ readonly [key: string]: unknown; } interface ModelHandle { /** Unique model instance ID. */ readonly id: string; /** Current lifecycle state. */ readonly state: ModelState; /** Approximate memory usage in MB. */ readonly memoryMB: number; /** Resolved inference device. */ readonly device: Device; /** * Run non-streaming inference. * @throws {InferisError} if the model is not in 'ready' state. * @throws {AbortError} if the signal is aborted. */ run: (input: unknown, options?: InferenceOptions) => Promise; /** * Run streaming inference. Returns a ReadableStream that emits output chunks. * @throws {InferisError} if the model is not in 'ready' state. */ stream: (input: unknown, options?: InferenceOptions) => ReadableStream; /** * Dispose the model and free its memory. * Waits for any in-flight inference to complete before unloading. */ dispose: () => Promise; /** * Subscribe to state changes. * @returns unsubscribe function */ onStateChange: (callback: (state: ModelState) => void) => () => void; } interface WorkerPoolInterface { /** * Load a model and return a handle for inference. * If the model is already loaded (same task + config), returns the existing handle. */ load: (task: string, config: ModelLoadConfig) => Promise>; /** * Return snapshot of detected browser capabilities. */ capabilities: () => CapabilityReport; /** * Return current memory budget snapshot. */ getMemoryBudget: () => { totalMB: number; allocatedMB: number; availableMB: number; } | null; /** * Gracefully terminate all workers and dispose all models. */ terminate: () => Promise; } interface LoadedModel { /** Opaque runtime-specific handle (pipeline instance, MLCEngine, etc.). */ readonly instance: unknown; /** Actual memory consumed after loading, in MB. */ readonly memoryMB: number; } /** * Adapter interface — implemented INSIDE the worker via the factory pattern. * Never instantiated on the main thread. */ interface ModelAdapter { readonly name: string; /** * Load model into memory. Called inside the worker. * Must call `onProgress` during download to forward progress to the main thread. * @throws on load failure */ load: (task: string, config: Record, device: Device, onProgress: (event: LoadProgressEvent) => void) => Promise; /** * Run non-streaming inference. * Return value must be structured-cloneable. */ run: (model: LoadedModel, input: unknown, options?: unknown) => Promise; /** * Run streaming inference. * Call `onChunk` for each output chunk (token, image tile, etc.). * onChunk values must be structured-cloneable. * Resolve the promise when the stream is complete. */ stream: (model: LoadedModel, input: unknown, onChunk: (chunk: unknown) => void, options?: unknown) => Promise; /** * Unload model and release all resources. * MUST call GPUBuffer.destroy() / GPUDevice.destroy() where applicable. */ unload: (model: LoadedModel) => Promise; /** * Estimate memory usage before loading. Used by MemoryBudget for pre-eviction. */ estimateMemoryMB: (task: string, config: Record) => number; } /** * Factory that creates a ModelAdapter inside the worker. * The factory itself is lightweight and runs on the main thread. * create() is called inside the worker and does the heavy dynamic import(). */ interface ModelAdapterFactory { readonly name: string; create: () => Promise; } type MainToWorkerMessage = { readonly type: 'load-model'; readonly reqId: string; readonly modelId: string; readonly task: string; readonly config: Record; readonly device: Device; } | { readonly type: 'unload-model'; readonly reqId: string; readonly modelId: string; } | { readonly type: 'run'; readonly reqId: string; readonly modelId: string; readonly input: unknown; readonly options?: unknown; } | { readonly type: 'run-stream'; readonly reqId: string; readonly modelId: string; readonly input: unknown; readonly options?: unknown; } | { readonly type: 'abort'; readonly reqId: string; } | { readonly type: 'probe'; readonly reqId: string; } | { readonly type: 'ping'; }; type WorkerToMainMessage = { readonly type: 'load-progress'; readonly reqId: string; readonly progress: LoadProgressEvent; } | { readonly type: 'load-complete'; readonly reqId: string; readonly memoryMB: number; } | { readonly type: 'load-error'; readonly reqId: string; readonly error: SerializedError; } | { readonly type: 'unload-complete'; readonly reqId: string; } | { readonly type: 'unload-error'; readonly reqId: string; readonly error: SerializedError; } | { readonly type: 'run-result'; readonly reqId: string; readonly output: unknown; } | { readonly type: 'run-error'; readonly reqId: string; readonly error: SerializedError; } | { readonly type: 'stream-chunk'; readonly reqId: string; readonly chunk: unknown; } | { readonly type: 'stream-end'; readonly reqId: string; readonly usage?: unknown; } | { readonly type: 'stream-error'; readonly reqId: string; readonly error: SerializedError; } | { readonly type: 'probe-result'; readonly reqId: string; readonly capabilities: unknown; } | { readonly type: 'device-lost'; readonly modelId: string; readonly reason: string; } | { readonly type: 'pong'; }; interface SerializedError { readonly name: string; readonly message: string; readonly code?: string; readonly stack?: string | undefined; } interface ModelEntry { readonly id: string; readonly task: string; readonly config: Record; state: ModelState; device: Device; memoryMB: number; workerId: number | null; stateListeners: Set<(state: ModelState) => void>; } type TaskPriority = 'high' | 'normal' | 'low'; interface ScheduledTask { readonly reqId: string; readonly modelId: string; readonly priority: TaskPriority; readonly enqueuedAt: number; execute: (workerId: number) => void; reject: (error: Error) => void; } export type { CapabilityReport as C, Device as D, InferenceOptions as I, LoadProgressEvent as L, MainToWorkerMessage as M, PoolConfig as P, SerializedError as S, TaskPriority as T, WorkerToMainMessage as W, ModelState as a, ModelEntry as b, ScheduledTask as c, ModelLoadConfig as d, ModelHandle as e, LoadedModel as f, ModelAdapter as g, ModelAdapterFactory as h, WasmCapability as i, WebGpuCapability as j, WorkerPoolInterface as k };