TypeScript 61.9%
HTML 37.2%
SQL 0.7%
1import type { z } from 'zod';23/**4 * Provider-neutral model abstraction (CLAUDE.md §168). Nothing outside packages/ai imports a5 * vendor SDK; callers speak in roles and these request shapes.6 */7export type Role = 'normalize' | 'classify' | 'resolve' | 'research' | 'vision' | 'embed' | 'summarize';89export type Effort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';1011export interface CostContext {12 connectorId?: string | null;13 categorySlug?: string | null;14 userId?: string | null;15 endpoint?: string | null;16 metadata?: Record<string, unknown>;17}1819export interface ImageInput {20 /** base64-encoded bytes (no data: prefix) or an https URL */21 data?: string;22 url?: string;23 mediaType: 'image/jpeg' | 'image/png' | 'image/webp' | 'image/gif';24}2526export type ContentPart = { type: 'text'; text: string } | { type: 'image'; image: ImageInput };2728export interface ChatMessage {29 role: 'user' | 'assistant';30 content: string | ContentPart[];31}3233export interface ToolDefinition {34 name: string;35 description: string;36 /** JSON Schema (draft 2020-12 subset) for the input object */37 inputSchema: Record<string, unknown>;38}3940export interface CompletionRequest {41 system?: string;42 messages: ChatMessage[];43 maxTokens?: number;44 temperature?: number;45 effort?: Effort;46 /** ask for JSON output (best effort; use extract() for schema-validated output) */47 json?: boolean;48 stopSequences?: string[];49 cost?: CostContext;50}5152export interface Usage {53 inputTokens: number;54 outputTokens: number;55 cacheReadTokens: number;56 cacheWriteTokens: number;57}5859export interface Completion {60 text: string;61 model: string;62 provider: string;63 usage: Usage;64 usdEst: number;65 stopReason: string | null;66 refusal: { category: string | null; explanation: string | null } | null;67}6869export type StreamDelta =70 | { type: 'text'; text: string }71 | { type: 'thinking'; text: string }72 | { type: 'tool_call'; id: string; name: string; input: unknown }73 | { type: 'tool_result'; id: string; name: string; output: unknown; isError: boolean; durationMs: number }74 | { type: 'usage'; usage: Usage; usdEst: number; model: string }75 | { type: 'error'; message: string }76 | { type: 'done'; stopReason: string | null };7778export interface ToolAgentRequest extends CompletionRequest {79 tools: ToolDefinition[];80 /** execute a tool call; return JSON-serialisable output (throw to signal an error result) */81 execute: (name: string, input: unknown) => Promise<unknown>;82 /** max model↔tool round trips (default 8) */83 maxIterations?: number;84 signal?: AbortSignal;85}8687export interface ExtractRequest<T> {88 schema: z.ZodType<T>;89 /** instruction for the extraction */90 prompt: string;91 /** raw input: text or content parts (images allowed) */92 input: string | ContentPart[];93 system?: string;94 maxTokens?: number;95 effort?: Effort;96 cost?: CostContext;97}9899export interface ExtractResult<T> {100 data: T;101 /** 0–1: the model's self-reported confidence when the schema has one, else 1 when parsed */102 confidence: number;103 model: string;104 provider: string;105 usage: Usage;106 usdEst: number;107}108109export interface EmbedRequest {110 texts: string[];111 cost?: CostContext;112}113114export interface EmbedResult {115 vectors: number[][];116 model: string;117 provider: string;118 dimensions: number;119 usdEst: number;120}121122export interface ModelProvider {123 readonly id: string;124 /** which roles this provider can serve given its configuration */125 supports(role: Role): boolean;126 complete(role: Role, req: CompletionRequest): Promise<Completion>;127 stream(role: Role, req: CompletionRequest): AsyncIterable<StreamDelta>;128 /** tool-use agent loop with streaming events */129 runTools(role: Role, req: ToolAgentRequest): AsyncIterable<StreamDelta>;130 extract<T>(role: Role, req: ExtractRequest<T>): Promise<ExtractResult<T>>;131 vision<T>(req: ExtractRequest<T>): Promise<ExtractResult<T>>;132 embed(req: EmbedRequest): Promise<EmbedResult>;133 modelFor(role: Role): string;134}135136export class AiNotConfiguredError extends Error {137 readonly code = 'ai_not_configured';138 constructor(detail = 'AI provider not configured') {139 super(detail);140 this.name = 'AiNotConfiguredError';141 }142}143144export class AiRefusalError extends Error {145 readonly code = 'ai_refusal';146 constructor(public readonly category: string | null, explanation: string | null) {147 super(explanation ?? 'The model declined this request');148 this.name = 'AiRefusalError';149 }150}151