UNPKG

@earendil-works/pi-ai

Version:

Unified LLM API with automatic model discovery and provider configuration

707 lines • 33.1 kB
import type { TelemetrySpan } from "@earendil-works/pi-telemetry"; import type { AnthropicOptions } from "./api/anthropic-messages.ts"; import type { AzureOpenAIResponsesOptions } from "./api/azure-openai-responses.ts"; import type { BedrockOptions } from "./api/bedrock-converse-stream.ts"; import type { GoogleOptions } from "./api/google-generative-ai.ts"; import type { GoogleVertexOptions } from "./api/google-vertex.ts"; import type { MistralOptions } from "./api/mistral-conversations.ts"; import type { OpenAICodexResponsesOptions } from "./api/openai-codex-responses.ts"; import type { OpenAICompletionsOptions } from "./api/openai-completions.ts"; import type { OpenAIResponsesOptions } from "./api/openai-responses.ts"; import type { PiMessagesOptions } from "./api/pi-messages.ts"; import type { AnthropicMessagesCompat, BedrockCompat, MistralConversationsCompat, OpenAICompletionsCompat, OpenAIResponsesCompat, SystemOneCompat } from "./providers/compat-schema.ts"; import type { CacheRetention, ModelCost, ModelInputLimits, ModelInputModality, ModelPromptCache, ModelThinkingLevel, ThinkingLevel, ThinkingLevelMap } from "./providers/model-schema.ts"; import type { AssistantMessageDiagnostic } from "./utils/diagnostics.ts"; import type { AssistantMessageEventStream } from "./utils/event-stream.ts"; import type { ClientIdentity } from "./utils/identity.ts"; export type { AnthropicAllowedFallbackModel, AnthropicMessagesCompat, BedrockCompat, ChatTemplateKwargValue, MistralConversationsCompat, OpenAICompletionsCompat, OpenAIResponsesCompat, OpenRouterRouting, SessionAffinityFormat, SystemOneCompat, ThinkingTokenBudgetField, VercelGatewayRouting, } from "./providers/compat-schema.ts"; export type { CacheRetention, ModelCost, ModelCostRates, ModelCostTier, ModelImageInputLimits, ModelImageResizeOptions, ModelInputLimits, ModelInputModality, ModelPromptCache, ModelThinkingLevel, ThinkingLevel, ThinkingLevelMap, } from "./providers/model-schema.ts"; export type { AssistantMessageEventStream } from "./utils/event-stream.ts"; export type KnownApi = "openai-completions" | "mistral-conversations" | "openai-responses" | "azure-openai-responses" | "openai-codex-responses" | "anthropic-messages" | "bedrock-converse-stream" | "google-generative-ai" | "google-vertex" | "pi-messages"; export type Api = KnownApi | (string & {}); export type KnownImageApi = "openrouter-images"; export type ImageApi = KnownImageApi | (string & {}); export type KnownClassifierApi = "typesafe-system-one" | "cloudflare-workers-ai-system-one" | "llama-cpp-classify" | "openai-decisions"; export type ClassifierApi = KnownClassifierApi | (string & {}); export type KnownProvider = "amazon-bedrock" | "ant-ling" | "anthropic" | "google" | "google-vertex" | "openai" | "azure" | "openai-codex" | "radius" | "typesafe" | "nvidia" | "deepseek" | "github-copilot" | "xai" | "groq" | "cerebras" | "openrouter" | "vercel-ai-gateway" | "zai" | "zai-coding-cn" | "mistral" | "minimax" | "minimax-cn" | "moonshotai" | "moonshotai-cn" | "huggingface" | "fireworks" | "together" | "baseten" | "opencode" | "opencode-go" | "kimi-coding" | "meta" | "cloudflare-workers-ai" | "cloudflare-ai-gateway" | "qwen-token-plan" | "qwen-token-plan-cn" | "qwen-token-plan-individual" | "qwen-token-plan-individual-cn" | "xiaomi" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-sgp"; export type ProviderId = KnownProvider | string; export type ToolChoice = "auto" | "none"; export type SamplingParams = Record<string, unknown>; export type SamplingParamsByThinkingLevel = Partial<Record<ModelThinkingLevel, SamplingParams>>; /** Token budgets for each thinking level (token-based providers only) */ export interface ThinkingBudgets { minimal?: number; low?: number; medium?: number; high?: number; } export type Transport = "sse" | "websocket" | "websocket-cached" | "auto"; /** Provider-scoped environment overrides. Values take precedence over process.env. */ export type ProviderEnv = Record<string, string>; export type ProviderHeaders = Record<string, string | null>; export type FetchFunction = typeof globalThis.fetch; export interface ProviderResponse { status: number; headers: Record<string, string>; } /** Authentication, HTTP transport, and lifecycle callbacks shared by provider requests. */ export interface ProviderRequestOptions<TModel = Model<Api>> { signal?: AbortSignal; /** Explicit parent span for telemetry produced by this logical request. */ telemetry?: TelemetrySpan; apiKey?: string; /** * Optional fetch implementation for provider HTTP requests. * Defaults to `globalThis.fetch`. Provider adapters that cannot inject a custom implementation may reject it. * This does not affect WebSocket transports. */ fetch?: FetchFunction; /** * Provider-scoped environment values. These take precedence over process.env for * provider configuration such as regional settings, endpoint placeholders, and * proxy variables. */ env?: ProviderEnv; /** * Optional callback for inspecting or replacing provider payloads before sending. * Return undefined to keep the payload unchanged. */ onPayload?: (payload: unknown, model: TModel) => unknown | undefined | Promise<unknown | undefined>; /** * Optional callback invoked after an HTTP response is received. */ onResponse?: (response: ProviderResponse, model: TModel) => void | Promise<void>; /** * Optional custom HTTP headers to include in API requests. * Merged with provider defaults; caller values override default headers. * On AWS Bedrock these are injected via a Smithy `build`-step middleware so * they are covered by SigV4 signing; reserved headers (`x-amz-*`, * `authorization`, `host`) are silently ignored to preserve SigV4 / bearer auth. * A null value suppresses a provider/API default header with the same name. */ headers?: ProviderHeaders; /** * How the request identifies the calling app: `User-Agent` and provider attribution headers. * Absent fields use pi-ai's defaults: a detailed `User-Agent` and no attribution. */ identity?: ClientIdentity; /** * HTTP request timeout in milliseconds for providers/SDKs that support it. * For example, OpenAI and Anthropic SDK clients default to 10 minutes. */ timeoutMs?: number; /** * Maximum retry attempts for providers/SDKs that support client-side retries. * For example, OpenAI and Anthropic SDK clients default to 2. */ maxRetries?: number; /** * Maximum delay in milliseconds to wait for a retry when the server requests a long wait. * If the server's requested delay exceeds this value, the request fails immediately * with an error containing the requested delay, allowing higher-level retry logic * to handle it with user visibility. * Default: 60000 (60 seconds). Set to 0 to disable the cap. */ maxRetryDelayMs?: number; } export interface StreamOptions extends ProviderRequestOptions<Model<Api>> { /** * Optional callback invoked after an HTTP response is received and before * its body stream is consumed. */ onResponse?: (response: ProviderResponse, model: Model<Api>) => void | Promise<void>; /** * Optional observer for each parsed provider stream event before Pi normalization. * Event data is adapter-owned and must be treated as read-only. * Adapter support is explicit; unsupported adapters do not invoke it. */ onProviderStreamEvent?: (data: unknown, model: Model<Api>) => void | Promise<void>; temperature?: number; /** * Arbitrary sampling parameters merged into the request body as-is, after the named request * fields, so keys here override them. Lets custom OpenAI-compatible servers (llama.cpp, vLLM, * SGLang, ...) receive parameters pi does not model, e.g. `top_p`, `top_k`, `min_p`, * `repetition_penalty`. Merged over `Model.samplingParams` per key. Only applied by * OpenAI-compatible adapters (completions, responses, Azure responses); other APIs ignore it. */ samplingParams?: SamplingParams; maxTokens?: number; /** * Preferred transport for providers that support multiple transports. * Providers that do not support this option ignore it. */ transport?: Transport; /** * Prompt cache retention preference. Providers map this to their supported values. * Default: "short". */ cacheRetention?: CacheRetention; /** * Optional session identifier for providers that support session-based caching. * Providers can use this to enable prompt caching, request routing, or other * session-aware features. Ignored by providers that don't support it. */ sessionId?: string; /** * Do not use or record server-side continuation state for this request (for example * Anthropic message threads). Set this for replays such as cache warming, which must not * replace the state of the real conversation. Providers that do not keep continuation * state ignore it. */ disableContinuation?: boolean; /** * WebSocket connect timeout in milliseconds for providers that support * WebSocket transports. This covers the connection/open handshake only; * stream idleness after connection uses timeoutMs. */ websocketConnectTimeoutMs?: number; /** * Optional metadata to include in API requests. * Providers extract the fields they understand and ignore the rest. * For example, Anthropic uses `user_id` for abuse tracking and rate limiting. */ metadata?: Record<string, unknown>; } export type ProviderStreamOptions = StreamOptions & Record<string, unknown>; export interface DeferredFetchOptions extends ProviderRequestOptions<Model<Api>> { /** * Maximum provider long-poll duration in milliseconds. * Defaults to 0, which performs one status check. */ wait?: number; } /** Request options for best-effort deferred-response cancellation. */ export type DeferredCancelOptions = ProviderRequestOptions<Model<Api>>; /** * Maps known APIs to their full provider-specific stream option types. * Type-only imports from API implementation modules are erased at emit, so * this is tree-shake safe. */ export interface ApiOptionsMap { "anthropic-messages": AnthropicOptions; "openai-completions": OpenAICompletionsOptions; "openai-responses": OpenAIResponsesOptions; "openai-codex-responses": OpenAICodexResponsesOptions; "azure-openai-responses": AzureOpenAIResponsesOptions; "google-generative-ai": GoogleOptions; "google-vertex": GoogleVertexOptions; "mistral-conversations": MistralOptions; "bedrock-converse-stream": BedrockOptions; "pi-messages": PiMessagesOptions; } /** * Full stream options for an API. Known APIs resolve to their concrete option * type; custom API strings fall back to the generic shape. */ export type ApiStreamOptions<TApi extends Api> = TApi extends keyof ApiOptionsMap ? ApiOptionsMap[TApi] : StreamOptions & Record<string, unknown>; /** * The uniform stream contract of an API implementation module: every module * under `src/api/` exports `stream` and `streamSimple`; capable modules may also * export deferred-response methods. Lazy wrappers (`lazyApi()`) and provider * factories pass these around as values. This is the untyped dispatch shape; * per-API option typing lives on the implementation modules themselves and on * `Provider.stream()` via `ApiStreamOptions`. */ export interface ProviderStreams { stream(model: Model<Api>, context: TranscriptContext, options?: StreamOptions): AssistantMessageEventStream; streamSimple(model: Model<Api>, context: TranscriptContext, options?: SimpleStreamOptions): AssistantMessageEventStream; fetchDeferred?(model: Model<Api>, handle: DeferredHandle, options?: DeferredFetchOptions): AssistantMessageEventStream; cancelDeferred?(model: Model<Api>, handle: DeferredHandle, options?: DeferredCancelOptions): Promise<void>; } /** * The uniform contract of an image-generation API implementation module: * every image API module under `src/api/` exports exactly `generateImages`, * so the module itself satisfies this interface. Lazy wrappers and * `createProvider({ images })` pass these around as values. */ export interface ProviderImages { generateImages(model: ImageModel<ImageApi>, context: ImagesContext, options?: ImagesOptions): Promise<AssistantImages>; } /** The uniform contract implemented by classifier API modules. */ export interface ProviderClassifier { classify(model: ClassifierModel<ClassifierApi>, context: ClassifierContext, options?: ClassifierOptions): Promise<ClassifierResult>; } export interface ClassifierOptions extends ProviderRequestOptions<ClassifierModel<ClassifierApi>> { /** * Divides the answer logits by this value before they are normalized into probabilities. * Values above 1 soften the distribution; values below 1 sharpen it. Must be positive. * APIs that cannot apply it ignore it. */ temperature?: number; } export interface ImagesOptions extends ProviderRequestOptions<ImageModel<ImageApi>> { /** * Optional metadata to include in API requests. * Providers extract the fields they understand and ignore the rest. */ metadata?: Record<string, unknown>; } export type ProviderImagesOptions = ImagesOptions & Record<string, unknown>; export interface SimpleStreamOptions extends StreamOptions { /** Provider-neutral tool selection for simple requests. When omitted, adapters use provider-specific behavior. */ toolChoice?: ToolChoice; reasoning?: ThinkingLevel; /** Ask a capable provider to return a durable handle and continue the request asynchronously. */ deferred?: boolean | { window?: "15m" | "1h" | "24h"; }; /** Custom token budgets for thinking levels (token-based providers only) */ thinkingBudgets?: ThinkingBudgets; } export type StreamFunction<TApi extends Api = Api, TOptions extends StreamOptions = StreamOptions> = (model: Model<TApi>, context: TranscriptContext, options?: TOptions) => AssistantMessageEventStream; export type ImagesFunction<TOptions extends ImagesOptions = ImagesOptions> = (model: ImageModel<ImageApi>, context: ImagesContext, options?: TOptions) => Promise<AssistantImages>; export type ClassifierFunction<TOptions extends ClassifierOptions = ClassifierOptions> = (model: ClassifierModel<ClassifierApi>, context: ClassifierContext, options?: TOptions) => Promise<ClassifierResult>; export interface TextSignatureV1 { v: 1; id: string; phase?: "commentary" | "final_answer"; } export interface TextContent { type: "text"; text: string; textSignature?: string; } export interface ThinkingContent { type: "thinking"; thinking: string; thinkingSignature?: string; /** When true, the thinking content was redacted by safety filters. The opaque * encrypted payload is stored in `thinkingSignature` so it can be passed back * to the API for multi-turn continuity. */ redacted?: boolean; } export interface ImageContent { type: "image"; data: string; mimeType: string; } export interface ToolCall { type: "toolCall"; id: string; name: string; arguments: JsonObject; thoughtSignature?: string; /** OpenAI Responses namespace for calls to dynamically loaded or namespaced tools. */ namespace?: string; /** * Set when the model's complete arguments text was not a valid JSON object. `arguments` is then `{}`. * Describes the problem and includes the text the model sent; tool argument validation fails with it. */ argumentsError?: string; } export interface Usage { input: number; output: number; cacheRead: number; cacheWrite: number; /** Subset of `cacheWrite` written with 1h retention. Only Anthropic reports this split. */ cacheWrite1h?: number; /** * Reasoning/thinking tokens, when the provider reports them. This is a subset of * `output`: `output` already includes these tokens. Set to a number (possibly 0) by * providers that expose a reasoning breakdown; left undefined by providers that don't. */ reasoning?: number; totalTokens: number; cost: { /** Catalog-derived input cost. */ input: number; /** Catalog-derived output cost. */ output: number; /** Catalog-derived cache-read cost. */ cacheRead: number; /** Catalog-derived cache-write cost. */ cacheWrite: number; /** Best available total: provider-reported billed cost when supported, otherwise the catalog estimate. */ total: number; /** True when `total` is the billed cost reported by the provider. False when it is a catalog estimate; absent also means false. */ totalFromProvider?: boolean; }; } export type StopReason = "pending" | "stop" | "length" | "toolUse" | "error" | "aborted" | "deferred"; export type JsonValue = null | boolean | number | string | readonly JsonValue[] | JsonObject; export type JsonObject = { [key: string]: JsonValue; }; type IsAny<T> = 0 extends 1 & T ? true : false; type IsExactlyJsonValue<T> = [T] extends [JsonValue] ? ([JsonValue] extends [T] ? true : false) : false; type IsJsonProperty<T> = IsAny<T> extends true ? false : unknown extends T ? false : [Exclude<T, undefined>] extends [never] ? true : IsJsonCompatible<Exclude<T, undefined>>; type InvalidJsonKeys<T extends object> = { [TKey in keyof T]-?: TKey extends string | number ? (IsJsonProperty<T[TKey]> extends true ? never : TKey) : TKey; }[keyof T]; type IsJsonCompatible<T> = IsAny<T> extends true ? false : unknown extends T ? false : IsExactlyJsonValue<T> extends true ? true : T extends null | boolean | number | string ? true : T extends undefined ? false : T extends readonly (infer TItem)[] ? IsJsonCompatible<TItem> : T extends (...args: never[]) => unknown ? false : T extends object ? [InvalidJsonKeys<T>] extends [never] ? true : false : false; /** The JSON representation of a typed in-memory value. Optional object properties remain optional. */ export type JsonRepresentation<T> = IsAny<T> extends true ? JsonValue : unknown extends T ? JsonValue : [T] extends [JsonValue] ? T : T extends readonly unknown[] ? { [TKey in keyof T]: JsonRepresentation<Exclude<T[TKey], undefined>>; } : T extends object ? { [TKey in keyof T]: JsonRepresentation<Exclude<T[TKey], undefined>>; } : never; export interface DeferredHandle { provider: string; modelId: string; api: string; /** Provider token, such as a response id or batch id plus row id. */ id: string; expiresAt?: number; pollAfterMs?: number; /** Provider conversion data required to reconstruct the final assistant message. */ data?: JsonValue; } /** * System instructions and tool declarations at one point in the transcript. * * The leading system message is the system prompt. Later system messages change it: * `content` adds instructions from that point on, `sections` replace or remove named * prompt sections, and `toolsAdded`/`toolsRemoved` change the tool set. Replaying * every system message in order yields the current prompt and tools. Providers that * accept system messages mid-conversation send each one in place; other providers * rebuild the leading system message from the replayed state. */ export interface SystemMessage { role: "system"; /** Instruction text. On the leading message this is the base prompt; later, additional instructions. */ content: string | TextContent[]; /** * Named, ordered prompt sections rendered verbatim after `content`. The leading message * declares them; later messages replace sections by name, and `null` removes one. Keep * each section self-delimiting (a tag, a heading) so the model can relate an update to * the original. Avoid integer-like names; JSON objects reorder those. */ sections?: Record<string, string | null>; /** Complete definitions of tools that become available at this point. */ toolsAdded?: Tool[]; /** Tools that stop being available at this point. */ toolsRemoved?: ToolReference[]; timestamp: number; } export interface UserMessage { role: "user"; content: string | (TextContent | ImageContent)[]; timestamp: number; } export interface AssistantMessage { role: "assistant"; content: (TextContent | ThinkingContent | ToolCall)[]; api: Api; provider: ProviderId; model: string; responseModel?: string; responseId?: string; /** Exact provider-native effort level used for this response. Absent for legacy or unmanaged responses. */ providerThinkingLevel?: string; /** Pi thinking level the agent loop requested for this response. Absent outside the agent loop and for legacy responses. */ thinkingLevel?: ModelThinkingLevel; diagnostics?: AssistantMessageDiagnostic[]; usage: Usage; stopReason: StopReason; deferred?: DeferredHandle; errorMessage?: string; rawStopReason?: string; /** * Provider indication of whether the model explicitly ended its turn. * Preserved for debugging and does not currently affect agent control flow. */ endTurn?: boolean; /** Unix timestamp in milliseconds when the request started. */ timestamp: number; /** * Milliseconds from `timestamp` until the response ended, measured with a monotonic clock. Set by * `AssistantMessageEventStream` on the final message of a response it saw start; absent for legacy messages and * for deferred results fetched later. */ durationMs?: number; } /** A tool call that another tool made while it ran, for example from a codemode script. */ export interface NestedToolCallRecord { id: string; name: string; /** Omitted when over the size limits; `argumentsBytes` then gives their size. */ arguments?: JsonObject; /** UTF-8 size of the arguments as JSON, set when `arguments` is omitted. */ argumentsBytes?: number; /** `unfinished`: the call was still running when the calling tool finished. */ status: "ok" | "error" | "unfinished"; durationMs?: number; /** Error text, truncated. */ error?: string; } /** Bounded record of the nested calls a tool made. Results are not recorded. */ export interface NestedToolCalls { calls: NestedToolCallRecord[]; /** False when calls were dropped, arguments omitted, or calls had not finished. */ complete: boolean; } export type ToolResultMessage<TDetails = JsonValue> = IsJsonCompatible<TDetails> extends true ? { role: "toolResult"; toolCallId: string; toolName: string; content: (TextContent | ImageContent)[]; details?: JsonRepresentation<TDetails>; /** Usage from the tool execution itself, if available. Not part of main LLM context accounting. */ usage?: Usage; /** Calls this tool made to other tools. Kept for the session record; not sent to the model. */ nestedCalls?: NestedToolCalls; isError: boolean; /** Unix timestamp in milliseconds when the result was created. */ timestamp: number; /** Milliseconds the tool's execution took, measured with a monotonic clock. Absent for legacy results. */ durationMs?: number; } : never; export type Message = SystemMessage | UserMessage | AssistantMessage | ToolResultMessage; export type ImagesInputContent = TextContent | ImageContent; export type ImagesOutputContent = TextContent | ImageContent; export interface ImagesContext { input: ImagesInputContent[]; } export type ImagesStopReason = "stop" | "error" | "aborted"; export interface AssistantImages { api: ImageApi; provider: ProviderId; model: string; output: ImagesOutputContent[]; responseId?: string; usage?: Usage; stopReason: ImagesStopReason; errorMessage?: string; timestamp: number; } export interface ClassifierChoiceQuestion { type: "choice"; instructions: string; criteria: Record<string, string>; } export interface ClassifierScoreQuestion { type: "score"; instructions: string; criteria: string[]; } export interface ClassifierBoolQuestion { type: "bool"; instructions: string; criteria: { true: string; false: string; }; } export type ClassifierQuestion = ClassifierChoiceQuestion | ClassifierScoreQuestion | ClassifierBoolQuestion; export interface ClassifierContext { state: JsonObject; /** * Images judged together with `state`. Only models whose `input` includes `"image"` accept them; * other models return an error result. */ images?: ImageContent[]; questions: Record<string, ClassifierQuestion>; } export interface ClassifierChoiceAnswer { type: "choice"; choice: string; probabilities: Record<string, number>; confidence: number; } export interface ClassifierScoreAnswer { type: "score"; score: number; confidence: number; } export interface ClassifierBoolAnswer { type: "bool"; probability: number; } export type ClassifierAnswer = ClassifierChoiceAnswer | ClassifierScoreAnswer | ClassifierBoolAnswer; export type ClassifierStopReason = "stop" | "error" | "aborted"; export interface ClassifierResult { api: ClassifierApi; provider: ProviderId; model: string; answers: Record<string, ClassifierAnswer>; /** Token usage and its cost at the model's catalog price, when the service reports token counts. */ usage?: Usage; stopReason: ClassifierStopReason; errorMessage?: string; timestamp: number; } /** OpenAI grammar variants for constrained sampling. */ export type GrammarFormat = "openai_lark" | "openai_regex"; export type GrammarVariants = Partial<Record<GrammarFormat, string>>; /** * Optional provider-side constrained sampling configs for a tool. * * The `json_schema` value roughly maps to the concept of `strict` in APIs which is * implemented as json-schema constrained sampling by APIs. Grammar variants let * callers provide provider-specific encodings of the same intended language. */ export type ConstrainedSamplingConfig = { type: "json_schema"; strict: "prefer" | "require"; } | { type: "grammar"; variants: GrammarVariants; }; /** * A tool the model may call. `parameters` is the JSON Schema of its arguments: pi-schema's builders (which also type * the arguments, see `Static` in `@earendil-works/pi-schema`), TypeBox schemas, or any JSON Schema object. */ export interface Tool<TParameters extends object = object> { name: string; description: string; parameters: TParameters; constrainedSampling?: false | ConstrainedSamplingConfig; } export interface ToolReference { name: string; } /** * Request input accepted by the public stream entry points (`Models.stream()`, * `streamSimple()`, ...). `systemPrompt` and `tools` are shorthand for a leading * system message; `normalizeContext()` folds them into one before the request * reaches a provider. */ export interface Context { systemPrompt?: string; messages: Message[]; tools?: Tool[]; } declare const transcriptContextBrand: unique symbol; /** * Normalized request context passed to providers and API implementations. The * prompt and tool declarations are carried by the transcript's system messages. * Only `normalizeContext()` produces this type, so a raw `Context` cannot reach * provider code by accident. */ export type TranscriptContext = { messages: Message[]; readonly [transcriptContextBrand]: true; }; /** * Event protocol for AssistantMessageEventStream. * * Successful streams emit `start` before partial updates and terminate with * `done`. A stream may terminate directly with `error` when request setup fails * before generation starts; after `start`, failures also terminate with `error`. * Direct `streamSimple()` calls throw synchronously when request auth is missing. * Updates and `done` must never appear before `start`. * * `partial` is the shared live response-so-far helper, not an event-time * snapshot. Text and thinking blocks are empty when their `*_start` event is * emitted and grow only through their corresponding `*_delta` events until the * authoritative `*_end`. Redacted thinking may be complete at start and emit no * deltas. Tool-call arguments at `toolcall_start` are provider-specific; * `toolcall_delta` carries subsequent JSON updates. */ export type AssistantMessageEvent = { type: "start"; partial: AssistantMessage; } | { type: "text_start"; contentIndex: number; partial: AssistantMessage; } | { type: "text_delta"; contentIndex: number; delta: string; partial: AssistantMessage; } | { type: "text_end"; contentIndex: number; content: string; partial: AssistantMessage; } | { type: "thinking_start"; contentIndex: number; partial: AssistantMessage; } | { type: "thinking_delta"; contentIndex: number; delta: string; partial: AssistantMessage; } | { type: "thinking_end"; contentIndex: number; content: string; partial: AssistantMessage; } | { type: "toolcall_start"; contentIndex: number; partial: AssistantMessage; } | { type: "toolcall_delta"; contentIndex: number; delta: string; partial: AssistantMessage; } | { type: "toolcall_end"; contentIndex: number; toolCall: ToolCall; partial: AssistantMessage; } | { type: "done"; reason: Extract<StopReason, "stop" | "length" | "toolUse" | "deferred">; message: AssistantMessage; } | { type: "error"; reason: Extract<StopReason, "aborted" | "error">; error: AssistantMessage; }; /** Fields shared by every catalog entry, regardless of what you can do with it. */ export interface BaseModel<TApi extends string> { id: string; name: string; api: TApi; provider: ProviderId; baseUrl: string; input: ModelInputModality[]; /** Provider input limits and cache-safe preprocessing metadata. */ inputLimits?: ModelInputLimits; cost: ModelCost; headers?: Record<string, string>; } /** Chat model: usable with `stream()` and friends. */ export interface Model<TApi extends Api> extends BaseModel<TApi> { /** * Optional: chat is the default model type, so models without `type` are chat * models. Narrow mixed model lists with `isModelType()` instead of comparing * `type` directly. */ type?: "chat"; reasoning: boolean; /** * Maps pi thinking levels to provider/model-specific values. * Missing keys use provider defaults. null marks a level as unsupported. */ thinkingLevelMap?: ThinkingLevelMap; /** Prompt cache lifetimes per retention tier. Unset when the provider's cache behavior is unknown. */ promptCache?: ModelPromptCache; contextWindow: number; maxTokens: number; /** Default sampling parameters for this model. See {@link StreamOptions.samplingParams}; per-request keys override these. */ samplingParams?: SamplingParams; /** Sampling parameter overrides selected by the effective pi thinking level. */ samplingParamsByThinkingLevel?: SamplingParamsByThinkingLevel; /** Compatibility overrides for OpenAI-compatible APIs. If not set, auto-detected from baseUrl. */ compat?: TApi extends "openai-completions" ? OpenAICompletionsCompat : TApi extends "openai-responses" | "azure-openai-responses" | "openai-codex-responses" ? OpenAIResponsesCompat : TApi extends "anthropic-messages" ? AnthropicMessagesCompat : TApi extends "bedrock-converse-stream" ? BedrockCompat : TApi extends "mistral-conversations" ? MistralConversationsCompat : never; } /** Image-generation model: usable with `generateImages()` only. */ export interface ImageModel<TApi extends ImageApi> extends BaseModel<TApi> { type: "image"; /** Output modalities. Always includes `"image"`; `"text"` means the model can also return text blocks. */ output: ("text" | "image")[]; } /** Structured classifier model: usable with `classify()` only. */ export interface ClassifierModel<TApi extends ClassifierApi> extends BaseModel<TApi> { type: "classifier"; contextWindow: number; /** Compatibility overrides for System One APIs. If not set, auto-detected from provider, baseUrl, and id. */ compat?: TApi extends "typesafe-system-one" | "cloudflare-workers-ai-system-one" ? SystemOneCompat : never; } /** Model shape for each model type. */ export interface ModelTypeMap { chat: Model<Api>; image: ImageModel<ImageApi>; classifier: ClassifierModel<ClassifierApi>; } /** What a catalog entry is for. Decides which `Models` operation accepts it. */ export type ModelType = keyof ModelTypeMap; /** Anything a provider can list. Narrow with `isModelType()`. */ export type AnyModel = ModelTypeMap[ModelType]; //# sourceMappingURL=types.d.ts.map