agents 0.26.0 → 0.27.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.
- package/README.md +8 -9
- package/dist/{agent-routing-0DR0Tk2v.d.ts → agent-routing-Bhdbvf7s.d.ts} +13 -8
- package/dist/agent-routing.d.ts +1 -1
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-YrATZJu2.d.ts → agent-tools-bJZwBMfq.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/ai-sdk-OoGkFy3s.js +2444 -0
- package/dist/ai-sdk-OoGkFy3s.js.map +1 -0
- package/dist/apply-chunks-1FheRb9W.js +99 -0
- package/dist/apply-chunks-1FheRb9W.js.map +1 -0
- package/dist/broadcast-state-CEyI4uAK.js +69 -0
- package/dist/broadcast-state-CEyI4uAK.js.map +1 -0
- package/dist/browser/ai-sdk.d.ts +1 -1
- package/dist/browser/ai-sdk.js +2 -2
- package/dist/browser/ai-sdk.js.map +1 -1
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/tanstack-ai.d.ts +1 -1
- package/dist/browser/tanstack-ai.js +1 -1
- package/dist/{browser-DE3d-RLk.d.ts → browser-tmkcAAI3.d.ts} +2 -2
- package/dist/{browser-tool-DuNdlwZ9.d.ts → browser-tool-Bn-nzJQI.d.ts} +3 -3
- package/dist/{browser-tool-CQ10e6Kj.js → browser-tool-CBqs6hqa.js} +58 -18
- package/dist/browser-tool-CBqs6hqa.js.map +1 -0
- package/dist/capability-B4WbF81e.js.map +1 -1
- package/dist/{capability-runner-DBAnGr6L.d.ts → capability-runner-O5VbQzqg.d.ts} +9 -1
- package/dist/channel-Bak_6zDP.d.ts +333 -0
- package/dist/chat/index.d.ts +11 -9
- package/dist/chat/index.js +5 -194
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/react.d.ts +2 -4
- package/dist/chat/react.js +3 -1
- package/dist/chat/react.js.map +1 -1
- package/dist/chat-sdk/index.d.ts +1 -1
- package/dist/chat-sdk/index.js +1 -1
- package/dist/cli.js +144 -0
- package/dist/{client-fyQrLGkD.js → client-1tEQ1Oqz.js} +27 -2
- package/dist/{client-fyQrLGkD.js.map → client-1tEQ1Oqz.js.map} +1 -1
- package/dist/{client-je3koD9Z.d.ts → client-DS3Dz9l0.d.ts} +2 -2
- package/dist/client-tools-aIBO0Fk7.d.ts +53 -0
- package/dist/client.d.ts +1 -1
- package/dist/conversations-DH0ut_8n.d.ts +192 -0
- package/dist/{current-agent-vAk_5JMt.d.ts → current-agent-C07C5o5Y.d.ts} +3 -3
- package/dist/daemon-core-Buubj-y1.js +481 -0
- package/dist/daemon-core-Buubj-y1.js.map +1 -0
- package/dist/daemon-core-CbohVPAu.d.ts +132 -0
- package/dist/{do-oauth-client-provider-Tmf1vgKz.d.ts → do-oauth-client-provider-DfsUcpc3.d.ts} +7 -1
- package/dist/{durable-object-lifecycle-HhgOMWq9.d.ts → durable-object-lifecycle-DRqp475_.d.ts} +2 -2
- package/dist/{channels/email.d.ts → experimental/channels/email/index.d.ts} +25 -12
- package/dist/{channels/email.js → experimental/channels/email/index.js} +13 -35
- package/dist/experimental/channels/email/index.js.map +1 -0
- package/dist/experimental/channels/index.d.ts +270 -0
- package/dist/experimental/channels/index.js +1186 -0
- package/dist/experimental/channels/index.js.map +1 -0
- package/dist/{channels/slack.d.ts → experimental/channels/slack/index.d.ts} +19 -9
- package/dist/experimental/channels/slack/index.js +267 -0
- package/dist/experimental/channels/slack/index.js.map +1 -0
- package/dist/{channels/telegram.d.ts → experimental/channels/telegram/index.d.ts} +19 -9
- package/dist/experimental/channels/telegram/index.js +198 -0
- package/dist/experimental/channels/telegram/index.js.map +1 -0
- package/dist/experimental/channels/web/ai-sdk.d.ts +55 -0
- package/dist/experimental/channels/web/ai-sdk.js +266 -0
- package/dist/experimental/channels/web/ai-sdk.js.map +1 -0
- package/dist/experimental/channels/web/client.d.ts +97 -0
- package/dist/experimental/channels/web/client.js +349 -0
- package/dist/experimental/channels/web/client.js.map +1 -0
- package/dist/experimental/channels/web/index.d.ts +189 -0
- package/dist/experimental/channels/web/index.js +332 -0
- package/dist/experimental/channels/web/index.js.map +1 -0
- package/dist/gateway-BDC07gYO.d.ts +100 -0
- package/dist/handle-zAzh0UW2.d.ts +460 -0
- package/dist/harness/ai-sdk/index.d.ts +175 -0
- package/dist/harness/ai-sdk/index.js +605 -0
- package/dist/harness/ai-sdk/index.js.map +1 -0
- package/dist/harness/container/daemon/index.d.ts +76 -0
- package/dist/harness/container/daemon/index.js +3 -0
- package/dist/harness/container/index.d.ts +740 -0
- package/dist/harness/container/index.js +2152 -0
- package/dist/harness/container/index.js.map +1 -0
- package/dist/harness/container/runtime/index.d.ts +144 -0
- package/dist/harness/container/runtime/index.js +1082 -0
- package/dist/harness/container/runtime/index.js.map +1 -0
- package/dist/harness/opencode/index.d.ts +369 -0
- package/dist/harness/opencode/index.js +1072 -0
- package/dist/harness/opencode/index.js.map +1 -0
- package/dist/harness/pi/index.d.ts +2 -1
- package/dist/harness/store/index.d.ts +24 -0
- package/dist/harness/store/index.js +2 -0
- package/dist/harness/think/index.d.ts +821 -0
- package/dist/harness/think/index.js +2529 -0
- package/dist/harness/think/index.js.map +1 -0
- package/dist/harness-B6B9S3rb.d.ts +203 -0
- package/dist/{images-iiTDSyRu.js → images-Ce9SCu3X.js} +2 -248
- package/dist/images-Ce9SCu3X.js.map +1 -0
- package/dist/{index-BreL0YrQ.d.ts → index-D0A5tbWu.d.ts} +2 -2
- package/dist/index-Ib_4dwOo.d.ts +200 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +2 -2
- package/dist/ingress-EFbrS547.js +9 -0
- package/dist/ingress-EFbrS547.js.map +1 -0
- package/dist/input-schema-DNrpTu49.js +23 -0
- package/dist/input-schema-DNrpTu49.js.map +1 -0
- package/dist/internal-kmw70xwR.js +46 -0
- package/dist/internal-kmw70xwR.js.map +1 -0
- package/dist/internal_context.d.ts +1 -1
- package/dist/lifecycle/index.d.ts +3 -3
- package/dist/mcp/client/do-oauth-client-provider.d.ts +1 -1
- package/dist/mcp/client/do-oauth-client-provider.js +9 -0
- package/dist/mcp/client/do-oauth-client-provider.js.map +1 -1
- package/dist/mcp/client/index.d.ts +1 -1
- package/dist/mcp/client/index.js +1 -1
- package/dist/mcp/client/x402.d.ts +35 -4
- package/dist/mcp/client/x402.js +24 -3
- package/dist/mcp/client/x402.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +2 -2
- package/dist/models/ai-sdk/index.d.ts +16 -14
- package/dist/models/ai-sdk/index.js +1 -2442
- package/dist/models/opencode/index.d.ts +65 -0
- package/dist/models/opencode/index.js +285 -0
- package/dist/models/opencode/index.js.map +1 -0
- package/dist/models/pi-ai/index.d.ts +9 -7
- package/dist/models/pi-ai/index.js +2 -1
- package/dist/models/pi-ai/index.js.map +1 -1
- package/dist/options-pwTNq9z6.d.ts +134 -0
- package/dist/protocol-BEgrJYC5.d.ts +331 -0
- package/dist/protocol-CukuI73M.d.ts +386 -0
- package/dist/protocol-cOklVBBD.js +227 -0
- package/dist/protocol-cOklVBBD.js.map +1 -0
- package/dist/{protocol-kHsr-f0X.js → protocol-eXeJxhgu.js} +2 -67
- package/dist/protocol-eXeJxhgu.js.map +1 -0
- package/dist/protocol-y2sSY584.js +148 -0
- package/dist/protocol-y2sSY584.js.map +1 -0
- package/dist/queue/index.d.ts +1 -1
- package/dist/react.d.ts +2 -2
- package/dist/routing/index.d.ts +2 -2
- package/dist/{scheduler-RdACNXDP.d.ts → scheduler-CrFCnv_J.d.ts} +2 -2
- package/dist/schedules/index.d.ts +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/sessions/index.d.ts +11 -434
- package/dist/sessions/index.js +1 -2271
- package/dist/sessions-B9pNuxdT.js +2272 -0
- package/dist/sessions-B9pNuxdT.js.map +1 -0
- package/dist/settings-C45hDliX.js +253 -0
- package/dist/settings-C45hDliX.js.map +1 -0
- package/dist/{transport-PfFnt-Ld.d.ts → settings-NgGwF7Qt.d.ts} +14 -208
- package/dist/{src-BZeu-SCD.js → src-DgCbZtIR.js} +4 -4
- package/dist/{src-BZeu-SCD.js.map → src-DgCbZtIR.js.map} +1 -1
- package/dist/stall-watchdog-BpRF2uwG.js +195 -0
- package/dist/stall-watchdog-BpRF2uwG.js.map +1 -0
- package/dist/state/index.d.ts +1 -1
- package/dist/store-DLeqKuj3.d.ts +310 -0
- package/dist/store-vgcPYo8K.js +432 -0
- package/dist/store-vgcPYo8K.js.map +1 -0
- package/dist/streams/index.d.ts +1 -1
- package/dist/streams/index.js +1 -1
- package/dist/{streams-DW-UCOUc.js → streams-CITClVer.js} +16 -3
- package/dist/streams-CITClVer.js.map +1 -0
- package/dist/{streams-Cmkj9QfW.d.ts → streams-fbG61qM8.d.ts} +2 -2
- package/dist/sub-routing.d.ts +1 -1
- package/dist/tasks/index.d.ts +1 -1
- package/dist/tasks/index.js +1 -1
- package/dist/{tasks-68DESxf0.js → tasks-CkTZNaV1.js} +2 -1
- package/dist/tasks-CkTZNaV1.js.map +1 -0
- package/dist/{tasks-9YxYtByh.d.ts → tasks-PtlB4Uyn.d.ts} +2 -2
- package/dist/tool-3PA8xjB_.js +421 -0
- package/dist/tool-3PA8xjB_.js.map +1 -0
- package/dist/tool-BPJEbwaX.d.ts +278 -0
- package/dist/transport-k2mFrtL8.d.ts +200 -0
- package/dist/turns-DCV3ycDl.js +317 -0
- package/dist/turns-DCV3ycDl.js.map +1 -0
- package/dist/voice/client.js +1 -1
- package/dist/voice/index.d.ts +2 -2
- package/dist/voice/index.js +1 -1
- package/dist/websearch/index.d.ts +58 -0
- package/dist/websearch/index.js +2 -0
- package/dist/websearch/tools/ai-sdk.d.ts +77 -0
- package/dist/websearch/tools/ai-sdk.js +46 -0
- package/dist/websearch/tools/ai-sdk.js.map +1 -0
- package/dist/websearch/tools/pi.d.ts +82 -0
- package/dist/websearch/tools/pi.js +89 -0
- package/dist/websearch/tools/pi.js.map +1 -0
- package/dist/websearch/tools/tanstack-ai.d.ts +71 -0
- package/dist/websearch/tools/tanstack-ai.js +46 -0
- package/dist/websearch/tools/tanstack-ai.js.map +1 -0
- package/dist/websockets/index.d.ts +12 -296
- package/dist/websockets/index.js +1 -1
- package/dist/{websockets-Ci-LZFHH.js → websockets-CmENGb-Z.js} +18 -4
- package/dist/websockets-CmENGb-Z.js.map +1 -0
- package/dist/{wire-types-CrjKvDyi.d.ts → wire-types-Cv0iwjk5.d.ts} +3 -51
- package/dist/workflow-types.d.ts +1 -1
- package/dist/workflows.d.ts +1 -1
- package/dist/workflows.js +1 -1
- package/docs/browse-the-web.md +3 -0
- package/docs/harnesses/think.md +215 -0
- package/docs/index.md +2 -1
- package/docs/lifecycle.md +40 -0
- package/docs/search-the-web.md +133 -0
- package/package.json +117 -38
- package/dist/browser-tool-CQ10e6Kj.js.map +0 -1
- package/dist/channel-Bnm4S7T2.d.ts +0 -491
- package/dist/channels/ai-sdk.d.ts +0 -46
- package/dist/channels/ai-sdk.js +0 -120
- package/dist/channels/ai-sdk.js.map +0 -1
- package/dist/channels/email.js.map +0 -1
- package/dist/channels/index.d.ts +0 -233
- package/dist/channels/index.js +0 -608
- package/dist/channels/index.js.map +0 -1
- package/dist/channels/slack.js +0 -614
- package/dist/channels/slack.js.map +0 -1
- package/dist/channels/tanstack-ai.d.ts +0 -39
- package/dist/channels/tanstack-ai.js +0 -17
- package/dist/channels/tanstack-ai.js.map +0 -1
- package/dist/channels/telegram.js +0 -427
- package/dist/channels/telegram.js.map +0 -1
- package/dist/channels/voice.d.ts +0 -45
- package/dist/channels/voice.js +0 -122
- package/dist/channels/voice.js.map +0 -1
- package/dist/images-iiTDSyRu.js.map +0 -1
- package/dist/index-BB0kqhIz.d.ts +0 -101
- package/dist/ingress-BfetZbMO.js +0 -83
- package/dist/ingress-BfetZbMO.js.map +0 -1
- package/dist/internal-CYlgHl1l.js +0 -59
- package/dist/internal-CYlgHl1l.js.map +0 -1
- package/dist/models/ai-sdk/index.js.map +0 -1
- package/dist/protocol-kHsr-f0X.js.map +0 -1
- package/dist/sessions/index.js.map +0 -1
- package/dist/streams-DW-UCOUc.js.map +0 -1
- package/dist/surface-bZZJqBka.js +0 -17
- package/dist/surface-bZZJqBka.js.map +0 -1
- package/dist/tasks-68DESxf0.js.map +0 -1
- package/dist/tool-schema-CBjGPrsQ.js +0 -31
- package/dist/tool-schema-CBjGPrsQ.js.map +0 -1
- package/dist/websockets-Ci-LZFHH.js.map +0 -1
- package/docs/channels.md +0 -323
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"telegram.js","names":[],"sources":["../../src/channels/adapters/telegram.ts"],"sourcesContent":["import type {\n Channel,\n ChannelApprovalRequest,\n ChannelChunk,\n ChannelMessage,\n ChannelRoute,\n ChannelStreamOptions,\n DeliveryResult\n} from \"../channel\";\nimport { consumeChunks, createPacer } from \"../stream\";\nimport type { ChannelIdentity } from \"../identity\";\nimport {\n isChannelMessageSurface,\n type ChannelMessageSurface\n} from \"../surface\";\nimport {\n matchesPath,\n type ChannelApprovalResponseInput,\n type ChannelEventContextInput,\n type ChannelInboundMessageInput,\n type ChannelIngress,\n type ChannelIngressEventInput\n} from \"../ingress\";\nimport {\n defaultText,\n emptyIngressResponse,\n encodeUtf8,\n isRecord,\n renderInput,\n uncertain\n} from \"../internal\";\n\nexport type TelegramUser = {\n id: number;\n is_bot: boolean;\n first_name: string;\n last_name?: string;\n username?: string;\n [key: string]: unknown;\n};\n\nexport type TelegramChat = {\n id: number;\n type: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n title?: string;\n username?: string;\n first_name?: string;\n last_name?: string;\n [key: string]: unknown;\n};\n\nexport type TelegramMessage = {\n message_id: number;\n date: number;\n chat: TelegramChat;\n message_thread_id?: number;\n from?: TelegramUser;\n sender_chat?: TelegramChat;\n text?: string;\n edit_date?: number;\n reply_to_message?: TelegramMessage;\n [key: string]: unknown;\n};\n\n/** Authenticated JSON body delivered by a Telegram webhook. */\nexport type TelegramUpdate = {\n update_id: number;\n message?: TelegramMessage;\n edited_message?: TelegramMessage;\n [key: string]: unknown;\n};\n\nexport type TelegramMessageSurface = ChannelMessageSurface<\n string,\n {\n chatId: string;\n botUserId?: number;\n messageThreadId?: number;\n replyToMessageId?: number;\n }\n>;\n\n/** Configuration for a Telegram Channel. */\nexport type TelegramChannelOptions = {\n /** Bot token issued by BotFather. */\n botToken: string;\n /** Telegram Bot API origin. @default \"https://api.telegram.org\" */\n apiBaseUrl?: string;\n /** Maximum text length accepted by this route. @default 4096 */\n maxLength?: number;\n /** Project the canonical message into Telegram text. */\n toText?: (message: ChannelMessage) => string;\n /** Parse mode for caller-formatted delivery text. */\n parseMode?: \"HTML\" | \"MarkdownV2\";\n /**\n * Smallest gap between `sendMessageDraft` previews. Snapshots produced\n * inside one interval are replaced rather than sent. @default 500\n */\n streamIntervalMs?: number;\n /** Select an application route from the event, raw update, and Host context. */\n route?: ChannelRoute<TelegramUpdate>;\n /** Add secret-verified Telegram webhook ingress to the returned Channel. */\n webhook?: {\n secretToken: string;\n /** Exact webhook pathname accepted by this ingress. @default \"/webhooks/telegram\" */\n path?: string;\n };\n /** Override fetch for testing or custom network routing. */\n fetch?: typeof globalThis.fetch;\n};\n\ntype TelegramApiResponse = {\n ok?: unknown;\n result?: unknown;\n error_code?: unknown;\n description?: unknown;\n};\n\nconst TELEGRAM_MESSAGE_LIMIT = 4096;\nconst DEFAULT_STREAM_INTERVAL_MS = 500;\nconst DEFAULT_TELEGRAM_WEBHOOK_PATH = \"/webhooks/telegram\";\nconst APPROVAL_INSTRUCTIONS = \"Reply YES to approve or NO to reject.\";\nconst INTERACTION_FOOTER =\n /\\n\\nReply YES to approve or NO to reject\\.\\n\\n\\[channel-interaction:v1:([A-Za-z0-9_-]+)\\]$/;\n\nfunction channelIdentity(chatId: number): string {\n return `telegram:chat:${chatId}`;\n}\n\nfunction userIdentity(userId: number): string {\n return `telegram:user:${userId}`;\n}\n\nfunction messageIdentity(chatId: number, messageId: number): string {\n return `${channelIdentity(chatId)}:message:${messageId}`;\n}\n\nfunction updateIdentity(chatId: number, updateId: number): string {\n return `${channelIdentity(chatId)}:update:${updateId}`;\n}\n\nfunction encodeInteractionId(interactionId: string): string {\n const bytes = encodeUtf8(interactionId);\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary)\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nfunction decodeInteractionId(value: string): string | undefined {\n try {\n const base64 = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padding = \"=\".repeat((4 - (base64.length % 4)) % 4);\n const binary = atob(base64 + padding);\n const bytes = Uint8Array.from(binary, (character) =>\n character.charCodeAt(0)\n );\n const interactionId = new TextDecoder(\"utf-8\", { fatal: true }).decode(\n bytes\n );\n return interactionId || undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction approvalText(\n interactionId: string,\n request: ChannelApprovalRequest\n): string {\n return [\n ...(request.title ? [request.title] : []),\n request.summary,\n `Input:\\n${renderInput(request.input)}`,\n APPROVAL_INSTRUCTIONS,\n `[channel-interaction:v1:${encodeInteractionId(interactionId)}]`\n ].join(\"\\n\\n\");\n}\n\nfunction asApiResponse(value: unknown): TelegramApiResponse | undefined {\n return value !== null && typeof value === \"object\"\n ? (value as TelegramApiResponse)\n : undefined;\n}\n\nfunction classifyResponse(\n response: Response,\n payload: TelegramApiResponse\n): DeliveryResult {\n if (payload.ok === true) {\n const result = asApiResponse(payload.result) as\n | { message_id?: unknown }\n | undefined;\n if (typeof result?.message_id === \"number\") {\n return { status: \"delivered\", reference: String(result.message_id) };\n }\n return uncertain(\n \"TELEGRAM_DELIVERY_ERROR\",\n \"Telegram returned an invalid delivery response\"\n );\n }\n\n if (payload.ok === false) {\n const errorCode =\n typeof payload.error_code === \"number\"\n ? payload.error_code\n : response.status;\n const message =\n typeof payload.description === \"string\"\n ? payload.description\n : \"Telegram rejected the message\";\n const error = { code: `TELEGRAM_API_ERROR_${errorCode}`, message };\n if (errorCode >= 500) return { status: \"uncertain\", error };\n return {\n status: \"failed\",\n retryable: errorCode === 429,\n error\n };\n }\n\n return uncertain(\n \"TELEGRAM_DELIVERY_ERROR\",\n \"Telegram returned an invalid delivery response\"\n );\n}\n\nexport type TelegramWebhookOptions = {\n /** Telegram webhook secret configured through setWebhook. */\n secretToken: string;\n /** Exact webhook pathname accepted by this ingress. @default \"/webhooks/telegram\" */\n path?: string;\n /**\n * Numeric user id of this bot, used to prove that an approval reply answers\n * a message this bot sent. Without it, marker replies stay ordinary\n * messages because their provenance cannot be established.\n */\n botUserId?: number;\n};\n\nfunction asTelegramMessage(value: unknown): TelegramMessage | undefined {\n return value !== null && typeof value === \"object\"\n ? (value as TelegramMessage)\n : undefined;\n}\n\nfunction telegramActor(message: TelegramMessage) {\n const sender = message.from;\n if (sender) {\n const fullName = [sender.first_name, sender.last_name]\n .filter(Boolean)\n .join(\" \");\n return {\n id: userIdentity(sender.id),\n identity: {\n subject: `user:${sender.id}`\n },\n ...(sender.username && { username: sender.username }),\n ...(fullName && { fullName }),\n isBot: sender.is_bot\n };\n }\n\n const senderChat = message.sender_chat;\n if (!senderChat) return undefined;\n const fullName =\n senderChat.title ??\n [senderChat.first_name, senderChat.last_name].filter(Boolean).join(\" \");\n return {\n id: channelIdentity(senderChat.id),\n identity: {\n subject: `chat:${senderChat.id}`\n },\n ...(senderChat.username && { username: senderChat.username }),\n ...(fullName && { fullName }),\n isBot: \"unknown\" as const\n };\n}\n\nfunction chatLabel(chat: TelegramChat): string {\n const name =\n chat.title ??\n (chat.username ? `@${chat.username}` : undefined) ??\n [chat.first_name, chat.last_name].filter(Boolean).join(\" \") ??\n String(chat.id);\n return `Telegram · ${name || chat.id}`;\n}\n\nfunction eventContext(\n message: TelegramMessage,\n eventId: string,\n botUserId: number | undefined\n): ChannelEventContextInput {\n const actor = telegramActor(message);\n const channelId = channelIdentity(message.chat.id);\n const threadId =\n typeof message.message_thread_id === \"number\"\n ? `${channelId}:topic:${message.message_thread_id}`\n : channelId;\n const isDirectMessage =\n message.chat.type === \"private\"\n ? true\n : message.chat.type === \"group\" ||\n message.chat.type === \"supergroup\" ||\n message.chat.type === \"channel\"\n ? false\n : (\"unknown\" as const);\n return {\n eventId,\n thread: { id: threadId, isDirectMessage },\n replySurface: {\n version: 1,\n address: {\n chatId: String(message.chat.id),\n ...(botUserId && { botUserId }),\n ...(typeof message.message_thread_id === \"number\" && {\n messageThreadId: message.message_thread_id\n }),\n replyToMessageId: message.message_id\n },\n label: chatLabel(message.chat)\n },\n ...(actor && { actor })\n };\n}\n\nfunction telegramTimestamp(value: unknown): string | undefined {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return undefined;\n const date = new Date(value * 1000);\n return Number.isFinite(date.getTime()) ? date.toISOString() : undefined;\n}\n\nfunction normalizedMessage(\n message: TelegramMessage,\n eventId: string,\n edited: boolean,\n botUserId: number | undefined\n): ChannelInboundMessageInput {\n const reply = asTelegramMessage(message.reply_to_message);\n const sentAt = telegramTimestamp(message.date);\n const editedAt = telegramTimestamp(message.edit_date);\n\n return {\n type: \"message\",\n ...eventContext(message, eventId, botUserId),\n message: {\n id: messageIdentity(message.chat.id, message.message_id),\n text: message.text as string,\n ...(typeof reply?.message_id === \"number\" && {\n reply: {\n id: messageIdentity(message.chat.id, reply.message_id),\n ...(typeof reply.text === \"string\" && { text: reply.text })\n }\n }),\n ...((sentAt || edited || editedAt) && {\n metadata: {\n ...(sentAt && { sentAt }),\n ...(edited && { edited: true }),\n ...(editedAt && { editedAt })\n }\n })\n }\n };\n}\n\nfunction approvalResponse(\n message: TelegramMessage,\n eventId: string,\n botUserId: number | undefined\n): ChannelApprovalResponseInput | undefined {\n if (botUserId === undefined) return undefined;\n if (message.text !== \"YES\" && message.text !== \"NO\") return undefined;\n\n const reply = asTelegramMessage(message.reply_to_message);\n if (typeof reply?.message_id !== \"number\") return undefined;\n\n // An interaction marker only authorizes a decision when this bot authored\n // the replied-to message; otherwise any chat member could forge one.\n const author = reply.from;\n if (author?.is_bot !== true || author.id !== botUserId) return undefined;\n\n const encodedInteractionId =\n typeof reply.text === \"string\"\n ? reply.text.match(INTERACTION_FOOTER)?.[1]\n : undefined;\n const interactionId = encodedInteractionId\n ? decodeInteractionId(encodedInteractionId)\n : undefined;\n if (!interactionId) return undefined;\n\n return {\n type: \"approval-response\",\n ...eventContext(message, eventId, botUserId),\n interactionId,\n decision: message.text === \"YES\" ? \"approve\" : \"reject\",\n reference: messageIdentity(message.chat.id, message.message_id)\n };\n}\n\nfunction inboundEvent(\n update: TelegramUpdate,\n botUserId: number | undefined\n): ChannelIngressEventInput | undefined {\n const edited = update.edited_message !== undefined;\n const message = asTelegramMessage(\n edited ? update.edited_message : update.message\n );\n if (\n typeof update.update_id !== \"number\" ||\n typeof message?.message_id !== \"number\" ||\n typeof message.text !== \"string\" ||\n typeof message.chat?.id !== \"number\"\n ) {\n return undefined;\n }\n\n const eventId = updateIdentity(message.chat.id, update.update_id);\n return (\n approvalResponse(message, eventId, botUserId) ??\n normalizedMessage(message, eventId, edited, botUserId)\n );\n}\n\n/** Recover this bot's numeric user id from its BotFather token prefix. */\nfunction telegramBotUserId(botToken: string): number | undefined {\n const prefix = botToken.match(/^(\\d+):/)?.[1];\n if (!prefix) return undefined;\n const botUserId = Number(prefix);\n return Number.isSafeInteger(botUserId) && botUserId > 0\n ? botUserId\n : undefined;\n}\n\n/** Create dependency-free Telegram webhook ingress for a destination chat. */\nexport function telegramWebhook(\n options: TelegramWebhookOptions\n): ChannelIngress<TelegramUpdate> {\n if (!options.secretToken.trim()) {\n throw new Error(\n \"secretToken is required to create Telegram webhook ingress\"\n );\n }\n if (\n options.botUserId !== undefined &&\n (!Number.isSafeInteger(options.botUserId) || options.botUserId <= 0)\n ) {\n throw new Error(\"botUserId must be a positive Telegram user id\");\n }\n\n const botUserId = options.botUserId;\n const path = options.path ?? DEFAULT_TELEGRAM_WEBHOOK_PATH;\n return {\n async receive(request) {\n if (!matchesPath(request, path)) return null;\n if (request.method !== \"POST\") return emptyIngressResponse(405);\n if (\n request.headers.get(\"x-telegram-bot-api-secret-token\") !==\n options.secretToken\n ) {\n return emptyIngressResponse(401);\n }\n\n let update: unknown;\n try {\n update = await request.json();\n } catch {\n return emptyIngressResponse(400);\n }\n if (update === null || typeof update !== \"object\") {\n return emptyIngressResponse(400);\n }\n\n const raw = update as TelegramUpdate;\n const event = inboundEvent(raw, botUserId);\n return {\n events: event ? [{ event, raw }] : [],\n response: new Response(null, { status: 200 })\n };\n }\n };\n}\n\nfunction telegramSurface(\n surface: ChannelMessageSurface\n): TelegramMessageSurface | undefined {\n if (\n !isChannelMessageSurface(surface) ||\n surface.version !== 1 ||\n !isRecord(surface.address) ||\n typeof surface.address.chatId !== \"string\" ||\n surface.address.chatId.length === 0 ||\n (surface.address.botUserId !== undefined &&\n (!Number.isSafeInteger(surface.address.botUserId) ||\n Number(surface.address.botUserId) <= 0))\n ) {\n return undefined;\n }\n if (\n (surface.address.messageThreadId !== undefined &&\n !Number.isSafeInteger(surface.address.messageThreadId)) ||\n (surface.address.replyToMessageId !== undefined &&\n !Number.isSafeInteger(surface.address.replyToMessageId))\n ) {\n return undefined;\n }\n return surface as TelegramMessageSurface;\n}\n\n/**\n * Whether a chat can show an animated draft.\n *\n * `sendMessageDraft` is private chats only, and Telegram gives private chats\n * positive ids. Anywhere else the answer is simply sent once at the end.\n */\nfunction supportsDraft(chatId: string): boolean {\n const numeric = Number(chatId);\n return Number.isSafeInteger(numeric) && numeric > 0;\n}\n\n/** A non-zero draft identifier; reusing one animates between snapshots. */\nfunction newDraftId(): number {\n const [random] = crypto.getRandomValues(new Uint32Array(1));\n return ((random ?? 1) % 2_147_483_647) + 1;\n}\n\nfunction splitText(text: string, limit: number): string[] {\n const pieces: string[] = [];\n let piece = \"\";\n let length = 0;\n for (const character of text) {\n if (length === limit) {\n pieces.push(piece);\n piece = \"\";\n length = 0;\n }\n piece += character;\n length += 1;\n }\n if (piece.length > 0) pieces.push(piece);\n return pieces;\n}\n\nfunction textLength(text: string): number {\n return [...text].length;\n}\n\n/** Create a configured Telegram Bot API Channel. */\nexport function telegram(\n options: TelegramChannelOptions\n): Channel<TelegramUpdate> {\n if (!options.botToken.trim()) {\n throw new Error(\"botToken is required to create a Telegram channel\");\n }\n const fetch = options.fetch ?? globalThis.fetch;\n const apiBaseUrl = (options.apiBaseUrl ?? \"https://api.telegram.org\").replace(\n /\\/$/,\n \"\"\n );\n const maxLength = options.maxLength ?? TELEGRAM_MESSAGE_LIMIT;\n if (\n !Number.isInteger(maxLength) ||\n maxLength < 1 ||\n maxLength > TELEGRAM_MESSAGE_LIMIT\n ) {\n throw new Error(\n `maxLength must be an integer between 1 and ${TELEGRAM_MESSAGE_LIMIT}`\n );\n }\n const toText = options.toText ?? defaultText;\n const streamIntervalMs =\n options.streamIntervalMs ?? DEFAULT_STREAM_INTERVAL_MS;\n if (!Number.isInteger(streamIntervalMs) || streamIntervalMs < 0) {\n throw new Error(\"streamIntervalMs must be a non-negative integer\");\n }\n const botUserId = telegramBotUserId(options.botToken);\n const ingress = options.webhook\n ? telegramWebhook({ ...options.webhook, botUserId })\n : undefined;\n\n async function send(\n destinationValue: ChannelMessageSurface,\n text: string,\n parseMode?: TelegramChannelOptions[\"parseMode\"]\n ): Promise<DeliveryResult> {\n const destination = telegramSurface(destinationValue);\n if (\n !destination ||\n (botUserId !== undefined &&\n destination.address.botUserId !== undefined &&\n destination.address.botUserId !== botUserId)\n ) {\n return {\n status: \"failed\",\n retryable: false,\n error: {\n code: \"TELEGRAM_SURFACE_INVALID\",\n message: `Telegram cannot parse the address for Channel \"${destinationValue.channelKey}\"`\n }\n };\n }\n if (textLength(text) > maxLength) {\n return {\n status: \"failed\",\n retryable: false,\n error: {\n code: \"TELEGRAM_MESSAGE_TOO_LONG\",\n message: `Telegram message exceeds the configured ${maxLength}-character limit`\n }\n };\n }\n\n let response: Response;\n try {\n response = await fetch(\n `${apiBaseUrl}/bot${options.botToken}/sendMessage`,\n {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n chat_id: destination.address.chatId,\n text,\n ...(destination.address.messageThreadId !== undefined && {\n message_thread_id: destination.address.messageThreadId\n }),\n ...(destination.address.replyToMessageId !== undefined && {\n reply_parameters: {\n message_id: destination.address.replyToMessageId\n }\n }),\n ...(parseMode && { parse_mode: parseMode })\n })\n }\n );\n } catch {\n return uncertain(\n \"TELEGRAM_DELIVERY_ERROR\",\n \"Telegram delivery failed with an unknown outcome\"\n );\n }\n\n let payload: unknown;\n try {\n payload = await response.json();\n } catch {\n return uncertain(\n \"TELEGRAM_DELIVERY_ERROR\",\n \"Telegram returned an invalid delivery response\"\n );\n }\n\n const apiResponse = asApiResponse(payload);\n return apiResponse\n ? classifyResponse(response, apiResponse)\n : uncertain(\n \"TELEGRAM_DELIVERY_ERROR\",\n \"Telegram returned an invalid delivery response\"\n );\n }\n\n /**\n * Show one ephemeral preview. Failures are swallowed on purpose: a draft is\n * a 30-second animation, and losing one must never cost the real message.\n *\n * The configured parse mode is deliberately not applied. A partial answer\n * routinely holds unbalanced markup, which Telegram rejects outright.\n */\n async function sendDraft(\n destination: TelegramMessageSurface,\n draftId: number,\n text: string\n ): Promise<boolean> {\n try {\n const response = await fetch(\n `${apiBaseUrl}/bot${options.botToken}/sendMessageDraft`,\n {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n chat_id: Number(destination.address.chatId),\n draft_id: draftId,\n text,\n ...(destination.address.messageThreadId !== undefined && {\n message_thread_id: destination.address.messageThreadId\n })\n })\n }\n );\n return asApiResponse(await response.json())?.ok === true;\n } catch {\n return false;\n }\n }\n\n /** Persist the answer, splitting it when it outgrows one Telegram message. */\n async function sendComplete(\n destination: ChannelMessageSurface,\n text: string\n ): Promise<DeliveryResult> {\n const [head, ...tail] = splitText(text, maxLength);\n // Raw HTML and Markdown cannot be partitioned safely without parsing it.\n // Preserve all content literally rather than send malformed fragments.\n const parseMode = tail.length === 0 ? options.parseMode : undefined;\n const first = await send(destination, head!, parseMode);\n if (first.status !== \"delivered\") return first;\n\n for (const piece of tail) {\n const result = await send(destination, piece, parseMode);\n // A later piece failing still leaves earlier ones in the chat.\n if (result.status !== \"delivered\") {\n return uncertain(\n \"TELEGRAM_STREAM_PARTIAL\",\n \"Telegram accepted only part of a split answer\",\n first.reference\n );\n }\n }\n return first;\n }\n\n async function streamMessage(\n destinationValue: ChannelMessageSurface,\n chunks: ReadableStream<ChannelChunk>,\n streamOptions: ChannelStreamOptions\n ): Promise<DeliveryResult> {\n const destination = telegramSurface(destinationValue);\n if (\n !destination ||\n (botUserId !== undefined &&\n destination.address.botUserId !== undefined &&\n destination.address.botUserId !== botUserId)\n ) {\n await chunks.cancel().catch(() => {});\n return {\n status: \"failed\",\n retryable: false,\n error: {\n code: \"TELEGRAM_SURFACE_INVALID\",\n message: `Telegram cannot parse the address for Channel \"${destinationValue.channelKey}\"`\n }\n };\n }\n\n const draftId = supportsDraft(destination.address.chatId)\n ? newDraftId()\n : undefined;\n const prefix = streamOptions.title ? `${streamOptions.title}\\n\\n` : \"\";\n const shouldPreview = createPacer(streamIntervalMs);\n let answer = \"\";\n let draftsStopped = draftId === undefined;\n\n return consumeChunks(chunks, {\n async onChunk(chunk) {\n if (chunk.type !== \"text\" || chunk.text.length === 0) return;\n answer += chunk.text;\n if (draftsStopped || !shouldPreview()) return;\n const preview = splitText(`${prefix}${answer}`, maxLength)[0] ?? \"\";\n const shown = await sendDraft(destination, draftId!, preview);\n if (!shown) draftsStopped = true;\n },\n async onFinish(outcome) {\n // The draft is not the message. Without this send the reader's screen\n // goes blank in thirty seconds and nothing is kept.\n if (answer.length === 0) {\n return {\n status: \"failed\",\n retryable: false,\n error: outcome.interrupted\n ? {\n code: \"TELEGRAM_STREAM_INTERRUPTED\",\n message: \"The answer ended before producing any text to send\"\n }\n : {\n code: \"TELEGRAM_STREAM_EMPTY\",\n message: \"The stream carried no text to send\"\n }\n };\n }\n\n const result = await sendComplete(destination, `${prefix}${answer}`);\n if (!outcome.interrupted || result.status !== \"delivered\") {\n return result;\n }\n return uncertain(\n \"TELEGRAM_STREAM_INTERRUPTED\",\n \"An incomplete answer was sent because the stream ended early\",\n result.reference\n );\n }\n });\n }\n\n return {\n ...(options.route && { route: options.route }),\n ...(ingress && { ingress }),\n contactSurface(identity: ChannelIdentity) {\n if ((identity.scope ?? \"default\") !== \"default\") return null;\n const match = identity.subject.match(/^(user|chat):(-?\\d+)$/);\n if (!match) return null;\n return {\n version: 1,\n address: {\n chatId: match[2],\n ...(botUserId && { botUserId })\n },\n label: `Telegram · ${match[1]} ${match[2]}`\n };\n },\n deliver(destination, message) {\n return send(destination, toText(message), options.parseMode);\n },\n stream(destination, chunks, streamOptions) {\n return streamMessage(destination, chunks, streamOptions);\n },\n requestApproval(destination, { interactionId, request }) {\n if (interactionId.length === 0) {\n return Promise.resolve({\n status: \"failed\",\n retryable: false,\n error: {\n code: \"TELEGRAM_INTERACTION_ID_REQUIRED\",\n message:\n \"Telegram approval requests require a non-empty interaction id\"\n }\n });\n }\n return send(destination, approvalText(interactionId, request));\n }\n };\n}\n"],"mappings":"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"}
|
package/dist/channels/voice.d.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
F as ChannelMessageSurface,
|
|
3
|
-
n as Channel,
|
|
4
|
-
u as ChannelMessage
|
|
5
|
-
} from "../channel-Bnm4S7T2.js";
|
|
6
|
-
import { c as VoiceAudioFormat, n as TTSProvider } from "../types-_Faxb570.js";
|
|
7
|
-
|
|
8
|
-
//#region src/channels/adapters/voice.d.ts
|
|
9
|
-
type BrowserVoiceSurface = ChannelMessageSurface<
|
|
10
|
-
string,
|
|
11
|
-
{
|
|
12
|
-
connection: "current";
|
|
13
|
-
}
|
|
14
|
-
>;
|
|
15
|
-
/** The subset of an Agent WebSocket connection needed for audio delivery. */
|
|
16
|
-
type BrowserVoiceConnection = {
|
|
17
|
-
id: string;
|
|
18
|
-
send(message: string | ArrayBuffer | ArrayBufferView): void;
|
|
19
|
-
};
|
|
20
|
-
/** Configuration for an output-only browser voice channel. */
|
|
21
|
-
type BrowserVoiceChannelOptions = {
|
|
22
|
-
/** Text-to-speech provider used to synthesize each outbound message. */ tts: TTSProvider /** Return the browser voice surface to use, or undefined when unavailable. */;
|
|
23
|
-
getConnection: () =>
|
|
24
|
-
| BrowserVoiceConnection
|
|
25
|
-
| undefined /** Encoded audio format returned by the TTS provider. @default "mp3" */;
|
|
26
|
-
audioFormat?: VoiceAudioFormat /** Sample rate for raw PCM audio. Ignored by encoded formats. @default 16000 */;
|
|
27
|
-
sampleRate?: number /** Project the canonical Markdown message into text suitable for speech. */;
|
|
28
|
-
toSpeechText?: (message: ChannelMessage) => string;
|
|
29
|
-
};
|
|
30
|
-
/**
|
|
31
|
-
* Create an output-only channel that synthesizes one message and sends its
|
|
32
|
-
* encoded audio to one browser using the Cloudflare Voice wire protocol.
|
|
33
|
-
*
|
|
34
|
-
* The browser should connect with `VoiceClient` or `useVoiceAgent()`. No
|
|
35
|
-
* `withVoice()` mixin, microphone, or speech-to-text provider is required.
|
|
36
|
-
*/
|
|
37
|
-
declare function browserVoice(options: BrowserVoiceChannelOptions): Channel;
|
|
38
|
-
//#endregion
|
|
39
|
-
export {
|
|
40
|
-
BrowserVoiceChannelOptions,
|
|
41
|
-
BrowserVoiceConnection,
|
|
42
|
-
BrowserVoiceSurface,
|
|
43
|
-
browserVoice
|
|
44
|
-
};
|
|
45
|
-
//# sourceMappingURL=voice.d.ts.map
|
package/dist/channels/voice.js
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import { t as isChannelMessageSurface } from "../surface-bZZJqBka.js";
|
|
2
|
-
import "../voice/types.js";
|
|
3
|
-
//#region src/channels/adapters/voice.ts
|
|
4
|
-
const DEFAULT_SAMPLE_RATE = 16e3;
|
|
5
|
-
function validSurface(surface) {
|
|
6
|
-
if (!isChannelMessageSurface(surface) || surface.version !== 1 || surface.address === null || typeof surface.address !== "object" || Array.isArray(surface.address)) return false;
|
|
7
|
-
return surface.address.connection === "current";
|
|
8
|
-
}
|
|
9
|
-
function unavailable() {
|
|
10
|
-
return {
|
|
11
|
-
status: "failed",
|
|
12
|
-
retryable: true,
|
|
13
|
-
error: {
|
|
14
|
-
code: "BROWSER_VOICE_UNAVAILABLE",
|
|
15
|
-
message: "No browser voice surface is connected"
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
function synthesisFailure(error) {
|
|
20
|
-
return {
|
|
21
|
-
status: "failed",
|
|
22
|
-
retryable: true,
|
|
23
|
-
error: {
|
|
24
|
-
code: "BROWSER_VOICE_TTS_FAILED",
|
|
25
|
-
message: error instanceof Error ? error.message : "The text-to-speech provider did not return audio"
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
function deliveryFailure(error, contentDeliveryStarted) {
|
|
30
|
-
if (!contentDeliveryStarted) {
|
|
31
|
-
const connectionClosed = error instanceof TypeError && error.message.includes("WebSocket send() after close");
|
|
32
|
-
return {
|
|
33
|
-
status: "failed",
|
|
34
|
-
retryable: true,
|
|
35
|
-
error: {
|
|
36
|
-
code: connectionClosed ? "BROWSER_VOICE_CONNECTION_CLOSED" : "BROWSER_VOICE_DELIVERY_FAILED",
|
|
37
|
-
message: connectionClosed ? "The browser voice surface disconnected before delivery" : error instanceof Error ? error.message : "Browser voice delivery failed before sending content"
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
return {
|
|
42
|
-
status: "uncertain",
|
|
43
|
-
error: {
|
|
44
|
-
code: "BROWSER_VOICE_DELIVERY_ERROR",
|
|
45
|
-
message: error instanceof Error ? error.message : "Browser voice delivery failed with an unknown outcome"
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
function sendJSON(connection, message) {
|
|
50
|
-
connection.send(JSON.stringify(message));
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Create an output-only channel that synthesizes one message and sends its
|
|
54
|
-
* encoded audio to one browser using the Cloudflare Voice wire protocol.
|
|
55
|
-
*
|
|
56
|
-
* The browser should connect with `VoiceClient` or `useVoiceAgent()`. No
|
|
57
|
-
* `withVoice()` mixin, microphone, or speech-to-text provider is required.
|
|
58
|
-
*/
|
|
59
|
-
function browserVoice(options) {
|
|
60
|
-
const audioFormat = options.audioFormat ?? "mp3";
|
|
61
|
-
const sampleRate = options.sampleRate ?? DEFAULT_SAMPLE_RATE;
|
|
62
|
-
const toSpeechText = options.toSpeechText ?? ((message) => message.markdown);
|
|
63
|
-
return {
|
|
64
|
-
isAvailable() {
|
|
65
|
-
return options.getConnection() !== void 0;
|
|
66
|
-
},
|
|
67
|
-
async deliver(surface, message) {
|
|
68
|
-
if (!validSurface(surface)) return {
|
|
69
|
-
status: "failed",
|
|
70
|
-
retryable: false,
|
|
71
|
-
error: {
|
|
72
|
-
code: "BROWSER_VOICE_SURFACE_INVALID",
|
|
73
|
-
message: `Browser voice cannot parse the address for Channel "${surface.channelKey}"`
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
const connection = options.getConnection();
|
|
77
|
-
if (!connection) return unavailable();
|
|
78
|
-
let audio;
|
|
79
|
-
const speechText = toSpeechText(message);
|
|
80
|
-
try {
|
|
81
|
-
audio = await options.tts.synthesize(speechText);
|
|
82
|
-
} catch (error) {
|
|
83
|
-
return synthesisFailure(error);
|
|
84
|
-
}
|
|
85
|
-
if (!audio) return synthesisFailure();
|
|
86
|
-
let contentDeliveryStarted = false;
|
|
87
|
-
try {
|
|
88
|
-
sendJSON(connection, {
|
|
89
|
-
type: "welcome",
|
|
90
|
-
protocol_version: 1
|
|
91
|
-
});
|
|
92
|
-
sendJSON(connection, {
|
|
93
|
-
type: "audio_config",
|
|
94
|
-
format: audioFormat,
|
|
95
|
-
sampleRate
|
|
96
|
-
});
|
|
97
|
-
sendJSON(connection, {
|
|
98
|
-
type: "status",
|
|
99
|
-
status: "speaking"
|
|
100
|
-
});
|
|
101
|
-
sendJSON(connection, {
|
|
102
|
-
type: "transcript",
|
|
103
|
-
role: "assistant",
|
|
104
|
-
text: speechText
|
|
105
|
-
});
|
|
106
|
-
contentDeliveryStarted = true;
|
|
107
|
-
connection.send(audio);
|
|
108
|
-
sendJSON(connection, {
|
|
109
|
-
type: "status",
|
|
110
|
-
status: "idle"
|
|
111
|
-
});
|
|
112
|
-
return { status: "delivered" };
|
|
113
|
-
} catch (error) {
|
|
114
|
-
return deliveryFailure(error, contentDeliveryStarted);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
//#endregion
|
|
120
|
-
export { browserVoice };
|
|
121
|
-
|
|
122
|
-
//# sourceMappingURL=voice.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"voice.js","names":[],"sources":["../../src/channels/adapters/voice.ts"],"sourcesContent":["import {\n VOICE_PROTOCOL_VERSION,\n type TTSProvider,\n type VoiceAudioFormat,\n type VoiceServerMessage\n} from \"../../voice/types\";\nimport type {\n Channel,\n ChannelMessage,\n DeliveryFailure,\n DeliveryResult\n} from \"../channel\";\nimport {\n isChannelMessageSurface,\n type ChannelMessageSurface\n} from \"../surface\";\n\nexport type BrowserVoiceSurface = ChannelMessageSurface<\n string,\n { connection: \"current\" }\n>;\n\n/** The subset of an Agent WebSocket connection needed for audio delivery. */\nexport type BrowserVoiceConnection = {\n id: string;\n send(message: string | ArrayBuffer | ArrayBufferView): void;\n};\n\n/** Configuration for an output-only browser voice channel. */\nexport type BrowserVoiceChannelOptions = {\n /** Text-to-speech provider used to synthesize each outbound message. */\n tts: TTSProvider;\n /** Return the browser voice surface to use, or undefined when unavailable. */\n getConnection: () => BrowserVoiceConnection | undefined;\n /** Encoded audio format returned by the TTS provider. @default \"mp3\" */\n audioFormat?: VoiceAudioFormat;\n /** Sample rate for raw PCM audio. Ignored by encoded formats. @default 16000 */\n sampleRate?: number;\n /** Project the canonical Markdown message into text suitable for speech. */\n toSpeechText?: (message: ChannelMessage) => string;\n};\n\nconst DEFAULT_SAMPLE_RATE = 16_000;\n\nfunction validSurface(surface: ChannelMessageSurface): boolean {\n if (\n !isChannelMessageSurface(surface) ||\n surface.version !== 1 ||\n surface.address === null ||\n typeof surface.address !== \"object\" ||\n Array.isArray(surface.address)\n ) {\n return false;\n }\n return (surface.address as Record<string, unknown>).connection === \"current\";\n}\n\nfunction unavailable(): DeliveryResult {\n return {\n status: \"failed\",\n retryable: true,\n error: {\n code: \"BROWSER_VOICE_UNAVAILABLE\",\n message: \"No browser voice surface is connected\"\n }\n };\n}\n\nfunction synthesisFailure(error?: unknown): DeliveryResult {\n const failure: DeliveryFailure = {\n code: \"BROWSER_VOICE_TTS_FAILED\",\n message:\n error instanceof Error\n ? error.message\n : \"The text-to-speech provider did not return audio\"\n };\n return { status: \"failed\", retryable: true, error: failure };\n}\n\nfunction deliveryFailure(\n error: unknown,\n contentDeliveryStarted: boolean\n): DeliveryResult {\n if (!contentDeliveryStarted) {\n const connectionClosed =\n error instanceof TypeError &&\n error.message.includes(\"WebSocket send() after close\");\n return {\n status: \"failed\",\n retryable: true,\n error: {\n code: connectionClosed\n ? \"BROWSER_VOICE_CONNECTION_CLOSED\"\n : \"BROWSER_VOICE_DELIVERY_FAILED\",\n message: connectionClosed\n ? \"The browser voice surface disconnected before delivery\"\n : error instanceof Error\n ? error.message\n : \"Browser voice delivery failed before sending content\"\n }\n };\n }\n\n return {\n status: \"uncertain\",\n error: {\n code: \"BROWSER_VOICE_DELIVERY_ERROR\",\n message:\n error instanceof Error\n ? error.message\n : \"Browser voice delivery failed with an unknown outcome\"\n }\n };\n}\n\nfunction sendJSON(\n connection: BrowserVoiceConnection,\n message: VoiceServerMessage\n): void {\n connection.send(JSON.stringify(message));\n}\n\n/**\n * Create an output-only channel that synthesizes one message and sends its\n * encoded audio to one browser using the Cloudflare Voice wire protocol.\n *\n * The browser should connect with `VoiceClient` or `useVoiceAgent()`. No\n * `withVoice()` mixin, microphone, or speech-to-text provider is required.\n */\nexport function browserVoice(options: BrowserVoiceChannelOptions): Channel {\n const audioFormat = options.audioFormat ?? \"mp3\";\n const sampleRate = options.sampleRate ?? DEFAULT_SAMPLE_RATE;\n const toSpeechText = options.toSpeechText ?? ((message) => message.markdown);\n\n return {\n isAvailable() {\n return options.getConnection() !== undefined;\n },\n\n async deliver(surface, message) {\n if (!validSurface(surface)) {\n return {\n status: \"failed\",\n retryable: false,\n error: {\n code: \"BROWSER_VOICE_SURFACE_INVALID\",\n message: `Browser voice cannot parse the address for Channel \"${surface.channelKey}\"`\n }\n };\n }\n const connection = options.getConnection();\n if (!connection) return unavailable();\n\n let audio: ArrayBuffer | null;\n const speechText = toSpeechText(message);\n try {\n audio = await options.tts.synthesize(speechText);\n } catch (error) {\n return synthesisFailure(error);\n }\n if (!audio) return synthesisFailure();\n\n let contentDeliveryStarted = false;\n try {\n sendJSON(connection, {\n type: \"welcome\",\n protocol_version: VOICE_PROTOCOL_VERSION\n });\n sendJSON(connection, {\n type: \"audio_config\",\n format: audioFormat,\n sampleRate\n });\n sendJSON(connection, { type: \"status\", status: \"speaking\" });\n sendJSON(connection, {\n type: \"transcript\",\n role: \"assistant\",\n text: speechText\n });\n contentDeliveryStarted = true;\n connection.send(audio);\n sendJSON(connection, { type: \"status\", status: \"idle\" });\n return { status: \"delivered\" };\n } catch (error) {\n return deliveryFailure(error, contentDeliveryStarted);\n }\n }\n };\n}\n"],"mappings":";;;AA0CA,MAAM,sBAAsB;AAE5B,SAAS,aAAa,SAAyC;CAC7D,IACE,CAAC,wBAAwB,OAAO,KAChC,QAAQ,YAAY,KACpB,QAAQ,YAAY,QACpB,OAAO,QAAQ,YAAY,YAC3B,MAAM,QAAQ,QAAQ,OAAO,GAE7B,OAAO;CAET,OAAQ,QAAQ,QAAoC,eAAe;AACrE;AAEA,SAAS,cAA8B;CACrC,OAAO;EACL,QAAQ;EACR,WAAW;EACX,OAAO;GACL,MAAM;GACN,SAAS;EACX;CACF;AACF;AAEA,SAAS,iBAAiB,OAAiC;CAQzD,OAAO;EAAE,QAAQ;EAAU,WAAW;EAAM,OAAO;GANjD,MAAM;GACN,SACE,iBAAiB,QACb,MAAM,UACN;EAEiD;CAAE;AAC7D;AAEA,SAAS,gBACP,OACA,wBACgB;CAChB,IAAI,CAAC,wBAAwB;EAC3B,MAAM,mBACJ,iBAAiB,aACjB,MAAM,QAAQ,SAAS,8BAA8B;EACvD,OAAO;GACL,QAAQ;GACR,WAAW;GACX,OAAO;IACL,MAAM,mBACF,oCACA;IACJ,SAAS,mBACL,2DACA,iBAAiB,QACf,MAAM,UACN;GACR;EACF;CACF;CAEA,OAAO;EACL,QAAQ;EACR,OAAO;GACL,MAAM;GACN,SACE,iBAAiB,QACb,MAAM,UACN;EACR;CACF;AACF;AAEA,SAAS,SACP,YACA,SACM;CACN,WAAW,KAAK,KAAK,UAAU,OAAO,CAAC;AACzC;;;;;;;;AASA,SAAgB,aAAa,SAA8C;CACzE,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,eAAe,QAAQ,kBAAkB,YAAY,QAAQ;CAEnE,OAAO;EACL,cAAc;GACZ,OAAO,QAAQ,cAAc,MAAM,KAAA;EACrC;EAEA,MAAM,QAAQ,SAAS,SAAS;GAC9B,IAAI,CAAC,aAAa,OAAO,GACvB,OAAO;IACL,QAAQ;IACR,WAAW;IACX,OAAO;KACL,MAAM;KACN,SAAS,uDAAuD,QAAQ,WAAW;IACrF;GACF;GAEF,MAAM,aAAa,QAAQ,cAAc;GACzC,IAAI,CAAC,YAAY,OAAO,YAAY;GAEpC,IAAI;GACJ,MAAM,aAAa,aAAa,OAAO;GACvC,IAAI;IACF,QAAQ,MAAM,QAAQ,IAAI,WAAW,UAAU;GACjD,SAAS,OAAO;IACd,OAAO,iBAAiB,KAAK;GAC/B;GACA,IAAI,CAAC,OAAO,OAAO,iBAAiB;GAEpC,IAAI,yBAAyB;GAC7B,IAAI;IACF,SAAS,YAAY;KACnB,MAAM;KACN,kBAAA;IACF,CAAC;IACD,SAAS,YAAY;KACnB,MAAM;KACN,QAAQ;KACR;IACF,CAAC;IACD,SAAS,YAAY;KAAE,MAAM;KAAU,QAAQ;IAAW,CAAC;IAC3D,SAAS,YAAY;KACnB,MAAM;KACN,MAAM;KACN,MAAM;IACR,CAAC;IACD,yBAAyB;IACzB,WAAW,KAAK,KAAK;IACrB,SAAS,YAAY;KAAE,MAAM;KAAU,QAAQ;IAAO,CAAC;IACvD,OAAO,EAAE,QAAQ,YAAY;GAC/B,SAAS,OAAO;IACd,OAAO,gBAAgB,OAAO,sBAAsB;GACtD;EACF;CACF;AACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"images-iiTDSyRu.js","names":["isRecord","isRecord","stripEchoSuffix"],"sources":["../src/models/core/errors.ts","../src/models/core/settings.ts","../src/models/core/transport.ts","../src/models/core/gateway-providers.ts","../src/models/core/chat-completions/quirks.ts","../src/models/core/chat-completions/request.ts","../src/models/core/chat-completions/response.ts","../src/models/core/chat-completions/stream.ts","../src/models/core/sse.ts","../src/models/core/images.ts"],"sourcesContent":["/**\n * Coarse classification of a failed Cloudflare AI call.\n *\n * @experimental This surface is experimental and may change.\n */\nexport type CloudflareAIErrorCode =\n | \"auth\"\n | \"rate-limit\"\n | \"not-found\"\n | \"bad-request\"\n | \"provider-error\"\n | \"gateway-error\"\n | \"unknown\";\n\n/**\n * One leg of a {@link CloudflareAIError} fallback chain.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface CloudflareAIAttempt {\n /** The model id that was tried. */\n model: string;\n /** The error that leg failed with. */\n error: unknown;\n}\n\n/**\n * Error thrown for every failed Cloudflare AI call, whether it came back as a\n * non-2xx `Response` or as a thrown Workers AI binding error. Framework\n * modules wrap it into their own error type at their boundary (the AI SDK\n * module into an `APICallError`, so `ai`'s retry loop honours\n * {@link CloudflareAIError.isRetryable}).\n *\n * @experimental This surface is experimental and may change.\n */\nexport class CloudflareAIError extends Error {\n /** HTTP status, when the failure carried one. */\n readonly status: number | undefined;\n /** Coarse classification used for routing and fallback decisions. */\n readonly code: CloudflareAIErrorCode;\n /** `cf-aig-log-id` of the failed request, when the response carried one. */\n readonly logId: string | undefined;\n /** The model id that produced this error. */\n readonly model: string;\n /** Which binding path the request went down, for error reporting. */\n readonly url: string;\n /** The request body that failed. */\n readonly requestBodyValues: unknown;\n /** Response headers, when there was a response. */\n readonly responseHeaders: Record<string, string> | undefined;\n /** Raw response body text, when there was a response. */\n readonly responseBody: string | undefined;\n /** Whether a retry is worth attempting. */\n readonly isRetryable: boolean;\n /** Parsed error envelope, or other structured detail. */\n readonly data: unknown;\n /** Every leg tried, when this error ends a fallback chain. */\n readonly attempts: CloudflareAIAttempt[] | undefined;\n override readonly cause: unknown;\n\n constructor(options: {\n message: string;\n model: string;\n url: string;\n requestBodyValues: unknown;\n status?: number;\n code: CloudflareAIErrorCode;\n logId?: string;\n responseHeaders?: Record<string, string>;\n responseBody?: string;\n isRetryable?: boolean;\n data?: unknown;\n cause?: unknown;\n attempts?: CloudflareAIAttempt[];\n }) {\n super(options.message);\n this.name = \"CloudflareAIError\";\n this.status = options.status;\n this.code = options.code;\n this.logId = options.logId;\n this.model = options.model;\n this.url = options.url;\n this.requestBodyValues = options.requestBodyValues;\n this.responseHeaders = options.responseHeaders;\n this.responseBody = options.responseBody;\n this.isRetryable = options.isRetryable ?? isRetryableStatus(options.status);\n this.data = options.data;\n this.cause = options.cause;\n this.attempts = options.attempts;\n }\n}\n\n/**\n * Whether a status is worth retrying. Missing status means a transport-level\n * failure (connection reset, DNS, abort-adjacent), which is retryable.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function isRetryableStatus(status: number | undefined): boolean {\n if (status === undefined) return true;\n return status === 408 || status === 409 || status === 429 || status >= 500;\n}\n\n/**\n * Classifies an HTTP status into a {@link CloudflareAIErrorCode}. The\n * `AiGatewayError` envelope name catches gateway-level statuses that are not\n * otherwise meaningful (notably 402 \"insufficient balance\").\n */\nexport function classifyStatus(\n status: number | undefined,\n envelopeName?: string\n): CloudflareAIErrorCode {\n if (status === 401 || status === 403) return \"auth\";\n if (status === 429) return \"rate-limit\";\n if (status === 404) return \"not-found\";\n if (status === 400 || status === 422) return \"bad-request\";\n if (status !== undefined && status >= 500) return \"provider-error\";\n if (envelopeName === \"AiGatewayError\") return \"gateway-error\";\n return \"unknown\";\n}\n\n/**\n * Workers AI binding error codes that map onto an HTTP status.\n *\n * @see https://developers.cloudflare.com/workers-ai/platform/errors/\n */\nconst BINDING_CODE_STATUS: Record<number, number> = {\n 3003: 400,\n 3006: 413,\n 3007: 408,\n 3008: 408,\n 3023: 403,\n 3036: 429,\n 3039: 400,\n 3040: 429,\n 3041: 403,\n 3042: 404,\n 5004: 400,\n 5005: 405,\n 5007: 400,\n 5016: 403,\n 5018: 403,\n 5019: 405\n};\n\n/** Abort-shaped errors must propagate untouched so callers can detect them. */\nexport function isAbortError(error: unknown): boolean {\n const name =\n error instanceof Error || error instanceof DOMException\n ? error.name\n : undefined;\n return (\n name === \"AbortError\" ||\n name === \"ResponseAborted\" ||\n name === \"TimeoutError\"\n );\n}\n\nfunction messageOf(error: unknown): string {\n if (typeof error === \"string\") return error;\n if (error instanceof Error) return error.message;\n if (error !== null && typeof error === \"object\" && \"message\" in error) {\n const message = (error as { message: unknown }).message;\n if (typeof message === \"string\") return message;\n }\n return String(error);\n}\n\n/**\n * Extracts a Workers AI internal error code from a thrown binding error. The\n * binding reports codes inside the message text (`\"3040: Capacity temporarily\n * exceeded\"`) rather than as a status, so only known codes are accepted — an\n * unrelated leading number must not be misread as a code.\n */\nfunction bindingErrorCode(error: unknown): number | undefined {\n if (error !== null && typeof error === \"object\" && \"code\" in error) {\n const code = (error as { code: unknown }).code;\n if (typeof code === \"number\" && code in BINDING_CODE_STATUS) return code;\n }\n const matches = messageOf(error).matchAll(/\\b(\\d{3,5})\\s*:/g);\n for (const match of matches) {\n const code = Number(match[1]);\n if (code in BINDING_CODE_STATUS) return code;\n }\n return undefined;\n}\n\n/**\n * Normalizes a thrown Workers AI binding error into a {@link CloudflareAIError}.\n * Abort errors and errors that are already {@link CloudflareAIError}s pass through.\n */\nexport function normalizeThrownError(\n error: unknown,\n context: {\n model: string;\n url: string;\n requestBodyValues: unknown;\n }\n): unknown {\n if (isAbortError(error)) return error;\n if (error instanceof CloudflareAIError) return error;\n\n const code = bindingErrorCode(error);\n const status = code === undefined ? undefined : BINDING_CODE_STATUS[code];\n return new CloudflareAIError({\n cause: error,\n code: classifyStatus(status),\n data: code === undefined ? undefined : { code },\n // A recognised code decides for itself. Everything else is not worth\n // retrying: the binding is the only backend, so a throw with no status is\n // a programming error rather than a transport failure, and re-running it\n // on every fallback leg helps nobody.\n isRetryable: status === undefined ? false : isRetryableStatus(status),\n message: messageOf(error),\n model: context.model,\n requestBodyValues: context.requestBodyValues,\n status,\n url: context.url\n });\n}\n","import type { WorkersAIModelId } from \"./catalog\";\n\n/** The gateway id Cloudflare auto-creates on first use. */\nexport const DEFAULT_GATEWAY_ID = \"default\";\n\n/** Key that per-call options live under in a framework's per-call options bag. */\nexport const PROVIDER_OPTIONS_KEY = \"cloudflare\";\n\n/**\n * AI Gateway settings for a request. The gateway is an option, not a separate\n * product: every call goes through one, and `id` defaults to `\"default\"`,\n * which Cloudflare creates on first use.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface GatewayOptions {\n /** Gateway id. Defaults to `\"default\"` (auto-created on first use). */\n id?: string;\n /** Bypass the cache for this request. */\n skipCache?: boolean;\n /** Cache lifetime in seconds. */\n cacheTtl?: number;\n /** Explicit cache key, instead of the request-derived one. */\n cacheKey?: string;\n /** Whether the gateway stores the request/response in its log. */\n collectLog?: boolean;\n /** Arbitrary key/values attached to the gateway log entry. */\n metadata?: Record<string, string | number | boolean | null>;\n /** Correlates several requests into one gateway event. */\n eventId?: string;\n /** Upstream request timeout in milliseconds. */\n requestTimeoutMs?: number;\n /** Server-side retry policy for the upstream provider call. */\n retries?: {\n maxAttempts?: 1 | 2 | 3 | 4 | 5;\n retryDelayMs?: number;\n backoff?: \"constant\" | \"linear\" | \"exponential\";\n };\n}\n\n/**\n * How `createAI` reaches Cloudflare: the Workers AI binding, and nothing else.\n * Workers AI models go through `env.AI.run`, vendor models through\n * `env.AI.gateway(id).run` — both are the binding, so there is no HTTP\n * transport, no account id and no API token to hold.\n *\n * @experimental This surface is experimental and may change.\n */\nexport type AISettings = {\n /** The `AI` binding from a Worker's env. */\n binding: Ai;\n} & ProviderGatewaySettings;\n\n/**\n * Provider-wide gateway defaults, in either spelling: nested under `gateway`,\n * or flat (`{ id: \"prod\", cacheTtl: 60 }`). Both merge, the flat key winning.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface ProviderGatewaySettings extends GatewayOptions {\n /** Gateway id or full gateway options. */\n gateway?: string | GatewayOptions;\n}\n\n/**\n * Per-model and per-call options. The flat gateway keys are sugar for\n * `gateway: { ... }`; both forms merge, with the flat key winning.\n *\n * The same shape is accepted per call under\n * `providerOptions.cloudflare`, where it takes precedence over the per-model\n * options, which in turn take precedence over the `createAI` settings.\n *\n * `Leg` is what a framework module accepts as a fallback leg. Workers AI ids\n * are the only kind this module can resolve on its own, so they are the\n * default; a module whose legs may also be model objects says so\n * (`ModelOptions<WorkersAIModelId | LanguageModelV4>`) rather than rebuilding\n * the type.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface ModelOptions<\n Leg = WorkersAIModelId\n> extends ProviderGatewaySettings {\n /**\n * Models to try, in order, if the primary fails before any output is\n * produced. A leg travels with the chain's gateway options — those win over\n * a leg's own, and `metadata` merges — while everything a leg was built with\n * itself stays its own. Client-side today; becomes server-side when the\n * platform ships model-first routing.\n */\n fallback?: Leg[];\n /** Extra request headers, merged last. */\n headers?: Record<string, string>;\n /**\n * Workers AI only: route same-key requests to the same replica for\n * prefix-cache hits. Sent as the `x-session-affinity` header.\n */\n sessionAffinity?: string;\n /**\n * Explicit reasoning effort. `null` disables reasoning on models that\n * support toggling it. The unified AI SDK `reasoning` call option maps onto\n * this when this is not set.\n */\n reasoningEffort?: \"low\" | \"medium\" | \"high\" | null;\n /**\n * Workers AI only: forwarded verbatim as `chat_template_kwargs`, e.g.\n * `{ enable_thinking: false }`.\n */\n chatTemplateKwargs?: Record<string, unknown>;\n}\n\n/** A gateway config with the id filled in. */\nexport interface ResolvedGateway extends GatewayOptions {\n id: string;\n}\n\n/** Everything one request needs, after merging all three option layers. */\nexport interface ResolvedOptions {\n gateway: ResolvedGateway;\n headers: Record<string, string>;\n sessionAffinity: string | undefined;\n reasoningEffort: \"low\" | \"medium\" | \"high\" | null | undefined;\n chatTemplateKwargs: Record<string, unknown> | undefined;\n /**\n * The fallback legs given as ids. A module whose legs may also be model\n * objects keeps its own ordered list; this one is what the id-only callers\n * (embeddings, the other modalities) need.\n */\n fallback: string[];\n}\n\n/** The id legs of a fallback list; model objects are their module's business. */\nfunction idLegs(fallback: unknown[] | undefined): string[] {\n return (fallback ?? []).filter(\n (leg): leg is string => typeof leg === \"string\"\n );\n}\n\n/** Strips `undefined` values so a later layer never blanks an earlier one. */\nfunction defined<T extends object>(value: T): T {\n const result: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value)) {\n if (entry !== undefined) result[key] = entry;\n }\n return result as T;\n}\n\nfunction normalizeGateway(\n gateway: string | GatewayOptions | undefined\n): GatewayOptions {\n if (gateway === undefined) return {};\n // An explicit `undefined` inside a gateway object means \"not set\", exactly\n // as the flat sugar does; it must not blank out a lower layer's value.\n return typeof gateway === \"string\" ? { id: gateway } : defined(gateway);\n}\n\n/**\n * Folds one layer's flat gateway sugar into its `gateway` object. The flat key\n * wins over the nested one, and an explicit `undefined` on either never blanks\n * a lower layer.\n */\nfunction layerGateway(\n options: ProviderGatewaySettings | undefined\n): GatewayOptions {\n if (options === undefined) return {};\n return {\n ...normalizeGateway(options.gateway),\n ...defined({\n cacheKey: options.cacheKey,\n cacheTtl: options.cacheTtl,\n collectLog: options.collectLog,\n eventId: options.eventId,\n id: options.id,\n metadata: options.metadata,\n requestTimeoutMs: options.requestTimeoutMs,\n retries: options.retries,\n skipCache: options.skipCache\n })\n };\n}\n\n/** The flat gateway sugar {@link layerGateway} folds into `gateway`. */\nconst FLAT_GATEWAY_KEYS = [\n \"cacheKey\",\n \"cacheTtl\",\n \"collectLog\",\n \"eventId\",\n \"gateway\",\n \"id\",\n \"metadata\",\n \"requestTimeoutMs\",\n \"retries\",\n \"skipCache\"\n] as const;\n\n/**\n * One layer's gateway options as a single object, both spellings folded in.\n * Exported so a module that collapses two option layers into one bag (a\n * fallback leg inheriting a chain's gateway) can merge them field by field\n * rather than replacing one object with the other.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function gatewayLayerOf(\n options: ProviderGatewaySettings | undefined\n): GatewayOptions {\n return layerGateway(options);\n}\n\n/** An option bag without the gateway keys, whichever spelling they used. */\nfunction withoutGatewayKeys<Leg>(\n options: ModelOptions<Leg>\n): ModelOptions<Leg> {\n const rest: Record<string, unknown> = { ...options };\n for (const key of FLAT_GATEWAY_KEYS) delete rest[key];\n return defined(rest as ModelOptions<Leg>);\n}\n\n/**\n * Collapses two option layers into one bag, `override` winning field by field.\n *\n * The gateway keys of both are folded into a single `gateway` object, so\n * neither layer's flat sugar can out-rank the other's nested spelling when the\n * bag is resolved later, and `metadata` merges rather than replaces — the same\n * rules {@link resolveOptions} applies across its three layers.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function mergeModelOptions<Leg>(\n base: ModelOptions<Leg> | undefined,\n override: ModelOptions<Leg> | undefined\n): ModelOptions<Leg> | undefined {\n if (base === undefined) return override;\n if (override === undefined) return base;\n const layers = [layerGateway(base), layerGateway(override)];\n const gateway: GatewayOptions = Object.assign({}, ...layers);\n const metadata = Object.assign({}, ...layers.map((layer) => layer.metadata));\n const retries = mergeRetries(layers);\n // Headers merge field by field, as they do across `resolveOptions`' three\n // layers: replacing the object wholesale would drop a header the lower layer\n // was configured with. The spread comes after the override's own keys so it\n // wins over the `headers` that spread carried.\n const headers = { ...base.headers, ...override.headers };\n return {\n ...withoutGatewayKeys(base),\n ...withoutGatewayKeys(override),\n ...(Object.keys(headers).length > 0 ? { headers } : {}),\n gateway: {\n ...gateway,\n ...(Object.keys(metadata).length > 0 ? { metadata } : {}),\n ...(retries === undefined ? {} : { retries })\n }\n };\n}\n\n/**\n * Merges the retry policies field by field, so a provider-wide `backoff` still\n * applies when a call only sets `maxAttempts`. `undefined` on any layer means\n * \"not set\" and never blanks a lower one.\n */\nfunction mergeRetries(\n layers: GatewayOptions[]\n): GatewayOptions[\"retries\"] | undefined {\n const merged = layers.reduce<NonNullable<GatewayOptions[\"retries\"]>>(\n (result, layer) => ({\n ...result,\n ...(layer.retries === undefined ? {} : defined(layer.retries))\n }),\n {}\n );\n return Object.keys(merged).length > 0 ? merged : undefined;\n}\n\n/**\n * Merges the option layers. Precedence is per-call\n * (`providerOptions.cloudflare`) > per-model (`ai(id, options)`) >\n * provider (`createAI({ ... })`).\n *\n * The provider layer takes the whole settings object as well as a bare\n * `gateway` value, so `createAI({ binding, id: \"prod\", cacheTtl: 60 })` reads\n * the same as `createAI({ binding, gateway: { id: \"prod\", cacheTtl: 60 } })`.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function resolveOptions(\n provider: string | ProviderGatewaySettings | undefined,\n model: ModelOptions<unknown> | undefined,\n call: ModelOptions<unknown> | undefined\n): ResolvedOptions {\n const layers =\n typeof provider === \"string\"\n ? [normalizeGateway(provider), layerGateway(model), layerGateway(call)]\n : [layerGateway(provider), layerGateway(model), layerGateway(call)];\n const gateway: GatewayOptions = Object.assign({}, ...layers);\n const metadata = Object.assign({}, ...layers.map((layer) => layer.metadata));\n const retries = mergeRetries(layers);\n return {\n chatTemplateKwargs: call?.chatTemplateKwargs ?? model?.chatTemplateKwargs,\n fallback: idLegs(call?.fallback ?? model?.fallback),\n gateway: {\n ...gateway,\n id: gateway.id ?? DEFAULT_GATEWAY_ID,\n ...(Object.keys(metadata).length > 0 ? { metadata } : {}),\n ...(retries === undefined ? {} : { retries })\n },\n headers: { ...model?.headers, ...call?.headers },\n // `null` is a meaningful value here (it disables reasoning), so the call\n // layer wins on any value it actually set, not just on a truthy one.\n reasoningEffort:\n call?.reasoningEffort !== undefined\n ? call.reasoningEffort\n : model?.reasoningEffort,\n sessionAffinity: call?.sessionAffinity ?? model?.sessionAffinity\n };\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value !== null && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction asStringRecord(value: unknown): Record<string, string> | undefined {\n const record = asRecord(value);\n if (record === undefined) return undefined;\n const result: Record<string, string> = {};\n for (const [key, entry] of Object.entries(record)) {\n if (typeof entry === \"string\") result[key] = entry;\n }\n return result;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === \"number\" ? value : undefined;\n}\n\nfunction asBoolean(value: unknown): boolean | undefined {\n return typeof value === \"boolean\" ? value : undefined;\n}\n\nfunction asReasoningEffort(\n value: unknown\n): \"low\" | \"medium\" | \"high\" | null | undefined {\n if (value === null) return null;\n if (value === \"low\" || value === \"medium\" || value === \"high\") return value;\n return undefined;\n}\n\n/**\n * Metadata values the gateway accepts are scalars only; a nested object or\n * array would be rejected by the binding, so drop those rather than forward\n * them.\n */\nfunction asMetadata(value: unknown): GatewayOptions[\"metadata\"] {\n const record = asRecord(value);\n if (record === undefined) return undefined;\n const result: NonNullable<GatewayOptions[\"metadata\"]> = {};\n for (const [key, entry] of Object.entries(record)) {\n if (\n entry === null ||\n typeof entry === \"string\" ||\n typeof entry === \"number\" ||\n typeof entry === \"boolean\"\n ) {\n result[key] = entry;\n }\n }\n return result;\n}\n\nconst BACKOFFS = [\"constant\", \"linear\", \"exponential\"] as const;\n\n/** Reads the retry policy field by field; the binding validates it strictly. */\nfunction asRetries(value: unknown): GatewayOptions[\"retries\"] {\n const record = asRecord(value);\n if (record === undefined) return undefined;\n const maxAttempts = asNumber(record.maxAttempts);\n const backoff = asString(record.backoff);\n const retries = defined({\n backoff: BACKOFFS.find((entry) => entry === backoff),\n maxAttempts:\n maxAttempts !== undefined &&\n Number.isInteger(maxAttempts) &&\n maxAttempts >= 1 &&\n maxAttempts <= 5\n ? (maxAttempts as 1 | 2 | 3 | 4 | 5)\n : undefined,\n retryDelayMs: asNumber(record.retryDelayMs)\n });\n // An empty policy is not a policy: returning `{}` would out-rank a lower\n // layer's real one when the layers merge.\n return Object.keys(retries).length > 0 ? retries : undefined;\n}\n\n/** Reads the shared gateway keys out of a loosely-typed record. */\nfunction parseGatewayFields(raw: Record<string, unknown>): GatewayOptions {\n return defined({\n cacheKey: asString(raw.cacheKey),\n cacheTtl: asNumber(raw.cacheTtl),\n collectLog: asBoolean(raw.collectLog),\n eventId: asString(raw.eventId),\n id: asString(raw.id),\n metadata: asMetadata(raw.metadata),\n requestTimeoutMs: asNumber(raw.requestTimeoutMs),\n retries: asRetries(raw.retries),\n skipCache: asBoolean(raw.skipCache)\n });\n}\n\n/**\n * Reads per-call options out of a loosely-typed options bag (the value a\n * framework keeps under {@link PROVIDER_OPTIONS_KEY}).\n *\n * The bag is plain JSON, so every field is read defensively: anything of an\n * unexpected type is dropped rather than thrown, because a malformed\n * observability hint should never fail a generation.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function parseModelOptions(value: unknown): ModelOptions | undefined {\n const raw = asRecord(value);\n if (raw === undefined) return undefined;\n\n const nested = asRecord(raw.gateway);\n const gateway: string | GatewayOptions | undefined =\n typeof raw.gateway === \"string\"\n ? raw.gateway\n : nested !== undefined\n ? parseGatewayFields(nested)\n : undefined;\n\n const fallback = Array.isArray(raw.fallback)\n ? raw.fallback.filter(\n (entry): entry is WorkersAIModelId => typeof entry === \"string\"\n )\n : undefined;\n\n return defined({\n ...parseGatewayFields(raw),\n chatTemplateKwargs: asRecord(raw.chatTemplateKwargs),\n fallback,\n gateway,\n headers: asStringRecord(raw.headers),\n reasoningEffort: asReasoningEffort(raw.reasoningEffort),\n sessionAffinity: asString(raw.sessionAffinity)\n });\n}\n","import {\n CloudflareAIError,\n classifyStatus,\n normalizeThrownError\n} from \"./errors\";\nimport type { GatewayProviderName } from \"./gateway-providers\";\nimport type { AISettings, ResolvedGateway } from \"./settings\";\n\n/** The reported `url` for a universal call made through the binding. */\nconst UNIVERSAL_BINDING_URL = \"ai-gateway-binding\";\n\n/** One request on the Cloudflare run path. */\nexport interface TransportRequest {\n /** Model id — Workers AI slug or catalog `<author>/<model>`. */\n model: string;\n /** The provider-shaped request body (`input` on the run path). */\n input: Record<string, unknown>;\n /** Gateway options for this request. */\n gateway: ResolvedGateway;\n /** Extra request headers, merged last. */\n headers: Record<string, string>;\n /** Abort signal, forwarded to the binding or to `fetch`. */\n signal?: AbortSignal;\n}\n\n/**\n * One request on the universal AI Gateway path: a vendor's own request, routed\n * by the gateway to that vendor. The body is the vendor's, untouched — nothing\n * here knows the vendor's wire format.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface UniversalRequest {\n /** The gateway provider slug the request is routed to. */\n provider: GatewayProviderName | string;\n /** The vendor path the gateway appends to that provider's base URL. */\n endpoint: string;\n /** The vendor's own request headers, minus its credential header. */\n headers: Record<string, string>;\n /** The vendor's request body, verbatim. */\n query: unknown;\n /** Gateway options for this request. */\n gateway: ResolvedGateway;\n /** Extra headers merged last, outside the vendor's own set. */\n extraHeaders?: Record<string, string>;\n /** Abort signal, forwarded to the binding or to `fetch`. */\n signal?: AbortSignal;\n}\n\n/**\n * The single code path both backends implement. Always resolves to a raw\n * `Response`, so streaming and non-streaming calls share one path and nothing\n * is buffered on the caller's behalf.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface Transport {\n /** A stable identifier for the endpoint, used in error reporting. */\n readonly url: string;\n run(request: TransportRequest): Promise<Response>;\n /**\n * Sends a vendor's own request through the gateway's universal endpoint.\n * Always resolves to the vendor's raw `Response`, error responses included:\n * only the gateway's own failures (a missing gateway, an unpaid account) are\n * lifted into a {@link CloudflareAIError}, because the vendor's provider\n * knows how to read its own errors and we do not.\n */\n universal(request: UniversalRequest): Promise<Response>;\n /**\n * A log id read off the backend itself when the response carried none. The\n * Workers AI binding exposes the last gateway log id as a mutable property,\n * so it is captured per response rather than read late.\n */\n logIdFallback(response: Response): string | undefined;\n}\n\n/**\n * Drops entries whose value is `undefined`. The AI SDK types call headers as\n * `Record<string, string | undefined>`, and an undefined value reaches the\n * binding as the string \"undefined\" rather than as an absent header.\n */\nexport function definedHeaders(\n headers: Record<string, string | undefined> | undefined\n): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers ?? {})) {\n if (value !== undefined) result[key] = value;\n }\n return result;\n}\n\n/** Copies response headers into a plain object. */\nexport function headersToObject(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n}\n\n/**\n * Some run-path responses arrive bare and some wrapped in the Cloudflare API\n * envelope. Unwrap only when the envelope keys are actually present, so a\n * provider payload that happens to have a `result` field is left alone.\n */\nexport function unwrapEnvelope(\n value: unknown,\n context?: { model: string; url: string; status: number }\n): unknown {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n const record = value as Record<string, unknown>;\n // A failure envelope may carry no `result` at all, only its errors.\n const failed =\n record.success === false && firstEnvelopeError(record) !== undefined;\n if (failed || (\"success\" in record && \"result\" in record)) {\n if (record.success === true) return record.result;\n // A failure envelope can arrive with a 2xx status. Parsing it as a\n // provider payload would produce an empty result and no diagnostic.\n throw new CloudflareAIError({\n code: classifyStatus(\n context?.status,\n typeof record.name === \"string\" ? record.name : undefined\n ),\n data: value,\n message: errorMessageFrom(value, context?.status),\n model: context?.model ?? \"\",\n requestBodyValues: undefined,\n status: context?.status,\n url: context?.url ?? \"\"\n });\n }\n return value;\n}\n\nfunction firstEnvelopeError(\n record: Record<string, unknown>\n): { code?: unknown; message?: unknown } | undefined {\n // Live gateway responses use `error` (an array of one); the documented\n // Cloudflare envelope uses `errors`. Accept either.\n for (const key of [\"error\", \"errors\"]) {\n const value = record[key];\n if (Array.isArray(value) && value.length > 0) {\n const first = value[0];\n if (first !== null && typeof first === \"object\") {\n return first as { code?: unknown; message?: unknown };\n }\n }\n if (value !== null && typeof value === \"object\" && !Array.isArray(value)) {\n return value as { code?: unknown; message?: unknown };\n }\n }\n return undefined;\n}\n\n/**\n * Pulls a human message out of any of the error envelopes the platform emits:\n * the gateway envelope (`error: [{ code, message }]`), the Workers AI\n * validation envelope (`message`/`description` only), a bare\n * `{ error: \"...\" }`, and the \"Model ID missing\" internal error, which carries\n * only `description`.\n */\nexport function errorMessageFrom(\n body: unknown,\n status: number | undefined\n): string {\n const record =\n body !== null && typeof body === \"object\" && !Array.isArray(body)\n ? (body as Record<string, unknown>)\n : undefined;\n if (record !== undefined) {\n const envelope = firstEnvelopeError(record);\n if (typeof envelope?.message === \"string\") return envelope.message;\n if (typeof record.error === \"string\") return record.error;\n if (typeof record.message === \"string\") return record.message;\n if (typeof record.description === \"string\") return record.description;\n }\n if (typeof body === \"string\" && body !== \"\") return body;\n return `HTTP ${status ?? \"error\"}`;\n}\n\n/** Builds a {@link CloudflareAIError} from a non-2xx run-path response. */\nexport async function errorFromResponse(\n response: Response,\n context: { model: string; url: string; requestBodyValues: unknown }\n): Promise<CloudflareAIError> {\n const text = await response.text().catch(() => \"\");\n let body: unknown = text;\n try {\n body = text === \"\" ? undefined : JSON.parse(text);\n } catch {\n // Not JSON — the raw text is the best message we have.\n }\n const record =\n body !== null && typeof body === \"object\" && !Array.isArray(body)\n ? (body as Record<string, unknown>)\n : undefined;\n const envelopeName =\n typeof record?.name === \"string\" ? record.name : undefined;\n const headers = headersToObject(response.headers);\n return new CloudflareAIError({\n code: classifyStatus(response.status, envelopeName),\n data: body,\n logId: headers[\"cf-aig-log-id\"],\n message: errorMessageFrom(body, response.status),\n model: context.model,\n requestBodyValues: context.requestBodyValues,\n responseBody: text,\n responseHeaders: headers,\n status: response.status,\n url: context.url\n });\n}\n\n/**\n * The gateway's own options for the universal call. The id is not among them:\n * it selects the gateway (`env.AI.gateway(id)`), and the binding's own `id`\n * field is deprecated.\n */\nfunction universalGatewayOptions(\n gateway: ResolvedGateway\n): UniversalGatewayOptions {\n // `id` is deprecated on this type but still required by it; the gateway is\n // already selected by `env.AI.gateway(id)`, so it repeats that id.\n const options: UniversalGatewayOptions = { id: gateway.id };\n if (gateway.skipCache !== undefined) options.skipCache = gateway.skipCache;\n if (gateway.cacheTtl !== undefined) options.cacheTtl = gateway.cacheTtl;\n if (gateway.cacheKey !== undefined) options.cacheKey = gateway.cacheKey;\n if (gateway.metadata !== undefined) options.metadata = gateway.metadata;\n if (gateway.collectLog !== undefined) options.collectLog = gateway.collectLog;\n if (gateway.eventId !== undefined) options.eventId = gateway.eventId;\n if (gateway.requestTimeoutMs !== undefined) {\n options.requestTimeoutMs = gateway.requestTimeoutMs;\n }\n if (gateway.retries !== undefined) options.retries = gateway.retries;\n return options;\n}\n\n/**\n * Whether a parsed body is the gateway's own error envelope rather than a\n * vendor payload — `{ success: false, error: [{ code, message }] }`, named\n * `AiGatewayError`. The gateway answers this for its own failures (no such\n * gateway, unified billing unpaid, provider not configured); everything else\n * on this path is the vendor's own error, which the vendor's provider reads.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function isGatewayErrorEnvelope(json: unknown): boolean {\n if (json === null || typeof json !== \"object\" || Array.isArray(json)) {\n return false;\n }\n const record = json as Record<string, unknown>;\n if (record.name === \"AiGatewayError\") return true;\n if (record.success !== false) return false;\n const errors = record.error ?? record.errors;\n return (\n Array.isArray(errors) &&\n errors.some(\n (entry) =>\n entry !== null &&\n typeof entry === \"object\" &&\n typeof (entry as { message?: unknown }).message === \"string\"\n )\n );\n}\n\n/**\n * Builds a {@link CloudflareAIError} from the gateway's own error envelope, so\n * a gateway failure on the universal path classifies and retries exactly as\n * one on the Workers AI run path.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function errorFromGatewayEnvelope(\n body: unknown,\n context: {\n model: string;\n url: string;\n requestBodyValues: unknown;\n status?: number;\n responseHeaders?: Record<string, string>;\n responseBody?: string;\n }\n): CloudflareAIError {\n const record =\n body !== null && typeof body === \"object\" && !Array.isArray(body)\n ? (body as Record<string, unknown>)\n : undefined;\n return new CloudflareAIError({\n code: classifyStatus(\n context.status,\n typeof record?.name === \"string\" ? record.name : \"AiGatewayError\"\n ),\n data: body,\n logId: context.responseHeaders?.[\"cf-aig-log-id\"],\n message: errorMessageFrom(body, context.status),\n model: context.model,\n requestBodyValues: context.requestBodyValues,\n responseBody: context.responseBody,\n responseHeaders: context.responseHeaders,\n status: context.status,\n url: context.url\n });\n}\n\n/**\n * The model id a universal request is about, for error reporting. Every vendor\n * body carries `model`; the endpoint is the fallback.\n */\nfunction universalModel(request: UniversalRequest): string {\n const query = request.query;\n if (query !== null && typeof query === \"object\" && !Array.isArray(query)) {\n const model = (query as Record<string, unknown>).model;\n if (typeof model === \"string\") return model;\n }\n return `${request.provider}/${request.endpoint}`;\n}\n\n/**\n * The `Ai` binding narrowed to the raw-response overload. The ambient\n * overloads pick their return type from the model id, and every catalog slug\n * lands on the `Record<string, unknown>` fallback, so the run-path signature\n * is stated explicitly here.\n */\ninterface RawResponseBinding {\n run(\n model: string,\n inputs: Record<string, unknown>,\n options: AiOptions & { returnRawResponse: true }\n ): Promise<Response>;\n}\n\n/** The keyless in-Worker backend: `env.AI.run(...)`. */\nfunction bindingTransport(binding: Ai): Transport {\n const raw = binding as unknown as RawResponseBinding;\n // `aiGatewayLogId` is a mutable property on the binding that every\n // concurrent `run` overwrites, so it is snapshotted against the response it\n // belongs to the moment that response arrives. A run that resolves while\n // another is mid-flight can still read the other's id; the window is one\n // microtask rather than the whole request.\n const logIds = new WeakMap<Response, string>();\n return {\n logIdFallback(response) {\n return logIds.get(response);\n },\n async run(request) {\n try {\n // Called as a method, never detached: the binding reads private\n // fields and throws on a detached reference.\n const response = await raw.run(request.model, request.input, {\n ...(Object.keys(request.headers).length > 0\n ? { extraHeaders: request.headers }\n : {}),\n gateway: request.gateway,\n returnRawResponse: true,\n signal: request.signal\n });\n const logId = binding.aiGatewayLogId;\n if (logId !== null && logId !== undefined) {\n logIds.set(response, logId);\n }\n return response;\n } catch (error) {\n // `returnRawResponse` resolves with a `Response` for upstream errors,\n // so a throw here means the binding itself failed (e.g. code 3040,\n // out of capacity).\n throw normalizeThrownError(error, {\n model: request.model,\n requestBodyValues: request.input,\n url: \"workers-ai-binding\"\n });\n }\n },\n async universal(request) {\n try {\n // Called as a method on the binding, and on the `AiGateway` it\n // returns: both read private fields.\n return await binding.gateway(request.gateway.id).run(\n {\n endpoint: request.endpoint,\n headers: request.headers,\n provider: request.provider,\n query: request.query\n },\n {\n ...(request.extraHeaders === undefined\n ? {}\n : { extraHeaders: request.extraHeaders }),\n gateway: universalGatewayOptions(request.gateway),\n signal: request.signal\n }\n );\n } catch (error) {\n throw normalizeThrownError(error, {\n model: universalModel(request),\n requestBodyValues: request.query,\n url: UNIVERSAL_BINDING_URL\n });\n }\n },\n url: \"workers-ai-binding\"\n };\n}\n\n/**\n * Builds the transport for a set of provider settings. The model id, not the\n * caller, decides the wire format; the transport only decides how the request\n * physically leaves the Worker.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function createTransport(settings: AISettings): Transport {\n if (settings.binding === undefined) {\n throw new Error(\"createAI requires { binding }: the Workers AI binding.\");\n }\n return bindingTransport(settings.binding);\n}\n","/**\n * The AI Gateway provider table: which gateway provider slug a vendor's own\n * base URL belongs to, and what the universal request's `endpoint` is for a\n * given upstream URL.\n *\n * This is platform knowledge, not vendor knowledge — the gateway publishes the\n * list, and every entry here appears in `AIGatewayProviders` from\n * `@cloudflare/workers-types`. Nothing about a vendor's wire format, model ids\n * or capabilities lives here: the vendor's own provider package builds the\n * request, and this table only says where it goes.\n *\n * Adapted from `@cloudflare/ai-gateway-provider`'s `providers.ts`.\n *\n * @experimental This surface is experimental and may change.\n */\n\n/**\n * The gateway provider slugs this table maps onto. A subset of the ambient\n * `AIGatewayProviders` union; {@link GatewayProviderNameCheck} keeps it one.\n *\n * @experimental This surface is experimental and may change.\n */\nexport const GATEWAY_PROVIDER_NAMES = [\n \"workers-ai\",\n \"anthropic\",\n \"openai\",\n \"azure-openai\",\n \"google-ai-studio\",\n \"google-vertex-ai\",\n \"grok\",\n \"mistral\",\n \"perplexity-ai\",\n \"replicate\",\n \"groq\",\n \"deepseek\",\n \"openrouter\",\n \"cerebras\",\n \"cohere\",\n \"huggingface\",\n \"aws-bedrock\",\n \"elevenlabs\",\n \"cartesia\"\n] as const;\n\n/**\n * A gateway provider slug.\n *\n * @experimental This surface is experimental and may change.\n */\nexport type GatewayProviderName = (typeof GATEWAY_PROVIDER_NAMES)[number];\n\n/**\n * Compile-time guard: every slug in this table must exist in the platform's\n * own provider union, so a workers-types bump that renames one fails `tsc`\n * here rather than at runtime with a 404 from the gateway.\n *\n * @internal\n */\nexport type GatewayProviderNameCheck<\n T extends AIGatewayProviders = GatewayProviderName\n> = T;\n\n/**\n * One row of the provider table.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface GatewayProvider {\n /** The gateway provider slug. */\n readonly name: GatewayProviderName;\n /** Matches the upstream host (`URL.host`), not the whole URL. */\n readonly host: RegExp;\n /**\n * Request headers carrying the vendor's own credential. They are stripped\n * before the request is handed to the gateway, which holds the real key\n * (unified billing or BYOK). Lowercase.\n */\n readonly authHeaders: readonly string[];\n /**\n * The universal request's `endpoint` for an upstream URL: everything after\n * the host, query string included, with the provider's fixed prefix removed.\n * `undefined` when the URL does not belong to this provider.\n */\n endpoint(url: string): string | undefined;\n}\n\n/** The default credential header; providers add their own on top. */\nconst AUTHORIZATION = [\"authorization\"] as const;\n\ninterface ProviderSpec {\n name: GatewayProviderName;\n host: RegExp;\n authHeaders?: readonly string[];\n /** A fixed path prefix stripped from the endpoint. */\n pathPrefix?: RegExp;\n /** A full replacement for the default path mapping. */\n endpoint?: (url: URL) => string | undefined;\n}\n\n/** Path after the host, leading slash removed, query string kept. */\nfunction pathOf(url: URL): string {\n return `${url.pathname.replace(/^\\/+/, \"\")}${url.search}`;\n}\n\nfunction buildProvider(spec: ProviderSpec): GatewayProvider {\n const map =\n spec.endpoint ??\n ((url: URL) => {\n const path = pathOf(url);\n return spec.pathPrefix === undefined\n ? path\n : path.replace(spec.pathPrefix, \"\");\n });\n return {\n authHeaders: spec.authHeaders ?? AUTHORIZATION,\n endpoint(url) {\n const parsed = parseUrl(url);\n if (parsed === undefined || !spec.host.test(parsed.host)) {\n return undefined;\n }\n return map(parsed);\n },\n host: spec.host,\n name: spec.name\n };\n}\n\nfunction parseUrl(url: string): URL | undefined {\n try {\n return new URL(url);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Azure names the deployment in the path; the gateway names it in the\n * endpoint as `<resource>/<deployment>/<rest>`.\n */\nfunction azureEndpoint(url: URL): string | undefined {\n const resource = /^([^.]+)\\.openai\\.azure\\.com$/.exec(url.host)?.[1];\n const rest = /^\\/openai\\/deployments\\/([^/]+)\\/(.+)$/.exec(url.pathname);\n if (resource === undefined || rest === null) return undefined;\n return `${resource}/${rest[1]}/${rest[2]}${url.search}`;\n}\n\n/**\n * Bedrock's region and service live in the host; the gateway wants them as the\n * first two endpoint segments.\n */\nfunction bedrockEndpoint(url: URL): string | undefined {\n const match = /^(bedrock[a-z0-9-]*)\\.([a-z0-9-]+)\\.amazonaws\\.com$/.exec(\n url.host\n );\n if (match === null) return undefined;\n return `${match[1]}/${match[2]}/${pathOf(url)}`;\n}\n\nconst SPECS: ProviderSpec[] = [\n {\n // Workers AI's own API host. `env.AI.run` is this package's path for\n // `@cf/` models; this row exists because the gateway lists the provider,\n // so a model object pointed at that host still resolves.\n host: /^api\\.cloudflare\\.com$/,\n name: \"workers-ai\",\n pathPrefix: /^client\\/v4\\/accounts\\/[^/]+\\/ai\\//\n },\n {\n authHeaders: [\"authorization\", \"x-api-key\"],\n host: /^api\\.anthropic\\.com$/,\n name: \"anthropic\"\n },\n { host: /^api\\.openai\\.com$/, name: \"openai\" },\n {\n authHeaders: [\"authorization\", \"api-key\"],\n endpoint: azureEndpoint,\n host: /^[^.]+\\.openai\\.azure\\.com$/,\n name: \"azure-openai\"\n },\n {\n authHeaders: [\"authorization\", \"x-goog-api-key\"],\n host: /^generativelanguage\\.googleapis\\.com$/,\n name: \"google-ai-studio\"\n },\n {\n host: /^(?:[a-z0-9-]+-)?aiplatform\\.googleapis\\.com$/,\n name: \"google-vertex-ai\"\n },\n { host: /^api\\.x\\.ai$/, name: \"grok\" },\n { host: /^api\\.mistral\\.ai$/, name: \"mistral\" },\n { host: /^api\\.perplexity\\.ai$/, name: \"perplexity-ai\" },\n { host: /^api\\.replicate\\.com$/, name: \"replicate\" },\n {\n host: /^api\\.groq\\.com$/,\n name: \"groq\",\n pathPrefix: /^openai\\/v1\\//\n },\n { host: /^api\\.deepseek\\.com$/, name: \"deepseek\" },\n {\n host: /^openrouter\\.ai$/,\n name: \"openrouter\",\n pathPrefix: /^api\\//\n },\n { host: /^api\\.cerebras\\.ai$/, name: \"cerebras\" },\n { host: /^api\\.cohere\\.(?:ai|com)$/, name: \"cohere\" },\n {\n host: /^(?:api-inference|router)\\.huggingface\\.co$/,\n name: \"huggingface\",\n pathPrefix: /^models\\//\n },\n {\n endpoint: bedrockEndpoint,\n host: /^bedrock.*\\.amazonaws\\.com$/,\n name: \"aws-bedrock\"\n },\n { host: /^api\\.elevenlabs\\.io$/, name: \"elevenlabs\" },\n { host: /^api\\.cartesia\\.ai$/, name: \"cartesia\" }\n];\n\n/**\n * The provider table, in declaration order. Hosts do not overlap, so the order\n * only decides which row a future overlapping host would win.\n *\n * @experimental This surface is experimental and may change.\n */\nexport const GATEWAY_PROVIDERS: readonly GatewayProvider[] =\n SPECS.map(buildProvider);\n\n/**\n * A vendor URL mapped onto the universal gateway request.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface ResolvedGatewayProvider {\n /** The gateway provider slug. */\n provider: GatewayProviderName;\n /** The universal request's `endpoint`. */\n endpoint: string;\n /** Request headers to strip before handing the request to the gateway. */\n authHeaders: readonly string[];\n}\n\n/**\n * The table row for a bare host (`api.anthropic.com`) or for anything a `URL`\n * can be built from. pi-ai models carry a `baseUrl` rather than a full request\n * URL, so both spellings resolve.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function gatewayProviderForHost(\n hostOrUrl: string\n): GatewayProvider | undefined {\n const host = parseUrl(hostOrUrl)?.host ?? hostOf(hostOrUrl);\n if (host === undefined) return undefined;\n return GATEWAY_PROVIDERS.find((provider) => provider.host.test(host));\n}\n\n/** Reads a host out of a bare host, `host/path` or `//host` spelling. */\nfunction hostOf(value: string): string | undefined {\n const host = value.replace(/^\\/\\//, \"\").split(\"/\")[0];\n return host === \"\" ? undefined : host;\n}\n\n/**\n * Maps a vendor request URL onto `{ provider, endpoint, authHeaders }` for the\n * universal gateway request, or `undefined` when the host is not a gateway\n * provider.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function resolveGatewayProvider(\n url: string\n): ResolvedGatewayProvider | undefined {\n const parsed = parseUrl(url);\n if (parsed === undefined) return undefined;\n for (const provider of GATEWAY_PROVIDERS) {\n if (!provider.host.test(parsed.host)) continue;\n const endpoint = provider.endpoint(url);\n if (endpoint === undefined) continue;\n return {\n authHeaders: provider.authHeaders,\n endpoint,\n provider: provider.name\n };\n }\n return undefined;\n}\n\n/**\n * {@link resolveGatewayProvider}, throwing a `TypeError` that names the host\n * and the provider list when the URL belongs to no gateway provider.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function requireGatewayProvider(url: string): ResolvedGatewayProvider {\n const resolved = resolveGatewayProvider(url);\n if (resolved !== undefined) return resolved;\n const host = parseUrl(url)?.host ?? url;\n throw new TypeError(\n `AI Gateway has no provider for ${host}. Requests are routed by host; the supported providers are ${GATEWAY_PROVIDER_NAMES.join(\", \")}.`\n );\n}\n\n/** The host a gateway-shaped base URL points at. */\nconst GATEWAY_HOST = \"gateway.ai.cloudflare.com\";\n\n/**\n * The provider slug of a gateway-shaped base URL —\n * `https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/{slug}`. Generated\n * registries write models that way (pi-ai's Cloudflare AI Gateway catalog\n * leaves the account and gateway as literal placeholders), so the slug is\n * already in the path rather than implied by a vendor host. The account and\n * gateway segments are ignored: the binding has already chosen both.\n */\nfunction gatewayShapedSlug(url: URL): string | undefined {\n if (url.host !== GATEWAY_HOST) return undefined;\n const segments = url.pathname.split(\"/\").filter((part) => part !== \"\");\n if (segments[0] !== \"v1\" || segments.length < 4) return undefined;\n return segments[3];\n}\n\n/**\n * Whether a base URL is written in the gateway's own shape\n * (`https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/{slug}`) rather\n * than as a vendor's. A generated Cloudflare registry writes models that way,\n * and the path after the slug is then the vendor's own, so a caller that\n * derives an endpoint from a base URL has to tell the two apart.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function isGatewayShapedUrl(url: string): boolean {\n return parseUrl(url)?.host === GATEWAY_HOST;\n}\n\nfunction isGatewayProviderName(slug: string): slug is GatewayProviderName {\n return (GATEWAY_PROVIDER_NAMES as readonly string[]).includes(slug);\n}\n\n/**\n * The gateway provider slug a model's base URL belongs to. Two spellings\n * resolve, because two kinds of registry write them:\n *\n * - a vendor's own base URL (`https://api.anthropic.com` → `anthropic`), which\n * is what a provider package configured for the vendor carries;\n * - a gateway-shaped base URL\n * (`https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/anthropic` →\n * `anthropic`), which is what a generated Cloudflare registry carries.\n *\n * A base URL neither shape resolves is a wiring mistake rather than a request\n * failure, so it throws a `TypeError` naming what was not recognised.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function gatewaySlugForBaseUrl(baseUrl: string): GatewayProviderName {\n const url = parseUrl(baseUrl);\n const shaped = url === undefined ? undefined : gatewayShapedSlug(url);\n if (shaped !== undefined) {\n if (isGatewayProviderName(shaped)) return shaped;\n throw new TypeError(\n `AI Gateway has no provider \"${shaped}\" (from ${baseUrl}). The supported providers are ${GATEWAY_PROVIDER_NAMES.join(\", \")}.`\n );\n }\n const provider = gatewayProviderForHost(baseUrl);\n if (provider !== undefined) return provider.name;\n throw new TypeError(\n `AI Gateway has no provider for ${url?.host ?? baseUrl}. Requests are routed by the model's base URL; the supported providers are ${GATEWAY_PROVIDER_NAMES.join(\", \")}.`\n );\n}\n","/**\n * Where a Cloudflare catalog model departs from strict OpenAI chat\n * completions, and how. Every entry is backed by a live capture from the\n * conformance probes (`research/40-*.json`, `41-*.json`); the default for an\n * unknown id is strict OpenAI, so a new conformant model needs no code here.\n *\n * Framework-neutral: both the AI SDK and the pi-ai providers consult this.\n */\n\n/** A request feature that had to be changed or dropped for a model. */\nexport interface CompatWarning {\n feature: string;\n message: string;\n}\n\nexport interface ChatCompletionsQuirks {\n /** Which field carries the output-token cap. OpenAI's current models reject `max_tokens`. */\n maxTokensField: \"max_tokens\" | \"max_completion_tokens\";\n /**\n * How reasoning can be turned off. `chat-template` sends\n * `chat_template_kwargs.enable_thinking = false` (vLLM); `unsupported` drops\n * the request with a warning because the model keeps reasoning regardless.\n */\n reasoningOff: \"chat-template\" | \"unsupported\";\n /**\n * Which `reasoning_effort` levels the model accepts. `openai` is the full\n * set (`minimal` … `xhigh`); `basic` is `low | medium | high`, everything\n * else clamped.\n */\n reasoningEffortLevels: \"openai\" | \"basic\";\n /** Whether `chat_template_kwargs` is accepted at all. */\n chatTemplateKwargs: \"supported\" | \"unsupported\";\n /** Whether `response_format: json_schema` is accepted at all. */\n jsonSchema: \"supported\" | \"unsupported\";\n /** Whether the OpenAI-only `strict` flag belongs on the json_schema envelope. */\n jsonSchemaStrict: boolean;\n /**\n * `tool_choice: \"required\"`. `named-fallback` rewrites it to the single\n * named tool when there is exactly one (glm-4.7-flash answers 400 to\n * `required`, a gateway serialization bug), and drops it otherwise.\n */\n toolChoiceRequired: \"supported\" | \"named-fallback\";\n /** Whether image parts may reference a URL, or must carry inline bytes. */\n imageUrls: \"any\" | \"data-only\";\n /** Whether replayed assistant reasoning (`reasoning_content`) is accepted. */\n reasoningReplay: \"reasoning_content\" | \"drop\";\n /**\n * Whether a `user` turn may directly follow a `tool` turn. Mistral rejects\n * it (\"Unexpected role 'user' after role 'tool'\"), so an empty assistant\n * turn is inserted between them.\n */\n requiresAssistantAfterToolResult: boolean;\n /**\n * What the model accepts as a tool-call id. `alnum-9` is Mistral's rule:\n * exactly nine `[A-Za-z0-9]` characters, anything else is a 400.\n */\n toolCallIds: \"any\" | \"alnum-9\";\n /** A suffix the model echoes on its own id that callers never asked for. */\n modelEchoSuffix: string | undefined;\n /** Whether a replayed assistant turn may carry `content: null`. */\n nullAssistantContent: \"allowed\" | \"empty-string\";\n /**\n * Where the answer lands in a stream once reasoning has been turned off.\n * `reasoning` means the model's streaming parser mislabels the whole answer\n * as reasoning (its non-streaming body is fine), so the normalizer moves\n * those deltas back into `content`.\n */\n reasoningOffStreamLabel: \"content\" | \"reasoning\";\n}\n\nconst STRICT_OPENAI: ChatCompletionsQuirks = {\n chatTemplateKwargs: \"unsupported\",\n imageUrls: \"any\",\n jsonSchema: \"supported\",\n jsonSchemaStrict: false,\n maxTokensField: \"max_tokens\",\n modelEchoSuffix: undefined,\n nullAssistantContent: \"allowed\",\n reasoningEffortLevels: \"basic\",\n reasoningOff: \"unsupported\",\n reasoningOffStreamLabel: \"content\",\n reasoningReplay: \"drop\",\n requiresAssistantAfterToolResult: false,\n toolCallIds: \"any\",\n toolChoiceRequired: \"supported\"\n};\n\n/** Workers AI's vLLM front end: what every `@cf/` model has in common. */\nconst WORKERS_AI: ChatCompletionsQuirks = {\n ...STRICT_OPENAI,\n chatTemplateKwargs: \"supported\",\n imageUrls: \"data-only\",\n nullAssistantContent: \"empty-string\",\n reasoningOff: \"chat-template\",\n reasoningReplay: \"reasoning_content\"\n};\n\n/**\n * Longest-prefix overrides. Keep each one evidence-backed (the capture that\n * proves it is named in the comment) and delete it when the platform fixes\n * the deviation.\n */\nconst OVERRIDES: [prefix: string, quirks: Partial<ChatCompletionsQuirks>][] = [\n // 40-demos-...-E1: `tool_choice: \"required\"` + tools → 400 pydantic parse error.\n [\"@cf/zai-org/glm-4.7-flash\", { toolChoiceRequired: \"named-fallback\" }],\n // 40-demos-kimi-k3-G3 / 40-matt-kimi-k2.7-code-G_ctk: enable_thinking=false\n // leaves reasoning on; nothing turns it off.\n [\"@cf/moonshotai/\", { reasoningOff: \"unsupported\" }],\n // 40-demos-gpt-oss-120b-G3: same.\n [\"@cf/openai/\", { reasoningOff: \"unsupported\" }],\n // 40-demos-...-F1/F2/G3/J1: \"chat_template is not supported for Mistral\n // tokenizers\", \"Unexpected role 'user' after role 'tool'\".\n // 40-matt-mistral-small-3.1-24b-instruct-J: \"Tool call id was call_1 but\n // must be a-z, A-Z, 0-9, with a length of 9.\"\n [\n \"@cf/mistralai/\",\n {\n chatTemplateKwargs: \"unsupported\",\n jsonSchema: \"unsupported\",\n reasoningOff: \"unsupported\",\n requiresAssistantAfterToolResult: true,\n toolCallIds: \"alnum-9\"\n }\n ],\n // 40-demos-gemma-4-26b-a4b-it-A: echoes \"@cf/google/gemma-4-26b-a4b-it-external\".\n [\"@cf/google/\", { modelEchoSuffix: \"-external\" }],\n // 41-matt-nemotron-3-120b-a12b-K_emoji / S_usage_s: with enable_thinking=false\n // every streamed token arrives as `delta.reasoning` and `content` stays\n // empty, while the non-streaming body (A0, 40-...-G_ctk) puts the same\n // answer in `content` with `reasoning: null`.\n [\"@cf/nvidia/nemotron-\", { reasoningOffStreamLabel: \"reasoning\" }]\n];\n\n/** The quirks for a catalog id: base profile plus the longest matching override. */\nexport function quirksFor(modelId: string): ChatCompletionsQuirks {\n const base = modelId.startsWith(\"@cf/\") ? WORKERS_AI : STRICT_OPENAI;\n let best: [string, Partial<ChatCompletionsQuirks>] | undefined;\n for (const entry of OVERRIDES) {\n if (\n modelId.startsWith(entry[0]) &&\n (best === undefined || entry[0].length > best[0].length)\n ) {\n best = entry;\n }\n }\n return best === undefined ? base : { ...base, ...best[1] };\n}\n\n/** Whether an id is a Workers AI model rather than a third-party catalog model. */\nexport function isWorkersAI(modelId: string): boolean {\n return modelId.startsWith(\"@cf/\");\n}\n","/**\n * Rewrites a strict OpenAI chat-completions request body into what a given\n * catalog model accepts. Frameworks build the strict body from their own\n * prompt types; everything Cloudflare- or vendor-specific happens here, once.\n *\n * The rewrite never throws: a feature the model cannot take is dropped and\n * reported as a {@link CompatWarning}.\n */\n\nimport { type CompatWarning, quirksFor } from \"./quirks\";\n\nexport interface PreparedRequest {\n body: Record<string, unknown>;\n warnings: CompatWarning[];\n /**\n * Whether the body turns the model's reasoning off through the chat\n * template. The stream normalizer needs this for models whose streaming\n * parser mislabels the answer once thinking is off.\n */\n reasoningOff: boolean;\n}\n\ntype Message = Record<string, unknown>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction clampEffort(effort: string): string {\n if (effort === \"minimal\") return \"low\";\n if (effort === \"xhigh\") return \"high\";\n return effort;\n}\n\n/** Drops URL image parts (keeps inline data URLs) from a user message. */\nfunction stripImageUrls(message: Message, warnings: CompatWarning[]): Message {\n if (!Array.isArray(message.content)) return message;\n let dropped = 0;\n const content = message.content.filter((part) => {\n if (!isRecord(part) || part.type !== \"image_url\") return true;\n const image = isRecord(part.image_url) ? part.image_url : undefined;\n const url = typeof image?.url === \"string\" ? image.url : \"\";\n if (url.startsWith(\"data:\")) return true;\n dropped += 1;\n return false;\n });\n if (dropped > 0) {\n warnings.push({\n feature: \"image-url\",\n message: `Workers AI models need image bytes; ${dropped} image URL${dropped === 1 ? \" was\" : \"s were\"} dropped.`\n });\n }\n return { ...message, content };\n}\n\n/** Nine `[A-Za-z0-9]` characters: what Mistral accepts as a tool-call id. */\nconst CONFORMANT_TOOL_CALL_ID = /^[0-9A-Za-z]{9}$/;\n\nconst TOOL_CALL_ID_ALPHABET =\n \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\n\n/**\n * A deterministic nine-character id for an original id: the same conversation\n * replayed twice produces the same ids, so a provider cache or a log stays\n * comparable. `salt` is bumped only to break a collision.\n */\nfunction hashedToolCallId(original: string, salt: number): string {\n let state = (0x811c9dc5 ^ salt) >>> 0;\n for (let index = 0; index < original.length; index += 1) {\n state = Math.imul(state ^ original.charCodeAt(index), 0x01000193) >>> 0;\n }\n let id = \"\";\n for (let index = 0; index < 9; index += 1) {\n state = Math.imul(state ^ (state >>> 15), 0x01000193) >>> 0;\n id += TOOL_CALL_ID_ALPHABET[state % TOOL_CALL_ID_ALPHABET.length];\n }\n return id;\n}\n\n/** Every tool-call id a message set mentions, in the order it mentions them. */\nfunction toolCallIdsIn(messages: unknown[]): string[] {\n const ids: string[] = [];\n const seen = new Set<string>();\n const add = (value: unknown) => {\n if (typeof value !== \"string\" || seen.has(value)) return;\n seen.add(value);\n ids.push(value);\n };\n for (const message of messages) {\n if (!isRecord(message)) continue;\n if (Array.isArray(message.tool_calls)) {\n for (const call of message.tool_calls) {\n if (isRecord(call)) add(call.id);\n }\n }\n add(message.tool_call_id);\n }\n return ids;\n}\n\n/**\n * Plans the rewrite: which ids have to change, and to what. Ids that already\n * conform are kept exactly as they are — including as reserved values, so a\n * rewritten id can never collide with one.\n */\nfunction planToolCallIds(messages: unknown[]): Map<string, string> {\n const plan = new Map<string, string>();\n const ids = toolCallIdsIn(messages);\n const taken = new Set(ids.filter((id) => CONFORMANT_TOOL_CALL_ID.test(id)));\n for (const id of ids) {\n if (taken.has(id)) continue;\n let replacement = hashedToolCallId(id, 0);\n for (let salt = 1; taken.has(replacement) && salt <= 64; salt += 1) {\n replacement = hashedToolCallId(id, salt);\n }\n taken.add(replacement);\n plan.set(id, replacement);\n }\n return plan;\n}\n\n/** Applies the plan to an assistant `tool_calls` turn or a `tool` result. */\nfunction rewriteToolCallIds(\n message: Message,\n plan: Map<string, string>\n): Message {\n let rewritten = message;\n if (Array.isArray(rewritten.tool_calls)) {\n rewritten = {\n ...rewritten,\n tool_calls: rewritten.tool_calls.map((call) => {\n if (!isRecord(call) || typeof call.id !== \"string\") return call;\n const replacement = plan.get(call.id);\n return replacement === undefined ? call : { ...call, id: replacement };\n })\n };\n }\n if (typeof rewritten.tool_call_id === \"string\") {\n const replacement = plan.get(rewritten.tool_call_id);\n if (replacement !== undefined) {\n rewritten = { ...rewritten, tool_call_id: replacement };\n }\n }\n return rewritten;\n}\n\n/**\n * Applies the model's quirks to a strict OpenAI chat-completions body.\n *\n * Conventions the strict body follows, which this function translates:\n * - `max_tokens` is the cap; it becomes `max_completion_tokens` where needed.\n * - `reasoning_effort: null` means \"turn reasoning off\".\n * - Replayed assistant reasoning sits in `reasoning_content`.\n * - `response_format.json_schema` is the OpenAI `{ name, schema }` envelope.\n * - `chat_template_kwargs` may be present; it is only meaningful on Workers AI.\n */\nexport function prepareChatCompletionsRequest(\n input: Record<string, unknown>,\n modelId: string\n): PreparedRequest {\n const quirks = quirksFor(modelId);\n const warnings: CompatWarning[] = [];\n const body: Record<string, unknown> = { ...input };\n\n // Output-token cap.\n if (\n quirks.maxTokensField === \"max_completion_tokens\" &&\n \"max_tokens\" in body\n ) {\n body.max_completion_tokens = body.max_tokens;\n delete body.max_tokens;\n }\n\n // Reasoning.\n if (\"reasoning_effort\" in body) {\n const effort = body.reasoning_effort;\n if (effort === null) {\n delete body.reasoning_effort;\n if (quirks.reasoningOff === \"chat-template\") {\n body.chat_template_kwargs = {\n ...(isRecord(body.chat_template_kwargs)\n ? body.chat_template_kwargs\n : {}),\n enable_thinking: false\n };\n } else {\n warnings.push({\n feature: \"reasoning-off\",\n message: `Reasoning cannot be turned off on ${modelId}; the request was sent with the model's default effort.`\n });\n }\n } else if (\n typeof effort === \"string\" &&\n quirks.reasoningEffortLevels === \"basic\"\n ) {\n body.reasoning_effort = clampEffort(effort);\n }\n }\n if (\n \"chat_template_kwargs\" in body &&\n quirks.chatTemplateKwargs === \"unsupported\"\n ) {\n delete body.chat_template_kwargs;\n warnings.push({\n feature: \"chat-template-kwargs\",\n message: `${modelId} does not take chat_template_kwargs; they were dropped.`\n });\n }\n\n // Structured output.\n if (isRecord(body.response_format)) {\n if (quirks.jsonSchema === \"unsupported\") {\n delete body.response_format;\n warnings.push({\n feature: \"response-format\",\n message: `${modelId} does not support response_format; the request was sent without it.`\n });\n } else if (\n body.response_format.type === \"json_schema\" &&\n isRecord(body.response_format.json_schema)\n ) {\n const { strict: _strict, ...envelope } = body.response_format.json_schema;\n body.response_format = {\n ...body.response_format,\n json_schema: quirks.jsonSchemaStrict\n ? { ...envelope, strict: true }\n : envelope\n };\n }\n }\n\n // Tools.\n if (\n body.tool_choice === \"required\" &&\n quirks.toolChoiceRequired === \"named-fallback\"\n ) {\n const tools = Array.isArray(body.tools) ? body.tools : [];\n const only =\n tools.length === 1 && isRecord(tools[0]) ? tools[0] : undefined;\n const name =\n only !== undefined &&\n isRecord(only.function) &&\n typeof only.function.name === \"string\"\n ? only.function.name\n : undefined;\n if (name !== undefined) {\n body.tool_choice = { function: { name }, type: \"function\" };\n } else {\n delete body.tool_choice;\n warnings.push({\n feature: \"tool-choice-required\",\n message: `${modelId} rejects tool_choice \"required\"; the model was left free to choose.`\n });\n }\n }\n\n // Messages.\n if (Array.isArray(body.messages)) {\n // Two passes: the ids are planned over the whole conversation first, so an\n // assistant turn and the tool result answering it are rewritten to the\n // same value however far apart they sit.\n const toolCallIds =\n quirks.toolCallIds === \"alnum-9\"\n ? planToolCallIds(body.messages)\n : new Map<string, string>();\n if (toolCallIds.size > 0) {\n warnings.push({\n feature: \"tool-call-id\",\n message: `${modelId} needs 9-character alphanumeric tool-call ids; ${toolCallIds.size} id${toolCallIds.size === 1 ? \" was\" : \"s were\"} rewritten.`\n });\n }\n const messages: Message[] = [];\n let previousRole: unknown;\n for (const entry of body.messages) {\n if (!isRecord(entry)) continue;\n let message: Message = entry;\n if (toolCallIds.size > 0) {\n message = rewriteToolCallIds(message, toolCallIds);\n }\n if (message.role === \"user\" && quirks.imageUrls === \"data-only\") {\n message = stripImageUrls(message, warnings);\n }\n if (\n message.role === \"assistant\" &&\n message.content === null &&\n quirks.nullAssistantContent === \"empty-string\"\n ) {\n // 41-demos-gpt-oss-120b-O_replay_null: a replayed assistant turn with\n // `content: null` is a 400 on Workers AI; `\"\"` is accepted everywhere.\n message = { ...message, content: \"\" };\n }\n if (message.role === \"assistant\" && \"reasoning_content\" in message) {\n if (quirks.reasoningReplay === \"drop\") {\n const { reasoning_content: _reasoning, ...rest } = message;\n message = rest;\n warnings.push({\n feature: \"assistant-reasoning\",\n message: `${modelId} has no field for replayed reasoning; the assistant reasoning was dropped.`\n });\n }\n }\n if (\n quirks.requiresAssistantAfterToolResult &&\n previousRole === \"tool\" &&\n message.role === \"user\"\n ) {\n messages.push({ content: \"\", role: \"assistant\" });\n }\n messages.push(message);\n previousRole = message.role;\n }\n body.messages = messages;\n }\n\n const reasoningOff =\n isRecord(body.chat_template_kwargs) &&\n body.chat_template_kwargs.enable_thinking === false;\n return { body, reasoningOff, warnings };\n}\n","/**\n * Normalizes a chat-completions response body from the run path into the\n * strict OpenAI `chat.completion` shape, so framework parsers never see\n * Workers AI's native envelope or its field spellings.\n */\n\nimport { quirksFor } from \"./quirks\";\n\ntype Record_ = Record<string, unknown>;\n\nfunction isRecord(value: unknown): value is Record_ {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/** Native `{ name, arguments: object }` → OpenAI `{ id, type, function }`. */\nexport function normalizeToolCall(\n entry: unknown,\n index: number\n): Record_ | undefined {\n if (!isRecord(entry)) return undefined;\n const fn = isRecord(entry.function) ? entry.function : undefined;\n const name =\n typeof fn?.name === \"string\"\n ? fn.name\n : typeof entry.name === \"string\"\n ? entry.name\n : undefined;\n if (name === undefined) return undefined;\n const rawArguments =\n fn !== undefined && \"arguments\" in fn ? fn.arguments : entry.arguments;\n const args =\n typeof rawArguments === \"string\"\n ? rawArguments\n : rawArguments === undefined || rawArguments === null\n ? \"{}\"\n : JSON.stringify(rawArguments);\n return {\n ...(typeof entry.index === \"number\" ? { index: entry.index } : { index }),\n ...(typeof entry.id === \"string\" ? { id: entry.id } : {}),\n function: { arguments: args, name },\n type: \"function\",\n ...(entry.extra_content !== undefined\n ? { extra_content: entry.extra_content }\n : {})\n };\n}\n\n/** Text as the model produced it; structured-output models may return an object. */\nfunction contentText(value: unknown): string | null {\n if (typeof value === \"string\") return value;\n if (value === null || value === undefined) return null;\n return JSON.stringify(value);\n}\n\nfunction stripEchoSuffix(model: unknown, modelId: string): unknown {\n const suffix = quirksFor(modelId).modelEchoSuffix;\n if (typeof model !== \"string\" || suffix === undefined) return model;\n return model.endsWith(suffix) ? model.slice(0, -suffix.length) : model;\n}\n\n/** Puts reasoning under `reasoning_content` whichever spelling the model used. */\nfunction normalizeMessage(message: Record_): Record_ {\n const out: Record_ = { ...message };\n const reasoning =\n typeof out.reasoning_content === \"string\" && out.reasoning_content !== \"\"\n ? out.reasoning_content\n : typeof out.reasoning === \"string\" && out.reasoning !== \"\"\n ? out.reasoning\n : undefined;\n delete out.reasoning;\n if (reasoning !== undefined) out.reasoning_content = reasoning;\n else delete out.reasoning_content;\n if (\"content\" in out) out.content = contentText(out.content);\n if (Array.isArray(out.tool_calls)) {\n const calls = out.tool_calls\n .map((call, index) => normalizeToolCall(call, index))\n .filter((call): call is Record_ => call !== undefined);\n if (calls.length > 0) out.tool_calls = calls;\n else delete out.tool_calls;\n }\n return out;\n}\n\n/**\n * Returns the body in the strict `chat.completion` shape. Already-OpenAI\n * bodies come back with their reasoning spelling unified and the echoed model\n * id cleaned; native Workers AI `{ response, tool_calls, usage }` bodies are\n * lifted into `choices[0]`.\n */\nexport function normalizeChatCompletion(\n body: unknown,\n modelId: string\n): Record_ {\n if (!isRecord(body)) return { choices: [] };\n if (Array.isArray(body.choices)) {\n const choices = body.choices.map((choice) => {\n if (!isRecord(choice)) return choice;\n const message = isRecord(choice.message)\n ? normalizeMessage(choice.message)\n : choice.message;\n const hasToolCalls =\n isRecord(message) &&\n Array.isArray(message.tool_calls) &&\n message.tool_calls.length > 0;\n return {\n ...choice,\n message,\n finish_reason:\n choice.finish_reason ?? (hasToolCalls ? \"tool_calls\" : \"stop\")\n };\n });\n return { ...body, choices, model: stripEchoSuffix(body.model, modelId) };\n }\n if (\"response\" in body || \"tool_calls\" in body) {\n const toolCalls = Array.isArray(body.tool_calls)\n ? body.tool_calls\n .map((call, index) => normalizeToolCall(call, index))\n .filter((call): call is Record_ => call !== undefined)\n : [];\n const { response, tool_calls: _toolCalls, usage, ...rest } = body;\n return {\n ...rest,\n choices: [\n {\n finish_reason:\n typeof body.finish_reason === \"string\"\n ? body.finish_reason\n : toolCalls.length > 0\n ? \"tool_calls\"\n : \"stop\",\n index: 0,\n message: {\n content: contentText(response),\n role: \"assistant\",\n ...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {})\n }\n }\n ],\n model: stripEchoSuffix(body.model, modelId),\n ...(usage !== undefined ? { usage } : {})\n };\n }\n return body;\n}\n","/**\n * Normalizes a chat-completions SSE stream from the run path into strict\n * OpenAI `chat.completion.chunk` events.\n *\n * Every Workers AI model streams the same three-part hybrid (live captures,\n * all families): OpenAI-shaped delta chunks that each carry a per-delta\n * `usage`, then a `choices: []` heartbeat, then a native\n * `{ response: \"\", usage }` tail with the cumulative usage, then `[DONE]`.\n * Some models also emit native `{ response: \"<text>\" }` deltas or top-level\n * `tool_calls`. After this transform a consumer sees only:\n *\n * - delta chunks without per-delta usage and with reasoning under\n * `reasoning_content`;\n * - at most one final `choices: []` chunk carrying the cumulative usage\n * (the OpenAI `stream_options.include_usage` shape);\n * - a `finish_reason` on some chunk before the end, synthesized when the\n * model finished cleanly without sending one;\n * - `[DONE]`.\n *\n * Input and output are SSE `data` payloads (strings), so it slots between the\n * SSE decoder and either framework's OpenAI chunk parser.\n */\n\nimport { isWorkersAI, quirksFor } from \"./quirks\";\nimport { normalizeToolCall } from \"./response\";\n\ntype Record_ = Record<string, unknown>;\n\nfunction isRecord(value: unknown): value is Record_ {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nconst NOISE_FIELDS = [\n \"p\",\n \"token_ids\",\n \"prompt_token_ids\",\n \"kv_transfer_params\"\n];\n\n/** Fields the run path adds to every chunk that mean nothing to a consumer. */\nfunction stripNoise(chunk: Record_): Record_ {\n const out = { ...chunk };\n for (const key of NOISE_FIELDS) delete out[key];\n return out;\n}\n\nfunction stripEchoSuffix(chunk: Record_, modelId: string): Record_ {\n const suffix = quirksFor(modelId).modelEchoSuffix;\n if (suffix === undefined || typeof chunk.model !== \"string\") return chunk;\n return chunk.model.endsWith(suffix)\n ? { ...chunk, model: chunk.model.slice(0, -suffix.length) }\n : chunk;\n}\n\nfunction normalizeDelta(delta: Record_, relabelReasoning: boolean): Record_ {\n const out: Record_ = { ...delta };\n const reasoning =\n typeof out.reasoning_content === \"string\" && out.reasoning_content !== \"\"\n ? out.reasoning_content\n : typeof out.reasoning === \"string\" && out.reasoning !== \"\"\n ? out.reasoning\n : undefined;\n delete out.reasoning;\n delete out.reasoning_content;\n if (reasoning !== undefined) {\n if (relabelReasoning) {\n // Reasoning is off, so these tokens are the answer (nemotron-3).\n out.content =\n (typeof out.content === \"string\" ? out.content : \"\") + reasoning;\n } else {\n out.reasoning_content = reasoning;\n }\n }\n if (Array.isArray(out.tool_calls)) {\n out.tool_calls = out.tool_calls.map((call, index) => {\n // Fragments and the null finalizer pass through untouched; only a\n // native complete call needs lifting into the OpenAI shape. A native\n // call names its tool at the top level, where no OpenAI fragment does,\n // and its arguments may be an object or already a string.\n if (!isRecord(call)) return call;\n const fn = isRecord(call.function) ? call.function : undefined;\n const args = fn !== undefined ? fn.arguments : call.arguments;\n const native = fn === undefined && typeof call.name === \"string\";\n return native || isRecord(args)\n ? (normalizeToolCall(call, index) ?? call)\n : call;\n });\n }\n return out;\n}\n\nexport interface StreamNormalizationOptions {\n /** Whether the request turned reasoning off (`PreparedRequest.reasoningOff`). */\n reasoningOff?: boolean;\n}\n\n/**\n * The transform. Backpressure is preserved: nothing is buffered except the\n * single pending usage chunk, which must wait for the tail.\n */\nexport function normalizeChatCompletionsStream(\n modelId: string,\n options: StreamNormalizationOptions = {}\n): TransformStream<string, string> {\n const quirks = quirksFor(modelId);\n const relabelReasoning =\n options.reasoningOff === true &&\n quirks.reasoningOffStreamLabel === \"reasoning\";\n let id: string | undefined;\n let model: string | undefined;\n let created: number | undefined;\n let sawFinishReason = false;\n let sawContent = false;\n let sawToolCalls = false;\n let sawDone = false;\n let finalUsage: unknown;\n let finalUsageTemplate: Record_ | undefined;\n // Workers AI stamps a per-delta usage on every content chunk and sends the\n // cumulative figure in its native tail; other vendors only ever put usage on\n // the final `choices: []` chunk, so theirs is left alone.\n const perDeltaUsage = isWorkersAI(modelId);\n\n const envelope = (extra: Record_): Record_ => ({\n ...(id !== undefined ? { id } : {}),\n object: \"chat.completion.chunk\",\n ...(created !== undefined ? { created } : {}),\n ...(model !== undefined ? { model } : {}),\n ...extra\n });\n\n const emit = (\n controller: TransformStreamDefaultController<string>,\n chunk: Record_\n ) => {\n controller.enqueue(JSON.stringify(chunk));\n };\n\n const emitTail = (controller: TransformStreamDefaultController<string>) => {\n if (!sawFinishReason && sawDone && (sawContent || sawToolCalls)) {\n emit(\n controller,\n envelope({\n choices: [\n {\n delta: {},\n finish_reason: sawToolCalls ? \"tool_calls\" : \"stop\",\n index: 0\n }\n ]\n })\n );\n sawFinishReason = true;\n }\n if (finalUsage !== undefined) {\n emit(controller, {\n ...(finalUsageTemplate ?? envelope({})),\n choices: [],\n usage: finalUsage\n });\n finalUsage = undefined;\n }\n if (sawDone) controller.enqueue(\"[DONE]\");\n };\n\n return new TransformStream<string, string>({\n flush(controller) {\n emitTail(controller);\n },\n transform(data, controller) {\n if (data === \"\") return;\n if (data === \"[DONE]\") {\n // Everything after the tail is emitted at flush, once.\n sawDone = true;\n return;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(data);\n } catch {\n // A malformed event is dropped rather than failing the stream.\n return;\n }\n if (!isRecord(parsed)) return;\n const chunk = stripEchoSuffix(stripNoise(parsed), modelId);\n\n if (typeof chunk.id === \"string\") id ??= chunk.id;\n if (typeof chunk.model === \"string\") model ??= chunk.model;\n if (typeof chunk.created === \"number\") created ??= chunk.created;\n\n // An error payload passes through untouched for the consumer to surface;\n // it also ends the generation, so no finish reason is synthesized after it.\n if (isRecord(chunk.error)) {\n sawFinishReason = true;\n controller.enqueue(JSON.stringify(chunk));\n return;\n }\n\n if (Array.isArray(chunk.choices)) {\n if (chunk.choices.length === 0) {\n // Heartbeat, or OpenAI's own final usage chunk: hold the usage\n // until the end so exactly one usage chunk is emitted.\n if (isRecord(chunk.usage)) {\n finalUsage = chunk.usage;\n finalUsageTemplate = { ...chunk, usage: undefined };\n delete finalUsageTemplate.usage;\n }\n return;\n }\n const choices = chunk.choices.map((choice) => {\n if (!isRecord(choice)) return choice;\n if (typeof choice.finish_reason === \"string\") sawFinishReason = true;\n const delta = isRecord(choice.delta)\n ? normalizeDelta(choice.delta, relabelReasoning)\n : choice.delta;\n if (isRecord(delta)) {\n if (typeof delta.content === \"string\" && delta.content !== \"\")\n sawContent = true;\n if (typeof delta.reasoning_content === \"string\") sawContent = true;\n if (Array.isArray(delta.tool_calls) && delta.tool_calls.length > 0)\n sawToolCalls = true;\n }\n if (!perDeltaUsage) return { ...choice, delta };\n const { usage: _perDeltaUsage, ...rest } = choice;\n return { ...rest, delta };\n });\n if (perDeltaUsage) {\n // The cumulative figure comes with the native tail.\n const { usage: _usage, ...rest } = chunk;\n emit(controller, { ...rest, choices });\n } else {\n emit(controller, { ...chunk, choices });\n }\n return;\n }\n\n // Native Workers AI events.\n if (\"response\" in chunk || \"tool_calls\" in chunk) {\n const text = chunk.response;\n const hasText = typeof text === \"string\" && text !== \"\";\n const calls = Array.isArray(chunk.tool_calls)\n ? chunk.tool_calls\n .map((call, index) => normalizeToolCall(call, index))\n .filter((call): call is Record_ => call !== undefined)\n : [];\n if (hasText || calls.length > 0) {\n if (hasText) sawContent = true;\n if (calls.length > 0) sawToolCalls = true;\n emit(\n controller,\n envelope({\n choices: [\n {\n delta: {\n ...(hasText ? { content: text } : {}),\n ...(calls.length > 0 ? { tool_calls: calls } : {})\n },\n finish_reason: null,\n index: 0\n }\n ]\n })\n );\n }\n if (isRecord(chunk.usage)) {\n // The native tail: cumulative usage for the whole stream.\n finalUsage = chunk.usage;\n finalUsageTemplate = undefined;\n }\n if (typeof chunk.finish_reason === \"string\") {\n sawFinishReason = true;\n emit(\n controller,\n envelope({\n choices: [\n { delta: {}, finish_reason: chunk.finish_reason, index: 0 }\n ]\n })\n );\n }\n }\n }\n });\n}\n","/**\n * Decodes a `text/event-stream` byte stream into the `data` payload of each\n * event, as a `TransformStream` so the whole pipeline keeps backpressure and\n * nothing is ever buffered beyond the current event.\n *\n * Handles all three line terminators the SSE spec allows (LF, CRLF and a bare\n * CR), multi-line `data:` fields (joined with `\\n`, per the spec), comment\n * lines (`:` prefixed), and non-`data` fields (`event:`, `id:`, `retry:`),\n * which are ignored. A trailing event that the server never terminated with a\n * blank line is still flushed.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function sseDataStream(): TransformStream<Uint8Array, string> {\n const decoder = new TextDecoder();\n let buffer = \"\";\n let data: string[] = [];\n\n const flushEvent = (controller: TransformStreamDefaultController<string>) => {\n if (data.length === 0) return;\n controller.enqueue(data.join(\"\\n\"));\n data = [];\n };\n\n const consumeLine = (\n line: string,\n controller: TransformStreamDefaultController<string>\n ) => {\n if (line === \"\") {\n flushEvent(controller);\n return;\n }\n if (line.startsWith(\":\")) return;\n const colon = line.indexOf(\":\");\n const field = colon === -1 ? line : line.slice(0, colon);\n if (field !== \"data\") return;\n let value = colon === -1 ? \"\" : line.slice(colon + 1);\n if (value.startsWith(\" \")) value = value.slice(1);\n data.push(value);\n };\n\n /**\n * Consumes whole lines out of the buffer. A buffer ending in a lone `\\r` is\n * held back while more bytes may arrive, because the next byte decides\n * whether that `\\r` was a CRLF pair or a bare-CR terminator.\n */\n const drain = (\n controller: TransformStreamDefaultController<string>,\n final: boolean\n ) => {\n for (;;) {\n const match = /\\r\\n|[\\r\\n]/.exec(buffer);\n if (match === null) break;\n const end = match.index + match[0].length;\n if (!final && match[0] === \"\\r\" && end === buffer.length) break;\n consumeLine(buffer.slice(0, match.index), controller);\n buffer = buffer.slice(end);\n }\n };\n\n return new TransformStream<Uint8Array, string>({\n flush(controller) {\n buffer += decoder.decode();\n drain(controller, true);\n // A server that closed without a final blank line still owes us the\n // last event; emit whatever is left rather than dropping it.\n if (buffer !== \"\") {\n consumeLine(buffer, controller);\n buffer = \"\";\n }\n flushEvent(controller);\n },\n transform(chunk, controller) {\n buffer += decoder.decode(chunk, { stream: true });\n drain(controller, false);\n }\n });\n}\n","/**\n * Workers AI text-to-image requests and answers, shared by both framework\n * modules.\n *\n * Two things about this catalog are easy to get wrong in one module and right\n * in the other, so neither module owns them: the flux-1 models take a two-key\n * subset of the common input shape, and the media type of a JSON answer is in\n * the bytes rather than in the model name (flux-1-schnell answers JPEG while\n * every other model here answers PNG).\n *\n * @experimental This surface is experimental and may change.\n */\n\nimport type { CompatWarning } from \"./chat-completions\";\n\n/**\n * `flux-1-schnell` takes `{ prompt, steps }` and nothing else — no size, no\n * seed, no guidance. Sending those anyway would be silently ignored, so they\n * come back as warnings instead.\n *\n * @see https://developers.cloudflare.com/workers-ai/models/flux-1-schnell/\n */\nconst PROMPT_AND_STEPS_ONLY = /^@cf\\/black-forest-labs\\/flux-1/;\n\n/**\n * The generation knobs Workers AI text-to-image models share, in this\n * package's own spelling. Each module maps its own call options onto them.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface ImageGenerationSettings {\n width?: number;\n height?: number;\n /** Diffusion steps. Sent as `num_steps`, or `steps` on the flux-1 models. */\n steps?: number;\n /** Classifier-free guidance scale. */\n guidance?: number;\n /** How strongly img2img transforms the input image, between 0 and 1. */\n strength?: number;\n negativePrompt?: string;\n seed?: number;\n /**\n * Whether the caller has a source image to attach. The field it goes in\n * differs per module, so only the warning is decided here.\n */\n sourceImage?: boolean;\n /** Whether the caller has an inpainting mask to attach. */\n mask?: boolean;\n}\n\n/**\n * A run-path image body with the knobs the model could not take reported.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface BuiltImageRequest {\n input: Record<string, unknown>;\n warnings: CompatWarning[];\n /**\n * The model takes `{ prompt, steps }` only, so the caller must not attach a\n * source image or a mask either.\n */\n minimal: boolean;\n}\n\n/**\n * Builds the run-path body for a text-to-image model: `prompt`, `width`,\n * `height`, `num_steps`, `guidance`, `strength`, `negative_prompt` and `seed`,\n * or the flux-1 two-key subset with a warning for everything dropped.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function buildImageInput(\n modelId: string,\n prompt: string,\n settings: ImageGenerationSettings\n): BuiltImageRequest {\n const warnings: CompatWarning[] = [];\n const input: Record<string, unknown> = { prompt };\n\n if (PROMPT_AND_STEPS_ONLY.test(modelId)) {\n if (settings.steps !== undefined) input.steps = settings.steps;\n for (const [feature, value] of [\n [\"size\", settings.width ?? settings.height],\n [\"seed\", settings.seed],\n [\"guidance\", settings.guidance],\n [\"negativePrompt\", settings.negativePrompt],\n [\"strength\", settings.strength],\n [\"files\", settings.sourceImage === true ? true : undefined],\n [\"mask\", settings.mask === true ? true : undefined]\n ] as const) {\n if (value !== undefined) {\n warnings.push({\n feature,\n message: `${modelId} takes only a prompt and steps.`\n });\n }\n }\n return { input, minimal: true, warnings };\n }\n\n if (settings.width !== undefined) input.width = settings.width;\n if (settings.height !== undefined) input.height = settings.height;\n if (settings.seed !== undefined) input.seed = settings.seed;\n if (settings.steps !== undefined) input.num_steps = settings.steps;\n if (settings.guidance !== undefined) input.guidance = settings.guidance;\n if (settings.strength !== undefined) input.strength = settings.strength;\n if (settings.negativePrompt !== undefined) {\n input.negative_prompt = settings.negativePrompt;\n }\n return { input, minimal: false, warnings };\n}\n\nconst JPEG_PREFIX = \"/9j/\";\nconst PNG_PREFIX = \"iVBORw0KGgo\";\nconst WEBP_PREFIX = \"UklGR\";\nconst GIF_PREFIX = \"R0lGOD\";\n\n/**\n * Sniffs an image media type from the head of its base64. The bytes decide,\n * never the model name: `flux-1-schnell` answers JPEG where every other model\n * in this catalog answers PNG.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function imageMediaTypeOf(base64: string): string {\n if (base64.startsWith(JPEG_PREFIX)) return \"image/jpeg\";\n if (base64.startsWith(PNG_PREFIX)) return \"image/png\";\n if (base64.startsWith(WEBP_PREFIX)) return \"image/webp\";\n if (base64.startsWith(GIF_PREFIX)) return \"image/gif\";\n return \"image/png\";\n}\n"],"mappings":"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"}
|