agents 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["definedEntries","effortForLevel","exhaustive"],"sources":["../../../src/models/pi-ai/catalog.ts","../../../src/models/pi-ai/routing.ts","../../../src/models/pi-ai/wires/shared.ts","../../../src/models/pi-ai/errors.ts","../../../src/models/pi-ai/wires/chat-completions.ts","../../../src/models/pi-ai/models/image.ts","../../../src/models/pi-ai/settings.ts","../../../src/models/pi-ai/wires/anthropic.ts","../../../src/models/pi-ai/wires/responses.ts","../../../src/models/pi-ai/models/fallback.ts","../../../src/models/pi-ai/models/language.ts","../../../src/models/pi-ai/index.ts"],"sourcesContent":["/**\n * pi-ai `Model` construction for this provider.\n *\n * There are exactly two sources of a model here, and neither of them is a\n * catalog of ours:\n *\n * 1. A Workers AI id (`@cf/<author>/<model>`) — the one catalog Cloudflare\n * owns. Its metadata comes from pi-ai's generated Workers AI registry.\n * 2. Anything else — a model object the caller built from their own pi-ai\n * registry import, or an id resolved through pi-ai's generated Cloudflare\n * AI Gateway registry. pi keeps those current; we only route them.\n *\n * A model is plain data in pi-ai, so the options a model was created with ride\n * on it under symbol keys: `JSON.stringify` and `structuredClone` drop them,\n * while an object spread — which pi-ai does when it copies a model — keeps\n * them. Routing survives that loss, because the vendor's own spelling of a\n * `<slug>/<id>` model is looked back up in pi-ai's registry; the per-model\n * options do not, so a model stored in Agent state and read back comes home\n * with this provider's defaults. Re-apply them with `ai(model, options)`\n * after loading if the model carried any.\n *\n * @experimental This surface is experimental and may change.\n */\n\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport { CLOUDFLARE_AI_GATEWAY_MODELS } from \"@earendil-works/pi-ai/providers/cloudflare-ai-gateway.models\";\nimport { CLOUDFLARE_WORKERS_AI_MODELS } from \"@earendil-works/pi-ai/providers/cloudflare-workers-ai.models\";\nimport type { WorkersAIModelId } from \"../core/catalog\";\nimport type { ModelOptions } from \"../core/settings\";\n\n/**\n * The `api` marker Workers AI models from this provider carry. It is not a\n * wire format: Workers AI runs on `env.AI.run`, and the compat layer maps that\n * onto strict OpenAI chat completions.\n *\n * @experimental This surface is experimental and may change.\n */\nexport const CLOUDFLARE_AI_API = \"cloudflare-ai\";\n\n/** @experimental This surface is experimental and may change. */\nexport type CloudflareAIApi = typeof CLOUDFLARE_AI_API;\n\n/**\n * The pi-ai provider id. A `Models` registry resolves specifiers as\n * `cloudflare/<id>`, e.g. `cloudflare/anthropic/claude-opus-4-8`.\n *\n * @experimental This surface is experimental and may change.\n */\nexport const CLOUDFLARE_PROVIDER_ID = \"cloudflare\";\n\n/**\n * A Workers AI model produced by this provider. `id` is the `@cf/` id exactly\n * as given; `api` is {@link CLOUDFLARE_AI_API}.\n *\n * @experimental This surface is experimental and may change.\n */\nexport type CloudflareModel = Model<CloudflareAIApi>;\n\n/** @experimental This surface is experimental and may change. */\nexport type ModelCost = Model<Api>[\"cost\"];\n\n/**\n * A model this provider routes: a Workers AI model or any pi-ai model the\n * caller handed to `ai(model)`.\n *\n * @experimental This surface is experimental and may change.\n */\nexport type RoutedModel = Model<Api>;\n\n/**\n * Per-model options: the gateway options, client-side fallback, headers and\n * session affinity, plus pi-ai model metadata overrides and the stream idle\n * deadline. Metadata overrides only apply to the `@cf/` form — a model object\n * brings its own metadata, and this module never second-guesses it.\n *\n * @experimental This surface is experimental and may change.\n */\n/**\n * A fallback leg: a Workers AI id, a `<slug>/<id>` pi-ai's gateway registry\n * knows, or a model object. A raw vendor id is refused when the chain is built.\n */\nexport type PiFallbackLeg = WorkersAIModelId | Model<Api> | (string & {});\n\nexport interface PiModelOptions extends ModelOptions<PiFallbackLeg> {\n /** Display name. Defaults to the catalog name, else the id. */\n name?: string;\n /** Context window in tokens. Defaults to the catalog value, else 128000. */\n contextWindow?: number;\n /** Maximum output tokens. Defaults to the catalog value, else 8192. */\n maxTokens?: number;\n /** Whether the model can reason. Defaults to the catalog value, else true. */\n reasoning?: boolean;\n /** Accepted input modalities. Defaults to the catalog value. */\n input?: (\"text\" | \"image\")[];\n /** Cost per million tokens, used by pi-ai's usage accounting. */\n cost?: ModelCost;\n /**\n * Fail a stream that delivers no bytes for this long, in milliseconds. The\n * timer only runs while a read is outstanding, so consumer backpressure\n * never trips it. `0` disables the guard. Default 300000 (five minutes).\n */\n streamIdleTimeoutMs?: number;\n}\n\nconst MODEL_OPTIONS: unique symbol = Symbol.for(\"agents.models.pi-ai.options\");\nconst MODEL_ROUTING: unique symbol = Symbol.for(\"agents.models.pi-ai.routing\");\n\n/** What a registry specifier resolved to, kept for routing and diagnostics. */\ninterface ModelRouting {\n /** The vendor's own spelling of the id, which is what the body must carry. */\n modelId: string;\n /** The `<slug>/<id>` specifier the caller asked for. */\n specifier: string;\n}\n\ntype TaggedModel = Model<Api> & {\n [MODEL_OPTIONS]?: PiModelOptions;\n [MODEL_ROUTING]?: ModelRouting;\n};\n\nfunction tag(model: Model<Api>, key: symbol, value: unknown): void {\n Object.defineProperty(model, key, {\n configurable: true,\n enumerable: true,\n value,\n writable: false\n });\n}\n\n/** Reads the options a model was created with, if it came from this provider. */\nexport function optionsOf(model: Model<Api>): PiModelOptions | undefined {\n const options = (model as TaggedModel)[MODEL_OPTIONS];\n return options !== null && typeof options === \"object\" ? options : undefined;\n}\n\n/**\n * The gateway registry entry a model's own id names, for a model this provider\n * built from a `<slug>/<id>` specifier. It is looked up rather than inferred,\n * so a model that lost its symbol tags — `JSON.stringify` and\n * `structuredClone` drop them, and an Agent's state goes through both — still\n * reaches the vendor under the vendor's own spelling.\n */\nfunction registryEntryFor(model: Model<Api>): Model<Api> | undefined {\n if (\n model.provider !== CLOUDFLARE_PROVIDER_ID ||\n model.id.startsWith(\"@cf/\")\n ) {\n return undefined;\n }\n gatewayRegistry ??= buildGatewayRegistry();\n return gatewayRegistry.get(model.id);\n}\n\n/**\n * The id the request body must carry. It differs from `model.id` only for a\n * `<slug>/<id>` specifier, whose model is listed under the specifier so a\n * `Models` registry can find it while the vendor still sees its own spelling.\n */\nexport function wireModelId(model: Model<Api>): string {\n const tagged = (model as TaggedModel)[MODEL_ROUTING]?.modelId;\n if (tagged !== undefined) return tagged;\n return registryEntryFor(model)?.id ?? model.id;\n}\n\n/** The `<slug>/<id>` specifier a model was resolved from, for diagnostics. */\nexport function specifierOf(model: Model<Api>): string | undefined {\n const tagged = (model as TaggedModel)[MODEL_ROUTING]?.specifier;\n if (tagged !== undefined) return tagged;\n return registryEntryFor(model) === undefined ? undefined : model.id;\n}\n\n/**\n * Copies a caller's model and tags the copy with the resolved options. The\n * caller's object is never mutated, and every field it declares — `api`,\n * `provider`, `id`, `baseUrl`, `compat`, `thinkingLevelMap`, cost and limits —\n * is kept verbatim, because that metadata is the model's own author's, not\n * ours.\n */\nexport function withOptions<TApi extends Api>(\n model: Model<TApi>,\n options: PiModelOptions | undefined\n): Model<TApi> {\n const copy = { ...model };\n if (options !== undefined) tag(copy, MODEL_OPTIONS, options);\n return copy;\n}\n\nconst DEFAULT_CONTEXT_WINDOW = 128_000;\nconst DEFAULT_MAX_TOKENS = 8192;\nconst ZERO_COST: ModelCost = {\n cacheRead: 0,\n cacheWrite: 0,\n input: 0,\n output: 0\n};\n\nlet workersAI: Map<string, Model<Api>> | undefined;\n\nfunction workersAIEntry(modelId: string): Model<Api> | undefined {\n workersAI ??= new Map(\n (Object.values(CLOUDFLARE_WORKERS_AI_MODELS) as Model<Api>[]).map(\n (entry) => [entry.id, entry]\n )\n );\n return workersAI.get(modelId);\n}\n\n/** Every Workers AI id pi-ai knows, for the provider's static model list. */\nexport function workersAIModelIds(): string[] {\n workersAI ??= new Map(\n (Object.values(CLOUDFLARE_WORKERS_AI_MODELS) as Model<Api>[]).map(\n (entry) => [entry.id, entry]\n )\n );\n return [...workersAI.keys()].sort();\n}\n\n/**\n * Builds the pi-ai model for a Workers AI id. Registry metadata is used when\n * pi-ai knows the id; explicit options override it; everything else falls back\n * to defaults that keep the model usable, because the Workers AI catalog moves\n * faster than any generated registry.\n */\nexport function buildWorkersAIModel(\n modelId: string,\n options: PiModelOptions | undefined\n): CloudflareModel {\n const known = workersAIEntry(modelId);\n const model: CloudflareModel = {\n api: CLOUDFLARE_AI_API,\n baseUrl: \"\",\n contextWindow:\n options?.contextWindow ?? known?.contextWindow ?? DEFAULT_CONTEXT_WINDOW,\n cost: options?.cost ?? known?.cost ?? ZERO_COST,\n id: modelId,\n input: options?.input ?? known?.input ?? [\"text\"],\n maxTokens: options?.maxTokens ?? known?.maxTokens ?? DEFAULT_MAX_TOKENS,\n name: options?.name ?? known?.name ?? modelId,\n provider: CLOUDFLARE_PROVIDER_ID,\n reasoning: options?.reasoning ?? known?.reasoning ?? true,\n ...(known?.thinkingLevelMap !== undefined\n ? { thinkingLevelMap: known.thinkingLevelMap }\n : {})\n };\n if (options !== undefined) tag(model, MODEL_OPTIONS, options);\n return model;\n}\n\n/** The gateway provider slug a registry entry's base URL names. */\nfunction slugOf(entry: Model<Api>): string | undefined {\n const segments = entry.baseUrl.split(\"/\").filter((part) => part !== \"\");\n return segments.at(-1);\n}\n\nlet gatewayRegistry: Map<string, Model<Api>> | undefined;\n\n/**\n * pi-ai's generated Cloudflare AI Gateway registry, keyed by `<slug>/<id>`.\n * `/compat` entries are skipped: they alias `@cf/` ids the Workers AI registry\n * already declares, and those belong on the run path.\n */\nfunction buildGatewayRegistry(): Map<string, Model<Api>> {\n const map = new Map<string, Model<Api>>();\n for (const entry of Object.values(\n CLOUDFLARE_AI_GATEWAY_MODELS\n ) as Model<Api>[]) {\n const slug = slugOf(entry);\n if (slug === undefined || slug === \"compat\") continue;\n map.set(`${slug}/${entry.id}`, entry);\n }\n return map;\n}\n\n/** Every `<slug>/<id>` specifier pi-ai's gateway registry declares. */\nexport function gatewayModelIds(): string[] {\n gatewayRegistry ??= buildGatewayRegistry();\n return [...gatewayRegistry.keys()].sort();\n}\n\n/** An id with case and separators (`.`, `-`, `_`) ignored. */\nfunction looseId(id: string): string {\n return id.toLowerCase().replace(/[._-]/g, \"-\");\n}\n\n/**\n * Catalog specifiers that differ from `specifier` only in case or separators.\n * AI Gateway's catalog spells `anthropic/claude-opus-4.8` where Anthropic\n * spells `claude-opus-4-8`, and the difference is easy to miss.\n */\nfunction nearSpecifiers(\n specifier: string,\n specifiers: Iterable<string>\n): string[] {\n const wanted = looseId(specifier);\n return [...specifiers].filter((id) => looseId(id) === wanted).sort();\n}\n\n/**\n * Resolves a `<slug>/<id>` specifier through pi-ai's generated Cloudflare AI\n * Gateway registry. The entry's metadata — api, base URL, compat,\n * `thinkingLevelMap`, cost, limits — is kept exactly as pi generated it; only\n * `id` and `provider` are restated so a `Models` registry can find the model\n * under `cloudflare/<slug>/<id>`, and the vendor's own spelling rides along for\n * the request body.\n *\n * There is no prefix guessing: an id pi-ai does not list is a `TypeError`,\n * pointing at the model-object form, which needs no catalog of ours at all.\n */\nexport function buildGatewayModel(\n specifier: string,\n options: PiModelOptions | undefined\n): Model<Api> {\n gatewayRegistry ??= buildGatewayRegistry();\n const separator = specifier.indexOf(\"/\");\n const slug = separator === -1 ? \"\" : specifier.slice(0, separator);\n const vendorId = specifier.slice(separator + 1);\n if (slug === \"workers-ai\") {\n throw new TypeError(\n `\"${specifier}\" is a Workers AI model: pass its id directly, ai(\"${vendorId}\").`\n );\n }\n const entry = gatewayRegistry.get(specifier);\n if (entry === undefined) {\n const near = nearSpecifiers(specifier, gatewayRegistry.keys());\n const suggestion =\n near.length === 0\n ? \"\"\n : ` Did you mean ${near.map((id) => `ai(\"${id}\")`).join(\" or \")}? The catalog spells ids as AI Gateway does.`;\n throw new TypeError(\n `\"${specifier}\" is not in pi-ai's Cloudflare AI Gateway catalog.${suggestion} Pass the model object instead, e.g. ai(getBuiltinModel(\"${slug || \"anthropic\"}\", \"${vendorId}\")) from \"@earendil-works/pi-ai/providers/all\", or any model from a provider registry you imported.`\n );\n }\n const model: Model<Api> = {\n ...entry,\n id: specifier,\n provider: CLOUDFLARE_PROVIDER_ID\n };\n tag(model, MODEL_ROUTING, { modelId: entry.id, specifier });\n if (options !== undefined) tag(model, MODEL_OPTIONS, options);\n return model;\n}\n","/**\n * Where a pi-ai model's request goes on the AI Gateway universal endpoint.\n *\n * A pi `Model` carries the vendor's own `baseUrl` and an `api` marker. Those\n * two are all the routing information the universal request needs, but neither\n * alone is enough: the gateway's `endpoint` is the vendor's request URL minus\n * that provider's own base, and the base differs per provider (groq serves\n * chat completions at `/openai/v1/chat/completions`, deepseek at\n * `/chat/completions`). So the api names the path pi's own client appends to\n * `model.baseUrl`, the two are joined, and `core/gateway-providers.ts` — the\n * same resolver the AI SDK module's routed `fetch` uses — maps the result onto\n * a provider slug and an endpoint. Nothing here knows a vendor's wire format;\n * pi's own converters build the body.\n */\n\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport {\n type GatewayProviderName,\n gatewaySlugForBaseUrl,\n isGatewayShapedUrl,\n resolveGatewayProvider\n} from \"../core/gateway-providers\";\n\n/**\n * The path each pi api speaks, relative to the model's own `baseUrl` — exactly\n * what pi's SDK clients append to it.\n */\nconst API_PATHS: Record<string, string> = {\n \"anthropic-messages\": \"v1/messages\",\n \"openai-completions\": \"chat/completions\",\n \"openai-responses\": \"responses\"\n};\n\n/**\n * The universal request's `endpoint` for a gateway-shaped base URL, whose path\n * already ends at the provider slug, so what follows is the vendor's own path.\n */\nconst GATEWAY_ENDPOINTS: Record<string, string> = {\n \"anthropic-messages\": \"v1/messages\",\n \"openai-completions\": \"v1/chat/completions\",\n \"openai-responses\": \"v1/responses\"\n};\n\n/** Where one model's request goes on the universal gateway endpoint. */\nexport interface UniversalRoute {\n provider: GatewayProviderName;\n endpoint: string;\n}\n\n/**\n * The gateway provider slug that serves a model, from its own base URL.\n *\n * @throws TypeError when the model carries no base URL, or one AI Gateway has\n * no provider for.\n */\nexport function gatewaySlugForModel(model: Model<Api>): GatewayProviderName {\n if (model.baseUrl === \"\") {\n throw new TypeError(\n `The model \"${model.id}\" has no baseUrl, so AI Gateway cannot tell which provider serves it.`\n );\n }\n return gatewaySlugForBaseUrl(model.baseUrl);\n}\n\n/** `https://api.groq.com/openai/v1` → `https://api.groq.com/openai/v1/`. */\nfunction asBase(baseUrl: string): string {\n return baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n}\n\n/**\n * The provider slug and endpoint one model's request travels on.\n *\n * @throws TypeError when the model has no base URL, when AI Gateway has no\n * provider for it, or when this module knows no path for the model's api.\n */\nexport function routeForModel(model: Model<Api>): UniversalRoute {\n const provider = gatewaySlugForModel(model);\n if (isGatewayShapedUrl(model.baseUrl)) {\n const endpoint = GATEWAY_ENDPOINTS[model.api];\n if (endpoint === undefined) throw noEndpoint(model.api);\n return { endpoint, provider };\n }\n const path = API_PATHS[model.api];\n if (path === undefined) throw noEndpoint(model.api);\n const resolved = resolveGatewayProvider(\n new URL(path, asBase(model.baseUrl)).toString()\n );\n // The base URL already resolved to a provider above, so the joined URL can\n // only fail to resolve if it left that provider's own host.\n if (resolved === undefined) {\n return { endpoint: GATEWAY_ENDPOINTS[model.api] ?? path, provider };\n }\n return { endpoint: resolved.endpoint, provider: resolved.provider };\n}\n\nfunction noEndpoint(api: string): TypeError {\n return new TypeError(`No AI Gateway endpoint is known for the \"${api}\" API.`);\n}\n","/**\n * Helpers shared by the three pi-ai wires: the empty assistant message every\n * stream starts from, usage and cost accounting, response diagnostics, the\n * stream idle deadline, SSE iteration, and error termination.\n */\n\nimport type { CompatWarning } from \"../../core/chat-completions\";\nimport {\n type Api,\n type AssistantMessage,\n type AssistantMessageDiagnostic,\n type JsonObject,\n type Model,\n type Usage,\n calculateCost\n} from \"@earendil-works/pi-ai\";\nimport { sseDataStream } from \"../../core/sse\";\nimport type { Transport } from \"../../core/transport\";\nimport {\n errorFromGatewayEnvelope,\n headersToObject,\n isGatewayErrorEnvelope\n} from \"../../core/transport\";\nimport { specifierOf, wireModelId } from \"../catalog\";\nimport { gatewaySlugForModel, routeForModel } from \"../routing\";\nimport type { WireRequest } from \"../settings\";\n\n/** Diagnostic type under which gateway correlation ids are recorded. */\nexport const CLOUDFLARE_DIAGNOSTIC = \"cloudflare\";\n\n/** The diagnostic type under which compat-layer warnings are recorded. */\nexport const COMPAT_DIAGNOSTIC = \"cloudflare-compat\";\n\n/** Records compat warnings on a message as a `cloudflare-compat` diagnostic. */\n/**\n * pi-ai types diagnostic details as JSON. These details are plain data this\n * module built, so a JSON round trip only drops their undefined fields.\n */\nexport function jsonDetails(value: object): JsonObject {\n return JSON.parse(JSON.stringify(value)) as JsonObject;\n}\n\nexport function recordWarnings(\n output: AssistantMessage,\n warnings: CompatWarning[]\n): void {\n if (warnings.length === 0) return;\n output.diagnostics = [\n ...(output.diagnostics ?? []),\n {\n details: jsonDetails({ warnings }),\n timestamp: Date.now(),\n type: COMPAT_DIAGNOSTIC\n }\n ];\n}\n\n/**\n * The Workers-AI-only knobs a vendor model cannot honour. They are not sent —\n * the vendor's own reasoning follows the model's metadata and the pi\n * `reasoning` level — and the drop is recorded rather than silent.\n */\nexport function ignoredWorkersAIKnobs(request: {\n resolved: { reasoningEffort?: unknown; chatTemplateKwargs?: unknown };\n}): CompatWarning[] {\n const warnings: CompatWarning[] = [];\n if (request.resolved.reasoningEffort !== undefined) {\n warnings.push({\n feature: \"reasoning-effort\",\n message:\n \"reasoningEffort is a Workers AI setting and does not apply to a model routed through AI Gateway; use the pi `reasoning` level, which the model's own metadata maps.\"\n });\n }\n if (request.resolved.chatTemplateKwargs !== undefined) {\n warnings.push({\n feature: \"chat-template-kwargs\",\n message:\n \"chatTemplateKwargs is a Workers AI setting and was not sent to a model routed through AI Gateway.\"\n });\n }\n return warnings;\n}\n\n/** Default cap on how long a stream may stay silent before it is failed. */\nexport const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 300_000;\n\n/** OpenAI Responses rejects `max_output_tokens` below 16. */\nexport const MIN_OUTPUT_TOKENS = 16;\n\nexport function emptyUsage(): Usage {\n return {\n cacheRead: 0,\n cacheWrite: 0,\n cost: { cacheRead: 0, cacheWrite: 0, input: 0, output: 0, total: 0 },\n input: 0,\n output: 0,\n totalTokens: 0\n };\n}\n\n/** The assistant message a stream mutates as events arrive. */\nexport function startMessage(model: Model<Api>): AssistantMessage {\n return {\n api: model.api,\n content: [],\n model: model.id,\n provider: model.provider,\n role: \"assistant\",\n stopReason: \"stop\",\n timestamp: Date.now(),\n usage: emptyUsage()\n };\n}\n\n/**\n * Usage in the OpenAI shape, shared by chat completions and Workers AI.\n *\n * The cache fields are the ones pi-ai's own `parseChunkUsage` reads, spelling\n * for spelling: `prompt_tokens_details.cached_tokens` is OpenAI's, DeepSeek\n * sends `prompt_cache_hit_tokens` instead, and OpenRouter-compatible providers\n * add `prompt_tokens_details.cache_write_tokens`.\n */\nexport interface OpenAIUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n prompt_cache_hit_tokens?: number;\n prompt_tokens_details?: {\n cached_tokens?: number;\n cache_write_tokens?: number;\n };\n completion_tokens_details?: { reasoning_tokens?: number };\n}\n\n/**\n * Maps OpenAI-shaped usage onto pi-ai's. `input` excludes cached tokens, as\n * pi-ai's own OpenAI adapter does, and cost comes from the model metadata.\n */\nexport function usageFromOpenAI(\n model: Model<Api>,\n raw: OpenAIUsage | undefined\n): Usage {\n if (raw === undefined) return emptyUsage();\n const prompt = raw.prompt_tokens ?? 0;\n const completion = raw.completion_tokens ?? 0;\n // pi-ai's `parseChunkUsage`, field for field: cached tokens are reads, cache\n // writes are counted separately and both come out of `input`, and a write\n // count is never subtracted from the read count.\n const cacheRead =\n raw.prompt_tokens_details?.cached_tokens ??\n raw.prompt_cache_hit_tokens ??\n 0;\n const cacheWrite = raw.prompt_tokens_details?.cache_write_tokens ?? 0;\n const reasoning = raw.completion_tokens_details?.reasoning_tokens;\n const totalTokens = raw.total_tokens ?? prompt + completion;\n // Google counts reasoning outside `completion_tokens` (live: prompt 6 +\n // completion 3 + reasoning 57 = total 66); OpenAI and Workers AI satisfy\n // prompt + completion = total, so the derived figure agrees with theirs.\n const output =\n raw.total_tokens === undefined\n ? completion\n : Math.max(completion, totalTokens - prompt);\n const usage: Usage = {\n cacheRead,\n cacheWrite,\n cost: { cacheRead: 0, cacheWrite: 0, input: 0, output: 0, total: 0 },\n input: Math.max(0, prompt - cacheRead - cacheWrite),\n output,\n ...(reasoning !== undefined ? { reasoning } : {}),\n totalTokens\n };\n usage.cost = calculateCost(model, usage);\n return usage;\n}\n\n/** Gateway correlation read off a response. */\nexport interface ResponseCorrelation {\n logId?: string;\n runId?: string;\n cacheStatus?: string;\n step?: string;\n eventId?: string;\n traceId?: string;\n}\n\nexport function correlationOf(\n response: Response,\n transport: Transport\n): ResponseCorrelation {\n const get = (name: string) => response.headers.get(name) ?? undefined;\n return {\n cacheStatus: get(\"cf-aig-cache-status\"),\n eventId: get(\"cf-aig-event-id\"),\n logId: get(\"cf-aig-log-id\") ?? transport.logIdFallback(response),\n runId: get(\"cf-aig-run-id\"),\n step: get(\"cf-aig-step\"),\n traceId: get(\"cf-aig-trace-id\")\n };\n}\n\nfunction definedEntries(\n record: Record<string, unknown>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(record)) {\n if (value !== undefined) result[key] = value;\n }\n return result;\n}\n\n/**\n * Records where a response came from on the assistant message, as a pi-ai\n * diagnostic: the gateway log id and friends, the answering model and the\n * gateway id. Callers read it back from `message.diagnostics`.\n */\nexport function attachCorrelation(\n message: AssistantMessage,\n details: ResponseCorrelation & {\n model: string;\n gateway: string;\n provider?: string;\n specifier?: string;\n }\n): void {\n const diagnostic: AssistantMessageDiagnostic = {\n details: jsonDetails(definedEntries({ ...details })),\n timestamp: Date.now(),\n type: CLOUDFLARE_DIAGNOSTIC\n };\n message.diagnostics = [...(message.diagnostics ?? []), diagnostic];\n}\n\n/**\n * Wraps a body so a gap longer than `idleMs` between chunks rejects the read\n * instead of pending forever. Only an outstanding read is timed, so a slow\n * consumer never trips it; `idleMs <= 0` disables the guard.\n */\nexport function withIdleDeadline(\n body: ReadableStream<Uint8Array>,\n idleMs: number\n): ReadableStream<Uint8Array> {\n if (idleMs <= 0) return body;\n const reader = body.getReader();\n return new ReadableStream<Uint8Array>({\n cancel(reason) {\n return reader.cancel(reason);\n },\n async pull(controller) {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const result = await Promise.race([\n reader.read(),\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n reject(\n new Error(\n `Model stream stalled: no data received for ${Math.round(idleMs / 1000)}s.`\n )\n );\n }, idleMs);\n })\n ]);\n if (result.done) controller.close();\n else controller.enqueue(result.value);\n } catch (error) {\n void reader.cancel().catch(() => {});\n controller.error(error);\n } finally {\n clearTimeout(timer);\n }\n }\n });\n}\n\n/**\n * Iterates the JSON payload of each SSE event. `[DONE]` sentinels and\n * unparseable payloads are skipped; the reader is cancelled if iteration\n * stops early so the upstream request is not left generating.\n */\nexport async function* sseJson(\n body: ReadableStream<Uint8Array>,\n onDone?: () => void\n): AsyncGenerator<unknown> {\n const reader = body.pipeThrough(sseDataStream()).getReader();\n let finished = false;\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n finished = true;\n return;\n }\n if (value === \"\") continue;\n if (value === \"[DONE]\") {\n onDone?.();\n continue;\n }\n try {\n yield JSON.parse(value);\n } catch {\n // A malformed event is dropped rather than failing the stream.\n }\n }\n } finally {\n if (!finished) {\n await reader.cancel().catch(() => {});\n }\n reader.releaseLock();\n }\n}\n\n/** `response.headers` as pi-ai's `onResponse` callback wants them. */\nexport function responseInfo(response: Response): {\n status: number;\n headers: Record<string, string>;\n} {\n return {\n headers: headersToObject(response.headers),\n status: response.status\n };\n}\n\n/**\n * The Anthropic API version every Messages request must name. pi-ai leaves it\n * to the Anthropic SDK, which we replace, so the wire states it here.\n */\nconst ANTHROPIC_VERSION = \"2023-06-01\";\n\n/**\n * The vendor headers an Anthropic Messages request needs. pi-ai normally gets\n * them from the Anthropic SDK's defaults plus its own `createClient`; this\n * wire owns the transport instead, so it sets the ones the vendor requires and\n * sends the beta features pi-ai chose as `anthropic-beta`, as the SDK would.\n * No credential header is sent: the gateway holds the key (unified billing or\n * BYOK).\n */\nexport function anthropicVendorHeaders(betas: readonly string[]): {\n [key: string]: string;\n} {\n return {\n accept: \"application/json\",\n \"anthropic-version\": ANTHROPIC_VERSION,\n ...(betas.length > 0 ? { \"anthropic-beta\": betas.join(\",\") } : {}),\n \"content-type\": \"application/json\"\n };\n}\n\n/** The vendor headers an OpenAI-shaped request needs. */\nexport function openAIVendorHeaders(): Record<string, string> {\n return { accept: \"application/json\", \"content-type\": \"application/json\" };\n}\n\n/**\n * Sends a vendor's own request body through AI Gateway's universal endpoint.\n *\n * The provider slug comes from the model's base URL and the endpoint from its\n * `api`; the body is what pi-ai's converter built, `model` included, because\n * that is what the universal request carries. The gateway's *own* failures\n * (no such gateway, unified billing unpaid) are lifted into a\n * `CloudflareAIError` so fallback and retry classification behave as they do on\n * the Workers AI run path; a vendor's own error response is left alone for the\n * wire's parser to read.\n */\nexport async function sendUniversal(\n request: WireRequest,\n transport: Transport,\n body: Record<string, unknown>,\n vendorHeaders: Record<string, string>,\n onResponse?: (response: Response) => void\n): Promise<Response> {\n const { model, options, resolved } = request;\n const route = routeForModel(model);\n const response = await transport.universal({\n endpoint: route.endpoint,\n extraHeaders:\n Object.keys(request.headers).length > 0 ? request.headers : undefined,\n gateway: resolved.gateway,\n headers: vendorHeaders,\n provider: route.provider,\n query: body,\n signal: options.signal\n });\n // The correlation ids are on the raw response, and a gateway envelope is\n // about to throw, so the caller sees them either way.\n onResponse?.(response);\n return await liftGatewayError(response, {\n model: wireModelId(model),\n requestBodyValues: body,\n url: transport.url\n });\n}\n\n/**\n * Turns the gateway's own error envelope into a `CloudflareAIError`. Only a\n * JSON body can be one, so a streaming response is passed straight through and\n * never buffered.\n */\nasync function liftGatewayError(\n response: Response,\n context: { model: string; url: string; requestBodyValues: unknown }\n): Promise<Response> {\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (!contentType.includes(\"application/json\")) return response;\n const text = await response.text().catch(() => \"\");\n let parsed: unknown;\n try {\n parsed = text === \"\" ? undefined : JSON.parse(text);\n } catch {\n parsed = undefined;\n }\n if (isGatewayErrorEnvelope(parsed)) {\n throw errorFromGatewayEnvelope(parsed, {\n ...context,\n responseBody: text,\n responseHeaders: headersToObject(response.headers),\n status: response.status\n });\n }\n return new Response(text, response);\n}\n\n/** The correlation details every wire records, with the routing it used. */\nexport function correlationDetails(\n request: WireRequest,\n response: Response,\n transport: Transport\n): ResponseCorrelation & {\n model: string;\n gateway: string;\n provider?: string;\n specifier?: string;\n} {\n const { model, resolved } = request;\n const specifier = specifierOf(model);\n return {\n ...correlationOf(response, transport),\n gateway: resolved.gateway.id,\n model: model.id,\n ...(specifier !== undefined ? { specifier } : {}),\n ...(model.api === \"cloudflare-ai\"\n ? {}\n : { provider: gatewaySlugForModel(model) })\n };\n}\n","/**\n * How a pi-ai stream reports failure: an `error` event carrying the assistant\n * message with `stopReason` and `errorMessage`, plus a diagnostic for the\n * failed dispatch. The framework-neutral `CloudflareAIError` from the core is\n * the source of the status, code and log id recorded there.\n */\n\nimport {\n type AssistantMessage,\n type AssistantMessageEventStream,\n type StopReason\n} from \"@earendil-works/pi-ai\";\nimport { CloudflareAIError, isAbortError } from \"../core/errors\";\nimport { errorFromResponse } from \"../core/transport\";\nimport { jsonDetails } from \"./wires/shared\";\n\n/** Diagnostic type under which a failed dispatch is recorded. */\nexport const CLOUDFLARE_ERROR_DIAGNOSTIC = \"cloudflare-error\";\n\nfunction definedEntries(\n record: Record<string, unknown>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(record)) {\n if (value !== undefined) result[key] = value;\n }\n return result;\n}\n\n/**\n * Terminates a stream with a pi-ai `error` event built from a thrown value.\n * `aborted` when the caller's signal fired or the error is an abort; `error`\n * otherwise, with the failed dispatch recorded as a diagnostic.\n */\nexport function failStream(\n stream: AssistantMessageEventStream,\n message: AssistantMessage,\n error: unknown,\n signal: AbortSignal | undefined\n): void {\n const aborted = signal?.aborted === true || isAbortError(error);\n const reason: Extract<StopReason, \"aborted\" | \"error\"> = aborted\n ? \"aborted\"\n : \"error\";\n message.stopReason = reason;\n message.errorMessage =\n error instanceof Error ? error.message : JSON.stringify(error);\n if (!aborted) {\n const details: Record<string, unknown> = {};\n if (error instanceof CloudflareAIError) {\n Object.assign(\n details,\n definedEntries({\n code: error.code,\n logId: error.logId,\n model: error.model,\n status: error.status\n })\n );\n }\n message.diagnostics = [\n ...(message.diagnostics ?? []),\n {\n details: jsonDetails(details),\n error: {\n message: message.errorMessage,\n name: error instanceof Error ? error.name : \"Error\",\n ...(error instanceof CloudflareAIError ? { code: error.code } : {})\n },\n timestamp: Date.now(),\n type: CLOUDFLARE_ERROR_DIAGNOSTIC\n }\n ];\n }\n stream.push({ error: message, reason, type: \"error\" });\n stream.end(message);\n}\n\n/** Throws the typed error for a non-2xx response. */\nexport async function assertOk(\n response: Response,\n context: { model: string; url: string; requestBodyValues: unknown }\n): Promise<void> {\n if (response.ok) return;\n throw await errorFromResponse(response, context);\n}\n","/**\n * Chat-completions wire: Workers AI on the run path, and any pi-ai model whose\n * `api` is `openai-completions` on AI Gateway's universal endpoint.\n *\n * The request is shaped with pi-ai's own message converter so replay rules\n * (tool-call id normalization, reasoning replay, role bridging) match pi's\n * other OpenAI-compatible providers. Workers AI then runs through the shared\n * compat layer, which absorbs its native events, heartbeats, per-delta usage\n * and per-family request quirks so the parser below only ever sees strict\n * OpenAI chunks. A vendor model brings its own `compat` profile and needs none\n * of that: its bytes are already what its author says they are.\n */\n\nimport {\n type AssistantMessage,\n type AssistantMessageEventStream,\n type Tool,\n type Model,\n type ThinkingContent,\n type ToolCall,\n createAssistantMessageEventStream,\n getCurrentTools,\n parseStreamingJson\n} from \"@earendil-works/pi-ai\";\nimport { convertMessages } from \"@earendil-works/pi-ai/api/openai-completions\";\nimport {\n type CompatWarning,\n normalizeChatCompletion,\n normalizeChatCompletionsStream,\n prepareChatCompletionsRequest\n} from \"../../core/chat-completions\";\nimport { sseDataStream } from \"../../core/sse\";\nimport type { Transport } from \"../../core/transport\";\nimport { CLOUDFLARE_AI_API, wireModelId } from \"../catalog\";\nimport { assertOk, failStream } from \"../errors\";\nimport {\n type OpenAIUsage,\n attachCorrelation,\n correlationDetails,\n openAIVendorHeaders,\n responseInfo,\n sendUniversal,\n startMessage,\n usageFromOpenAI,\n withIdleDeadline,\n recordWarnings\n} from \"./shared\";\nimport type { WireRequest } from \"../settings\";\n\ntype Compat = Parameters<typeof convertMessages>[2];\n\n/**\n * pi-ai's message converter wants a fully resolved compat profile. This is\n * the strict OpenAI profile: replayed reasoning goes to `reasoning_content`,\n * `max_tokens` is the cap, and nothing vendor-specific is applied here — the\n * shared compat layer handles that per model afterwards.\n */\nconst STRICT_OPENAI_COMPAT: Compat = {\n chatTemplateArgs: {},\n chatTemplateKwargs: {},\n maxTokensField: \"max_tokens\",\n openRouterRouting: {},\n requiresAssistantAfterToolResult: false,\n requiresReasoningContentOnAssistantMessages: false,\n requiresThinkingAsText: false,\n requiresToolResultName: false,\n sendSessionAffinityHeaders: false,\n sessionAffinityFormat: \"openai\",\n supportsDeveloperRole: false,\n supportsFinishReason: true,\n supportsLongCacheRetention: false,\n supportsOpenAIGrammarTools: false,\n supportsReasoningEffort: true,\n supportsStore: false,\n supportsStrictMode: false,\n supportsUsageInStreaming: true,\n thinkingFormat: \"openai\",\n vercelGatewayRouting: {},\n zaiToolStream: false\n};\n\n/** Diagnostic type under which compat-layer warnings are recorded. */\nexport { COMPAT_DIAGNOSTIC } from \"./shared\";\n\ninterface ToolCallDelta {\n index?: number;\n id?: string | null;\n function?: { name?: string | null; arguments?: string | null };\n}\n\ninterface ChoiceDelta {\n content?: string | null;\n reasoning_content?: string | null;\n reasoning?: string | null;\n reasoning_text?: string | null;\n tool_calls?: ToolCallDelta[];\n}\n\n/**\n * The fields an OpenAI-compatible endpoint puts reasoning in, in pi-ai's own\n * order (`dist/api/openai-completions.js`). The first non-empty one wins and\n * the rest are skipped: some endpoints send the same text under two spellings,\n * and reading both would double the thinking block.\n */\nconst REASONING_FIELDS = [\n \"reasoning_content\",\n \"reasoning\",\n \"reasoning_text\"\n] as const;\n\ninterface Choice {\n delta?: ChoiceDelta;\n message?: ChoiceDelta;\n finish_reason?: string | null;\n}\n\ninterface Chunk {\n id?: string;\n model?: string;\n choices?: Choice[];\n usage?: OpenAIUsage;\n error?: { message?: string; type?: string };\n}\n\ntype TextBlock = { type: \"text\"; text: string };\ntype ToolCallBlock = ToolCall & { partialArguments?: string };\ntype Block = TextBlock | ThinkingContent | ToolCallBlock;\n\nfunction mapFinishReason(reason: string): AssistantMessage[\"stopReason\"] {\n switch (reason) {\n case \"stop\":\n case \"eos\":\n return \"stop\";\n case \"length\":\n case \"model_length\":\n return \"length\";\n case \"tool_calls\":\n case \"function_call\":\n return \"toolUse\";\n default:\n return \"error\";\n }\n}\n\nfunction convertTools(tools: readonly Tool[]) {\n return tools.map((tool) => ({\n function: {\n description: tool.description,\n name: tool.name,\n parameters: tool.parameters\n },\n type: \"function\" as const\n }));\n}\n\n/** Whether a tool-call chunk is the null finalizer some vLLM parsers emit. */\nfunction isFinalizer(call: ToolCallDelta): boolean {\n const fn = call.function;\n return (\n call.index === undefined &&\n (call.id === null || call.id === undefined) &&\n (fn?.name === null || fn?.name === undefined) &&\n (fn?.arguments === null ||\n fn?.arguments === undefined ||\n fn?.arguments === \"\")\n );\n}\n\n/**\n * Incremental state for one streamed completion: the blocks being built on\n * the assistant message and the events that announce them.\n */\nclass CompletionAssembler {\n private textBlock: TextBlock | undefined;\n private thinkingBlock: ThinkingContent | undefined;\n private readonly openToolCalls = new Map<number, ToolCallBlock>();\n private readonly closedToolCalls = new Set<number>();\n private lastToolIndex: number | undefined;\n private readonly blocks: Block[];\n\n constructor(\n private readonly model: Model<string>,\n private readonly output: AssistantMessage,\n private readonly stream: AssistantMessageEventStream\n ) {\n this.blocks = output.content as Block[];\n }\n\n private indexOf(block: Block): number {\n return this.blocks.indexOf(block);\n }\n\n stripScratch(): void {\n for (const block of this.blocks) {\n if (block.type === \"toolCall\") delete block.partialArguments;\n }\n }\n\n private endText(): void {\n if (this.textBlock === undefined) return;\n this.stream.push({\n content: this.textBlock.text,\n contentIndex: this.indexOf(this.textBlock),\n partial: this.output,\n type: \"text_end\"\n });\n this.textBlock = undefined;\n }\n\n private endThinking(): void {\n if (this.thinkingBlock === undefined) return;\n this.stream.push({\n content: this.thinkingBlock.thinking,\n contentIndex: this.indexOf(this.thinkingBlock),\n partial: this.output,\n type: \"thinking_end\"\n });\n this.thinkingBlock = undefined;\n }\n\n private pushText(delta: string): void {\n if (delta.length === 0) return;\n this.endThinking();\n if (this.textBlock === undefined) {\n this.textBlock = { text: \"\", type: \"text\" };\n this.blocks.push(this.textBlock);\n this.stream.push({\n contentIndex: this.indexOf(this.textBlock),\n partial: this.output,\n type: \"text_start\"\n });\n }\n this.textBlock.text += delta;\n this.stream.push({\n contentIndex: this.indexOf(this.textBlock),\n delta,\n partial: this.output,\n type: \"text_delta\"\n });\n }\n\n private pushThinking(delta: string, signature: string): void {\n if (delta.length === 0) return;\n this.endText();\n if (this.thinkingBlock === undefined) {\n // The signature names the field the text came back in, so a later turn\n // replays it under that same key rather than as plain text. Workers AI\n // always resolves to `reasoning_content`: the compat layer rewrites its\n // `reasoning` deltas before the assembler sees them.\n this.thinkingBlock = {\n thinking: \"\",\n thinkingSignature: signature,\n type: \"thinking\"\n };\n this.blocks.push(this.thinkingBlock);\n this.stream.push({\n contentIndex: this.indexOf(this.thinkingBlock),\n partial: this.output,\n type: \"thinking_start\"\n });\n }\n this.thinkingBlock.thinking += delta;\n this.stream.push({\n contentIndex: this.indexOf(this.thinkingBlock),\n delta,\n partial: this.output,\n type: \"thinking_delta\"\n });\n }\n\n private closeToolCall(index: number): void {\n const block = this.openToolCalls.get(index);\n if (block === undefined || this.closedToolCalls.has(index)) return;\n this.closedToolCalls.add(index);\n block.arguments = parseStreamingJson(block.partialArguments ?? \"\");\n delete block.partialArguments;\n this.stream.push({\n contentIndex: this.indexOf(block),\n partial: this.output,\n toolCall: block,\n type: \"toolcall_end\"\n });\n }\n\n private pushToolCalls(calls: ToolCallDelta[]): void {\n this.endThinking();\n this.endText();\n for (const call of calls) {\n if (isFinalizer(call)) {\n if (this.lastToolIndex !== undefined) {\n this.closeToolCall(this.lastToolIndex);\n }\n continue;\n }\n const name = call.function?.name ?? undefined;\n const args = call.function?.arguments ?? \"\";\n const index =\n typeof call.index === \"number\" ? call.index : (this.lastToolIndex ?? 0);\n if (this.closedToolCalls.has(index)) continue;\n\n let block = this.openToolCalls.get(index);\n if (block === undefined) {\n if (this.lastToolIndex !== undefined && this.lastToolIndex !== index) {\n this.closeToolCall(this.lastToolIndex);\n }\n block = {\n arguments: {},\n id: call.id ?? crypto.randomUUID(),\n name: name ?? \"\",\n partialArguments: \"\",\n type: \"toolCall\"\n };\n this.openToolCalls.set(index, block);\n this.blocks.push(block);\n this.stream.push({\n contentIndex: this.indexOf(block),\n partial: this.output,\n type: \"toolcall_start\"\n });\n } else {\n if (block.name === \"\" && name) block.name = name;\n if (call.id) block.id = call.id;\n }\n this.lastToolIndex = index;\n if (args.length > 0) {\n block.partialArguments = (block.partialArguments ?? \"\") + args;\n block.arguments = parseStreamingJson(block.partialArguments);\n this.stream.push({\n contentIndex: this.indexOf(block),\n delta: args,\n partial: this.output,\n type: \"toolcall_delta\"\n });\n }\n }\n }\n\n private applyFinishReason(reason: string | null | undefined): boolean {\n if (reason === null || reason === undefined) return false;\n this.output.stopReason = mapFinishReason(reason);\n if (this.output.stopReason === \"error\") {\n this.output.errorMessage = `The model stopped with finish_reason \"${reason}\".`;\n }\n return true;\n }\n\n /** Applies one strict chunk (or a whole normalized body); true if it carried a finish reason. */\n apply(chunk: Chunk): boolean {\n if (chunk.error !== undefined) {\n this.output.stopReason = \"error\";\n this.output.errorMessage =\n chunk.error.message ?? \"The model reported an error.\";\n return true;\n }\n const choice = chunk.choices?.[0];\n if (chunk.id !== undefined) this.output.responseId ??= chunk.id;\n if (\n typeof chunk.model === \"string\" &&\n chunk.model.length > 0 &&\n chunk.model !== this.model.id\n ) {\n this.output.responseModel ??= chunk.model;\n }\n if (chunk.usage !== undefined) {\n this.output.usage = usageFromOpenAI(this.model, chunk.usage);\n }\n const finished = this.applyFinishReason(choice?.finish_reason);\n const delta = choice?.delta ?? choice?.message;\n if (delta !== undefined) {\n for (const field of REASONING_FIELDS) {\n const value = delta[field];\n if (typeof value === \"string\" && value.length > 0) {\n this.pushThinking(value, field);\n break;\n }\n }\n if (typeof delta.content === \"string\") this.pushText(delta.content);\n if (Array.isArray(delta.tool_calls)) {\n // A complete `message` is not a delta: OpenAI's schema gives its\n // `tool_calls` no `index` at all, so array position is the index.\n // Without it every call in a parallel set files under 0, merging into\n // one block. The Workers AI branch is normalized before it gets here\n // and fills the same positional index, so this changes nothing there.\n const complete = choice?.delta === undefined;\n this.pushToolCalls(\n complete\n ? delta.tool_calls.map((call, position) => ({\n ...call,\n index: typeof call.index === \"number\" ? call.index : position\n }))\n : delta.tool_calls\n );\n }\n }\n return finished;\n }\n\n /** Closes open blocks and settles the stop reason. */\n finish(sawFinishReason: boolean, sawDone: boolean): void {\n for (const index of this.openToolCalls.keys()) this.closeToolCall(index);\n this.endThinking();\n this.endText();\n const hasToolCalls = this.blocks.some((b) => b.type === \"toolCall\");\n if (this.output.stopReason === \"error\") return;\n if (!sawFinishReason) {\n // A complete stream ends with a finish reason or `[DONE]`; a stream\n // that closes without either was cut off, whatever it delivered first.\n if (sawDone) {\n this.output.stopReason = hasToolCalls ? \"toolUse\" : \"stop\";\n } else {\n this.output.stopReason = \"error\";\n this.output.errorMessage =\n this.blocks.length > 0\n ? \"The stream ended before the model finished its answer.\"\n : \"The stream ended before the model produced any output.\";\n }\n } else if (this.output.stopReason === \"stop\" && hasToolCalls) {\n this.output.stopReason = \"toolUse\";\n }\n }\n}\n\n/**\n * Puts the reasoning knobs on a chat-completions body, and reports the ones a\n * model cannot take.\n *\n * Workers AI is the one model family with knobs of ours: `reasoning_effort` on\n * its own three-level scale and `chat_template_kwargs`, both of which the\n * compat layer re-checks against the quirk table afterwards. For every other\n * model the decision is the model author's, read off the merged compat profile\n * exactly as pi-ai's own `openai-completions` implementation reads it: the\n * effort is emitted only when the model reasons, declares\n * `supportsReasoningEffort` and asks for OpenAI's `reasoning_effort` shape,\n * and it is remapped through the model's own `thinkingLevelMap`.\n */\nfunction applyReasoning(\n strict: Record<string, unknown>,\n context: {\n model: Model<string>;\n compat: Compat;\n effort: string | null | undefined;\n /** The Workers AI `reasoningEffort` setting, which a vendor model drops. */\n workersAIEffort: unknown;\n chatTemplateKwargs: Record<string, unknown> | undefined;\n workersAI: boolean;\n }\n): CompatWarning[] {\n const { chatTemplateKwargs, compat, effort, model, workersAI } = context;\n if (workersAI) {\n if (effort !== undefined) strict.reasoning_effort = effort;\n if (chatTemplateKwargs !== undefined) {\n strict.chat_template_kwargs = chatTemplateKwargs;\n }\n return [];\n }\n\n const ignored: CompatWarning[] = [];\n const thinkingFormat = (compat as { thinkingFormat?: string }).thinkingFormat;\n if (typeof effort === \"string\") {\n if (\n model.reasoning === true &&\n (compat as { supportsReasoningEffort?: boolean })\n .supportsReasoningEffort !== false &&\n thinkingFormat === \"openai\"\n ) {\n const map = model.thinkingLevelMap as\n | Record<string, string | null | undefined>\n | undefined;\n strict.reasoning_effort = map?.[effort] ?? effort;\n } else if (thinkingFormat !== \"openai\") {\n ignored.push({\n feature: \"reasoning-effort\",\n message: `This model declares the \"${thinkingFormat}\" thinking format, which this wire does not build; its reasoning level was dropped. Reach it through pi-ai's own provider if you need that shape.`\n });\n }\n }\n if (context.workersAIEffort === null) {\n ignored.push({\n feature: \"reasoning-off\",\n message:\n \"`reasoningEffort: null` is a Workers AI setting; a model routed through AI Gateway decides its own reasoning, so it was dropped.\"\n });\n } else if (context.workersAIEffort !== undefined) {\n ignored.push({\n feature: \"reasoning-effort\",\n message:\n \"`reasoningEffort` is a Workers AI setting and does not apply to a model routed through AI Gateway; use the pi `reasoning` level, which the model's own metadata maps.\"\n });\n }\n if (chatTemplateKwargs !== undefined) {\n ignored.push({\n feature: \"chat-template-kwargs\",\n message:\n \"`chatTemplateKwargs` is a Workers AI setting and does not apply to a model routed through AI Gateway; it was dropped.\"\n });\n }\n return ignored;\n}\n\n/** Streams a chat-completions request and maps it onto pi-ai events. */\nexport function streamCompletions(\n request: WireRequest,\n transport: Transport\n): AssistantMessageEventStream {\n const { model, context, options, resolved } = request;\n const stream = createAssistantMessageEventStream();\n const output = startMessage(model);\n const assembler = new CompletionAssembler(model, output, stream);\n\n const workersAI = model.api === CLOUDFLARE_AI_API;\n\n void (async () => {\n let response: Response | undefined;\n try {\n // A vendor model's own compat profile wins: its author knows which\n // fields that endpoint accepts, and this module deliberately does not.\n const compat: Compat = workersAI\n ? STRICT_OPENAI_COMPAT\n : { ...STRICT_OPENAI_COMPAT, ...(model.compat ?? {}) };\n const messages = convertMessages(\n // Only provider/id/reasoning are read; the api marker is not.\n model as unknown as Model<\"openai-completions\">,\n context,\n compat\n );\n\n const strict: Record<string, unknown> = {\n messages,\n stream: true,\n stream_options: { include_usage: true }\n };\n // The run path names the model in the call; the universal request names\n // it in the body, in the vendor's own spelling.\n if (!workersAI) strict.model = wireModelId(model);\n const tools = getCurrentTools(context.messages);\n if (tools.length > 0) strict.tools = convertTools(tools);\n if (request.toolChoice !== undefined) {\n strict.tool_choice = request.toolChoice;\n }\n if (options.maxTokens !== undefined)\n strict.max_tokens = options.maxTokens;\n if (options.temperature !== undefined) {\n strict.temperature = options.temperature;\n }\n const ignored = applyReasoning(strict, {\n chatTemplateKwargs: resolved.chatTemplateKwargs,\n compat,\n effort: request.reasoningEffort,\n model,\n workersAI,\n workersAIEffort: resolved.reasoningEffort\n });\n const sampling = (options as { samplingParams?: Record<string, unknown> })\n .samplingParams;\n if (sampling !== undefined) Object.assign(strict, sampling);\n\n const prepared = workersAI\n ? prepareChatCompletionsRequest(strict, model.id)\n : { body: strict, reasoningOff: false, warnings: [] };\n recordWarnings(output, [...ignored, ...prepared.warnings]);\n const overridden = await options.onPayload?.(prepared.body, model);\n const payload =\n overridden === undefined\n ? prepared.body\n : (overridden as Record<string, unknown>);\n\n response = workersAI\n ? await transport.run({\n gateway: resolved.gateway,\n headers: request.headers,\n input: payload,\n model: model.id,\n signal: options.signal\n })\n : await sendUniversal(\n request,\n transport,\n payload,\n openAIVendorHeaders()\n );\n await options.onResponse?.(responseInfo(response), model);\n attachCorrelation(\n output,\n correlationDetails(request, response, transport)\n );\n await assertOk(response, {\n model: model.id,\n requestBodyValues: payload,\n url: transport.url\n });\n if (response.body === null) {\n throw new Error(\"The model returned an empty response body.\");\n }\n\n stream.push({ partial: output, type: \"start\" });\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"text/event-stream\")) {\n let sawFinishReason = false;\n let sawDone = false;\n const decoded = withIdleDeadline(\n response.body,\n request.streamIdleTimeoutMs\n ).pipeThrough(sseDataStream());\n const chunks = workersAI\n ? decoded.pipeThrough(\n normalizeChatCompletionsStream(model.id, {\n reasoningOff: prepared.reasoningOff\n })\n )\n : decoded;\n const reader = chunks.getReader();\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value === \"[DONE]\") {\n sawDone = true;\n continue;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(value);\n } catch {\n continue;\n }\n if (parsed === null || typeof parsed !== \"object\") continue;\n sawFinishReason =\n assembler.apply(parsed as Chunk) || sawFinishReason;\n }\n } finally {\n reader.releaseLock();\n }\n assembler.finish(sawFinishReason, sawDone);\n } else {\n // A complete JSON body came back for a streaming request. Emit it as\n // a one-shot stream rather than failing.\n const body = await response.json();\n const json = workersAI\n ? normalizeChatCompletion(body, model.id)\n : (body as Chunk);\n assembler.finish(assembler.apply(json as Chunk), true);\n }\n\n if (options.signal?.aborted) throw new Error(\"Request was aborted.\");\n if (output.stopReason === \"error\") {\n throw new Error(\n output.errorMessage ?? \"The model reported an error stop reason.\"\n );\n }\n stream.push({\n message: output,\n reason: output.stopReason as \"stop\" | \"length\" | \"toolUse\",\n type: \"done\"\n });\n stream.end(output);\n } catch (error) {\n if (response?.body !== null && response?.body?.locked === false) {\n void response.body.cancel().catch(() => {});\n }\n assembler.stripScratch();\n failStream(stream, output, error, options.signal);\n }\n })();\n\n return stream;\n}\n","/**\n * Image generation for pi-ai: `ai.images(id)` builds a pi `ImagesModel` and\n * `ai.generateImages(model, context)` runs it through the transport.\n *\n * Workers AI text-to-image models take `{ prompt, width?, height?, seed?,\n * num_steps?, guidance?, negative_prompt?, image? }` and answer with raw PNG\n * bytes or, for some models, JSON `{ image: \"<base64>\" }`; both are mapped to\n * a pi `image` output part.\n */\n\nimport type {\n AssistantImages,\n ImagesContext,\n ImageModel,\n ImagesOptions\n} from \"@earendil-works/pi-ai\";\nimport type { CompatWarning } from \"../../core/chat-completions\";\nimport { buildImageInput, imageMediaTypeOf } from \"../../core/images\";\nimport type {\n ModelOptions,\n ProviderGatewaySettings\n} from \"../../core/settings\";\nimport { resolveOptions } from \"../../core/settings\";\nimport type { Transport } from \"../../core/transport\";\nimport { unwrapEnvelope } from \"../../core/transport\";\nimport { CLOUDFLARE_PROVIDER_ID } from \"../catalog\";\nimport { assertOk } from \"../errors\";\nimport { COMPAT_DIAGNOSTIC } from \"../wires/chat-completions\";\nimport { emptyUsage } from \"../wires/shared\";\n\n/**\n * The `api` marker on image models from this provider.\n *\n * @experimental This surface is experimental and may change.\n */\nexport const CLOUDFLARE_AI_IMAGES_API = \"cloudflare-ai-images\";\n\n/** @experimental This surface is experimental and may change. */\nexport type CloudflareImagesModel = ImageModel<typeof CLOUDFLARE_AI_IMAGES_API>;\n\n/**\n * Per-model options for image models: gateway options plus the generation\n * knobs Workers AI understands. Anything given here is the default for every\n * call; `generateImages` options override it.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface PiImagesModelOptions extends ModelOptions {\n name?: string;\n width?: number;\n height?: number;\n /** Diffusion steps, for models that accept it. */\n steps?: number;\n /** Classifier-free guidance scale, for models that accept it. */\n guidance?: number;\n negativePrompt?: string;\n seed?: number;\n}\n\n/** Per-call options for {@link generateImages}. */\nexport interface PiImagesCallOptions extends ImagesOptions {\n width?: number;\n height?: number;\n steps?: number;\n guidance?: number;\n negativePrompt?: string;\n seed?: number;\n}\n\nconst IMAGE_OPTIONS: unique symbol = Symbol.for(\n \"agents.models.pi-ai.image-options\"\n);\n\ntype TaggedImagesModel = CloudflareImagesModel & {\n [IMAGE_OPTIONS]?: PiImagesModelOptions;\n};\n\n/** Builds the pi image model for a catalog id. */\nexport function buildImagesModel(\n modelId: string,\n options: PiImagesModelOptions | undefined\n): CloudflareImagesModel {\n const model: TaggedImagesModel = {\n api: CLOUDFLARE_AI_IMAGES_API,\n baseUrl: \"\",\n cost: { cacheRead: 0, cacheWrite: 0, input: 0, output: 0 },\n id: modelId,\n input: [\"text\", \"image\"],\n name: options?.name ?? modelId,\n output: [\"image\"],\n provider: CLOUDFLARE_PROVIDER_ID,\n type: \"image\"\n };\n if (options !== undefined) {\n Object.defineProperty(model, IMAGE_OPTIONS, {\n configurable: true,\n enumerable: true,\n value: options,\n writable: false\n });\n }\n return model;\n}\n\nfunction imageOptionsOf(\n model: ImageModel<string>\n): PiImagesModelOptions | undefined {\n const options = (model as TaggedImagesModel)[IMAGE_OPTIONS];\n return options !== null && typeof options === \"object\" ? options : undefined;\n}\n\nfunction base64ToBytes(base64: string): Uint8Array {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n let binary = \"\";\n const chunk = 8192;\n for (let i = 0; i < bytes.length; i += chunk) {\n binary += String.fromCharCode(...bytes.subarray(i, i + chunk));\n }\n return btoa(binary);\n}\n\n/** Reads an image out of the run path's response, whichever shape it used. */\nasync function readImage(\n response: Response\n): Promise<{ data: string; mimeType: string }> {\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n const body = unwrapEnvelope(await response.json());\n const record =\n body !== null && typeof body === \"object\"\n ? (body as Record<string, unknown>)\n : {};\n if (typeof record.image === \"string\") {\n // The bytes decide the media type, never the model name: flux-1-schnell\n // answers JPEG where every other model in this catalog answers PNG.\n return { data: record.image, mimeType: imageMediaTypeOf(record.image) };\n }\n throw new Error(\"The image model returned JSON without an image field.\");\n }\n const bytes = new Uint8Array(await response.arrayBuffer());\n const data = bytesToBase64(bytes);\n return {\n data,\n mimeType: contentType.split(\";\")[0] || imageMediaTypeOf(data)\n };\n}\n\n/**\n * pi-ai's `AssistantImages` has no warnings channel, so a knob this catalog\n * drops is reported the way the language wires report theirs: as a diagnostic\n * of type {@link COMPAT_DIAGNOSTIC}.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface CloudflareAssistantImages extends AssistantImages {\n diagnostics?: {\n type: string;\n timestamp: number;\n details: { warnings: CompatWarning[] };\n }[];\n}\n\n/** Everything `generateImages` needs from `createAI`. */\nexport interface ImagesConfig {\n transport: Transport;\n providerGateway: string | ProviderGatewaySettings | undefined;\n}\n\n/**\n * Generates images with a Cloudflare catalog model. Text input parts join into\n * the prompt; the first image part, when present, is passed as the source\n * image for image-to-image models. Failures are reported through\n * `stopReason`/`errorMessage`, as pi-ai's images contract expects.\n */\nexport async function generateImages(\n config: ImagesConfig,\n model: ImageModel<string>,\n context: ImagesContext,\n options: PiImagesCallOptions | undefined\n): Promise<CloudflareAssistantImages> {\n const modelOptions = imageOptionsOf(model);\n const resolved = resolveOptions(\n config.providerGateway,\n modelOptions,\n undefined\n );\n const prompt = context.input\n .filter(\n (part): part is { type: \"text\"; text: string } => part.type === \"text\"\n )\n .map((part) => part.text)\n .join(\"\\n\");\n const source = context.input.find((part) => part.type === \"image\");\n\n const setting = <\n K extends keyof PiImagesCallOptions & keyof PiImagesModelOptions\n >(\n key: K\n ): PiImagesCallOptions[K] | undefined =>\n options?.[key] !== undefined ? options[key] : modelOptions?.[key];\n // The knob names and the flux-1 subset rule are shared with the AI SDK\n // module, so a model that takes only `{ prompt, steps }` gets only that from\n // either provider.\n const built = buildImageInput(model.id, prompt, {\n ...(setting(\"width\") === undefined ? {} : { width: setting(\"width\") }),\n ...(setting(\"height\") === undefined ? {} : { height: setting(\"height\") }),\n ...(setting(\"steps\") === undefined ? {} : { steps: setting(\"steps\") }),\n ...(setting(\"guidance\") === undefined\n ? {}\n : { guidance: setting(\"guidance\") }),\n ...(setting(\"negativePrompt\") === undefined\n ? {}\n : { negativePrompt: setting(\"negativePrompt\") }),\n ...(setting(\"seed\") === undefined ? {} : { seed: setting(\"seed\") }),\n ...(source === undefined ? {} : { sourceImage: true })\n });\n const input = built.input;\n const warnings: CompatWarning[] = built.warnings;\n if (!built.minimal && source !== undefined && source.type === \"image\") {\n input.image = Array.from(base64ToBytes(source.data));\n }\n\n const result: CloudflareAssistantImages = {\n api: model.api,\n model: model.id,\n output: [],\n provider: model.provider,\n stopReason: \"stop\",\n timestamp: Date.now(),\n usage: emptyUsage()\n };\n\n try {\n const response = await config.transport.run({\n gateway: resolved.gateway,\n headers: resolved.headers,\n input,\n model: model.id,\n signal: options?.signal\n });\n await assertOk(response, {\n model: model.id,\n requestBodyValues: input,\n url: config.transport.url\n });\n const image = await readImage(response);\n result.output.push({\n data: image.data,\n mimeType: image.mimeType,\n type: \"image\"\n });\n const requestId = response.headers.get(\"cf-aig-log-id\");\n if (requestId !== null) result.responseId = requestId;\n } catch (error) {\n result.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n result.errorMessage =\n error instanceof Error ? error.message : JSON.stringify(error);\n }\n // pi-ai's `AssistantImages` has no warnings channel, so a dropped knob is\n // reported the way the language wires report theirs: as a diagnostic.\n if (warnings.length > 0) {\n result.diagnostics = [\n { details: { warnings }, timestamp: Date.now(), type: COMPAT_DIAGNOSTIC }\n ];\n }\n return result;\n}\n","/**\n * Per-request option resolution for pi-ai calls: pi's call options and the\n * per-model options become one resolved request that every wire consumes.\n */\n\nimport type {\n Api,\n Model,\n SimpleStreamOptions,\n StreamOptions,\n ThinkingLevel,\n TranscriptContext\n} from \"@earendil-works/pi-ai\";\nimport { clampThinkingLevel } from \"@earendil-works/pi-ai\";\nimport type {\n GatewayOptions,\n ModelOptions,\n ProviderGatewaySettings,\n ResolvedOptions\n} from \"../core/settings\";\nimport { resolveOptions } from \"../core/settings\";\nimport type { Transport } from \"../core/transport\";\nimport { CLOUDFLARE_AI_API, optionsOf } from \"./catalog\";\nimport { DEFAULT_STREAM_IDLE_TIMEOUT_MS } from \"./wires/shared\";\n\n/** What `createAI` fixes for every request. */\nexport interface StreamConfig {\n transport: Transport;\n /** The `createAI` settings, whose gateway keys are the lowest layer. */\n providerGateway: string | ProviderGatewaySettings | undefined;\n}\n\n/** pi-ai's provider-neutral tool choice, in OpenAI's shape. */\nexport type ToolChoice =\n | \"auto\"\n | \"none\"\n | \"required\"\n | { type: \"function\"; function: { name: string } };\n\n/** Everything a wire needs, resolved once per request. */\nexport interface WireRequest {\n model: Model<Api>;\n context: TranscriptContext;\n /** The pi-ai call options; simple options carry `reasoning`. */\n options: SimpleStreamOptions;\n /** Whether this came through `streamSimple` (reasoning is a level). */\n simple: boolean;\n resolved: ResolvedOptions;\n /**\n * Legs to try if this one fails before producing output. A leg may be a\n * model object as well as an id, so this list — rather than\n * {@link ResolvedOptions.fallback}, which is ids only — is what the\n * dispatcher walks.\n */\n fallback: (string | Model<Api>)[];\n /** Request headers after gateway and affinity merging. */\n headers: Record<string, string>;\n /**\n * The reasoning effort to send, `null` to disable, `undefined` to omit.\n *\n * For a Workers AI model it is already collapsed onto the three levels the\n * compat layer's quirk table declares. For every other model it is the\n * model's own clamped thinking level, un-mapped: each wire applies that\n * model's `thinkingLevelMap` itself, exactly as pi-ai's own implementations\n * do, so no effort table of ours ever reaches a vendor.\n */\n reasoningEffort: string | null | undefined;\n toolChoice: ToolChoice | undefined;\n streamIdleTimeoutMs: number;\n}\n\n/** The pi thinking levels, for reading a caller's explicit effort. */\nconst THINKING_LEVELS: readonly string[] = [\n \"minimal\",\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\"\n];\n\nfunction isThinkingLevel(value: unknown): value is ThinkingLevel {\n return typeof value === \"string\" && THINKING_LEVELS.includes(value);\n}\n\n/**\n * Resolves a pi thinking level onto the effort a request carries.\n *\n * Workers AI is the one catalog with an effort scale of ours: its quirk table\n * declares three levels, so the run path collapses onto them. Every other\n * model keeps its own level name — the wire then applies the model's own\n * `thinkingLevelMap`, the way pi-ai's implementations do — because a table of\n * ours has no business deciding a vendor's efforts.\n */\nfunction effortForLevel(\n model: Model<Api>,\n level: ThinkingLevel | undefined\n): string | undefined {\n if (level === undefined || !model.reasoning) return undefined;\n const clamped = clampThinkingLevel(model, level);\n if (clamped === \"off\") return undefined;\n if (model.api !== CLOUDFLARE_AI_API) return clamped;\n switch (clamped) {\n case \"minimal\":\n case \"low\":\n return \"low\";\n case \"medium\":\n return \"medium\";\n case \"high\":\n case \"xhigh\":\n case \"max\":\n return \"high\";\n default: {\n const exhaustive: never = clamped;\n return exhaustive;\n }\n }\n}\n\n/** Scalars only: the gateway rejects nested metadata. */\nfunction scalarMetadata(\n metadata: Record<string, unknown> | undefined\n): GatewayOptions[\"metadata\"] {\n if (metadata === undefined) return undefined;\n const result: NonNullable<GatewayOptions[\"metadata\"]> = {};\n for (const [key, value] of Object.entries(metadata)) {\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n result[key] = value;\n }\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n/** pi headers allow `null` to suppress a default; those are dropped here. */\nfunction stringHeaders(\n headers: StreamOptions[\"headers\"]\n): Record<string, string> | undefined {\n if (headers === undefined) return undefined;\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (typeof value === \"string\") result[key] = value;\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n/** The per-call layer of options, read off pi-ai's call options. */\nfunction callLayer(options: SimpleStreamOptions): ModelOptions {\n const layer: ModelOptions = {};\n const headers = stringHeaders(options.headers);\n if (headers !== undefined) layer.headers = headers;\n const metadata = scalarMetadata(options.metadata);\n if (metadata !== undefined) layer.metadata = metadata;\n if (options.sessionId !== undefined)\n layer.sessionAffinity = options.sessionId;\n return layer;\n}\n\nfunction toolChoiceOf(options: SimpleStreamOptions): ToolChoice | undefined {\n const raw = (options as { toolChoice?: unknown }).toolChoice;\n if (raw === \"auto\" || raw === \"none\" || raw === \"required\") return raw;\n if (raw === \"any\") return \"required\";\n if (raw !== null && typeof raw === \"object\") {\n const record = raw as {\n type?: unknown;\n name?: unknown;\n function?: { name?: unknown };\n };\n const name =\n typeof record.function?.name === \"string\"\n ? record.function.name\n : typeof record.name === \"string\"\n ? record.name\n : undefined;\n if (name !== undefined) return { function: { name }, type: \"function\" };\n }\n return undefined;\n}\n\nexport function buildRequest(\n model: Model<Api>,\n context: TranscriptContext,\n options: SimpleStreamOptions,\n simple: boolean,\n config: StreamConfig\n): WireRequest {\n const modelOptions = optionsOf(model);\n const resolved = resolveOptions(\n config.providerGateway,\n modelOptions,\n callLayer(options)\n );\n const headers: Record<string, string> = { ...resolved.headers };\n // Session affinity is a Workers AI replica hint, sent as a request header on\n // the run path; it means nothing to a third-party vendor.\n if (\n resolved.sessionAffinity !== undefined &&\n model.api === CLOUDFLARE_AI_API\n ) {\n headers[\"x-session-affinity\"] = resolved.sessionAffinity;\n }\n const explicitEffort = (options as { reasoningEffort?: unknown })\n .reasoningEffort;\n // An explicitly named level goes through the same model-aware resolution as\n // `reasoning` does, so `\"xhigh\"` and `\"minimal\"` survive on a model whose\n // own metadata declares them; anything else a caller wrote is theirs.\n // `reasoningEffort` in the model options is a Workers AI setting. A vendor\n // model's reasoning follows the call's own level and the model's metadata;\n // the wires record the dropped setting as a diagnostic.\n const reasoningEffort =\n resolved.reasoningEffort !== undefined && model.api === CLOUDFLARE_AI_API\n ? resolved.reasoningEffort\n : isThinkingLevel(explicitEffort)\n ? effortForLevel(model, explicitEffort)\n : explicitEffort === \"off\"\n ? undefined\n : typeof explicitEffort === \"string\"\n ? explicitEffort\n : simple\n ? effortForLevel(model, options.reasoning)\n : undefined;\n return {\n context,\n fallback: modelOptions?.fallback ?? [],\n headers,\n model,\n options,\n reasoningEffort,\n resolved,\n simple,\n streamIdleTimeoutMs:\n modelOptions?.streamIdleTimeoutMs ?? DEFAULT_STREAM_IDLE_TIMEOUT_MS,\n toolChoice: toolChoiceOf(options)\n };\n}\n","/**\n * Anthropic Messages wire: pi-ai's own Anthropic implementation, over AI\n * Gateway's universal endpoint.\n *\n * Everything about the wire — request shaping, thinking, tool use, stream\n * parsing, thinking-signature replay — is pi-ai's. It accepts a `client` whose\n * `messages.create(...).asResponse()` returns the raw HTTP response; the one\n * built here routes that call through the gateway instead of the Anthropic\n * SDK, and sets the vendor headers the SDK would otherwise have added.\n *\n * The model object is never rewritten: `api`, `provider` and `id` reach pi's\n * implementation exactly as they will be recorded on the assistant message, so\n * a later turn replaying a thinking block is recognised as the same model.\n */\n\nimport {\n type AnthropicEffort,\n type AnthropicOptions,\n type Api,\n type AssistantMessageEventStream,\n type Model,\n type SimpleStreamOptions,\n type ThinkingLevel,\n createAssistantMessageEventStream\n} from \"@earendil-works/pi-ai\";\nimport { anthropicMessagesApi } from \"@earendil-works/pi-ai/api/anthropic-messages.lazy\";\nimport { adjustMaxTokensForThinking } from \"@earendil-works/pi-ai/api/simple-options\";\nimport type { Transport } from \"../../core/transport\";\nimport { wireModelId } from \"../catalog\";\nimport { assertOk, failStream } from \"../errors\";\nimport {\n anthropicVendorHeaders,\n attachCorrelation,\n correlationDetails,\n sendUniversal,\n startMessage,\n withIdleDeadline,\n ignoredWorkersAIKnobs,\n recordWarnings\n} from \"./shared\";\nimport type { WireRequest } from \"../settings\";\n\n/**\n * Maps a pi thinking level onto an Anthropic effort the way pi-ai's own\n * `streamSimple` does: the model's `thinkingLevelMap` first, then the level's\n * own name. The map is the model author's; nothing here decides it.\n */\nfunction effortForLevel(\n model: Model<Api>,\n level: ThinkingLevel\n): AnthropicEffort {\n const mapped = model.thinkingLevelMap?.[level];\n if (typeof mapped === \"string\") return mapped as AnthropicEffort;\n switch (level) {\n case \"minimal\":\n case \"low\":\n return \"low\";\n case \"medium\":\n return \"medium\";\n default:\n return \"high\";\n }\n}\n\n/**\n * pi-ai's `streamSimple` thinking rules, applied here because that entry point\n * insists on a credential and this transport has none. Which branch a model\n * takes is the model's own `compat.forceAdaptiveThinking`, not a rule of ours.\n */\nfunction thinkingOptions(\n model: Model<Api>,\n options: SimpleStreamOptions\n): Pick<\n AnthropicOptions,\n \"thinkingEnabled\" | \"thinkingBudgetTokens\" | \"maxTokens\" | \"effort\"\n> {\n const level = options.reasoning;\n if (level === undefined || !model.reasoning) {\n return { thinkingEnabled: false };\n }\n const compat = (model as { compat?: { forceAdaptiveThinking?: boolean } })\n .compat;\n if (compat?.forceAdaptiveThinking === true) {\n return { effort: effortForLevel(model, level), thinkingEnabled: true };\n }\n const { maxTokens, thinkingBudget } = adjustMaxTokensForThinking(\n options.maxTokens,\n model.maxTokens,\n level,\n options.thinkingBudgets\n );\n return {\n maxTokens,\n thinkingBudgetTokens: thinkingBudget,\n thinkingEnabled: true\n };\n}\n\n/** Streams an Anthropic request through pi-ai's implementation. */\nexport function streamAnthropic(\n request: WireRequest,\n transport: Transport\n): AssistantMessageEventStream {\n const { model, context, options } = request;\n const outer = createAssistantMessageEventStream();\n const placeholder = startMessage(model);\n let correlation: ReturnType<typeof correlationDetails> | undefined;\n // pi-ai's own implementation catches whatever `asResponse()` throws and ends\n // the stream with its own error event, which would lose the typed\n // Cloudflare error. Holding it here lets the wire report it instead.\n let transportError: unknown;\n\n // pi-ai calls the SDK's beta endpoint with the beta features it chose in\n // `params.betas`. The SDK would send those as the `anthropic-beta` header,\n // not in the body, so this client does the same.\n const create = (params: Record<string, unknown>) => ({\n async asResponse(): Promise<Response> {\n const { betas, ...vendorParams } = params;\n // The universal request wants the vendor's own spelling of the id\n // in the body, whatever this provider lists the model under.\n const body = { ...vendorParams, model: wireModelId(model) };\n try {\n const response = await sendUniversal(\n request,\n transport,\n body,\n anthropicVendorHeaders(Array.isArray(betas) ? betas : []),\n (raw) => {\n correlation = correlationDetails(request, raw, transport);\n }\n );\n await assertOk(response, {\n model: model.id,\n requestBodyValues: body,\n url: transport.url\n });\n if (response.body === null) return response;\n return new Response(\n withIdleDeadline(response.body, request.streamIdleTimeoutMs),\n response\n );\n } catch (error) {\n transportError = error;\n throw error;\n }\n }\n });\n const client = {\n beta: { messages: { create } },\n messages: { create }\n } as unknown as NonNullable<AnthropicOptions[\"client\"]>;\n\n const anthropicOptions: AnthropicOptions = {\n ...options,\n ...(request.simple ? thinkingOptions(model, options) : {}),\n client,\n ...(request.toolChoice !== undefined\n ? {\n toolChoice:\n typeof request.toolChoice === \"string\"\n ? request.toolChoice === \"required\"\n ? \"any\"\n : request.toolChoice\n : { name: request.toolChoice.function.name, type: \"tool\" }\n }\n : {})\n };\n\n void (async () => {\n try {\n const inner = anthropicMessagesApi().stream(\n model as Model<\"anthropic-messages\">,\n context,\n anthropicOptions\n );\n for await (const event of inner) {\n // A transport failure is ours to report: pi-ai's own error event knows\n // nothing of the gateway's status, code or log id, so the message it\n // built is re-failed here with that diagnostic attached.\n if (event.type === \"error\" && transportError !== undefined) {\n failFrom(event.error);\n return;\n }\n if (event.type === \"done\" || event.type === \"error\") {\n const message = event.type === \"done\" ? event.message : event.error;\n if (correlation !== undefined) {\n attachCorrelation(message, correlation);\n }\n recordWarnings(message, ignoredWorkersAIKnobs(request));\n }\n outer.push(event);\n }\n if (transportError !== undefined) {\n failFrom(placeholder);\n return;\n }\n outer.end(await inner.result());\n } catch (error) {\n failStream(outer, placeholder, transportError ?? error, options.signal);\n }\n })();\n\n /** Ends the stream with the transport's own error, keeping any content. */\n function failFrom(message: typeof placeholder): void {\n if (correlation !== undefined) attachCorrelation(message, correlation);\n failStream(outer, message, transportError, options.signal);\n }\n\n return outer;\n}\n","/**\n * OpenAI Responses wire: pi-ai's own Responses converters and stream\n * processor, over AI Gateway's universal endpoint.\n *\n * Only the transport differs from talking to OpenAI directly: the body goes to\n * the gateway, which forwards it to `api.openai.com/v1/responses` with the key\n * it holds, and the raw SSE `Response` comes back. The model object is passed\n * through untouched, so the encrypted reasoning items pi replays on a later\n * turn are recognised as the same model's.\n */\n\nimport {\n type AssistantMessageEventStream,\n type Model,\n createAssistantMessageEventStream,\n getCurrentTools\n} from \"@earendil-works/pi-ai\";\nimport {\n convertResponsesMessages,\n convertResponsesTools,\n processResponsesStream\n} from \"@earendil-works/pi-ai/api/openai-responses-shared\";\nimport { clampOpenAIPromptCacheKey } from \"@earendil-works/pi-ai/api/openai-prompt-cache\";\nimport type { Transport } from \"../../core/transport\";\nimport { wireModelId } from \"../catalog\";\nimport { assertOk, failStream } from \"../errors\";\nimport {\n MIN_OUTPUT_TOKENS,\n attachCorrelation,\n correlationDetails,\n openAIVendorHeaders,\n responseInfo,\n sendUniversal,\n sseJson,\n startMessage,\n withIdleDeadline,\n ignoredWorkersAIKnobs,\n recordWarnings\n} from \"./shared\";\nimport type { WireRequest } from \"../settings\";\n\n/**\n * Providers whose tool-call ids carry OpenAI `call|item` pairing across\n * turns. This provider sanitizes ids instead, like pi-ai's own gateway\n * provider, so the set is empty.\n */\nconst TOOL_CALL_ID_PROVIDERS: ReadonlySet<string> = new Set();\n\nconst TERMINAL_EVENTS = new Set([\n \"response.completed\",\n \"response.incomplete\",\n \"response.failed\"\n]);\n\n/** A level through the model's own map, or the level's own name. */\nfunction mappedEffort(model: Model<string>, effort: string): string {\n const map = model.thinkingLevelMap as\n | Record<string, string | null | undefined>\n | undefined;\n return map?.[effort] ?? effort;\n}\n\n/** Streams a Responses request and maps it onto pi-ai events. */\nexport function streamResponses(\n request: WireRequest,\n transport: Transport\n): AssistantMessageEventStream {\n const { model, context, options, resolved } = request;\n const stream = createAssistantMessageEventStream();\n const output = startMessage(model);\n const observed = { endedCleanly: false, sawTerminalEvent: false };\n\n void (async () => {\n let response: Response | undefined;\n try {\n const responsesModel = model as Model<\"openai-responses\">;\n const body: Record<string, unknown> = {\n input: convertResponsesMessages(\n responsesModel,\n context,\n TOOL_CALL_ID_PROVIDERS\n ),\n // The universal request carries the vendor's own spelling of the id.\n model: wireModelId(model),\n store: false,\n stream: true\n };\n const tools = getCurrentTools(context.messages);\n if (tools.length > 0) body.tools = convertResponsesTools(tools);\n if (request.toolChoice !== undefined) {\n body.tool_choice =\n typeof request.toolChoice === \"string\"\n ? request.toolChoice\n : { name: request.toolChoice.function.name, type: \"function\" };\n }\n if (options.maxTokens !== undefined) {\n body.max_output_tokens = Math.max(options.maxTokens, MIN_OUTPUT_TOKENS);\n }\n if (options.temperature !== undefined) {\n body.temperature = options.temperature;\n }\n const cacheKey = clampOpenAIPromptCacheKey(\n resolved.sessionAffinity ?? options.sessionId\n );\n if (cacheKey !== undefined) body.prompt_cache_key = cacheKey;\n // The effort a level names is the model's own to decide: its\n // `thinkingLevelMap` maps it, and its `off` entry says whether the model\n // can be asked for no reasoning at all. Both reads mirror pi-ai's own\n // Responses implementation; neither is a rule of this package.\n if (model.reasoning === true) {\n // With `store: false`, a reasoning item can only be replayed on the\n // next turn if it carries its encrypted content. A model that cannot\n // turn reasoning off reasons even when no effort is asked for, so the\n // content is requested whenever the model reasons at all.\n body.include = [\"reasoning.encrypted_content\"];\n const effort = request.reasoningEffort;\n if (typeof effort === \"string\") {\n body.reasoning = {\n effort: mappedEffort(model, effort),\n summary: \"auto\"\n };\n } else if (model.thinkingLevelMap?.off !== null) {\n body.reasoning = { effort: model.thinkingLevelMap?.off ?? \"none\" };\n }\n }\n const sampling = (options as { samplingParams?: Record<string, unknown> })\n .samplingParams;\n if (sampling !== undefined) Object.assign(body, sampling);\n const overridden = await options.onPayload?.(body, model);\n const payload =\n overridden === undefined\n ? body\n : (overridden as Record<string, unknown>);\n\n response = await sendUniversal(\n request,\n transport,\n payload,\n openAIVendorHeaders()\n );\n await options.onResponse?.(responseInfo(response), model);\n attachCorrelation(\n output,\n correlationDetails(request, response, transport)\n );\n recordWarnings(output, ignoredWorkersAIKnobs(request));\n await assertOk(response, {\n model: model.id,\n requestBodyValues: payload,\n url: transport.url\n });\n if (response.body === null) {\n throw new Error(\"The model returned an empty response body.\");\n }\n\n stream.push({ partial: output, type: \"start\" });\n\n const events = observe(\n sseJson(withIdleDeadline(response.body, request.streamIdleTimeoutMs))\n );\n await processResponsesStream(\n events as Parameters<typeof processResponsesStream>[0],\n output,\n stream,\n responsesModel\n );\n\n if (options.signal?.aborted) throw new Error(\"Request was aborted.\");\n if (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n throw new Error(\n output.errorMessage ?? \"The model reported an error stop reason.\"\n );\n }\n if (observed.endedCleanly && !observed.sawTerminalEvent) {\n throw new Error(\"The stream ended without a terminal response event.\");\n }\n stream.push({\n message: output,\n reason: output.stopReason as \"stop\" | \"length\" | \"toolUse\",\n type: \"done\"\n });\n stream.end(output);\n } catch (error) {\n if (response?.body !== null && response?.body?.locked === false) {\n void response.body.cancel().catch(() => {});\n }\n for (const block of output.content) {\n delete (block as { index?: number }).index;\n delete (block as { partialJson?: string }).partialJson;\n delete (block as { customInput?: unknown }).customInput;\n }\n failStream(stream, output, error, options.signal);\n }\n })();\n\n return stream;\n\n async function* observe(\n events: AsyncIterable<unknown>\n ): AsyncIterable<unknown> {\n for await (const event of events) {\n const type = (event as { type?: unknown } | null)?.type;\n if (typeof type === \"string\" && TERMINAL_EVENTS.has(type)) {\n observed.sawTerminalEvent = true;\n }\n yield event;\n }\n observed.endedCleanly = true;\n }\n}\n","/**\n * Client-side model fallback for pi-ai streams.\n *\n * A leg is abandoned when its stream terminates with an `error` event before\n * it produced any content; the next model is tried with the same context and\n * options. Once a leg has emitted content it is committed to, and a later\n * error propagates. `start` and the block starts that may follow it carry no\n * content, so they are held back until a leg proves itself.\n */\n\nimport {\n type Api,\n type AssistantMessage,\n type AssistantMessageEvent,\n type AssistantMessageEventStream,\n type Model,\n createAssistantMessageEventStream\n} from \"@earendil-works/pi-ai\";\nimport { failStream } from \"../errors\";\nimport { jsonDetails, startMessage } from \"../wires/shared\";\n\n/** One model to try, with the stream that dispatches it. */\nexport interface FallbackLeg {\n model: Model<Api>;\n start(): AssistantMessageEventStream;\n}\n\n/** A leg that was tried and failed before producing output. */\nexport interface FallbackAttempt {\n model: string;\n errorMessage: string | undefined;\n}\n\n/** Diagnostic type under which abandoned legs are recorded. */\nexport const FALLBACK_DIAGNOSTIC = \"cloudflare-fallback\";\n\n/**\n * Events that announce output without carrying any. A leg that emits only\n * these and then fails has produced nothing, so they are held back with\n * `start` until the leg proves itself.\n */\nconst PREAMBLE_EVENTS = new Set<AssistantMessageEvent[\"type\"]>([\n \"start\",\n \"text_start\",\n \"thinking_start\",\n \"toolcall_start\"\n]);\n\nfunction isAbandonable(event: AssistantMessageEvent): boolean {\n return event.type === \"error\" && event.reason === \"error\";\n}\n\n/**\n * Runs legs in order, committing to the first one that produces output.\n *\n * The returned stream always ends. A leg that throws, a stream that rejects,\n * a leg that starts answering and then ends without a `done` or `error`\n * event, and a last leg that ends without producing anything all end it\n * with an `error` event, so a caller awaiting the result is never left\n * waiting.\n */\nexport function streamWithFallback(\n legs: FallbackLeg[],\n signal?: AbortSignal\n): AssistantMessageEventStream {\n const first = legs[0];\n if (first === undefined) {\n throw new Error(\"streamWithFallback needs at least one leg.\");\n }\n const outer = createAssistantMessageEventStream();\n const attempts: FallbackAttempt[] = [];\n let ended = false;\n const end = (message: AssistantMessage): void => {\n ended = true;\n outer.end(message);\n };\n const recordAttempts = (message: AssistantMessage): void => {\n message.diagnostics = [\n ...(message.diagnostics ?? []),\n {\n details: jsonDetails({ attempts }),\n timestamp: Date.now(),\n type: FALLBACK_DIAGNOSTIC\n }\n ];\n };\n\n void (async () => {\n let current = first;\n let lastError: AssistantMessage | undefined;\n try {\n for (const [index, leg] of legs.entries()) {\n current = leg;\n const isLast = index === legs.length - 1;\n const inner = leg.start();\n let pending: AssistantMessageEvent[] = [];\n let committed = false;\n let finished = false;\n for await (const event of inner) {\n if (!committed && PREAMBLE_EVENTS.has(event.type)) {\n pending.push(event);\n continue;\n }\n if (!committed) {\n if (event.type === \"error\" && isAbandonable(event) && !isLast) {\n attempts.push({\n errorMessage: event.error.errorMessage,\n model: leg.model.id\n });\n lastError = event.error;\n break;\n }\n committed = true;\n for (const held of pending) outer.push(held);\n pending = [];\n }\n if (\n (event.type === \"done\" || event.type === \"error\") &&\n attempts.length > 0\n ) {\n recordAttempts(event.type === \"done\" ? event.message : event.error);\n }\n outer.push(event);\n if (event.type === \"done\" || event.type === \"error\") finished = true;\n }\n // A terminal event resolves the leg's result. pi's protocol ends every\n // stream with one, and a leg that ends without it has no result to\n // wait for.\n if (finished) {\n end(await inner.result());\n return;\n }\n if (committed) {\n throw new Error(\n `${leg.model.id} ended its stream without a done or error event.`\n );\n }\n }\n // Every leg was abandoned; surface the last error as the result.\n if (lastError !== undefined) {\n recordAttempts(lastError);\n outer.push({ error: lastError, reason: \"error\", type: \"error\" });\n end(lastError);\n return;\n }\n throw new Error(`${current.model.id} ended its stream without output.`);\n } catch (error) {\n if (ended) return;\n const message = startMessage(current.model);\n if (attempts.length > 0) recordAttempts(message);\n ended = true;\n failStream(outer, message, error, signal);\n }\n })();\n\n return outer;\n}\n","/**\n * The pi-ai language dispatcher: picks the wire from the model's own `api`\n * marker and runs the request through the transport, with client-side fallback\n * across models.\n *\n * The `api` is the model author's declaration, not a guess of ours: Workers AI\n * models carry {@link CLOUDFLARE_AI_API} and run on `env.AI.run`; every other\n * model carries whatever protocol its registry says it speaks, and goes to AI\n * Gateway's universal endpoint.\n */\n\nimport {\n type Api,\n type AssistantMessageEventStream,\n type TranscriptContext,\n type Model,\n type ProviderStreams,\n type SimpleStreamOptions,\n createAssistantMessageEventStream\n} from \"@earendil-works/pi-ai\";\nimport { gatewayLayerOf, mergeModelOptions } from \"../../core/settings\";\nimport type { Transport } from \"../../core/transport\";\nimport {\n CLOUDFLARE_AI_API,\n type PiModelOptions,\n buildGatewayModel,\n buildWorkersAIModel,\n optionsOf,\n withOptions,\n type PiFallbackLeg\n} from \"../catalog\";\nimport { failStream } from \"../errors\";\nimport { type StreamConfig, type WireRequest, buildRequest } from \"../settings\";\nimport { streamAnthropic } from \"../wires/anthropic\";\nimport { streamCompletions } from \"../wires/chat-completions\";\nimport { streamResponses } from \"../wires/responses\";\nimport { startMessage } from \"../wires/shared\";\nimport { streamWithFallback } from \"./fallback\";\n\n/** A stream that fails immediately, for a model this provider cannot route. */\nfunction failedStream(\n request: WireRequest,\n error: Error\n): AssistantMessageEventStream {\n const stream = createAssistantMessageEventStream();\n failStream(\n stream,\n startMessage(request.model),\n error,\n request.options.signal\n );\n return stream;\n}\n\nfunction dispatchOne(\n request: WireRequest,\n transport: Transport\n): AssistantMessageEventStream {\n switch (request.model.api) {\n case CLOUDFLARE_AI_API:\n case \"openai-completions\":\n return streamCompletions(request, transport);\n case \"anthropic-messages\":\n return streamAnthropic(request, transport);\n case \"openai-responses\":\n return streamResponses(request, transport);\n default:\n return failedStream(\n request,\n new TypeError(\n `agents/models/pi-ai cannot route the \"${request.model.api}\" API. AI Gateway serves anthropic-messages, openai-responses and openai-completions models; Workers AI models use \"${CLOUDFLARE_AI_API}\".`\n )\n );\n }\n}\n\n/**\n * The options a fallback leg inherits from the chain: the transport bag, and\n * nothing that describes a model.\n *\n * `name`, `cost`, `contextWindow`, `maxTokens`, `reasoning` and `input` were\n * written about the model they were written on — a leg has its own, from pi's\n * registry — and inheriting them bills the leg's answer at the primary's\n * prices. The leg's own `fallback` is dropped for the same reason `ai()`\n * expands a chain once: a leg is already part of one.\n */\nfunction legOptions(\n options: PiModelOptions | undefined\n): PiModelOptions | undefined {\n if (options === undefined) return undefined;\n const {\n fallback: _fallback,\n name: _name,\n cost: _cost,\n contextWindow: _contextWindow,\n maxTokens: _maxTokens,\n reasoning: _reasoning,\n input: _input,\n ...rest\n } = options;\n return rest;\n}\n\n/** A leg may be given as a Workers AI id or as a model of any kind. */\nfunction legModel(\n leg: string | Model<Api>,\n options: PiModelOptions | undefined\n): Model<Api> {\n // An id has no options of its own, so it takes the chain's transport bag.\n // It resolves exactly as `ai(string)` does: a Workers AI id, or a\n // `<slug>/<id>` pi-ai's gateway registry knows — never a raw vendor id.\n if (typeof leg === \"string\") {\n return leg.startsWith(\"@cf/\")\n ? buildWorkersAIModel(leg, options)\n : buildGatewayModel(leg, options);\n }\n // A configured leg keeps everything it was built with; the chain's gateway\n // options are layered over its own, field by field, so a chain and its legs\n // travel through one gateway — the same rule the AI SDK module applies.\n const own = optionsOf(leg);\n const inherited = gatewayLayerOf(options);\n const merged = mergeModelOptions<PiFallbackLeg>(\n own,\n Object.keys(inherited).length > 0 ? inherited : undefined\n ) as PiModelOptions | undefined;\n return withOptions(leg, merged);\n}\n\n/**\n * Builds pi-ai's `stream` and `streamSimple` for one provider instance. Any\n * model reaches them — this provider's own, or one the caller built from their\n * registry and handed to `ai(model)` — and dispatches on its `api`.\n */\nexport function createStreams(config: StreamConfig): ProviderStreams {\n const run = (\n model: Model<Api>,\n context: TranscriptContext,\n options: SimpleStreamOptions | undefined,\n simple: boolean\n ): AssistantMessageEventStream => {\n const callOptions = options ?? {};\n const primary = buildRequest(model, context, callOptions, simple, config);\n if (primary.fallback.length === 0) {\n return dispatchOne(primary, config.transport);\n }\n\n const shared = legOptions(optionsOf(model));\n const legs = [\n {\n model,\n start: () => dispatchOne(primary, config.transport)\n },\n ...primary.fallback.map((leg) => {\n const legTarget = legModel(leg, shared);\n return {\n model: legTarget,\n start: () =>\n dispatchOne(\n buildRequest(legTarget, context, callOptions, simple, config),\n config.transport\n )\n };\n })\n ];\n return streamWithFallback(legs, callOptions.signal);\n };\n\n return {\n stream: (model, context, options) =>\n run(model, context, options as SimpleStreamOptions | undefined, false),\n streamSimple: (model, context, options) =>\n run(model, context, options, true)\n };\n}\n","/**\n * `agents/models/pi-ai` — Cloudflare's AI as a pi-ai provider, with the same\n * shape as `agents/models/ai-sdk`.\n *\n * One rule decides everything here: **Workers AI is the catalog Cloudflare\n * keeps; every other vendor is pi-ai's.** So there are two call forms, and no\n * third:\n *\n * ```ts\n * import { createAI } from \"agents/models/pi-ai\";\n * import { getBuiltinModel } from \"@earendil-works/pi-ai/providers/all\";\n *\n * const ai = createAI({ binding: env.AI, id: \"prod\" });\n *\n * ai(\"@cf/zai-org/glm-4.7-flash\"); // Workers AI: ours\n * ai(getBuiltinModel(\"anthropic\", \"claude-opus-4-8\")); // theirs, our transport\n * ai(\"anthropic/claude-opus-4-8\"); // same, via pi's catalog\n * ```\n *\n * Workers AI runs on `env.AI.run` with Cloudflare's own compat layer. Every\n * other model goes to AI Gateway's universal endpoint, which forwards the\n * vendor's own request to the vendor with the key the gateway holds — so no\n * provider key, and no vendor wire format, lives in your Worker. The model's\n * metadata (`api`, `compat`, `thinkingLevelMap`, cost, limits) is whatever its\n * own registry says, and pi-ai's converters and stream processors do the rest.\n *\n * @experimental Everything exported here is experimental: the surface may\n * change in a minor release while the design settles.\n *\n * @module\n */\n\nimport {\n type Api,\n type AssistantMessage,\n type Context,\n type ImagesContext,\n type Model,\n type Provider,\n type SimpleStreamOptions,\n type StreamOptions,\n createProvider,\n normalizeContext\n} from \"@earendil-works/pi-ai\";\nimport type { WorkersAIModelId } from \"../core/catalog\";\nimport type { AISettings } from \"../core/settings\";\nimport { createTransport } from \"../core/transport\";\nimport {\n type CloudflareAssistantImages,\n type CloudflareImagesModel,\n type PiImagesCallOptions,\n type PiImagesModelOptions,\n buildImagesModel,\n generateImages\n} from \"./models/image\";\nimport {\n CLOUDFLARE_PROVIDER_ID,\n type CloudflareModel,\n type PiModelOptions,\n type RoutedModel,\n buildGatewayModel,\n buildWorkersAIModel,\n gatewayModelIds,\n withOptions,\n workersAIModelIds\n} from \"./catalog\";\nimport { createStreams } from \"./models/language\";\n\nexport type {\n CloudflareEmbeddingModelId,\n WorkersAIModelId\n} from \"../core/catalog\";\nexport {\n CloudflareAIError,\n type CloudflareAIAttempt,\n type CloudflareAIErrorCode\n} from \"../core/errors\";\nexport type {\n AISettings,\n GatewayOptions,\n ModelOptions\n} from \"../core/settings\";\nexport {\n GATEWAY_PROVIDER_NAMES,\n type GatewayProviderName\n} from \"../core/gateway-providers\";\nexport { FALLBACK_DIAGNOSTIC, type FallbackAttempt } from \"./models/fallback\";\nexport {\n CLOUDFLARE_AI_IMAGES_API,\n type CloudflareAssistantImages,\n type CloudflareImagesModel,\n type PiImagesCallOptions,\n type PiImagesModelOptions\n} from \"./models/image\";\nexport {\n CLOUDFLARE_AI_API,\n CLOUDFLARE_PROVIDER_ID,\n type CloudflareAIApi,\n type CloudflareModel,\n type ModelCost,\n type PiModelOptions,\n type RoutedModel\n} from \"./catalog\";\nexport { CLOUDFLARE_ERROR_DIAGNOSTIC } from \"./errors\";\nexport { CLOUDFLARE_DIAGNOSTIC } from \"./wires/shared\";\n\n/**\n * pi-agent-core's `streamFn` shape: what `Agent` calls to run a turn.\n *\n * @experimental This surface is experimental and may change.\n */\nexport type StreamFn = (\n model: Model<string>,\n context: Context,\n options?: SimpleStreamOptions\n) => ReturnType<Provider[\"streamSimple\"]>;\n\n/**\n * The provider `createAI` returns. Call it with a Workers AI id or with a\n * pi-ai model to get a model this instance routes; use `stream`/`complete` to\n * run it, `streamFn` with pi-agent-core's `Agent`, and `provider` with a pi-ai\n * `Models` registry.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface AI {\n /** A Workers AI model: Cloudflare's own catalog, on the run path. */\n (modelId: WorkersAIModelId, options?: PiModelOptions): CloudflareModel;\n /** Any pi-ai model, routed through AI Gateway with its metadata intact. */\n <TApi extends Api>(model: Model<TApi>, options?: PiModelOptions): Model<TApi>;\n /**\n * A `<slug>/<id>` id from pi-ai's Cloudflare AI Gateway catalog, or either\n * form when the caller only knows which at runtime.\n */\n (target: string | Model<Api>, options?: PiModelOptions): RoutedModel;\n /** Same as calling the provider directly. */\n model(modelId: WorkersAIModelId, options?: PiModelOptions): CloudflareModel;\n model<TApi extends Api>(\n model: Model<TApi>,\n options?: PiModelOptions\n ): Model<TApi>;\n model(target: string | Model<Api>, options?: PiModelOptions): RoutedModel;\n /**\n * The pi-ai `Provider` (id `cloudflare`) for `Models.setProvider` and\n * frameworks built on the registry. Its static model list is every Workers\n * AI id plus every `<slug>/<id>` in pi-ai's Cloudflare AI Gateway catalog;\n * any other model still streams when passed to `ai(model)`.\n */\n readonly provider: Provider;\n /** Full-options streaming, like pi-ai's `stream`. */\n stream(\n model: Model<string>,\n context: Context,\n options?: StreamOptions\n ): ReturnType<Provider[\"stream\"]>;\n /** Full-options completion, like pi-ai's `complete`. */\n complete(\n model: Model<string>,\n context: Context,\n options?: StreamOptions\n ): Promise<AssistantMessage>;\n /** Simple streaming, with `reasoning` as a level, like pi-ai's `streamSimple`. */\n streamSimple(\n model: Model<string>,\n context: Context,\n options?: SimpleStreamOptions\n ): ReturnType<Provider[\"streamSimple\"]>;\n /** Simple completion, like pi-ai's `completeSimple`. */\n completeSimple(\n model: Model<string>,\n context: Context,\n options?: SimpleStreamOptions\n ): Promise<AssistantMessage>;\n /** `streamSimple`, bound, for pi-agent-core's `Agent({ streamFn })`. */\n readonly streamFn: StreamFn;\n /** A pi-ai image model over a Workers AI text-to-image id. */\n images(\n modelId: string,\n options?: PiImagesModelOptions\n ): CloudflareImagesModel;\n /** Generates images with a model from {@link AI.images}, like pi-ai's `generateImages`. */\n generateImages(\n model: CloudflareImagesModel,\n context: ImagesContext,\n options?: PiImagesCallOptions\n ): Promise<CloudflareAssistantImages>;\n}\n\n/** The prefixes a bare vendor id is most often written with, for the error. */\nconst VENDOR_HINTS: Record<string, string> = {\n anthropic: \"anthropic\",\n google: \"google\",\n openai: \"openai\"\n};\n\n/**\n * A string that is neither a Workers AI id nor a `<slug>/<id>` this provider\n * can resolve. There is no guessing here by design: a model we cannot name\n * exactly is the caller's to construct.\n */\nfunction unroutableString(specifier: string): TypeError {\n const prefix = specifier.split(\"/\")[0] ?? \"\";\n const hint = VENDOR_HINTS[prefix];\n return new TypeError(\n `ai(\"${specifier}\") is not a model this provider knows. Workers AI ids start with \"@cf/\". A third-party model comes from its own pi-ai registry: ai(getBuiltinModel(${\n hint === undefined ? '\"<provider>\"' : `\"${hint}\"`\n }, \"<model id>\")) from \"@earendil-works/pi-ai/providers/all\", or any Model object you built yourself.`\n );\n}\n\nfunction buildModel(\n target: string | Model<Api>,\n options: PiModelOptions | undefined\n): Model<Api> {\n // A string leg follows the same rule as a string target, checked here so\n // the mistake is reported at the line that wrote the chain.\n for (const leg of options?.fallback ?? []) {\n if (typeof leg !== \"string\" || leg.startsWith(\"@cf/\")) continue;\n if (!leg.includes(\"/\")) throw unroutableString(leg);\n buildGatewayModel(leg, undefined);\n }\n if (typeof target !== \"string\") return withOptions(target, options);\n if (target.startsWith(\"@cf/\")) return buildWorkersAIModel(target, options);\n if (!target.includes(\"/\")) throw unroutableString(target);\n return buildGatewayModel(target, options);\n}\n\n/**\n * Creates a pi-ai provider over Cloudflare's AI.\n *\n * The Workers AI binding is the only way in — Workers AI models go through\n * `env.AI.run`, vendor models through `env.AI.gateway(id).run`, and there is\n * no HTTP transport and no API token. Gateway options may be given flat\n * (`{ binding, id: \"prod\", cacheTtl: 60 }`) or nested under `gateway`;\n * per-model options and per-call pi-ai options (`headers`, `metadata`,\n * `sessionId`) override them in that order.\n *\n * ```ts\n * const ai = createAI({ binding: env.AI, id: \"prod\" });\n * ai(\"@cf/zai-org/glm-4.7-flash\");\n * ai(anthropicModel, { fallback: [\"@cf/zai-org/glm-4.7-flash\"] });\n * new Agent({ streamFn: ai.streamFn, initialState: { model: ai(openaiModel) } });\n * ```\n *\n * @experimental This surface is experimental and may change.\n */\nexport function createAI(settings: AISettings): AI {\n const transport = createTransport(settings);\n const streams = createStreams({ providerGateway: settings, transport });\n\n const model = ((\n target: string | Model<Api>,\n options?: PiModelOptions\n ): Model<Api> => buildModel(target, options)) as AI[\"model\"];\n\n const provider = createProvider({\n api: streams,\n auth: {\n apiKey: {\n name: \"Cloudflare (the AI binding)\",\n // The transport is already authenticated; nothing to resolve.\n resolve: async () => ({ auth: {} })\n }\n },\n id: CLOUDFLARE_PROVIDER_ID,\n models: [\n ...workersAIModelIds().map((id) => buildWorkersAIModel(id, undefined)),\n ...gatewayModelIds().map((id) => buildGatewayModel(id, undefined))\n ],\n name: \"Cloudflare\"\n });\n\n const stream: AI[\"stream\"] = (target, context, options) =>\n streams.stream(target, normalizeContext(context), options);\n const streamSimple: AI[\"streamSimple\"] = (target, context, options) =>\n streams.streamSimple(target, normalizeContext(context), options);\n\n return Object.assign(model as AI, {\n complete: (target, context, options) =>\n stream(target, context, options).result(),\n completeSimple: (target, context, options) =>\n streamSimple(target, context, options).result(),\n generateImages: (target, context, options) =>\n generateImages(\n { providerGateway: settings, transport },\n target,\n context,\n options\n ),\n images: (modelId, options) => buildImagesModel(modelId, options),\n model,\n provider,\n stream,\n streamFn: streamSimple,\n streamSimple\n } satisfies Omit<AI, \"call\">);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["definedEntries","effortForLevel","exhaustive"],"sources":["../../../src/models/pi-ai/catalog.ts","../../../src/models/pi-ai/routing.ts","../../../src/models/pi-ai/wires/shared.ts","../../../src/models/pi-ai/errors.ts","../../../src/models/pi-ai/wires/chat-completions.ts","../../../src/models/pi-ai/models/image.ts","../../../src/models/pi-ai/settings.ts","../../../src/models/pi-ai/wires/anthropic.ts","../../../src/models/pi-ai/wires/responses.ts","../../../src/models/pi-ai/models/fallback.ts","../../../src/models/pi-ai/models/language.ts","../../../src/models/pi-ai/index.ts"],"sourcesContent":["/**\n * pi-ai `Model` construction for this provider.\n *\n * There are exactly two sources of a model here, and neither of them is a\n * catalog of ours:\n *\n * 1. A Workers AI id (`@cf/<author>/<model>`) — the one catalog Cloudflare\n * owns. Its metadata comes from pi-ai's generated Workers AI registry.\n * 2. Anything else — a model object the caller built from their own pi-ai\n * registry import, or an id resolved through pi-ai's generated Cloudflare\n * AI Gateway registry. pi keeps those current; we only route them.\n *\n * A model is plain data in pi-ai, so the options a model was created with ride\n * on it under symbol keys: `JSON.stringify` and `structuredClone` drop them,\n * while an object spread — which pi-ai does when it copies a model — keeps\n * them. Routing survives that loss, because the vendor's own spelling of a\n * `<slug>/<id>` model is looked back up in pi-ai's registry; the per-model\n * options do not, so a model stored in Agent state and read back comes home\n * with this provider's defaults. Re-apply them with `ai(model, options)`\n * after loading if the model carried any.\n *\n * @beta This surface is in beta and may change.\n */\n\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport { CLOUDFLARE_AI_GATEWAY_MODELS } from \"@earendil-works/pi-ai/providers/cloudflare-ai-gateway.models\";\nimport { CLOUDFLARE_WORKERS_AI_MODELS } from \"@earendil-works/pi-ai/providers/cloudflare-workers-ai.models\";\nimport type { WorkersAIModelId } from \"../core/catalog\";\nimport type { ModelOptions } from \"../core/settings\";\n\n/**\n * The `api` marker Workers AI models from this provider carry. It is not a\n * wire format: Workers AI runs on `env.AI.run`, and the compat layer maps that\n * onto strict OpenAI chat completions.\n *\n * @beta This surface is in beta and may change.\n */\nexport const CLOUDFLARE_AI_API = \"cloudflare-ai\";\n\n/** @beta This surface is in beta and may change. */\nexport type CloudflareAIApi = typeof CLOUDFLARE_AI_API;\n\n/**\n * The pi-ai provider id. A `Models` registry resolves specifiers as\n * `cloudflare/<id>`, e.g. `cloudflare/anthropic/claude-opus-4-8`.\n *\n * @beta This surface is in beta and may change.\n */\nexport const CLOUDFLARE_PROVIDER_ID = \"cloudflare\";\n\n/**\n * A Workers AI model produced by this provider. `id` is the `@cf/` id exactly\n * as given; `api` is {@link CLOUDFLARE_AI_API}.\n *\n * @beta This surface is in beta and may change.\n */\nexport type CloudflareModel = Model<CloudflareAIApi>;\n\n/** @beta This surface is in beta and may change. */\nexport type ModelCost = Model<Api>[\"cost\"];\n\n/**\n * A model this provider routes: a Workers AI model or any pi-ai model the\n * caller handed to `ai(model)`.\n *\n * @beta This surface is in beta and may change.\n */\nexport type RoutedModel = Model<Api>;\n\n/**\n * Per-model options: the gateway options, client-side fallback, headers and\n * session affinity, plus pi-ai model metadata overrides and the stream idle\n * deadline. Metadata overrides only apply to the `@cf/` form — a model object\n * brings its own metadata, and this module never second-guesses it.\n *\n * @beta This surface is in beta and may change.\n */\n/**\n * A fallback leg: a Workers AI id, a `<slug>/<id>` pi-ai's gateway registry\n * knows, or a model object. A raw vendor id is refused when the chain is built.\n */\nexport type PiFallbackLeg = WorkersAIModelId | Model<Api> | (string & {});\n\nexport interface PiModelOptions extends ModelOptions<PiFallbackLeg> {\n /** Display name. Defaults to the catalog name, else the id. */\n name?: string;\n /** Context window in tokens. Defaults to the catalog value, else 128000. */\n contextWindow?: number;\n /** Maximum output tokens. Defaults to the catalog value, else 8192. */\n maxTokens?: number;\n /** Whether the model can reason. Defaults to the catalog value, else true. */\n reasoning?: boolean;\n /** Accepted input modalities. Defaults to the catalog value. */\n input?: (\"text\" | \"image\")[];\n /** Cost per million tokens, used by pi-ai's usage accounting. */\n cost?: ModelCost;\n /**\n * Fail a stream that delivers no bytes for this long, in milliseconds. The\n * timer only runs while a read is outstanding, so consumer backpressure\n * never trips it. `0` disables the guard. Default 300000 (five minutes).\n */\n streamIdleTimeoutMs?: number;\n}\n\nconst MODEL_OPTIONS: unique symbol = Symbol.for(\"agents.models.pi-ai.options\");\nconst MODEL_ROUTING: unique symbol = Symbol.for(\"agents.models.pi-ai.routing\");\n\n/** What a registry specifier resolved to, kept for routing and diagnostics. */\ninterface ModelRouting {\n /** The vendor's own spelling of the id, which is what the body must carry. */\n modelId: string;\n /** The `<slug>/<id>` specifier the caller asked for. */\n specifier: string;\n}\n\ntype TaggedModel = Model<Api> & {\n [MODEL_OPTIONS]?: PiModelOptions;\n [MODEL_ROUTING]?: ModelRouting;\n};\n\nfunction tag(model: Model<Api>, key: symbol, value: unknown): void {\n Object.defineProperty(model, key, {\n configurable: true,\n enumerable: true,\n value,\n writable: false\n });\n}\n\n/** Reads the options a model was created with, if it came from this provider. */\nexport function optionsOf(model: Model<Api>): PiModelOptions | undefined {\n const options = (model as TaggedModel)[MODEL_OPTIONS];\n return options !== null && typeof options === \"object\" ? options : undefined;\n}\n\n/**\n * The gateway registry entry a model's own id names, for a model this provider\n * built from a `<slug>/<id>` specifier. It is looked up rather than inferred,\n * so a model that lost its symbol tags — `JSON.stringify` and\n * `structuredClone` drop them, and an Agent's state goes through both — still\n * reaches the vendor under the vendor's own spelling.\n */\nfunction registryEntryFor(model: Model<Api>): Model<Api> | undefined {\n if (\n model.provider !== CLOUDFLARE_PROVIDER_ID ||\n model.id.startsWith(\"@cf/\")\n ) {\n return undefined;\n }\n gatewayRegistry ??= buildGatewayRegistry();\n return gatewayRegistry.get(model.id);\n}\n\n/**\n * The id the request body must carry. It differs from `model.id` only for a\n * `<slug>/<id>` specifier, whose model is listed under the specifier so a\n * `Models` registry can find it while the vendor still sees its own spelling.\n */\nexport function wireModelId(model: Model<Api>): string {\n const tagged = (model as TaggedModel)[MODEL_ROUTING]?.modelId;\n if (tagged !== undefined) return tagged;\n return registryEntryFor(model)?.id ?? model.id;\n}\n\n/** The `<slug>/<id>` specifier a model was resolved from, for diagnostics. */\nexport function specifierOf(model: Model<Api>): string | undefined {\n const tagged = (model as TaggedModel)[MODEL_ROUTING]?.specifier;\n if (tagged !== undefined) return tagged;\n return registryEntryFor(model) === undefined ? undefined : model.id;\n}\n\n/**\n * Copies a caller's model and tags the copy with the resolved options. The\n * caller's object is never mutated, and every field it declares — `api`,\n * `provider`, `id`, `baseUrl`, `compat`, `thinkingLevelMap`, cost and limits —\n * is kept verbatim, because that metadata is the model's own author's, not\n * ours.\n */\nexport function withOptions<TApi extends Api>(\n model: Model<TApi>,\n options: PiModelOptions | undefined\n): Model<TApi> {\n const copy = { ...model };\n if (options !== undefined) tag(copy, MODEL_OPTIONS, options);\n return copy;\n}\n\nconst DEFAULT_CONTEXT_WINDOW = 128_000;\nconst DEFAULT_MAX_TOKENS = 8192;\nconst ZERO_COST: ModelCost = {\n cacheRead: 0,\n cacheWrite: 0,\n input: 0,\n output: 0\n};\n\nlet workersAI: Map<string, Model<Api>> | undefined;\n\nfunction workersAIEntry(modelId: string): Model<Api> | undefined {\n workersAI ??= new Map(\n (Object.values(CLOUDFLARE_WORKERS_AI_MODELS) as Model<Api>[]).map(\n (entry) => [entry.id, entry]\n )\n );\n return workersAI.get(modelId);\n}\n\n/** Every Workers AI id pi-ai knows, for the provider's static model list. */\nexport function workersAIModelIds(): string[] {\n workersAI ??= new Map(\n (Object.values(CLOUDFLARE_WORKERS_AI_MODELS) as Model<Api>[]).map(\n (entry) => [entry.id, entry]\n )\n );\n return [...workersAI.keys()].sort();\n}\n\n/**\n * Builds the pi-ai model for a Workers AI id. Registry metadata is used when\n * pi-ai knows the id; explicit options override it; everything else falls back\n * to defaults that keep the model usable, because the Workers AI catalog moves\n * faster than any generated registry.\n */\nexport function buildWorkersAIModel(\n modelId: string,\n options: PiModelOptions | undefined\n): CloudflareModel {\n const known = workersAIEntry(modelId);\n const model: CloudflareModel = {\n api: CLOUDFLARE_AI_API,\n baseUrl: \"\",\n contextWindow:\n options?.contextWindow ?? known?.contextWindow ?? DEFAULT_CONTEXT_WINDOW,\n cost: options?.cost ?? known?.cost ?? ZERO_COST,\n id: modelId,\n input: options?.input ?? known?.input ?? [\"text\"],\n maxTokens: options?.maxTokens ?? known?.maxTokens ?? DEFAULT_MAX_TOKENS,\n name: options?.name ?? known?.name ?? modelId,\n provider: CLOUDFLARE_PROVIDER_ID,\n reasoning: options?.reasoning ?? known?.reasoning ?? true,\n ...(known?.thinkingLevelMap !== undefined\n ? { thinkingLevelMap: known.thinkingLevelMap }\n : {})\n };\n if (options !== undefined) tag(model, MODEL_OPTIONS, options);\n return model;\n}\n\n/** The gateway provider slug a registry entry's base URL names. */\nfunction slugOf(entry: Model<Api>): string | undefined {\n const segments = entry.baseUrl.split(\"/\").filter((part) => part !== \"\");\n return segments.at(-1);\n}\n\nlet gatewayRegistry: Map<string, Model<Api>> | undefined;\n\n/**\n * pi-ai's generated Cloudflare AI Gateway registry, keyed by `<slug>/<id>`.\n * `/compat` entries are skipped: they alias `@cf/` ids the Workers AI registry\n * already declares, and those belong on the run path.\n */\nfunction buildGatewayRegistry(): Map<string, Model<Api>> {\n const map = new Map<string, Model<Api>>();\n for (const entry of Object.values(\n CLOUDFLARE_AI_GATEWAY_MODELS\n ) as Model<Api>[]) {\n const slug = slugOf(entry);\n if (slug === undefined || slug === \"compat\") continue;\n map.set(`${slug}/${entry.id}`, entry);\n }\n return map;\n}\n\n/** Every `<slug>/<id>` specifier pi-ai's gateway registry declares. */\nexport function gatewayModelIds(): string[] {\n gatewayRegistry ??= buildGatewayRegistry();\n return [...gatewayRegistry.keys()].sort();\n}\n\n/** An id with case and separators (`.`, `-`, `_`) ignored. */\nfunction looseId(id: string): string {\n return id.toLowerCase().replace(/[._-]/g, \"-\");\n}\n\n/**\n * Catalog specifiers that differ from `specifier` only in case or separators.\n * AI Gateway's catalog spells `anthropic/claude-opus-4.8` where Anthropic\n * spells `claude-opus-4-8`, and the difference is easy to miss.\n */\nfunction nearSpecifiers(\n specifier: string,\n specifiers: Iterable<string>\n): string[] {\n const wanted = looseId(specifier);\n return [...specifiers].filter((id) => looseId(id) === wanted).sort();\n}\n\n/**\n * Resolves a `<slug>/<id>` specifier through pi-ai's generated Cloudflare AI\n * Gateway registry. The entry's metadata — api, base URL, compat,\n * `thinkingLevelMap`, cost, limits — is kept exactly as pi generated it; only\n * `id` and `provider` are restated so a `Models` registry can find the model\n * under `cloudflare/<slug>/<id>`, and the vendor's own spelling rides along for\n * the request body.\n *\n * There is no prefix guessing: an id pi-ai does not list is a `TypeError`,\n * pointing at the model-object form, which needs no catalog of ours at all.\n */\nexport function buildGatewayModel(\n specifier: string,\n options: PiModelOptions | undefined\n): Model<Api> {\n gatewayRegistry ??= buildGatewayRegistry();\n const separator = specifier.indexOf(\"/\");\n const slug = separator === -1 ? \"\" : specifier.slice(0, separator);\n const vendorId = specifier.slice(separator + 1);\n if (slug === \"workers-ai\") {\n throw new TypeError(\n `\"${specifier}\" is a Workers AI model: pass its id directly, ai(\"${vendorId}\").`\n );\n }\n const entry = gatewayRegistry.get(specifier);\n if (entry === undefined) {\n const near = nearSpecifiers(specifier, gatewayRegistry.keys());\n const suggestion =\n near.length === 0\n ? \"\"\n : ` Did you mean ${near.map((id) => `ai(\"${id}\")`).join(\" or \")}? The catalog spells ids as AI Gateway does.`;\n throw new TypeError(\n `\"${specifier}\" is not in pi-ai's Cloudflare AI Gateway catalog.${suggestion} Pass the model object instead, e.g. ai(getBuiltinModel(\"${slug || \"anthropic\"}\", \"${vendorId}\")) from \"@earendil-works/pi-ai/providers/all\", or any model from a provider registry you imported.`\n );\n }\n const model: Model<Api> = {\n ...entry,\n id: specifier,\n provider: CLOUDFLARE_PROVIDER_ID\n };\n tag(model, MODEL_ROUTING, { modelId: entry.id, specifier });\n if (options !== undefined) tag(model, MODEL_OPTIONS, options);\n return model;\n}\n","/**\n * Where a pi-ai model's request goes on the AI Gateway universal endpoint.\n *\n * A pi `Model` carries the vendor's own `baseUrl` and an `api` marker. Those\n * two are all the routing information the universal request needs, but neither\n * alone is enough: the gateway's `endpoint` is the vendor's request URL minus\n * that provider's own base, and the base differs per provider (groq serves\n * chat completions at `/openai/v1/chat/completions`, deepseek at\n * `/chat/completions`). So the api names the path pi's own client appends to\n * `model.baseUrl`, the two are joined, and `core/gateway-providers.ts` — the\n * same resolver the AI SDK module's routed `fetch` uses — maps the result onto\n * a provider slug and an endpoint. Nothing here knows a vendor's wire format;\n * pi's own converters build the body.\n */\n\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport {\n type GatewayProviderName,\n gatewaySlugForBaseUrl,\n isGatewayShapedUrl,\n resolveGatewayProvider\n} from \"../core/gateway-providers\";\n\n/**\n * The path each pi api speaks, relative to the model's own `baseUrl` — exactly\n * what pi's SDK clients append to it.\n */\nconst API_PATHS: Record<string, string> = {\n \"anthropic-messages\": \"v1/messages\",\n \"openai-completions\": \"chat/completions\",\n \"openai-responses\": \"responses\"\n};\n\n/**\n * The universal request's `endpoint` for a gateway-shaped base URL, whose path\n * already ends at the provider slug, so what follows is the vendor's own path.\n */\nconst GATEWAY_ENDPOINTS: Record<string, string> = {\n \"anthropic-messages\": \"v1/messages\",\n \"openai-completions\": \"v1/chat/completions\",\n \"openai-responses\": \"v1/responses\"\n};\n\n/** Where one model's request goes on the universal gateway endpoint. */\nexport interface UniversalRoute {\n provider: GatewayProviderName;\n endpoint: string;\n}\n\n/**\n * The gateway provider slug that serves a model, from its own base URL.\n *\n * @throws TypeError when the model carries no base URL, or one AI Gateway has\n * no provider for.\n */\nexport function gatewaySlugForModel(model: Model<Api>): GatewayProviderName {\n if (model.baseUrl === \"\") {\n throw new TypeError(\n `The model \"${model.id}\" has no baseUrl, so AI Gateway cannot tell which provider serves it.`\n );\n }\n return gatewaySlugForBaseUrl(model.baseUrl);\n}\n\n/** `https://api.groq.com/openai/v1` → `https://api.groq.com/openai/v1/`. */\nfunction asBase(baseUrl: string): string {\n return baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n}\n\n/**\n * The provider slug and endpoint one model's request travels on.\n *\n * @throws TypeError when the model has no base URL, when AI Gateway has no\n * provider for it, or when this module knows no path for the model's api.\n */\nexport function routeForModel(model: Model<Api>): UniversalRoute {\n const provider = gatewaySlugForModel(model);\n if (isGatewayShapedUrl(model.baseUrl)) {\n const endpoint = GATEWAY_ENDPOINTS[model.api];\n if (endpoint === undefined) throw noEndpoint(model.api);\n return { endpoint, provider };\n }\n const path = API_PATHS[model.api];\n if (path === undefined) throw noEndpoint(model.api);\n const resolved = resolveGatewayProvider(\n new URL(path, asBase(model.baseUrl)).toString()\n );\n // The base URL already resolved to a provider above, so the joined URL can\n // only fail to resolve if it left that provider's own host.\n if (resolved === undefined) {\n return { endpoint: GATEWAY_ENDPOINTS[model.api] ?? path, provider };\n }\n return { endpoint: resolved.endpoint, provider: resolved.provider };\n}\n\nfunction noEndpoint(api: string): TypeError {\n return new TypeError(`No AI Gateway endpoint is known for the \"${api}\" API.`);\n}\n","/**\n * Helpers shared by the three pi-ai wires: the empty assistant message every\n * stream starts from, usage and cost accounting, response diagnostics, the\n * stream idle deadline, SSE iteration, and error termination.\n */\n\nimport type { CompatWarning } from \"../../core/chat-completions\";\nimport {\n type Api,\n type AssistantMessage,\n type AssistantMessageDiagnostic,\n type JsonObject,\n type Model,\n type Usage,\n calculateCost\n} from \"@earendil-works/pi-ai\";\nimport { sseDataStream } from \"../../core/sse\";\nimport type { Transport } from \"../../core/transport\";\nimport {\n errorFromGatewayEnvelope,\n headersToObject,\n isGatewayErrorEnvelope\n} from \"../../core/transport\";\nimport { specifierOf, wireModelId } from \"../catalog\";\nimport { gatewaySlugForModel, routeForModel } from \"../routing\";\nimport type { WireRequest } from \"../settings\";\n\n/** Diagnostic type under which gateway correlation ids are recorded. */\nexport const CLOUDFLARE_DIAGNOSTIC = \"cloudflare\";\n\n/** The diagnostic type under which compat-layer warnings are recorded. */\nexport const COMPAT_DIAGNOSTIC = \"cloudflare-compat\";\n\n/** Records compat warnings on a message as a `cloudflare-compat` diagnostic. */\n/**\n * pi-ai types diagnostic details as JSON. These details are plain data this\n * module built, so a JSON round trip only drops their undefined fields.\n */\nexport function jsonDetails(value: object): JsonObject {\n return JSON.parse(JSON.stringify(value)) as JsonObject;\n}\n\nexport function recordWarnings(\n output: AssistantMessage,\n warnings: CompatWarning[]\n): void {\n if (warnings.length === 0) return;\n output.diagnostics = [\n ...(output.diagnostics ?? []),\n {\n details: jsonDetails({ warnings }),\n timestamp: Date.now(),\n type: COMPAT_DIAGNOSTIC\n }\n ];\n}\n\n/**\n * The Workers-AI-only knobs a vendor model cannot honour. They are not sent —\n * the vendor's own reasoning follows the model's metadata and the pi\n * `reasoning` level — and the drop is recorded rather than silent.\n */\nexport function ignoredWorkersAIKnobs(request: {\n resolved: { reasoningEffort?: unknown; chatTemplateKwargs?: unknown };\n}): CompatWarning[] {\n const warnings: CompatWarning[] = [];\n if (request.resolved.reasoningEffort !== undefined) {\n warnings.push({\n feature: \"reasoning-effort\",\n message:\n \"reasoningEffort is a Workers AI setting and does not apply to a model routed through AI Gateway; use the pi `reasoning` level, which the model's own metadata maps.\"\n });\n }\n if (request.resolved.chatTemplateKwargs !== undefined) {\n warnings.push({\n feature: \"chat-template-kwargs\",\n message:\n \"chatTemplateKwargs is a Workers AI setting and was not sent to a model routed through AI Gateway.\"\n });\n }\n return warnings;\n}\n\n/** Default cap on how long a stream may stay silent before it is failed. */\nexport const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 300_000;\n\n/** OpenAI Responses rejects `max_output_tokens` below 16. */\nexport const MIN_OUTPUT_TOKENS = 16;\n\nexport function emptyUsage(): Usage {\n return {\n cacheRead: 0,\n cacheWrite: 0,\n cost: { cacheRead: 0, cacheWrite: 0, input: 0, output: 0, total: 0 },\n input: 0,\n output: 0,\n totalTokens: 0\n };\n}\n\n/** The assistant message a stream mutates as events arrive. */\nexport function startMessage(model: Model<Api>): AssistantMessage {\n return {\n api: model.api,\n content: [],\n model: model.id,\n provider: model.provider,\n role: \"assistant\",\n stopReason: \"stop\",\n timestamp: Date.now(),\n usage: emptyUsage()\n };\n}\n\n/**\n * Usage in the OpenAI shape, shared by chat completions and Workers AI.\n *\n * The cache fields are the ones pi-ai's own `parseChunkUsage` reads, spelling\n * for spelling: `prompt_tokens_details.cached_tokens` is OpenAI's, DeepSeek\n * sends `prompt_cache_hit_tokens` instead, and OpenRouter-compatible providers\n * add `prompt_tokens_details.cache_write_tokens`.\n */\nexport interface OpenAIUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n prompt_cache_hit_tokens?: number;\n prompt_tokens_details?: {\n cached_tokens?: number;\n cache_write_tokens?: number;\n };\n completion_tokens_details?: { reasoning_tokens?: number };\n}\n\n/**\n * Maps OpenAI-shaped usage onto pi-ai's. `input` excludes cached tokens, as\n * pi-ai's own OpenAI adapter does, and cost comes from the model metadata.\n */\nexport function usageFromOpenAI(\n model: Model<Api>,\n raw: OpenAIUsage | undefined\n): Usage {\n if (raw === undefined) return emptyUsage();\n const prompt = raw.prompt_tokens ?? 0;\n const completion = raw.completion_tokens ?? 0;\n // pi-ai's `parseChunkUsage`, field for field: cached tokens are reads, cache\n // writes are counted separately and both come out of `input`, and a write\n // count is never subtracted from the read count.\n const cacheRead =\n raw.prompt_tokens_details?.cached_tokens ??\n raw.prompt_cache_hit_tokens ??\n 0;\n const cacheWrite = raw.prompt_tokens_details?.cache_write_tokens ?? 0;\n const reasoning = raw.completion_tokens_details?.reasoning_tokens;\n const totalTokens = raw.total_tokens ?? prompt + completion;\n // Google counts reasoning outside `completion_tokens` (live: prompt 6 +\n // completion 3 + reasoning 57 = total 66); OpenAI and Workers AI satisfy\n // prompt + completion = total, so the derived figure agrees with theirs.\n const output =\n raw.total_tokens === undefined\n ? completion\n : Math.max(completion, totalTokens - prompt);\n const usage: Usage = {\n cacheRead,\n cacheWrite,\n cost: { cacheRead: 0, cacheWrite: 0, input: 0, output: 0, total: 0 },\n input: Math.max(0, prompt - cacheRead - cacheWrite),\n output,\n ...(reasoning !== undefined ? { reasoning } : {}),\n totalTokens\n };\n usage.cost = calculateCost(model, usage);\n return usage;\n}\n\n/** Gateway correlation read off a response. */\nexport interface ResponseCorrelation {\n logId?: string;\n runId?: string;\n cacheStatus?: string;\n step?: string;\n eventId?: string;\n traceId?: string;\n}\n\nexport function correlationOf(\n response: Response,\n transport: Transport\n): ResponseCorrelation {\n const get = (name: string) => response.headers.get(name) ?? undefined;\n return {\n cacheStatus: get(\"cf-aig-cache-status\"),\n eventId: get(\"cf-aig-event-id\"),\n logId: get(\"cf-aig-log-id\") ?? transport.logIdFallback(response),\n runId: get(\"cf-aig-run-id\"),\n step: get(\"cf-aig-step\"),\n traceId: get(\"cf-aig-trace-id\")\n };\n}\n\nfunction definedEntries(\n record: Record<string, unknown>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(record)) {\n if (value !== undefined) result[key] = value;\n }\n return result;\n}\n\n/**\n * Records where a response came from on the assistant message, as a pi-ai\n * diagnostic: the gateway log id and friends, the answering model and the\n * gateway id. Callers read it back from `message.diagnostics`.\n */\nexport function attachCorrelation(\n message: AssistantMessage,\n details: ResponseCorrelation & {\n model: string;\n gateway: string;\n provider?: string;\n specifier?: string;\n }\n): void {\n const diagnostic: AssistantMessageDiagnostic = {\n details: jsonDetails(definedEntries({ ...details })),\n timestamp: Date.now(),\n type: CLOUDFLARE_DIAGNOSTIC\n };\n message.diagnostics = [...(message.diagnostics ?? []), diagnostic];\n}\n\n/**\n * Wraps a body so a gap longer than `idleMs` between chunks rejects the read\n * instead of pending forever. Only an outstanding read is timed, so a slow\n * consumer never trips it; `idleMs <= 0` disables the guard.\n */\nexport function withIdleDeadline(\n body: ReadableStream<Uint8Array>,\n idleMs: number\n): ReadableStream<Uint8Array> {\n if (idleMs <= 0) return body;\n const reader = body.getReader();\n return new ReadableStream<Uint8Array>({\n cancel(reason) {\n return reader.cancel(reason);\n },\n async pull(controller) {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const result = await Promise.race([\n reader.read(),\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n reject(\n new Error(\n `Model stream stalled: no data received for ${Math.round(idleMs / 1000)}s.`\n )\n );\n }, idleMs);\n })\n ]);\n if (result.done) controller.close();\n else controller.enqueue(result.value);\n } catch (error) {\n void reader.cancel().catch(() => {});\n controller.error(error);\n } finally {\n clearTimeout(timer);\n }\n }\n });\n}\n\n/**\n * Iterates the JSON payload of each SSE event. `[DONE]` sentinels and\n * unparseable payloads are skipped; the reader is cancelled if iteration\n * stops early so the upstream request is not left generating.\n */\nexport async function* sseJson(\n body: ReadableStream<Uint8Array>,\n onDone?: () => void\n): AsyncGenerator<unknown> {\n const reader = body.pipeThrough(sseDataStream()).getReader();\n let finished = false;\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n finished = true;\n return;\n }\n if (value === \"\") continue;\n if (value === \"[DONE]\") {\n onDone?.();\n continue;\n }\n try {\n yield JSON.parse(value);\n } catch {\n // A malformed event is dropped rather than failing the stream.\n }\n }\n } finally {\n if (!finished) {\n await reader.cancel().catch(() => {});\n }\n reader.releaseLock();\n }\n}\n\n/** `response.headers` as pi-ai's `onResponse` callback wants them. */\nexport function responseInfo(response: Response): {\n status: number;\n headers: Record<string, string>;\n} {\n return {\n headers: headersToObject(response.headers),\n status: response.status\n };\n}\n\n/**\n * The Anthropic API version every Messages request must name. pi-ai leaves it\n * to the Anthropic SDK, which we replace, so the wire states it here.\n */\nconst ANTHROPIC_VERSION = \"2023-06-01\";\n\n/**\n * The vendor headers an Anthropic Messages request needs. pi-ai normally gets\n * them from the Anthropic SDK's defaults plus its own `createClient`; this\n * wire owns the transport instead, so it sets the ones the vendor requires and\n * sends the beta features pi-ai chose as `anthropic-beta`, as the SDK would.\n * No credential header is sent: the gateway holds the key (unified billing or\n * BYOK).\n */\nexport function anthropicVendorHeaders(betas: readonly string[]): {\n [key: string]: string;\n} {\n return {\n accept: \"application/json\",\n \"anthropic-version\": ANTHROPIC_VERSION,\n ...(betas.length > 0 ? { \"anthropic-beta\": betas.join(\",\") } : {}),\n \"content-type\": \"application/json\"\n };\n}\n\n/** The vendor headers an OpenAI-shaped request needs. */\nexport function openAIVendorHeaders(): Record<string, string> {\n return { accept: \"application/json\", \"content-type\": \"application/json\" };\n}\n\n/**\n * Sends a vendor's own request body through AI Gateway's universal endpoint.\n *\n * The provider slug comes from the model's base URL and the endpoint from its\n * `api`; the body is what pi-ai's converter built, `model` included, because\n * that is what the universal request carries. The gateway's *own* failures\n * (no such gateway, unified billing unpaid) are lifted into a\n * `CloudflareAIError` so fallback and retry classification behave as they do on\n * the Workers AI run path; a vendor's own error response is left alone for the\n * wire's parser to read.\n */\nexport async function sendUniversal(\n request: WireRequest,\n transport: Transport,\n body: Record<string, unknown>,\n vendorHeaders: Record<string, string>,\n onResponse?: (response: Response) => void\n): Promise<Response> {\n const { model, options, resolved } = request;\n const route = routeForModel(model);\n const response = await transport.universal({\n endpoint: route.endpoint,\n extraHeaders:\n Object.keys(request.headers).length > 0 ? request.headers : undefined,\n gateway: resolved.gateway,\n headers: vendorHeaders,\n provider: route.provider,\n query: body,\n signal: options.signal\n });\n // The correlation ids are on the raw response, and a gateway envelope is\n // about to throw, so the caller sees them either way.\n onResponse?.(response);\n return await liftGatewayError(response, {\n model: wireModelId(model),\n requestBodyValues: body,\n url: transport.url\n });\n}\n\n/**\n * Turns the gateway's own error envelope into a `CloudflareAIError`. Only a\n * JSON body can be one, so a streaming response is passed straight through and\n * never buffered.\n */\nasync function liftGatewayError(\n response: Response,\n context: { model: string; url: string; requestBodyValues: unknown }\n): Promise<Response> {\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (!contentType.includes(\"application/json\")) return response;\n const text = await response.text().catch(() => \"\");\n let parsed: unknown;\n try {\n parsed = text === \"\" ? undefined : JSON.parse(text);\n } catch {\n parsed = undefined;\n }\n if (isGatewayErrorEnvelope(parsed)) {\n throw errorFromGatewayEnvelope(parsed, {\n ...context,\n responseBody: text,\n responseHeaders: headersToObject(response.headers),\n status: response.status\n });\n }\n return new Response(text, response);\n}\n\n/** The correlation details every wire records, with the routing it used. */\nexport function correlationDetails(\n request: WireRequest,\n response: Response,\n transport: Transport\n): ResponseCorrelation & {\n model: string;\n gateway: string;\n provider?: string;\n specifier?: string;\n} {\n const { model, resolved } = request;\n const specifier = specifierOf(model);\n return {\n ...correlationOf(response, transport),\n gateway: resolved.gateway.id,\n model: model.id,\n ...(specifier !== undefined ? { specifier } : {}),\n ...(model.api === \"cloudflare-ai\"\n ? {}\n : { provider: gatewaySlugForModel(model) })\n };\n}\n","/**\n * How a pi-ai stream reports failure: an `error` event carrying the assistant\n * message with `stopReason` and `errorMessage`, plus a diagnostic for the\n * failed dispatch. The framework-neutral `CloudflareAIError` from the core is\n * the source of the status, code and log id recorded there.\n */\n\nimport {\n type AssistantMessage,\n type AssistantMessageEventStream,\n type StopReason\n} from \"@earendil-works/pi-ai\";\nimport { CloudflareAIError, isAbortError } from \"../core/errors\";\nimport { errorFromResponse } from \"../core/transport\";\nimport { jsonDetails } from \"./wires/shared\";\n\n/** Diagnostic type under which a failed dispatch is recorded. */\nexport const CLOUDFLARE_ERROR_DIAGNOSTIC = \"cloudflare-error\";\n\nfunction definedEntries(\n record: Record<string, unknown>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(record)) {\n if (value !== undefined) result[key] = value;\n }\n return result;\n}\n\n/**\n * Terminates a stream with a pi-ai `error` event built from a thrown value.\n * `aborted` when the caller's signal fired or the error is an abort; `error`\n * otherwise, with the failed dispatch recorded as a diagnostic.\n */\nexport function failStream(\n stream: AssistantMessageEventStream,\n message: AssistantMessage,\n error: unknown,\n signal: AbortSignal | undefined\n): void {\n const aborted = signal?.aborted === true || isAbortError(error);\n const reason: Extract<StopReason, \"aborted\" | \"error\"> = aborted\n ? \"aborted\"\n : \"error\";\n message.stopReason = reason;\n message.errorMessage =\n error instanceof Error ? error.message : JSON.stringify(error);\n if (!aborted) {\n const details: Record<string, unknown> = {};\n if (error instanceof CloudflareAIError) {\n Object.assign(\n details,\n definedEntries({\n code: error.code,\n logId: error.logId,\n model: error.model,\n status: error.status\n })\n );\n }\n message.diagnostics = [\n ...(message.diagnostics ?? []),\n {\n details: jsonDetails(details),\n error: {\n message: message.errorMessage,\n name: error instanceof Error ? error.name : \"Error\",\n ...(error instanceof CloudflareAIError ? { code: error.code } : {})\n },\n timestamp: Date.now(),\n type: CLOUDFLARE_ERROR_DIAGNOSTIC\n }\n ];\n }\n stream.push({ error: message, reason, type: \"error\" });\n stream.end(message);\n}\n\n/** Throws the typed error for a non-2xx response. */\nexport async function assertOk(\n response: Response,\n context: { model: string; url: string; requestBodyValues: unknown }\n): Promise<void> {\n if (response.ok) return;\n throw await errorFromResponse(response, context);\n}\n","/**\n * Chat-completions wire: Workers AI on the run path, and any pi-ai model whose\n * `api` is `openai-completions` on AI Gateway's universal endpoint.\n *\n * The request is shaped with pi-ai's own message converter so replay rules\n * (tool-call id normalization, reasoning replay, role bridging) match pi's\n * other OpenAI-compatible providers. Workers AI then runs through the shared\n * compat layer, which absorbs its native events, heartbeats, per-delta usage\n * and per-family request quirks so the parser below only ever sees strict\n * OpenAI chunks. A vendor model brings its own `compat` profile and needs none\n * of that: its bytes are already what its author says they are.\n */\n\nimport {\n type AssistantMessage,\n type AssistantMessageEventStream,\n type Tool,\n type Model,\n type ThinkingContent,\n type ToolCall,\n createAssistantMessageEventStream,\n getCurrentTools,\n parseStreamingJson\n} from \"@earendil-works/pi-ai\";\nimport { convertMessages } from \"@earendil-works/pi-ai/api/openai-completions\";\nimport {\n type CompatWarning,\n normalizeChatCompletion,\n normalizeChatCompletionsStream,\n prepareChatCompletionsRequest\n} from \"../../core/chat-completions\";\nimport { sseDataStream } from \"../../core/sse\";\nimport type { Transport } from \"../../core/transport\";\nimport { CLOUDFLARE_AI_API, wireModelId } from \"../catalog\";\nimport { assertOk, failStream } from \"../errors\";\nimport {\n type OpenAIUsage,\n attachCorrelation,\n correlationDetails,\n openAIVendorHeaders,\n responseInfo,\n sendUniversal,\n startMessage,\n usageFromOpenAI,\n withIdleDeadline,\n recordWarnings\n} from \"./shared\";\nimport type { WireRequest } from \"../settings\";\n\ntype Compat = Parameters<typeof convertMessages>[2];\n\n/**\n * pi-ai's message converter wants a fully resolved compat profile. This is\n * the strict OpenAI profile: replayed reasoning goes to `reasoning_content`,\n * `max_tokens` is the cap, and nothing vendor-specific is applied here — the\n * shared compat layer handles that per model afterwards.\n */\nconst STRICT_OPENAI_COMPAT: Compat = {\n chatTemplateArgs: {},\n chatTemplateKwargs: {},\n maxTokensField: \"max_tokens\",\n openRouterRouting: {},\n requiresAssistantAfterToolResult: false,\n requiresReasoningContentOnAssistantMessages: false,\n requiresThinkingAsText: false,\n requiresToolResultName: false,\n sendSessionAffinityHeaders: false,\n sessionAffinityFormat: \"openai\",\n supportsDeveloperRole: false,\n supportsFinishReason: true,\n supportsLongCacheRetention: false,\n supportsOpenAIGrammarTools: false,\n supportsReasoningEffort: true,\n supportsStore: false,\n supportsStrictMode: false,\n supportsUsageInStreaming: true,\n thinkingFormat: \"openai\",\n vercelGatewayRouting: {},\n zaiToolStream: false\n};\n\n/** Diagnostic type under which compat-layer warnings are recorded. */\nexport { COMPAT_DIAGNOSTIC } from \"./shared\";\n\ninterface ToolCallDelta {\n index?: number;\n id?: string | null;\n function?: { name?: string | null; arguments?: string | null };\n}\n\ninterface ChoiceDelta {\n content?: string | null;\n reasoning_content?: string | null;\n reasoning?: string | null;\n reasoning_text?: string | null;\n tool_calls?: ToolCallDelta[];\n}\n\n/**\n * The fields an OpenAI-compatible endpoint puts reasoning in, in pi-ai's own\n * order (`dist/api/openai-completions.js`). The first non-empty one wins and\n * the rest are skipped: some endpoints send the same text under two spellings,\n * and reading both would double the thinking block.\n */\nconst REASONING_FIELDS = [\n \"reasoning_content\",\n \"reasoning\",\n \"reasoning_text\"\n] as const;\n\ninterface Choice {\n delta?: ChoiceDelta;\n message?: ChoiceDelta;\n finish_reason?: string | null;\n}\n\ninterface Chunk {\n id?: string;\n model?: string;\n choices?: Choice[];\n usage?: OpenAIUsage;\n error?: { message?: string; type?: string };\n}\n\ntype TextBlock = { type: \"text\"; text: string };\ntype ToolCallBlock = ToolCall & { partialArguments?: string };\ntype Block = TextBlock | ThinkingContent | ToolCallBlock;\n\nfunction mapFinishReason(reason: string): AssistantMessage[\"stopReason\"] {\n switch (reason) {\n case \"stop\":\n case \"eos\":\n return \"stop\";\n case \"length\":\n case \"model_length\":\n return \"length\";\n case \"tool_calls\":\n case \"function_call\":\n return \"toolUse\";\n default:\n return \"error\";\n }\n}\n\nfunction convertTools(tools: readonly Tool[]) {\n return tools.map((tool) => ({\n function: {\n description: tool.description,\n name: tool.name,\n parameters: tool.parameters\n },\n type: \"function\" as const\n }));\n}\n\n/** Whether a tool-call chunk is the null finalizer some vLLM parsers emit. */\nfunction isFinalizer(call: ToolCallDelta): boolean {\n const fn = call.function;\n return (\n call.index === undefined &&\n (call.id === null || call.id === undefined) &&\n (fn?.name === null || fn?.name === undefined) &&\n (fn?.arguments === null ||\n fn?.arguments === undefined ||\n fn?.arguments === \"\")\n );\n}\n\n/**\n * Incremental state for one streamed completion: the blocks being built on\n * the assistant message and the events that announce them.\n */\nclass CompletionAssembler {\n private textBlock: TextBlock | undefined;\n private thinkingBlock: ThinkingContent | undefined;\n private readonly openToolCalls = new Map<number, ToolCallBlock>();\n private readonly closedToolCalls = new Set<number>();\n private lastToolIndex: number | undefined;\n private readonly blocks: Block[];\n\n constructor(\n private readonly model: Model<string>,\n private readonly output: AssistantMessage,\n private readonly stream: AssistantMessageEventStream\n ) {\n this.blocks = output.content as Block[];\n }\n\n private indexOf(block: Block): number {\n return this.blocks.indexOf(block);\n }\n\n stripScratch(): void {\n for (const block of this.blocks) {\n if (block.type === \"toolCall\") delete block.partialArguments;\n }\n }\n\n private endText(): void {\n if (this.textBlock === undefined) return;\n this.stream.push({\n content: this.textBlock.text,\n contentIndex: this.indexOf(this.textBlock),\n partial: this.output,\n type: \"text_end\"\n });\n this.textBlock = undefined;\n }\n\n private endThinking(): void {\n if (this.thinkingBlock === undefined) return;\n this.stream.push({\n content: this.thinkingBlock.thinking,\n contentIndex: this.indexOf(this.thinkingBlock),\n partial: this.output,\n type: \"thinking_end\"\n });\n this.thinkingBlock = undefined;\n }\n\n private pushText(delta: string): void {\n if (delta.length === 0) return;\n this.endThinking();\n if (this.textBlock === undefined) {\n this.textBlock = { text: \"\", type: \"text\" };\n this.blocks.push(this.textBlock);\n this.stream.push({\n contentIndex: this.indexOf(this.textBlock),\n partial: this.output,\n type: \"text_start\"\n });\n }\n this.textBlock.text += delta;\n this.stream.push({\n contentIndex: this.indexOf(this.textBlock),\n delta,\n partial: this.output,\n type: \"text_delta\"\n });\n }\n\n private pushThinking(delta: string, signature: string): void {\n if (delta.length === 0) return;\n this.endText();\n if (this.thinkingBlock === undefined) {\n // The signature names the field the text came back in, so a later turn\n // replays it under that same key rather than as plain text. Workers AI\n // always resolves to `reasoning_content`: the compat layer rewrites its\n // `reasoning` deltas before the assembler sees them.\n this.thinkingBlock = {\n thinking: \"\",\n thinkingSignature: signature,\n type: \"thinking\"\n };\n this.blocks.push(this.thinkingBlock);\n this.stream.push({\n contentIndex: this.indexOf(this.thinkingBlock),\n partial: this.output,\n type: \"thinking_start\"\n });\n }\n this.thinkingBlock.thinking += delta;\n this.stream.push({\n contentIndex: this.indexOf(this.thinkingBlock),\n delta,\n partial: this.output,\n type: \"thinking_delta\"\n });\n }\n\n private closeToolCall(index: number): void {\n const block = this.openToolCalls.get(index);\n if (block === undefined || this.closedToolCalls.has(index)) return;\n this.closedToolCalls.add(index);\n block.arguments = parseStreamingJson(block.partialArguments ?? \"\");\n delete block.partialArguments;\n this.stream.push({\n contentIndex: this.indexOf(block),\n partial: this.output,\n toolCall: block,\n type: \"toolcall_end\"\n });\n }\n\n private pushToolCalls(calls: ToolCallDelta[]): void {\n this.endThinking();\n this.endText();\n for (const call of calls) {\n if (isFinalizer(call)) {\n if (this.lastToolIndex !== undefined) {\n this.closeToolCall(this.lastToolIndex);\n }\n continue;\n }\n const name = call.function?.name ?? undefined;\n const args = call.function?.arguments ?? \"\";\n const index =\n typeof call.index === \"number\" ? call.index : (this.lastToolIndex ?? 0);\n if (this.closedToolCalls.has(index)) continue;\n\n let block = this.openToolCalls.get(index);\n if (block === undefined) {\n if (this.lastToolIndex !== undefined && this.lastToolIndex !== index) {\n this.closeToolCall(this.lastToolIndex);\n }\n block = {\n arguments: {},\n id: call.id ?? crypto.randomUUID(),\n name: name ?? \"\",\n partialArguments: \"\",\n type: \"toolCall\"\n };\n this.openToolCalls.set(index, block);\n this.blocks.push(block);\n this.stream.push({\n contentIndex: this.indexOf(block),\n partial: this.output,\n type: \"toolcall_start\"\n });\n } else {\n if (block.name === \"\" && name) block.name = name;\n if (call.id) block.id = call.id;\n }\n this.lastToolIndex = index;\n if (args.length > 0) {\n block.partialArguments = (block.partialArguments ?? \"\") + args;\n block.arguments = parseStreamingJson(block.partialArguments);\n this.stream.push({\n contentIndex: this.indexOf(block),\n delta: args,\n partial: this.output,\n type: \"toolcall_delta\"\n });\n }\n }\n }\n\n private applyFinishReason(reason: string | null | undefined): boolean {\n if (reason === null || reason === undefined) return false;\n this.output.stopReason = mapFinishReason(reason);\n if (this.output.stopReason === \"error\") {\n this.output.errorMessage = `The model stopped with finish_reason \"${reason}\".`;\n }\n return true;\n }\n\n /** Applies one strict chunk (or a whole normalized body); true if it carried a finish reason. */\n apply(chunk: Chunk): boolean {\n if (chunk.error !== undefined) {\n this.output.stopReason = \"error\";\n this.output.errorMessage =\n chunk.error.message ?? \"The model reported an error.\";\n return true;\n }\n const choice = chunk.choices?.[0];\n if (chunk.id !== undefined) this.output.responseId ??= chunk.id;\n if (\n typeof chunk.model === \"string\" &&\n chunk.model.length > 0 &&\n chunk.model !== this.model.id\n ) {\n this.output.responseModel ??= chunk.model;\n }\n if (chunk.usage !== undefined) {\n this.output.usage = usageFromOpenAI(this.model, chunk.usage);\n }\n const finished = this.applyFinishReason(choice?.finish_reason);\n const delta = choice?.delta ?? choice?.message;\n if (delta !== undefined) {\n for (const field of REASONING_FIELDS) {\n const value = delta[field];\n if (typeof value === \"string\" && value.length > 0) {\n this.pushThinking(value, field);\n break;\n }\n }\n if (typeof delta.content === \"string\") this.pushText(delta.content);\n if (Array.isArray(delta.tool_calls)) {\n // A complete `message` is not a delta: OpenAI's schema gives its\n // `tool_calls` no `index` at all, so array position is the index.\n // Without it every call in a parallel set files under 0, merging into\n // one block. The Workers AI branch is normalized before it gets here\n // and fills the same positional index, so this changes nothing there.\n const complete = choice?.delta === undefined;\n this.pushToolCalls(\n complete\n ? delta.tool_calls.map((call, position) => ({\n ...call,\n index: typeof call.index === \"number\" ? call.index : position\n }))\n : delta.tool_calls\n );\n }\n }\n return finished;\n }\n\n /** Closes open blocks and settles the stop reason. */\n finish(sawFinishReason: boolean, sawDone: boolean): void {\n for (const index of this.openToolCalls.keys()) this.closeToolCall(index);\n this.endThinking();\n this.endText();\n const hasToolCalls = this.blocks.some((b) => b.type === \"toolCall\");\n if (this.output.stopReason === \"error\") return;\n if (!sawFinishReason) {\n // A complete stream ends with a finish reason or `[DONE]`; a stream\n // that closes without either was cut off, whatever it delivered first.\n if (sawDone) {\n this.output.stopReason = hasToolCalls ? \"toolUse\" : \"stop\";\n } else {\n this.output.stopReason = \"error\";\n this.output.errorMessage =\n this.blocks.length > 0\n ? \"The stream ended before the model finished its answer.\"\n : \"The stream ended before the model produced any output.\";\n }\n } else if (this.output.stopReason === \"stop\" && hasToolCalls) {\n this.output.stopReason = \"toolUse\";\n }\n }\n}\n\n/**\n * Puts the reasoning knobs on a chat-completions body, and reports the ones a\n * model cannot take.\n *\n * Workers AI is the one model family with knobs of ours: `reasoning_effort` on\n * its own three-level scale and `chat_template_kwargs`, both of which the\n * compat layer re-checks against the quirk table afterwards. For every other\n * model the decision is the model author's, read off the merged compat profile\n * exactly as pi-ai's own `openai-completions` implementation reads it: the\n * effort is emitted only when the model reasons, declares\n * `supportsReasoningEffort` and asks for OpenAI's `reasoning_effort` shape,\n * and it is remapped through the model's own `thinkingLevelMap`.\n */\nfunction applyReasoning(\n strict: Record<string, unknown>,\n context: {\n model: Model<string>;\n compat: Compat;\n effort: string | null | undefined;\n /** The Workers AI `reasoningEffort` setting, which a vendor model drops. */\n workersAIEffort: unknown;\n chatTemplateKwargs: Record<string, unknown> | undefined;\n workersAI: boolean;\n }\n): CompatWarning[] {\n const { chatTemplateKwargs, compat, effort, model, workersAI } = context;\n if (workersAI) {\n if (effort !== undefined) strict.reasoning_effort = effort;\n if (chatTemplateKwargs !== undefined) {\n strict.chat_template_kwargs = chatTemplateKwargs;\n }\n return [];\n }\n\n const ignored: CompatWarning[] = [];\n const thinkingFormat = (compat as { thinkingFormat?: string }).thinkingFormat;\n if (typeof effort === \"string\") {\n if (\n model.reasoning === true &&\n (compat as { supportsReasoningEffort?: boolean })\n .supportsReasoningEffort !== false &&\n thinkingFormat === \"openai\"\n ) {\n const map = model.thinkingLevelMap as\n | Record<string, string | null | undefined>\n | undefined;\n strict.reasoning_effort = map?.[effort] ?? effort;\n } else if (thinkingFormat !== \"openai\") {\n ignored.push({\n feature: \"reasoning-effort\",\n message: `This model declares the \"${thinkingFormat}\" thinking format, which this wire does not build; its reasoning level was dropped. Reach it through pi-ai's own provider if you need that shape.`\n });\n }\n }\n if (context.workersAIEffort === null) {\n ignored.push({\n feature: \"reasoning-off\",\n message:\n \"`reasoningEffort: null` is a Workers AI setting; a model routed through AI Gateway decides its own reasoning, so it was dropped.\"\n });\n } else if (context.workersAIEffort !== undefined) {\n ignored.push({\n feature: \"reasoning-effort\",\n message:\n \"`reasoningEffort` is a Workers AI setting and does not apply to a model routed through AI Gateway; use the pi `reasoning` level, which the model's own metadata maps.\"\n });\n }\n if (chatTemplateKwargs !== undefined) {\n ignored.push({\n feature: \"chat-template-kwargs\",\n message:\n \"`chatTemplateKwargs` is a Workers AI setting and does not apply to a model routed through AI Gateway; it was dropped.\"\n });\n }\n return ignored;\n}\n\n/** Streams a chat-completions request and maps it onto pi-ai events. */\nexport function streamCompletions(\n request: WireRequest,\n transport: Transport\n): AssistantMessageEventStream {\n const { model, context, options, resolved } = request;\n const stream = createAssistantMessageEventStream();\n const output = startMessage(model);\n const assembler = new CompletionAssembler(model, output, stream);\n\n const workersAI = model.api === CLOUDFLARE_AI_API;\n\n void (async () => {\n let response: Response | undefined;\n try {\n // A vendor model's own compat profile wins: its author knows which\n // fields that endpoint accepts, and this module deliberately does not.\n const compat: Compat = workersAI\n ? STRICT_OPENAI_COMPAT\n : { ...STRICT_OPENAI_COMPAT, ...(model.compat ?? {}) };\n const messages = convertMessages(\n // Only provider/id/reasoning are read; the api marker is not.\n model as unknown as Model<\"openai-completions\">,\n context,\n compat\n );\n\n const strict: Record<string, unknown> = {\n messages,\n stream: true,\n stream_options: { include_usage: true }\n };\n // The run path names the model in the call; the universal request names\n // it in the body, in the vendor's own spelling.\n if (!workersAI) strict.model = wireModelId(model);\n const tools = getCurrentTools(context.messages);\n if (tools.length > 0) strict.tools = convertTools(tools);\n if (request.toolChoice !== undefined) {\n strict.tool_choice = request.toolChoice;\n }\n if (options.maxTokens !== undefined)\n strict.max_tokens = options.maxTokens;\n if (options.temperature !== undefined) {\n strict.temperature = options.temperature;\n }\n const ignored = applyReasoning(strict, {\n chatTemplateKwargs: resolved.chatTemplateKwargs,\n compat,\n effort: request.reasoningEffort,\n model,\n workersAI,\n workersAIEffort: resolved.reasoningEffort\n });\n const sampling = (options as { samplingParams?: Record<string, unknown> })\n .samplingParams;\n if (sampling !== undefined) Object.assign(strict, sampling);\n\n const prepared = workersAI\n ? prepareChatCompletionsRequest(strict, model.id)\n : { body: strict, reasoningOff: false, warnings: [] };\n recordWarnings(output, [...ignored, ...prepared.warnings]);\n const overridden = await options.onPayload?.(prepared.body, model);\n const payload =\n overridden === undefined\n ? prepared.body\n : (overridden as Record<string, unknown>);\n\n response = workersAI\n ? await transport.run({\n gateway: resolved.gateway,\n headers: request.headers,\n input: payload,\n model: model.id,\n signal: options.signal\n })\n : await sendUniversal(\n request,\n transport,\n payload,\n openAIVendorHeaders()\n );\n await options.onResponse?.(responseInfo(response), model);\n attachCorrelation(\n output,\n correlationDetails(request, response, transport)\n );\n await assertOk(response, {\n model: model.id,\n requestBodyValues: payload,\n url: transport.url\n });\n if (response.body === null) {\n throw new Error(\"The model returned an empty response body.\");\n }\n\n stream.push({ partial: output, type: \"start\" });\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"text/event-stream\")) {\n let sawFinishReason = false;\n let sawDone = false;\n const decoded = withIdleDeadline(\n response.body,\n request.streamIdleTimeoutMs\n ).pipeThrough(sseDataStream());\n const chunks = workersAI\n ? decoded.pipeThrough(\n normalizeChatCompletionsStream(model.id, {\n reasoningOff: prepared.reasoningOff\n })\n )\n : decoded;\n const reader = chunks.getReader();\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value === \"[DONE]\") {\n sawDone = true;\n continue;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(value);\n } catch {\n continue;\n }\n if (parsed === null || typeof parsed !== \"object\") continue;\n sawFinishReason =\n assembler.apply(parsed as Chunk) || sawFinishReason;\n }\n } finally {\n reader.releaseLock();\n }\n assembler.finish(sawFinishReason, sawDone);\n } else {\n // A complete JSON body came back for a streaming request. Emit it as\n // a one-shot stream rather than failing.\n const body = await response.json();\n const json = workersAI\n ? normalizeChatCompletion(body, model.id)\n : (body as Chunk);\n assembler.finish(assembler.apply(json as Chunk), true);\n }\n\n if (options.signal?.aborted) throw new Error(\"Request was aborted.\");\n if (output.stopReason === \"error\") {\n throw new Error(\n output.errorMessage ?? \"The model reported an error stop reason.\"\n );\n }\n stream.push({\n message: output,\n reason: output.stopReason as \"stop\" | \"length\" | \"toolUse\",\n type: \"done\"\n });\n stream.end(output);\n } catch (error) {\n if (response?.body !== null && response?.body?.locked === false) {\n void response.body.cancel().catch(() => {});\n }\n assembler.stripScratch();\n failStream(stream, output, error, options.signal);\n }\n })();\n\n return stream;\n}\n","/**\n * Image generation for pi-ai: `ai.images(id)` builds a pi `ImagesModel` and\n * `ai.generateImages(model, context)` runs it through the transport.\n *\n * Workers AI text-to-image models take `{ prompt, width?, height?, seed?,\n * num_steps?, guidance?, negative_prompt?, image? }` and answer with raw PNG\n * bytes or, for some models, JSON `{ image: \"<base64>\" }`; both are mapped to\n * a pi `image` output part.\n */\n\nimport type {\n AssistantImages,\n ImagesContext,\n ImageModel,\n ImagesOptions\n} from \"@earendil-works/pi-ai\";\nimport type { CompatWarning } from \"../../core/chat-completions\";\nimport { buildImageInput, imageMediaTypeOf } from \"../../core/images\";\nimport type {\n ModelOptions,\n ProviderGatewaySettings\n} from \"../../core/settings\";\nimport { resolveOptions } from \"../../core/settings\";\nimport type { Transport } from \"../../core/transport\";\nimport { unwrapEnvelope } from \"../../core/transport\";\nimport { CLOUDFLARE_PROVIDER_ID } from \"../catalog\";\nimport { assertOk } from \"../errors\";\nimport { COMPAT_DIAGNOSTIC } from \"../wires/chat-completions\";\nimport { emptyUsage } from \"../wires/shared\";\n\n/**\n * The `api` marker on image models from this provider.\n *\n * @beta This surface is in beta and may change.\n */\nexport const CLOUDFLARE_AI_IMAGES_API = \"cloudflare-ai-images\";\n\n/** @beta This surface is in beta and may change. */\nexport type CloudflareImagesModel = ImageModel<typeof CLOUDFLARE_AI_IMAGES_API>;\n\n/**\n * Per-model options for image models: gateway options plus the generation\n * knobs Workers AI understands. Anything given here is the default for every\n * call; `generateImages` options override it.\n *\n * @beta This surface is in beta and may change.\n */\nexport interface PiImagesModelOptions extends ModelOptions {\n name?: string;\n width?: number;\n height?: number;\n /** Diffusion steps, for models that accept it. */\n steps?: number;\n /** Classifier-free guidance scale, for models that accept it. */\n guidance?: number;\n negativePrompt?: string;\n seed?: number;\n}\n\n/** Per-call options for {@link generateImages}. */\nexport interface PiImagesCallOptions extends ImagesOptions {\n width?: number;\n height?: number;\n steps?: number;\n guidance?: number;\n negativePrompt?: string;\n seed?: number;\n}\n\nconst IMAGE_OPTIONS: unique symbol = Symbol.for(\n \"agents.models.pi-ai.image-options\"\n);\n\ntype TaggedImagesModel = CloudflareImagesModel & {\n [IMAGE_OPTIONS]?: PiImagesModelOptions;\n};\n\n/** Builds the pi image model for a catalog id. */\nexport function buildImagesModel(\n modelId: string,\n options: PiImagesModelOptions | undefined\n): CloudflareImagesModel {\n const model: TaggedImagesModel = {\n api: CLOUDFLARE_AI_IMAGES_API,\n baseUrl: \"\",\n cost: { cacheRead: 0, cacheWrite: 0, input: 0, output: 0 },\n id: modelId,\n input: [\"text\", \"image\"],\n name: options?.name ?? modelId,\n output: [\"image\"],\n provider: CLOUDFLARE_PROVIDER_ID,\n type: \"image\"\n };\n if (options !== undefined) {\n Object.defineProperty(model, IMAGE_OPTIONS, {\n configurable: true,\n enumerable: true,\n value: options,\n writable: false\n });\n }\n return model;\n}\n\nfunction imageOptionsOf(\n model: ImageModel<string>\n): PiImagesModelOptions | undefined {\n const options = (model as TaggedImagesModel)[IMAGE_OPTIONS];\n return options !== null && typeof options === \"object\" ? options : undefined;\n}\n\nfunction base64ToBytes(base64: string): Uint8Array {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n let binary = \"\";\n const chunk = 8192;\n for (let i = 0; i < bytes.length; i += chunk) {\n binary += String.fromCharCode(...bytes.subarray(i, i + chunk));\n }\n return btoa(binary);\n}\n\n/** Reads an image out of the run path's response, whichever shape it used. */\nasync function readImage(\n response: Response\n): Promise<{ data: string; mimeType: string }> {\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n const body = unwrapEnvelope(await response.json());\n const record =\n body !== null && typeof body === \"object\"\n ? (body as Record<string, unknown>)\n : {};\n if (typeof record.image === \"string\") {\n // The bytes decide the media type, never the model name: flux-1-schnell\n // answers JPEG where every other model in this catalog answers PNG.\n return { data: record.image, mimeType: imageMediaTypeOf(record.image) };\n }\n throw new Error(\"The image model returned JSON without an image field.\");\n }\n const bytes = new Uint8Array(await response.arrayBuffer());\n const data = bytesToBase64(bytes);\n return {\n data,\n mimeType: contentType.split(\";\")[0] || imageMediaTypeOf(data)\n };\n}\n\n/**\n * pi-ai's `AssistantImages` has no warnings channel, so a knob this catalog\n * drops is reported the way the language wires report theirs: as a diagnostic\n * of type {@link COMPAT_DIAGNOSTIC}.\n *\n * @beta This surface is in beta and may change.\n */\nexport interface CloudflareAssistantImages extends AssistantImages {\n diagnostics?: {\n type: string;\n timestamp: number;\n details: { warnings: CompatWarning[] };\n }[];\n}\n\n/** Everything `generateImages` needs from `createAI`. */\nexport interface ImagesConfig {\n transport: Transport;\n providerGateway: string | ProviderGatewaySettings | undefined;\n}\n\n/**\n * Generates images with a Cloudflare catalog model. Text input parts join into\n * the prompt; the first image part, when present, is passed as the source\n * image for image-to-image models. Failures are reported through\n * `stopReason`/`errorMessage`, as pi-ai's images contract expects.\n */\nexport async function generateImages(\n config: ImagesConfig,\n model: ImageModel<string>,\n context: ImagesContext,\n options: PiImagesCallOptions | undefined\n): Promise<CloudflareAssistantImages> {\n const modelOptions = imageOptionsOf(model);\n const resolved = resolveOptions(\n config.providerGateway,\n modelOptions,\n undefined\n );\n const prompt = context.input\n .filter(\n (part): part is { type: \"text\"; text: string } => part.type === \"text\"\n )\n .map((part) => part.text)\n .join(\"\\n\");\n const source = context.input.find((part) => part.type === \"image\");\n\n const setting = <\n K extends keyof PiImagesCallOptions & keyof PiImagesModelOptions\n >(\n key: K\n ): PiImagesCallOptions[K] | undefined =>\n options?.[key] !== undefined ? options[key] : modelOptions?.[key];\n // The knob names and the flux-1 subset rule are shared with the AI SDK\n // module, so a model that takes only `{ prompt, steps }` gets only that from\n // either provider.\n const built = buildImageInput(model.id, prompt, {\n ...(setting(\"width\") === undefined ? {} : { width: setting(\"width\") }),\n ...(setting(\"height\") === undefined ? {} : { height: setting(\"height\") }),\n ...(setting(\"steps\") === undefined ? {} : { steps: setting(\"steps\") }),\n ...(setting(\"guidance\") === undefined\n ? {}\n : { guidance: setting(\"guidance\") }),\n ...(setting(\"negativePrompt\") === undefined\n ? {}\n : { negativePrompt: setting(\"negativePrompt\") }),\n ...(setting(\"seed\") === undefined ? {} : { seed: setting(\"seed\") }),\n ...(source === undefined ? {} : { sourceImage: true })\n });\n const input = built.input;\n const warnings: CompatWarning[] = built.warnings;\n if (!built.minimal && source !== undefined && source.type === \"image\") {\n input.image = Array.from(base64ToBytes(source.data));\n }\n\n const result: CloudflareAssistantImages = {\n api: model.api,\n model: model.id,\n output: [],\n provider: model.provider,\n stopReason: \"stop\",\n timestamp: Date.now(),\n usage: emptyUsage()\n };\n\n try {\n const response = await config.transport.run({\n gateway: resolved.gateway,\n headers: resolved.headers,\n input,\n model: model.id,\n signal: options?.signal\n });\n await assertOk(response, {\n model: model.id,\n requestBodyValues: input,\n url: config.transport.url\n });\n const image = await readImage(response);\n result.output.push({\n data: image.data,\n mimeType: image.mimeType,\n type: \"image\"\n });\n const requestId = response.headers.get(\"cf-aig-log-id\");\n if (requestId !== null) result.responseId = requestId;\n } catch (error) {\n result.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n result.errorMessage =\n error instanceof Error ? error.message : JSON.stringify(error);\n }\n // pi-ai's `AssistantImages` has no warnings channel, so a dropped knob is\n // reported the way the language wires report theirs: as a diagnostic.\n if (warnings.length > 0) {\n result.diagnostics = [\n { details: { warnings }, timestamp: Date.now(), type: COMPAT_DIAGNOSTIC }\n ];\n }\n return result;\n}\n","/**\n * Per-request option resolution for pi-ai calls: pi's call options and the\n * per-model options become one resolved request that every wire consumes.\n */\n\nimport type {\n Api,\n Model,\n SimpleStreamOptions,\n StreamOptions,\n ThinkingLevel,\n TranscriptContext\n} from \"@earendil-works/pi-ai\";\nimport { clampThinkingLevel } from \"@earendil-works/pi-ai\";\nimport type {\n GatewayOptions,\n ModelOptions,\n ProviderGatewaySettings,\n ResolvedOptions\n} from \"../core/settings\";\nimport { resolveOptions } from \"../core/settings\";\nimport type { Transport } from \"../core/transport\";\nimport { CLOUDFLARE_AI_API, optionsOf } from \"./catalog\";\nimport { DEFAULT_STREAM_IDLE_TIMEOUT_MS } from \"./wires/shared\";\n\n/** What `createAI` fixes for every request. */\nexport interface StreamConfig {\n transport: Transport;\n /** The `createAI` settings, whose gateway keys are the lowest layer. */\n providerGateway: string | ProviderGatewaySettings | undefined;\n}\n\n/** pi-ai's provider-neutral tool choice, in OpenAI's shape. */\nexport type ToolChoice =\n | \"auto\"\n | \"none\"\n | \"required\"\n | { type: \"function\"; function: { name: string } };\n\n/** Everything a wire needs, resolved once per request. */\nexport interface WireRequest {\n model: Model<Api>;\n context: TranscriptContext;\n /** The pi-ai call options; simple options carry `reasoning`. */\n options: SimpleStreamOptions;\n /** Whether this came through `streamSimple` (reasoning is a level). */\n simple: boolean;\n resolved: ResolvedOptions;\n /**\n * Legs to try if this one fails before producing output. A leg may be a\n * model object as well as an id, so this list — rather than\n * {@link ResolvedOptions.fallback}, which is ids only — is what the\n * dispatcher walks.\n */\n fallback: (string | Model<Api>)[];\n /** Request headers after gateway and affinity merging. */\n headers: Record<string, string>;\n /**\n * The reasoning effort to send, `null` to disable, `undefined` to omit.\n *\n * For a Workers AI model it is already collapsed onto the three levels the\n * compat layer's quirk table declares. For every other model it is the\n * model's own clamped thinking level, un-mapped: each wire applies that\n * model's `thinkingLevelMap` itself, exactly as pi-ai's own implementations\n * do, so no effort table of ours ever reaches a vendor.\n */\n reasoningEffort: string | null | undefined;\n toolChoice: ToolChoice | undefined;\n streamIdleTimeoutMs: number;\n}\n\n/** The pi thinking levels, for reading a caller's explicit effort. */\nconst THINKING_LEVELS: readonly string[] = [\n \"minimal\",\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\"\n];\n\nfunction isThinkingLevel(value: unknown): value is ThinkingLevel {\n return typeof value === \"string\" && THINKING_LEVELS.includes(value);\n}\n\n/**\n * Resolves a pi thinking level onto the effort a request carries.\n *\n * Workers AI is the one catalog with an effort scale of ours: its quirk table\n * declares three levels, so the run path collapses onto them. Every other\n * model keeps its own level name — the wire then applies the model's own\n * `thinkingLevelMap`, the way pi-ai's implementations do — because a table of\n * ours has no business deciding a vendor's efforts.\n */\nfunction effortForLevel(\n model: Model<Api>,\n level: ThinkingLevel | undefined\n): string | undefined {\n if (level === undefined || !model.reasoning) return undefined;\n const clamped = clampThinkingLevel(model, level);\n if (clamped === \"off\") return undefined;\n if (model.api !== CLOUDFLARE_AI_API) return clamped;\n switch (clamped) {\n case \"minimal\":\n case \"low\":\n return \"low\";\n case \"medium\":\n return \"medium\";\n case \"high\":\n case \"xhigh\":\n case \"max\":\n return \"high\";\n default: {\n const exhaustive: never = clamped;\n return exhaustive;\n }\n }\n}\n\n/** Scalars only: the gateway rejects nested metadata. */\nfunction scalarMetadata(\n metadata: Record<string, unknown> | undefined\n): GatewayOptions[\"metadata\"] {\n if (metadata === undefined) return undefined;\n const result: NonNullable<GatewayOptions[\"metadata\"]> = {};\n for (const [key, value] of Object.entries(metadata)) {\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n result[key] = value;\n }\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n/** pi headers allow `null` to suppress a default; those are dropped here. */\nfunction stringHeaders(\n headers: StreamOptions[\"headers\"]\n): Record<string, string> | undefined {\n if (headers === undefined) return undefined;\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (typeof value === \"string\") result[key] = value;\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n/** The per-call layer of options, read off pi-ai's call options. */\nfunction callLayer(options: SimpleStreamOptions): ModelOptions {\n const layer: ModelOptions = {};\n const headers = stringHeaders(options.headers);\n if (headers !== undefined) layer.headers = headers;\n const metadata = scalarMetadata(options.metadata);\n if (metadata !== undefined) layer.metadata = metadata;\n if (options.sessionId !== undefined)\n layer.sessionAffinity = options.sessionId;\n return layer;\n}\n\nfunction toolChoiceOf(options: SimpleStreamOptions): ToolChoice | undefined {\n const raw = (options as { toolChoice?: unknown }).toolChoice;\n if (raw === \"auto\" || raw === \"none\" || raw === \"required\") return raw;\n if (raw === \"any\") return \"required\";\n if (raw !== null && typeof raw === \"object\") {\n const record = raw as {\n type?: unknown;\n name?: unknown;\n function?: { name?: unknown };\n };\n const name =\n typeof record.function?.name === \"string\"\n ? record.function.name\n : typeof record.name === \"string\"\n ? record.name\n : undefined;\n if (name !== undefined) return { function: { name }, type: \"function\" };\n }\n return undefined;\n}\n\nexport function buildRequest(\n model: Model<Api>,\n context: TranscriptContext,\n options: SimpleStreamOptions,\n simple: boolean,\n config: StreamConfig\n): WireRequest {\n const modelOptions = optionsOf(model);\n const resolved = resolveOptions(\n config.providerGateway,\n modelOptions,\n callLayer(options)\n );\n const headers: Record<string, string> = { ...resolved.headers };\n // Session affinity is a Workers AI replica hint, sent as a request header on\n // the run path; it means nothing to a third-party vendor.\n if (\n resolved.sessionAffinity !== undefined &&\n model.api === CLOUDFLARE_AI_API\n ) {\n headers[\"x-session-affinity\"] = resolved.sessionAffinity;\n }\n const explicitEffort = (options as { reasoningEffort?: unknown })\n .reasoningEffort;\n // An explicitly named level goes through the same model-aware resolution as\n // `reasoning` does, so `\"xhigh\"` and `\"minimal\"` survive on a model whose\n // own metadata declares them; anything else a caller wrote is theirs.\n // `reasoningEffort` in the model options is a Workers AI setting. A vendor\n // model's reasoning follows the call's own level and the model's metadata;\n // the wires record the dropped setting as a diagnostic.\n const reasoningEffort =\n resolved.reasoningEffort !== undefined && model.api === CLOUDFLARE_AI_API\n ? resolved.reasoningEffort\n : isThinkingLevel(explicitEffort)\n ? effortForLevel(model, explicitEffort)\n : explicitEffort === \"off\"\n ? undefined\n : typeof explicitEffort === \"string\"\n ? explicitEffort\n : simple\n ? effortForLevel(model, options.reasoning)\n : undefined;\n return {\n context,\n fallback: modelOptions?.fallback ?? [],\n headers,\n model,\n options,\n reasoningEffort,\n resolved,\n simple,\n streamIdleTimeoutMs:\n modelOptions?.streamIdleTimeoutMs ?? DEFAULT_STREAM_IDLE_TIMEOUT_MS,\n toolChoice: toolChoiceOf(options)\n };\n}\n","/**\n * Anthropic Messages wire: pi-ai's own Anthropic implementation, over AI\n * Gateway's universal endpoint.\n *\n * Everything about the wire — request shaping, thinking, tool use, stream\n * parsing, thinking-signature replay — is pi-ai's. It accepts a `client` whose\n * `messages.create(...).asResponse()` returns the raw HTTP response; the one\n * built here routes that call through the gateway instead of the Anthropic\n * SDK, and sets the vendor headers the SDK would otherwise have added.\n *\n * The model object is never rewritten: `api`, `provider` and `id` reach pi's\n * implementation exactly as they will be recorded on the assistant message, so\n * a later turn replaying a thinking block is recognised as the same model.\n */\n\nimport {\n type AnthropicEffort,\n type AnthropicOptions,\n type Api,\n type AssistantMessageEventStream,\n type Model,\n type SimpleStreamOptions,\n type ThinkingLevel,\n createAssistantMessageEventStream\n} from \"@earendil-works/pi-ai\";\nimport { anthropicMessagesApi } from \"@earendil-works/pi-ai/api/anthropic-messages.lazy\";\nimport { adjustMaxTokensForThinking } from \"@earendil-works/pi-ai/api/simple-options\";\nimport type { Transport } from \"../../core/transport\";\nimport { wireModelId } from \"../catalog\";\nimport { assertOk, failStream } from \"../errors\";\nimport {\n anthropicVendorHeaders,\n attachCorrelation,\n correlationDetails,\n sendUniversal,\n startMessage,\n withIdleDeadline,\n ignoredWorkersAIKnobs,\n recordWarnings\n} from \"./shared\";\nimport type { WireRequest } from \"../settings\";\n\n/**\n * Maps a pi thinking level onto an Anthropic effort the way pi-ai's own\n * `streamSimple` does: the model's `thinkingLevelMap` first, then the level's\n * own name. The map is the model author's; nothing here decides it.\n */\nfunction effortForLevel(\n model: Model<Api>,\n level: ThinkingLevel\n): AnthropicEffort {\n const mapped = model.thinkingLevelMap?.[level];\n if (typeof mapped === \"string\") return mapped as AnthropicEffort;\n switch (level) {\n case \"minimal\":\n case \"low\":\n return \"low\";\n case \"medium\":\n return \"medium\";\n default:\n return \"high\";\n }\n}\n\n/**\n * pi-ai's `streamSimple` thinking rules, applied here because that entry point\n * insists on a credential and this transport has none. Which branch a model\n * takes is the model's own `compat.forceAdaptiveThinking`, not a rule of ours.\n */\nfunction thinkingOptions(\n model: Model<Api>,\n options: SimpleStreamOptions\n): Pick<\n AnthropicOptions,\n \"thinkingEnabled\" | \"thinkingBudgetTokens\" | \"maxTokens\" | \"effort\"\n> {\n const level = options.reasoning;\n if (level === undefined || !model.reasoning) {\n return { thinkingEnabled: false };\n }\n const compat = (model as { compat?: { forceAdaptiveThinking?: boolean } })\n .compat;\n if (compat?.forceAdaptiveThinking === true) {\n return { effort: effortForLevel(model, level), thinkingEnabled: true };\n }\n const { maxTokens, thinkingBudget } = adjustMaxTokensForThinking(\n options.maxTokens,\n model.maxTokens,\n level,\n options.thinkingBudgets\n );\n return {\n maxTokens,\n thinkingBudgetTokens: thinkingBudget,\n thinkingEnabled: true\n };\n}\n\n/** Streams an Anthropic request through pi-ai's implementation. */\nexport function streamAnthropic(\n request: WireRequest,\n transport: Transport\n): AssistantMessageEventStream {\n const { model, context, options } = request;\n const outer = createAssistantMessageEventStream();\n const placeholder = startMessage(model);\n let correlation: ReturnType<typeof correlationDetails> | undefined;\n // pi-ai's own implementation catches whatever `asResponse()` throws and ends\n // the stream with its own error event, which would lose the typed\n // Cloudflare error. Holding it here lets the wire report it instead.\n let transportError: unknown;\n\n // pi-ai calls the SDK's beta endpoint with the beta features it chose in\n // `params.betas`. The SDK would send those as the `anthropic-beta` header,\n // not in the body, so this client does the same.\n const create = (params: Record<string, unknown>) => ({\n async asResponse(): Promise<Response> {\n const { betas, ...vendorParams } = params;\n // The universal request wants the vendor's own spelling of the id\n // in the body, whatever this provider lists the model under.\n const body = { ...vendorParams, model: wireModelId(model) };\n try {\n const response = await sendUniversal(\n request,\n transport,\n body,\n anthropicVendorHeaders(Array.isArray(betas) ? betas : []),\n (raw) => {\n correlation = correlationDetails(request, raw, transport);\n }\n );\n await assertOk(response, {\n model: model.id,\n requestBodyValues: body,\n url: transport.url\n });\n if (response.body === null) return response;\n return new Response(\n withIdleDeadline(response.body, request.streamIdleTimeoutMs),\n response\n );\n } catch (error) {\n transportError = error;\n throw error;\n }\n }\n });\n const client = {\n beta: { messages: { create } },\n messages: { create }\n } as unknown as NonNullable<AnthropicOptions[\"client\"]>;\n\n const anthropicOptions: AnthropicOptions = {\n ...options,\n ...(request.simple ? thinkingOptions(model, options) : {}),\n client,\n ...(request.toolChoice !== undefined\n ? {\n toolChoice:\n typeof request.toolChoice === \"string\"\n ? request.toolChoice === \"required\"\n ? \"any\"\n : request.toolChoice\n : { name: request.toolChoice.function.name, type: \"tool\" }\n }\n : {})\n };\n\n void (async () => {\n try {\n const inner = anthropicMessagesApi().stream(\n model as Model<\"anthropic-messages\">,\n context,\n anthropicOptions\n );\n for await (const event of inner) {\n // A transport failure is ours to report: pi-ai's own error event knows\n // nothing of the gateway's status, code or log id, so the message it\n // built is re-failed here with that diagnostic attached.\n if (event.type === \"error\" && transportError !== undefined) {\n failFrom(event.error);\n return;\n }\n if (event.type === \"done\" || event.type === \"error\") {\n const message = event.type === \"done\" ? event.message : event.error;\n if (correlation !== undefined) {\n attachCorrelation(message, correlation);\n }\n recordWarnings(message, ignoredWorkersAIKnobs(request));\n }\n outer.push(event);\n }\n if (transportError !== undefined) {\n failFrom(placeholder);\n return;\n }\n outer.end(await inner.result());\n } catch (error) {\n failStream(outer, placeholder, transportError ?? error, options.signal);\n }\n })();\n\n /** Ends the stream with the transport's own error, keeping any content. */\n function failFrom(message: typeof placeholder): void {\n if (correlation !== undefined) attachCorrelation(message, correlation);\n failStream(outer, message, transportError, options.signal);\n }\n\n return outer;\n}\n","/**\n * OpenAI Responses wire: pi-ai's own Responses converters and stream\n * processor, over AI Gateway's universal endpoint.\n *\n * Only the transport differs from talking to OpenAI directly: the body goes to\n * the gateway, which forwards it to `api.openai.com/v1/responses` with the key\n * it holds, and the raw SSE `Response` comes back. The model object is passed\n * through untouched, so the encrypted reasoning items pi replays on a later\n * turn are recognised as the same model's.\n */\n\nimport {\n type AssistantMessageEventStream,\n type Model,\n createAssistantMessageEventStream,\n getCurrentTools\n} from \"@earendil-works/pi-ai\";\nimport {\n convertResponsesMessages,\n convertResponsesTools,\n processResponsesStream\n} from \"@earendil-works/pi-ai/api/openai-responses-shared\";\nimport { clampOpenAIPromptCacheKey } from \"@earendil-works/pi-ai/api/openai-prompt-cache\";\nimport type { Transport } from \"../../core/transport\";\nimport { wireModelId } from \"../catalog\";\nimport { assertOk, failStream } from \"../errors\";\nimport {\n MIN_OUTPUT_TOKENS,\n attachCorrelation,\n correlationDetails,\n openAIVendorHeaders,\n responseInfo,\n sendUniversal,\n sseJson,\n startMessage,\n withIdleDeadline,\n ignoredWorkersAIKnobs,\n recordWarnings\n} from \"./shared\";\nimport type { WireRequest } from \"../settings\";\n\n/**\n * Providers whose tool-call ids carry OpenAI `call|item` pairing across\n * turns. This provider sanitizes ids instead, like pi-ai's own gateway\n * provider, so the set is empty.\n */\nconst TOOL_CALL_ID_PROVIDERS: ReadonlySet<string> = new Set();\n\nconst TERMINAL_EVENTS = new Set([\n \"response.completed\",\n \"response.incomplete\",\n \"response.failed\"\n]);\n\n/** A level through the model's own map, or the level's own name. */\nfunction mappedEffort(model: Model<string>, effort: string): string {\n const map = model.thinkingLevelMap as\n | Record<string, string | null | undefined>\n | undefined;\n return map?.[effort] ?? effort;\n}\n\n/** Streams a Responses request and maps it onto pi-ai events. */\nexport function streamResponses(\n request: WireRequest,\n transport: Transport\n): AssistantMessageEventStream {\n const { model, context, options, resolved } = request;\n const stream = createAssistantMessageEventStream();\n const output = startMessage(model);\n const observed = { endedCleanly: false, sawTerminalEvent: false };\n\n void (async () => {\n let response: Response | undefined;\n try {\n const responsesModel = model as Model<\"openai-responses\">;\n const body: Record<string, unknown> = {\n input: convertResponsesMessages(\n responsesModel,\n context,\n TOOL_CALL_ID_PROVIDERS\n ),\n // The universal request carries the vendor's own spelling of the id.\n model: wireModelId(model),\n store: false,\n stream: true\n };\n const tools = getCurrentTools(context.messages);\n if (tools.length > 0) body.tools = convertResponsesTools(tools);\n if (request.toolChoice !== undefined) {\n body.tool_choice =\n typeof request.toolChoice === \"string\"\n ? request.toolChoice\n : { name: request.toolChoice.function.name, type: \"function\" };\n }\n if (options.maxTokens !== undefined) {\n body.max_output_tokens = Math.max(options.maxTokens, MIN_OUTPUT_TOKENS);\n }\n if (options.temperature !== undefined) {\n body.temperature = options.temperature;\n }\n const cacheKey = clampOpenAIPromptCacheKey(\n resolved.sessionAffinity ?? options.sessionId\n );\n if (cacheKey !== undefined) body.prompt_cache_key = cacheKey;\n // The effort a level names is the model's own to decide: its\n // `thinkingLevelMap` maps it, and its `off` entry says whether the model\n // can be asked for no reasoning at all. Both reads mirror pi-ai's own\n // Responses implementation; neither is a rule of this package.\n if (model.reasoning === true) {\n // With `store: false`, a reasoning item can only be replayed on the\n // next turn if it carries its encrypted content. A model that cannot\n // turn reasoning off reasons even when no effort is asked for, so the\n // content is requested whenever the model reasons at all.\n body.include = [\"reasoning.encrypted_content\"];\n const effort = request.reasoningEffort;\n if (typeof effort === \"string\") {\n body.reasoning = {\n effort: mappedEffort(model, effort),\n summary: \"auto\"\n };\n } else if (model.thinkingLevelMap?.off !== null) {\n body.reasoning = { effort: model.thinkingLevelMap?.off ?? \"none\" };\n }\n }\n const sampling = (options as { samplingParams?: Record<string, unknown> })\n .samplingParams;\n if (sampling !== undefined) Object.assign(body, sampling);\n const overridden = await options.onPayload?.(body, model);\n const payload =\n overridden === undefined\n ? body\n : (overridden as Record<string, unknown>);\n\n response = await sendUniversal(\n request,\n transport,\n payload,\n openAIVendorHeaders()\n );\n await options.onResponse?.(responseInfo(response), model);\n attachCorrelation(\n output,\n correlationDetails(request, response, transport)\n );\n recordWarnings(output, ignoredWorkersAIKnobs(request));\n await assertOk(response, {\n model: model.id,\n requestBodyValues: payload,\n url: transport.url\n });\n if (response.body === null) {\n throw new Error(\"The model returned an empty response body.\");\n }\n\n stream.push({ partial: output, type: \"start\" });\n\n const events = observe(\n sseJson(withIdleDeadline(response.body, request.streamIdleTimeoutMs))\n );\n await processResponsesStream(\n events as Parameters<typeof processResponsesStream>[0],\n output,\n stream,\n responsesModel\n );\n\n if (options.signal?.aborted) throw new Error(\"Request was aborted.\");\n if (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n throw new Error(\n output.errorMessage ?? \"The model reported an error stop reason.\"\n );\n }\n if (observed.endedCleanly && !observed.sawTerminalEvent) {\n throw new Error(\"The stream ended without a terminal response event.\");\n }\n stream.push({\n message: output,\n reason: output.stopReason as \"stop\" | \"length\" | \"toolUse\",\n type: \"done\"\n });\n stream.end(output);\n } catch (error) {\n if (response?.body !== null && response?.body?.locked === false) {\n void response.body.cancel().catch(() => {});\n }\n for (const block of output.content) {\n delete (block as { index?: number }).index;\n delete (block as { partialJson?: string }).partialJson;\n delete (block as { customInput?: unknown }).customInput;\n }\n failStream(stream, output, error, options.signal);\n }\n })();\n\n return stream;\n\n async function* observe(\n events: AsyncIterable<unknown>\n ): AsyncIterable<unknown> {\n for await (const event of events) {\n const type = (event as { type?: unknown } | null)?.type;\n if (typeof type === \"string\" && TERMINAL_EVENTS.has(type)) {\n observed.sawTerminalEvent = true;\n }\n yield event;\n }\n observed.endedCleanly = true;\n }\n}\n","/**\n * Client-side model fallback for pi-ai streams.\n *\n * A leg is abandoned when its stream terminates with an `error` event before\n * it produced any content; the next model is tried with the same context and\n * options. Once a leg has emitted content it is committed to, and a later\n * error propagates. `start` and the block starts that may follow it carry no\n * content, so they are held back until a leg proves itself.\n */\n\nimport {\n type Api,\n type AssistantMessage,\n type AssistantMessageEvent,\n type AssistantMessageEventStream,\n type Model,\n createAssistantMessageEventStream\n} from \"@earendil-works/pi-ai\";\nimport { failStream } from \"../errors\";\nimport { jsonDetails, startMessage } from \"../wires/shared\";\n\n/** One model to try, with the stream that dispatches it. */\nexport interface FallbackLeg {\n model: Model<Api>;\n start(): AssistantMessageEventStream;\n}\n\n/** A leg that was tried and failed before producing output. */\nexport interface FallbackAttempt {\n model: string;\n errorMessage: string | undefined;\n}\n\n/** Diagnostic type under which abandoned legs are recorded. */\nexport const FALLBACK_DIAGNOSTIC = \"cloudflare-fallback\";\n\n/**\n * Events that announce output without carrying any. A leg that emits only\n * these and then fails has produced nothing, so they are held back with\n * `start` until the leg proves itself.\n */\nconst PREAMBLE_EVENTS = new Set<AssistantMessageEvent[\"type\"]>([\n \"start\",\n \"text_start\",\n \"thinking_start\",\n \"toolcall_start\"\n]);\n\nfunction isAbandonable(event: AssistantMessageEvent): boolean {\n return event.type === \"error\" && event.reason === \"error\";\n}\n\n/**\n * Runs legs in order, committing to the first one that produces output.\n *\n * The returned stream always ends. A leg that throws, a stream that rejects,\n * a leg that starts answering and then ends without a `done` or `error`\n * event, and a last leg that ends without producing anything all end it\n * with an `error` event, so a caller awaiting the result is never left\n * waiting.\n */\nexport function streamWithFallback(\n legs: FallbackLeg[],\n signal?: AbortSignal\n): AssistantMessageEventStream {\n const first = legs[0];\n if (first === undefined) {\n throw new Error(\"streamWithFallback needs at least one leg.\");\n }\n const outer = createAssistantMessageEventStream();\n const attempts: FallbackAttempt[] = [];\n let ended = false;\n const end = (message: AssistantMessage): void => {\n ended = true;\n outer.end(message);\n };\n const recordAttempts = (message: AssistantMessage): void => {\n message.diagnostics = [\n ...(message.diagnostics ?? []),\n {\n details: jsonDetails({ attempts }),\n timestamp: Date.now(),\n type: FALLBACK_DIAGNOSTIC\n }\n ];\n };\n\n void (async () => {\n let current = first;\n let lastError: AssistantMessage | undefined;\n try {\n for (const [index, leg] of legs.entries()) {\n current = leg;\n const isLast = index === legs.length - 1;\n const inner = leg.start();\n let pending: AssistantMessageEvent[] = [];\n let committed = false;\n let finished = false;\n for await (const event of inner) {\n if (!committed && PREAMBLE_EVENTS.has(event.type)) {\n pending.push(event);\n continue;\n }\n if (!committed) {\n if (event.type === \"error\" && isAbandonable(event) && !isLast) {\n attempts.push({\n errorMessage: event.error.errorMessage,\n model: leg.model.id\n });\n lastError = event.error;\n break;\n }\n committed = true;\n for (const held of pending) outer.push(held);\n pending = [];\n }\n if (\n (event.type === \"done\" || event.type === \"error\") &&\n attempts.length > 0\n ) {\n recordAttempts(event.type === \"done\" ? event.message : event.error);\n }\n outer.push(event);\n if (event.type === \"done\" || event.type === \"error\") finished = true;\n }\n // A terminal event resolves the leg's result. pi's protocol ends every\n // stream with one, and a leg that ends without it has no result to\n // wait for.\n if (finished) {\n end(await inner.result());\n return;\n }\n if (committed) {\n throw new Error(\n `${leg.model.id} ended its stream without a done or error event.`\n );\n }\n }\n // Every leg was abandoned; surface the last error as the result.\n if (lastError !== undefined) {\n recordAttempts(lastError);\n outer.push({ error: lastError, reason: \"error\", type: \"error\" });\n end(lastError);\n return;\n }\n throw new Error(`${current.model.id} ended its stream without output.`);\n } catch (error) {\n if (ended) return;\n const message = startMessage(current.model);\n if (attempts.length > 0) recordAttempts(message);\n ended = true;\n failStream(outer, message, error, signal);\n }\n })();\n\n return outer;\n}\n","/**\n * The pi-ai language dispatcher: picks the wire from the model's own `api`\n * marker and runs the request through the transport, with client-side fallback\n * across models.\n *\n * The `api` is the model author's declaration, not a guess of ours: Workers AI\n * models carry {@link CLOUDFLARE_AI_API} and run on `env.AI.run`; every other\n * model carries whatever protocol its registry says it speaks, and goes to AI\n * Gateway's universal endpoint.\n */\n\nimport {\n type Api,\n type AssistantMessageEventStream,\n type TranscriptContext,\n type Model,\n type ProviderStreams,\n type SimpleStreamOptions,\n createAssistantMessageEventStream\n} from \"@earendil-works/pi-ai\";\nimport { gatewayLayerOf, mergeModelOptions } from \"../../core/settings\";\nimport type { Transport } from \"../../core/transport\";\nimport {\n CLOUDFLARE_AI_API,\n type PiModelOptions,\n buildGatewayModel,\n buildWorkersAIModel,\n optionsOf,\n withOptions,\n type PiFallbackLeg\n} from \"../catalog\";\nimport { failStream } from \"../errors\";\nimport { type StreamConfig, type WireRequest, buildRequest } from \"../settings\";\nimport { streamAnthropic } from \"../wires/anthropic\";\nimport { streamCompletions } from \"../wires/chat-completions\";\nimport { streamResponses } from \"../wires/responses\";\nimport { startMessage } from \"../wires/shared\";\nimport { streamWithFallback } from \"./fallback\";\n\n/** A stream that fails immediately, for a model this provider cannot route. */\nfunction failedStream(\n request: WireRequest,\n error: Error\n): AssistantMessageEventStream {\n const stream = createAssistantMessageEventStream();\n failStream(\n stream,\n startMessage(request.model),\n error,\n request.options.signal\n );\n return stream;\n}\n\nfunction dispatchOne(\n request: WireRequest,\n transport: Transport\n): AssistantMessageEventStream {\n switch (request.model.api) {\n case CLOUDFLARE_AI_API:\n case \"openai-completions\":\n return streamCompletions(request, transport);\n case \"anthropic-messages\":\n return streamAnthropic(request, transport);\n case \"openai-responses\":\n return streamResponses(request, transport);\n default:\n return failedStream(\n request,\n new TypeError(\n `agents/models/pi-ai cannot route the \"${request.model.api}\" API. AI Gateway serves anthropic-messages, openai-responses and openai-completions models; Workers AI models use \"${CLOUDFLARE_AI_API}\".`\n )\n );\n }\n}\n\n/**\n * The options a fallback leg inherits from the chain: the transport bag, and\n * nothing that describes a model.\n *\n * `name`, `cost`, `contextWindow`, `maxTokens`, `reasoning` and `input` were\n * written about the model they were written on — a leg has its own, from pi's\n * registry — and inheriting them bills the leg's answer at the primary's\n * prices. The leg's own `fallback` is dropped for the same reason `ai()`\n * expands a chain once: a leg is already part of one.\n */\nfunction legOptions(\n options: PiModelOptions | undefined\n): PiModelOptions | undefined {\n if (options === undefined) return undefined;\n const {\n fallback: _fallback,\n name: _name,\n cost: _cost,\n contextWindow: _contextWindow,\n maxTokens: _maxTokens,\n reasoning: _reasoning,\n input: _input,\n ...rest\n } = options;\n return rest;\n}\n\n/** A leg may be given as a Workers AI id or as a model of any kind. */\nfunction legModel(\n leg: string | Model<Api>,\n options: PiModelOptions | undefined\n): Model<Api> {\n // An id has no options of its own, so it takes the chain's transport bag.\n // It resolves exactly as `ai(string)` does: a Workers AI id, or a\n // `<slug>/<id>` pi-ai's gateway registry knows — never a raw vendor id.\n if (typeof leg === \"string\") {\n return leg.startsWith(\"@cf/\")\n ? buildWorkersAIModel(leg, options)\n : buildGatewayModel(leg, options);\n }\n // A configured leg keeps everything it was built with; the chain's gateway\n // options are layered over its own, field by field, so a chain and its legs\n // travel through one gateway — the same rule the AI SDK module applies.\n const own = optionsOf(leg);\n const inherited = gatewayLayerOf(options);\n const merged = mergeModelOptions<PiFallbackLeg>(\n own,\n Object.keys(inherited).length > 0 ? inherited : undefined\n ) as PiModelOptions | undefined;\n return withOptions(leg, merged);\n}\n\n/**\n * Builds pi-ai's `stream` and `streamSimple` for one provider instance. Any\n * model reaches them — this provider's own, or one the caller built from their\n * registry and handed to `ai(model)` — and dispatches on its `api`.\n */\nexport function createStreams(config: StreamConfig): ProviderStreams {\n const run = (\n model: Model<Api>,\n context: TranscriptContext,\n options: SimpleStreamOptions | undefined,\n simple: boolean\n ): AssistantMessageEventStream => {\n const callOptions = options ?? {};\n const primary = buildRequest(model, context, callOptions, simple, config);\n if (primary.fallback.length === 0) {\n return dispatchOne(primary, config.transport);\n }\n\n const shared = legOptions(optionsOf(model));\n const legs = [\n {\n model,\n start: () => dispatchOne(primary, config.transport)\n },\n ...primary.fallback.map((leg) => {\n const legTarget = legModel(leg, shared);\n return {\n model: legTarget,\n start: () =>\n dispatchOne(\n buildRequest(legTarget, context, callOptions, simple, config),\n config.transport\n )\n };\n })\n ];\n return streamWithFallback(legs, callOptions.signal);\n };\n\n return {\n stream: (model, context, options) =>\n run(model, context, options as SimpleStreamOptions | undefined, false),\n streamSimple: (model, context, options) =>\n run(model, context, options, true)\n };\n}\n","/**\n * `agents/models/pi-ai` — Cloudflare's AI as a pi-ai provider, with the same\n * shape as `agents/models/ai-sdk`.\n *\n * One rule decides everything here: **Workers AI is the catalog Cloudflare\n * keeps; every other vendor is pi-ai's.** So there are two call forms, and no\n * third:\n *\n * ```ts\n * import { createAI } from \"agents/models/pi-ai\";\n * import { getBuiltinModel } from \"@earendil-works/pi-ai/providers/all\";\n *\n * const ai = createAI({ binding: env.AI, id: \"prod\" });\n *\n * ai(\"@cf/zai-org/glm-4.7-flash\"); // Workers AI: ours\n * ai(getBuiltinModel(\"anthropic\", \"claude-opus-4-8\")); // theirs, our transport\n * ai(\"anthropic/claude-opus-4-8\"); // same, via pi's catalog\n * ```\n *\n * Workers AI runs on `env.AI.run` with Cloudflare's own compat layer. Every\n * other model goes to AI Gateway's universal endpoint, which forwards the\n * vendor's own request to the vendor with the key the gateway holds — so no\n * provider key, and no vendor wire format, lives in your Worker. The model's\n * metadata (`api`, `compat`, `thinkingLevelMap`, cost, limits) is whatever its\n * own registry says, and pi-ai's converters and stream processors do the rest.\n *\n * @beta Everything exported here is in beta: the surface may\n * change in a minor release while the design settles.\n *\n * @module\n */\n\nimport {\n type Api,\n type AssistantMessage,\n type Context,\n type ImagesContext,\n type Model,\n type Provider,\n type SimpleStreamOptions,\n type StreamOptions,\n createProvider,\n normalizeContext\n} from \"@earendil-works/pi-ai\";\nimport type { WorkersAIModelId } from \"../core/catalog\";\nimport type { AISettings } from \"../core/settings\";\nimport { createTransport } from \"../core/transport\";\nimport {\n type CloudflareAssistantImages,\n type CloudflareImagesModel,\n type PiImagesCallOptions,\n type PiImagesModelOptions,\n buildImagesModel,\n generateImages\n} from \"./models/image\";\nimport {\n CLOUDFLARE_PROVIDER_ID,\n type CloudflareModel,\n type PiModelOptions,\n type RoutedModel,\n buildGatewayModel,\n buildWorkersAIModel,\n gatewayModelIds,\n withOptions,\n workersAIModelIds\n} from \"./catalog\";\nimport { createStreams } from \"./models/language\";\n\nexport type {\n CloudflareEmbeddingModelId,\n WorkersAIModelId\n} from \"../core/catalog\";\nexport {\n CloudflareAIError,\n type CloudflareAIAttempt,\n type CloudflareAIErrorCode\n} from \"../core/errors\";\nexport type {\n AISettings,\n GatewayOptions,\n ModelOptions\n} from \"../core/settings\";\nexport {\n GATEWAY_PROVIDER_NAMES,\n type GatewayProviderName\n} from \"../core/gateway-providers\";\nexport { FALLBACK_DIAGNOSTIC, type FallbackAttempt } from \"./models/fallback\";\nexport {\n CLOUDFLARE_AI_IMAGES_API,\n type CloudflareAssistantImages,\n type CloudflareImagesModel,\n type PiImagesCallOptions,\n type PiImagesModelOptions\n} from \"./models/image\";\nexport {\n CLOUDFLARE_AI_API,\n CLOUDFLARE_PROVIDER_ID,\n type CloudflareAIApi,\n type CloudflareModel,\n type ModelCost,\n type PiModelOptions,\n type RoutedModel\n} from \"./catalog\";\nexport { CLOUDFLARE_ERROR_DIAGNOSTIC } from \"./errors\";\nexport { CLOUDFLARE_DIAGNOSTIC } from \"./wires/shared\";\n\n/**\n * pi-agent-core's `streamFn` shape: what `Agent` calls to run a turn.\n *\n * @beta This surface is in beta and may change.\n */\nexport type StreamFn = (\n model: Model<string>,\n context: Context,\n options?: SimpleStreamOptions\n) => ReturnType<Provider[\"streamSimple\"]>;\n\n/**\n * The provider `createAI` returns. Call it with a Workers AI id or with a\n * pi-ai model to get a model this instance routes; use `stream`/`complete` to\n * run it, `streamFn` with pi-agent-core's `Agent`, and `provider` with a pi-ai\n * `Models` registry.\n *\n * @beta This surface is in beta and may change.\n */\nexport interface AI {\n /** A Workers AI model: Cloudflare's own catalog, on the run path. */\n (modelId: WorkersAIModelId, options?: PiModelOptions): CloudflareModel;\n /** Any pi-ai model, routed through AI Gateway with its metadata intact. */\n <TApi extends Api>(model: Model<TApi>, options?: PiModelOptions): Model<TApi>;\n /**\n * A `<slug>/<id>` id from pi-ai's Cloudflare AI Gateway catalog, or either\n * form when the caller only knows which at runtime.\n */\n (target: string | Model<Api>, options?: PiModelOptions): RoutedModel;\n /** Same as calling the provider directly. */\n model(modelId: WorkersAIModelId, options?: PiModelOptions): CloudflareModel;\n model<TApi extends Api>(\n model: Model<TApi>,\n options?: PiModelOptions\n ): Model<TApi>;\n model(target: string | Model<Api>, options?: PiModelOptions): RoutedModel;\n /**\n * The pi-ai `Provider` (id `cloudflare`) for `Models.setProvider` and\n * frameworks built on the registry. Its static model list is every Workers\n * AI id plus every `<slug>/<id>` in pi-ai's Cloudflare AI Gateway catalog;\n * any other model still streams when passed to `ai(model)`.\n */\n readonly provider: Provider;\n /** Full-options streaming, like pi-ai's `stream`. */\n stream(\n model: Model<string>,\n context: Context,\n options?: StreamOptions\n ): ReturnType<Provider[\"stream\"]>;\n /** Full-options completion, like pi-ai's `complete`. */\n complete(\n model: Model<string>,\n context: Context,\n options?: StreamOptions\n ): Promise<AssistantMessage>;\n /** Simple streaming, with `reasoning` as a level, like pi-ai's `streamSimple`. */\n streamSimple(\n model: Model<string>,\n context: Context,\n options?: SimpleStreamOptions\n ): ReturnType<Provider[\"streamSimple\"]>;\n /** Simple completion, like pi-ai's `completeSimple`. */\n completeSimple(\n model: Model<string>,\n context: Context,\n options?: SimpleStreamOptions\n ): Promise<AssistantMessage>;\n /** `streamSimple`, bound, for pi-agent-core's `Agent({ streamFn })`. */\n readonly streamFn: StreamFn;\n /** A pi-ai image model over a Workers AI text-to-image id. */\n images(\n modelId: string,\n options?: PiImagesModelOptions\n ): CloudflareImagesModel;\n /** Generates images with a model from {@link AI.images}, like pi-ai's `generateImages`. */\n generateImages(\n model: CloudflareImagesModel,\n context: ImagesContext,\n options?: PiImagesCallOptions\n ): Promise<CloudflareAssistantImages>;\n}\n\n/** The prefixes a bare vendor id is most often written with, for the error. */\nconst VENDOR_HINTS: Record<string, string> = {\n anthropic: \"anthropic\",\n google: \"google\",\n openai: \"openai\"\n};\n\n/**\n * A string that is neither a Workers AI id nor a `<slug>/<id>` this provider\n * can resolve. There is no guessing here by design: a model we cannot name\n * exactly is the caller's to construct.\n */\nfunction unroutableString(specifier: string): TypeError {\n const prefix = specifier.split(\"/\")[0] ?? \"\";\n const hint = VENDOR_HINTS[prefix];\n return new TypeError(\n `ai(\"${specifier}\") is not a model this provider knows. Workers AI ids start with \"@cf/\". A third-party model comes from its own pi-ai registry: ai(getBuiltinModel(${\n hint === undefined ? '\"<provider>\"' : `\"${hint}\"`\n }, \"<model id>\")) from \"@earendil-works/pi-ai/providers/all\", or any Model object you built yourself.`\n );\n}\n\nfunction buildModel(\n target: string | Model<Api>,\n options: PiModelOptions | undefined\n): Model<Api> {\n // A string leg follows the same rule as a string target, checked here so\n // the mistake is reported at the line that wrote the chain.\n for (const leg of options?.fallback ?? []) {\n if (typeof leg !== \"string\" || leg.startsWith(\"@cf/\")) continue;\n if (!leg.includes(\"/\")) throw unroutableString(leg);\n buildGatewayModel(leg, undefined);\n }\n if (typeof target !== \"string\") return withOptions(target, options);\n if (target.startsWith(\"@cf/\")) return buildWorkersAIModel(target, options);\n if (!target.includes(\"/\")) throw unroutableString(target);\n return buildGatewayModel(target, options);\n}\n\n/**\n * Creates a pi-ai provider over Cloudflare's AI.\n *\n * The Workers AI binding is the only way in — Workers AI models go through\n * `env.AI.run`, vendor models through `env.AI.gateway(id).run`, and there is\n * no HTTP transport and no API token. Gateway options may be given flat\n * (`{ binding, id: \"prod\", cacheTtl: 60 }`) or nested under `gateway`;\n * per-model options and per-call pi-ai options (`headers`, `metadata`,\n * `sessionId`) override them in that order.\n *\n * ```ts\n * const ai = createAI({ binding: env.AI, id: \"prod\" });\n * ai(\"@cf/zai-org/glm-4.7-flash\");\n * ai(anthropicModel, { fallback: [\"@cf/zai-org/glm-4.7-flash\"] });\n * new Agent({ streamFn: ai.streamFn, initialState: { model: ai(openaiModel) } });\n * ```\n *\n * @beta This surface is in beta and may change.\n */\nexport function createAI(settings: AISettings): AI {\n const transport = createTransport(settings);\n const streams = createStreams({ providerGateway: settings, transport });\n\n const model = ((\n target: string | Model<Api>,\n options?: PiModelOptions\n ): Model<Api> => buildModel(target, options)) as AI[\"model\"];\n\n const provider = createProvider({\n api: streams,\n auth: {\n apiKey: {\n name: \"Cloudflare (the AI binding)\",\n // The transport is already authenticated; nothing to resolve.\n resolve: async () => ({ auth: {} })\n }\n },\n id: CLOUDFLARE_PROVIDER_ID,\n models: [\n ...workersAIModelIds().map((id) => buildWorkersAIModel(id, undefined)),\n ...gatewayModelIds().map((id) => buildGatewayModel(id, undefined))\n ],\n name: \"Cloudflare\"\n });\n\n const stream: AI[\"stream\"] = (target, context, options) =>\n streams.stream(target, normalizeContext(context), options);\n const streamSimple: AI[\"streamSimple\"] = (target, context, options) =>\n streams.streamSimple(target, normalizeContext(context), options);\n\n return Object.assign(model as AI, {\n complete: (target, context, options) =>\n stream(target, context, options).result(),\n completeSimple: (target, context, options) =>\n streamSimple(target, context, options).result(),\n generateImages: (target, context, options) =>\n generateImages(\n { providerGateway: settings, transport },\n target,\n context,\n options\n ),\n images: (modelId, options) => buildImagesModel(modelId, options),\n model,\n provider,\n stream,\n streamFn: streamSimple,\n streamSimple\n } satisfies Omit<AI, \"call\">);\n}\n"],"mappings":"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"}