// Author: Simon-Pierre Boucher // Contact: contact@spboucher.ai // Project: chat.spboucher.ai // Minimal runtime validation of OpenRouter wire shapes (no external dep). export interface ORModelRaw { id: string; name?: string; description?: string; context_length?: number; created?: number; pricing?: Record; architecture?: { modality?: string; input_modalities?: string[]; output_modalities?: string[]; tokenizer?: string; instruct_type?: string | null; }; supported_parameters?: string[]; top_provider?: { context_length?: number; max_completion_tokens?: number }; } export function parseModelsResponse(json: unknown): ORModelRaw[] { if (typeof json !== "object" || json === null) return []; const data = (json as { data?: unknown }).data; if (!Array.isArray(data)) return []; return data.filter( (m): m is ORModelRaw => typeof m === "object" && m !== null && typeof (m as ORModelRaw).id === "string" ); } /** One parsed SSE chunk from the OpenRouter chat stream. */ export interface ORStreamChunk { id?: string; choices?: Array<{ delta?: { content?: string | null; reasoning?: string | null; tool_calls?: Array<{ index?: number; id?: string; function?: { name?: string; arguments?: string }; }>; }; finish_reason?: string | null; }>; usage?: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number; cost?: number; completion_tokens_details?: { reasoning_tokens?: number }; prompt_tokens_details?: { cached_tokens?: number }; }; error?: { message?: string; code?: number | string }; } export function parseStreamChunk(line: string): ORStreamChunk | null { try { const parsed = JSON.parse(line); if (typeof parsed !== "object" || parsed === null) return null; return parsed as ORStreamChunk; } catch { return null; } }