@cloudflare/tanstack-ai 0.1.9 → 0.1.10

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.
Files changed (84) hide show
  1. package/README.md +5 -5
  2. package/dist/adapters/anthropic.cjs +2 -3
  3. package/dist/adapters/anthropic.cjs.map +1 -1
  4. package/dist/adapters/anthropic.d.cts +4 -3
  5. package/dist/adapters/anthropic.d.mts +4 -3
  6. package/dist/adapters/anthropic.mjs +3 -3
  7. package/dist/adapters/anthropic.mjs.map +1 -1
  8. package/dist/adapters/gemini.cjs +2 -3
  9. package/dist/adapters/gemini.cjs.map +1 -1
  10. package/dist/adapters/gemini.d.cts +6 -6
  11. package/dist/adapters/gemini.d.mts +6 -6
  12. package/dist/adapters/gemini.mjs +4 -3
  13. package/dist/adapters/gemini.mjs.map +1 -1
  14. package/dist/adapters/grok.cjs +2 -6
  15. package/dist/adapters/grok.cjs.map +1 -1
  16. package/dist/adapters/grok.d.cts +5 -4
  17. package/dist/adapters/grok.d.mts +5 -4
  18. package/dist/adapters/grok.mjs +3 -6
  19. package/dist/adapters/grok.mjs.map +1 -1
  20. package/dist/adapters/openai.cjs +2 -3
  21. package/dist/adapters/openai.cjs.map +1 -1
  22. package/dist/adapters/openai.d.cts +6 -5
  23. package/dist/adapters/openai.d.mts +6 -5
  24. package/dist/adapters/openai.mjs +3 -3
  25. package/dist/adapters/openai.mjs.map +1 -1
  26. package/dist/adapters/openrouter.cjs +3 -17
  27. package/dist/adapters/openrouter.cjs.map +1 -1
  28. package/dist/adapters/openrouter.d.cts +4 -4
  29. package/dist/adapters/openrouter.d.mts +4 -4
  30. package/dist/adapters/openrouter.mjs +4 -17
  31. package/dist/adapters/openrouter.mjs.map +1 -1
  32. package/dist/adapters/workers-ai-image.cjs +5 -6
  33. package/dist/adapters/workers-ai-image.cjs.map +1 -1
  34. package/dist/adapters/workers-ai-image.d.cts +1 -1
  35. package/dist/adapters/workers-ai-image.d.mts +2 -2
  36. package/dist/adapters/workers-ai-image.mjs +5 -5
  37. package/dist/adapters/workers-ai-image.mjs.map +1 -1
  38. package/dist/adapters/workers-ai-summarize.cjs +3 -4
  39. package/dist/adapters/workers-ai-summarize.cjs.map +1 -1
  40. package/dist/adapters/workers-ai-summarize.d.cts +1 -1
  41. package/dist/adapters/workers-ai-summarize.d.mts +2 -2
  42. package/dist/adapters/workers-ai-summarize.mjs +3 -3
  43. package/dist/adapters/workers-ai-summarize.mjs.map +1 -1
  44. package/dist/adapters/workers-ai-transcription.cjs +5 -6
  45. package/dist/adapters/workers-ai-transcription.cjs.map +1 -1
  46. package/dist/adapters/workers-ai-transcription.d.cts +1 -1
  47. package/dist/adapters/workers-ai-transcription.d.mts +2 -2
  48. package/dist/adapters/workers-ai-transcription.mjs +5 -5
  49. package/dist/adapters/workers-ai-transcription.mjs.map +1 -1
  50. package/dist/adapters/workers-ai-tts.cjs +5 -6
  51. package/dist/adapters/workers-ai-tts.cjs.map +1 -1
  52. package/dist/adapters/workers-ai-tts.d.cts +1 -1
  53. package/dist/adapters/workers-ai-tts.d.mts +2 -2
  54. package/dist/adapters/workers-ai-tts.mjs +5 -5
  55. package/dist/adapters/workers-ai-tts.mjs.map +1 -1
  56. package/dist/adapters/workers-ai.cjs +520 -3
  57. package/dist/adapters/workers-ai.cjs.map +1 -0
  58. package/dist/adapters/workers-ai.d.cts +2 -2
  59. package/dist/adapters/workers-ai.d.mts +3 -3
  60. package/dist/adapters/workers-ai.mjs +56 -41
  61. package/dist/adapters/workers-ai.mjs.map +1 -1
  62. package/dist/{binary-p4H_N_3M.mjs → binary-B5YCVsro.mjs} +1 -1
  63. package/dist/{binary-C9FAYwZj.cjs.map → binary-B5YCVsro.mjs.map} +1 -1
  64. package/dist/{binary-C9FAYwZj.cjs → binary-CZhr1_2n.cjs} +1 -1
  65. package/dist/{binary-p4H_N_3M.mjs.map → binary-CZhr1_2n.cjs.map} +1 -1
  66. package/dist/{create-fetcher-CeUOJgrh.mjs → create-fetcher-BnSnCaHf.mjs} +1 -1
  67. package/dist/{create-fetcher-By-hTiT9.cjs.map → create-fetcher-BnSnCaHf.mjs.map} +1 -1
  68. package/dist/{create-fetcher-6p6heb85.d.mts → create-fetcher-Bp5yCNaO.d.cts} +1 -1
  69. package/dist/{create-fetcher-vAQ8WW-p.d.cts → create-fetcher-Bp5yCNaO.d.mts} +1 -1
  70. package/dist/{create-fetcher-By-hTiT9.cjs → create-fetcher-YVxWCTVL.cjs} +1 -1
  71. package/dist/{create-fetcher-CeUOJgrh.mjs.map → create-fetcher-YVxWCTVL.cjs.map} +1 -1
  72. package/dist/{defineProperty-CbyrzcbA.mjs → defineProperty-BC3bEcwq.mjs} +4 -4
  73. package/dist/{defineProperty-DQoAg20E.cjs → defineProperty-In8g9yAD.cjs} +4 -4
  74. package/dist/index.cjs +2 -3
  75. package/dist/index.d.cts +3 -3
  76. package/dist/index.d.mts +3 -3
  77. package/dist/index.mjs +2 -2
  78. package/dist/{workers-ai-rest-GKy2r7eG.mjs → workers-ai-rest-B6_yU35Q.mjs} +1 -1
  79. package/dist/{workers-ai-rest-CkNCtBwv.cjs.map → workers-ai-rest-B6_yU35Q.mjs.map} +1 -1
  80. package/dist/{workers-ai-rest-CkNCtBwv.cjs → workers-ai-rest-_MXOmyDs.cjs} +1 -1
  81. package/dist/{workers-ai-rest-GKy2r7eG.mjs.map → workers-ai-rest-_MXOmyDs.cjs.map} +1 -1
  82. package/package.json +9 -9
  83. package/dist/workers-ai-BOZ5iyhY.cjs +0 -521
  84. package/dist/workers-ai-BOZ5iyhY.cjs.map +0 -1
@@ -1,4 +1,521 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_workers_ai = require("../workers-ai-BOZ5iyhY.cjs");
3
- exports.WorkersAiTextAdapter = require_workers_ai.WorkersAiTextAdapter;
4
- exports.createWorkersAiChat = require_workers_ai.createWorkersAiChat;
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ const require_create_fetcher = require("../create-fetcher-YVxWCTVL.cjs");
25
+ const require_defineProperty = require("../defineProperty-In8g9yAD.cjs");
26
+ let _tanstack_ai = require("@tanstack/ai");
27
+ let _tanstack_ai_adapters = require("@tanstack/ai/adapters");
28
+ let openai = require("openai");
29
+ openai = __toESM(openai, 1);
30
+ //#region src/adapters/workers-ai.ts
31
+ function buildWorkersAiClient(config) {
32
+ require_create_fetcher.validateWorkersAiConfig(config);
33
+ const sessionHeaders = config.sessionAffinity ? { "x-session-affinity": config.sessionAffinity } : void 0;
34
+ if (require_create_fetcher.isDirectBindingConfig(config)) return new openai.default({
35
+ apiKey: "unused",
36
+ fetch: require_create_fetcher.createWorkersAiBindingFetch(config.binding, sessionHeaders ? { extraHeaders: sessionHeaders } : void 0)
37
+ });
38
+ if (require_create_fetcher.isDirectCredentialsConfig(config)) return new openai.default({
39
+ baseURL: `https://api.cloudflare.com/client/v4/accounts/${config.accountId}/ai/v1`,
40
+ apiKey: config.apiKey,
41
+ defaultHeaders: sessionHeaders
42
+ });
43
+ const gatewayConfig = config;
44
+ return new openai.default({
45
+ fetch: require_create_fetcher.createGatewayFetch("workers-ai", gatewayConfig, sessionHeaders),
46
+ apiKey: gatewayConfig.apiKey ?? "unused"
47
+ });
48
+ }
49
+ function extractTextContent(content) {
50
+ if (content === null) return "";
51
+ if (typeof content === "string") return content;
52
+ return content.flatMap((p) => p.type === "text" ? [p.content] : []).join("");
53
+ }
54
+ /**
55
+ * Convert a single TanStack AI {@link ContentPart} to the OpenAI Chat
56
+ * Completions multi-modal format.
57
+ *
58
+ * TODO: handle other content types (audio, video, document)
59
+ */
60
+ function convertContentPart(part) {
61
+ switch (part.type) {
62
+ case "text":
63
+ if (part.content) return {
64
+ type: "text",
65
+ text: part.content
66
+ };
67
+ return;
68
+ case "image": {
69
+ let url;
70
+ if (part.source.type === "data") url = part.source.value.startsWith("data:") ? part.source.value : `data:${part.source.mimeType};base64,${part.source.value}`;
71
+ else url = part.source.value;
72
+ return {
73
+ type: "image_url",
74
+ image_url: { url }
75
+ };
76
+ }
77
+ default:
78
+ console.warn(`[@cloudflare/tanstack-ai] Unsupported content part type "${part.type}" — skipping`);
79
+ return;
80
+ }
81
+ }
82
+ /**
83
+ * Build OpenAI-compatible user message content from TanStack AI content.
84
+ *
85
+ * If the content has only text parts, returns a plain string.
86
+ * If it includes image parts, returns an array of content parts in
87
+ * OpenAI's multi-modal format (text + image_url).
88
+ */
89
+ function buildUserContent(content) {
90
+ if (content === null) return "";
91
+ if (typeof content === "string") return content;
92
+ if (!content.some((p) => p.type === "image")) return content.flatMap((p) => p.type === "text" ? [p.content] : []).join("");
93
+ const parts = [];
94
+ for (const part of content) {
95
+ const converted = convertContentPart(part);
96
+ if (converted) parts.push(converted);
97
+ }
98
+ return parts;
99
+ }
100
+ function buildOpenAIMessages(systemPrompts, messages, options) {
101
+ const includeTools = options?.includeToolMessages ?? true;
102
+ const openAIMessages = [];
103
+ if (systemPrompts && systemPrompts.length > 0) openAIMessages.push({
104
+ role: "system",
105
+ content: systemPrompts.map((prompt) => typeof prompt === "string" ? prompt : prompt.content).join("\n")
106
+ });
107
+ for (const message of messages) if (message.role === "user") openAIMessages.push({
108
+ role: "user",
109
+ content: buildUserContent(message.content)
110
+ });
111
+ else if (message.role === "assistant") {
112
+ const assistantMessage = {
113
+ role: "assistant",
114
+ content: extractTextContent(message.content)
115
+ };
116
+ if (includeTools && message.toolCalls && message.toolCalls.length > 0) assistantMessage.tool_calls = message.toolCalls.map((tc) => ({
117
+ id: tc.id,
118
+ type: "function",
119
+ function: {
120
+ name: tc.function.name,
121
+ arguments: tc.function.arguments
122
+ }
123
+ }));
124
+ openAIMessages.push(assistantMessage);
125
+ } else if (includeTools && message.role === "tool") {
126
+ let toolContent;
127
+ if (typeof message.content === "string") try {
128
+ JSON.parse(message.content);
129
+ toolContent = message.content;
130
+ } catch {
131
+ toolContent = JSON.stringify(message.content);
132
+ }
133
+ else toolContent = JSON.stringify(message.content);
134
+ openAIMessages.push({
135
+ role: "tool",
136
+ tool_call_id: message.toolCallId || `tool_${crypto.randomUUID().slice(0, 8)}`,
137
+ content: toolContent
138
+ });
139
+ }
140
+ return openAIMessages;
141
+ }
142
+ function buildOpenAITools(tools) {
143
+ if (!tools) return void 0;
144
+ return tools.map((tool) => ({
145
+ type: "function",
146
+ function: {
147
+ name: tool.name,
148
+ description: tool.description,
149
+ parameters: tool.inputSchema
150
+ }
151
+ }));
152
+ }
153
+ function generateId(prefix = "chatcmpl") {
154
+ return `${prefix}-${crypto.randomUUID().replace(/-/g, "").slice(0, 16)}`;
155
+ }
156
+ function normalizeModelOptions(modelOptions) {
157
+ if (modelOptions === null || typeof modelOptions !== "object" || Array.isArray(modelOptions)) return {};
158
+ const out = {};
159
+ for (const [key, value] of Object.entries(modelOptions)) if (value !== void 0) out[key] = value;
160
+ return out;
161
+ }
162
+ var WorkersAiTextAdapter = class extends _tanstack_ai_adapters.BaseTextAdapter {
163
+ constructor(model, config) {
164
+ super({ apiKey: "unused" }, model);
165
+ require_defineProperty._defineProperty(this, "name", "workers-ai");
166
+ require_defineProperty._defineProperty(this, "client", void 0);
167
+ this.client = buildWorkersAiClient(config);
168
+ }
169
+ async *chatStream(options) {
170
+ const { systemPrompts, messages, tools, model, modelOptions } = options;
171
+ const extraBody = normalizeModelOptions(modelOptions);
172
+ const openAIMessages = buildOpenAIMessages(systemPrompts, messages);
173
+ const openAITools = buildOpenAITools(tools);
174
+ const timestamp = Date.now();
175
+ const runId = options.runId ?? generateId();
176
+ const threadId = options.threadId ?? generateId("thread");
177
+ const messageId = generateId();
178
+ let hasEmittedRunStarted = false;
179
+ let hasEmittedTextMessageStart = false;
180
+ let accumulatedContent = "";
181
+ let hasEmittedStepStarted = false;
182
+ let accumulatedReasoning = "";
183
+ const stepId = generateId();
184
+ let hasReceivedFinishReason = false;
185
+ const toolCallsInProgress = /* @__PURE__ */ new Map();
186
+ try {
187
+ let stream;
188
+ try {
189
+ stream = await this.client.chat.completions.create({
190
+ ...extraBody,
191
+ model: model ?? this.model,
192
+ messages: openAIMessages,
193
+ tools: openAITools,
194
+ stream: true,
195
+ stream_options: { include_usage: true }
196
+ });
197
+ } catch (streamError) {
198
+ console.warn("[tanstack-ai] Streaming failed, falling back to non-streaming:", streamError instanceof Error ? streamError.message : streamError);
199
+ const nonStreamResult = await this.client.chat.completions.create({
200
+ ...extraBody,
201
+ model: model ?? this.model,
202
+ messages: openAIMessages,
203
+ tools: openAITools
204
+ });
205
+ yield {
206
+ type: _tanstack_ai.EventType.RUN_STARTED,
207
+ runId,
208
+ threadId,
209
+ model: nonStreamResult.model || model || this.model,
210
+ timestamp
211
+ };
212
+ const msg = nonStreamResult.choices[0]?.message;
213
+ if (msg?.content) {
214
+ yield {
215
+ type: _tanstack_ai.EventType.TEXT_MESSAGE_START,
216
+ messageId,
217
+ model: nonStreamResult.model || model || this.model,
218
+ timestamp,
219
+ role: "assistant"
220
+ };
221
+ yield {
222
+ type: _tanstack_ai.EventType.TEXT_MESSAGE_CONTENT,
223
+ messageId,
224
+ model: nonStreamResult.model || model || this.model,
225
+ timestamp,
226
+ delta: msg.content,
227
+ content: msg.content
228
+ };
229
+ yield {
230
+ type: _tanstack_ai.EventType.TEXT_MESSAGE_END,
231
+ messageId,
232
+ model: nonStreamResult.model || model || this.model,
233
+ timestamp
234
+ };
235
+ }
236
+ if (msg?.tool_calls) for (const tc of msg.tool_calls) {
237
+ if (tc.type !== "function") continue;
238
+ const fn = tc.function;
239
+ let parsedInput = {};
240
+ try {
241
+ parsedInput = fn.arguments ? JSON.parse(fn.arguments) : {};
242
+ } catch {
243
+ parsedInput = {};
244
+ }
245
+ yield {
246
+ type: _tanstack_ai.EventType.TOOL_CALL_START,
247
+ toolCallId: tc.id,
248
+ toolCallName: fn.name,
249
+ toolName: fn.name,
250
+ model: nonStreamResult.model || model || this.model,
251
+ timestamp,
252
+ index: 0
253
+ };
254
+ yield {
255
+ type: _tanstack_ai.EventType.TOOL_CALL_END,
256
+ toolCallId: tc.id,
257
+ toolName: fn.name,
258
+ model: nonStreamResult.model || model || this.model,
259
+ timestamp,
260
+ input: parsedInput
261
+ };
262
+ }
263
+ const finishReason = nonStreamResult.choices[0]?.finish_reason;
264
+ yield {
265
+ type: _tanstack_ai.EventType.RUN_FINISHED,
266
+ runId,
267
+ threadId,
268
+ model: nonStreamResult.model || model || this.model,
269
+ timestamp,
270
+ usage: nonStreamResult.usage ? {
271
+ promptTokens: nonStreamResult.usage.prompt_tokens,
272
+ completionTokens: nonStreamResult.usage.completion_tokens,
273
+ totalTokens: nonStreamResult.usage.total_tokens
274
+ } : void 0,
275
+ finishReason: finishReason === "tool_calls" || finishReason === "function_call" ? "tool_calls" : finishReason ?? "stop"
276
+ };
277
+ return;
278
+ }
279
+ for await (const chunk of stream) {
280
+ if (!chunk.choices || chunk.choices.length === 0) continue;
281
+ const choice = chunk.choices[0];
282
+ if (!choice) continue;
283
+ if (!hasEmittedRunStarted) {
284
+ hasEmittedRunStarted = true;
285
+ yield {
286
+ type: _tanstack_ai.EventType.RUN_STARTED,
287
+ runId,
288
+ threadId,
289
+ model: chunk.model || model || this.model,
290
+ timestamp
291
+ };
292
+ }
293
+ const delta = choice.delta;
294
+ const reasoningContent = delta.reasoning_content ?? delta.reasoning;
295
+ if (reasoningContent) {
296
+ if (!hasEmittedStepStarted) {
297
+ hasEmittedStepStarted = true;
298
+ yield {
299
+ type: _tanstack_ai.EventType.STEP_STARTED,
300
+ stepName: "thinking",
301
+ stepId,
302
+ stepType: "thinking",
303
+ model: chunk.model || model || this.model,
304
+ timestamp
305
+ };
306
+ }
307
+ accumulatedReasoning += reasoningContent;
308
+ yield {
309
+ type: _tanstack_ai.EventType.STEP_FINISHED,
310
+ stepName: "thinking",
311
+ stepId,
312
+ delta: reasoningContent,
313
+ content: accumulatedReasoning,
314
+ model: chunk.model || model || this.model,
315
+ timestamp
316
+ };
317
+ }
318
+ if (delta.content) {
319
+ if (!hasEmittedTextMessageStart) {
320
+ hasEmittedTextMessageStart = true;
321
+ yield {
322
+ type: _tanstack_ai.EventType.TEXT_MESSAGE_START,
323
+ messageId,
324
+ model: chunk.model || model || this.model,
325
+ timestamp,
326
+ role: "assistant"
327
+ };
328
+ }
329
+ accumulatedContent += delta.content;
330
+ yield {
331
+ type: _tanstack_ai.EventType.TEXT_MESSAGE_CONTENT,
332
+ messageId,
333
+ model: chunk.model || model || this.model,
334
+ timestamp,
335
+ delta: delta.content,
336
+ content: accumulatedContent
337
+ };
338
+ }
339
+ if (delta.tool_calls) for (const toolCallDelta of delta.tool_calls) {
340
+ const index = toolCallDelta.index;
341
+ if (!toolCallsInProgress.has(index)) toolCallsInProgress.set(index, {
342
+ id: generateId("chatcmpl-tool"),
343
+ name: toolCallDelta.function?.name || "",
344
+ arguments: "",
345
+ started: false,
346
+ emittedArgsLength: 0
347
+ });
348
+ const toolCall = toolCallsInProgress.get(index);
349
+ if (toolCallDelta.function?.name) toolCall.name = toolCallDelta.function.name;
350
+ if (toolCallDelta.function?.arguments) toolCall.arguments += toolCallDelta.function.arguments;
351
+ if (toolCall.id && toolCall.name && !toolCall.started) {
352
+ toolCall.started = true;
353
+ yield {
354
+ type: _tanstack_ai.EventType.TOOL_CALL_START,
355
+ toolCallId: toolCall.id,
356
+ toolCallName: toolCall.name,
357
+ toolName: toolCall.name,
358
+ model: chunk.model || model || this.model,
359
+ timestamp,
360
+ index
361
+ };
362
+ }
363
+ if (toolCall.started && toolCall.arguments.length > toolCall.emittedArgsLength) {
364
+ const argsDelta = toolCall.arguments.slice(toolCall.emittedArgsLength);
365
+ toolCall.emittedArgsLength = toolCall.arguments.length;
366
+ yield {
367
+ type: _tanstack_ai.EventType.TOOL_CALL_ARGS,
368
+ toolCallId: toolCall.id,
369
+ model: chunk.model || model || this.model,
370
+ timestamp,
371
+ delta: argsDelta
372
+ };
373
+ }
374
+ }
375
+ if (choice.finish_reason) {
376
+ hasReceivedFinishReason = true;
377
+ if (choice.finish_reason === "tool_calls" || toolCallsInProgress.size > 0) for (const [, toolCall] of toolCallsInProgress) {
378
+ let parsedInput = {};
379
+ try {
380
+ parsedInput = toolCall.arguments ? JSON.parse(toolCall.arguments) : {};
381
+ } catch {
382
+ parsedInput = {};
383
+ }
384
+ yield {
385
+ type: _tanstack_ai.EventType.TOOL_CALL_END,
386
+ toolCallId: toolCall.id,
387
+ toolName: toolCall.name,
388
+ model: chunk.model || model || this.model,
389
+ timestamp,
390
+ input: parsedInput
391
+ };
392
+ }
393
+ const computedFinishReason = choice.finish_reason === "tool_calls" || choice.finish_reason === "function_call" || toolCallsInProgress.size > 0 ? "tool_calls" : choice.finish_reason;
394
+ if (hasEmittedTextMessageStart) yield {
395
+ type: _tanstack_ai.EventType.TEXT_MESSAGE_END,
396
+ messageId,
397
+ model: chunk.model || model || this.model,
398
+ timestamp
399
+ };
400
+ yield {
401
+ type: _tanstack_ai.EventType.RUN_FINISHED,
402
+ runId,
403
+ threadId,
404
+ model: chunk.model || model || this.model,
405
+ timestamp,
406
+ usage: chunk.usage ? {
407
+ promptTokens: chunk.usage.prompt_tokens,
408
+ completionTokens: chunk.usage.completion_tokens,
409
+ totalTokens: chunk.usage.total_tokens
410
+ } : void 0,
411
+ finishReason: computedFinishReason
412
+ };
413
+ }
414
+ }
415
+ if (hasEmittedRunStarted && !hasReceivedFinishReason) {
416
+ console.warn("[tanstack-ai] Stream ended without finish_reason — possible truncation or connection drop");
417
+ for (const [, toolCall] of toolCallsInProgress) if (toolCall.started) {
418
+ let parsedInput = {};
419
+ try {
420
+ parsedInput = toolCall.arguments ? JSON.parse(toolCall.arguments) : {};
421
+ } catch {
422
+ parsedInput = {};
423
+ }
424
+ yield {
425
+ type: _tanstack_ai.EventType.TOOL_CALL_END,
426
+ toolCallId: toolCall.id,
427
+ toolName: toolCall.name,
428
+ model: model ?? this.model,
429
+ timestamp,
430
+ input: parsedInput
431
+ };
432
+ }
433
+ if (hasEmittedTextMessageStart) yield {
434
+ type: _tanstack_ai.EventType.TEXT_MESSAGE_END,
435
+ messageId,
436
+ model: model ?? this.model,
437
+ timestamp
438
+ };
439
+ yield {
440
+ type: _tanstack_ai.EventType.RUN_FINISHED,
441
+ runId,
442
+ threadId,
443
+ model: model ?? this.model,
444
+ timestamp,
445
+ finishReason: "stop"
446
+ };
447
+ }
448
+ } catch (error) {
449
+ const message = error instanceof Error ? error.message : String(error);
450
+ const code = error instanceof Error ? error.code : void 0;
451
+ if (!hasEmittedRunStarted) yield {
452
+ type: _tanstack_ai.EventType.RUN_STARTED,
453
+ runId,
454
+ threadId,
455
+ model: model ?? this.model,
456
+ timestamp
457
+ };
458
+ yield {
459
+ type: _tanstack_ai.EventType.RUN_ERROR,
460
+ runId,
461
+ threadId,
462
+ model: model ?? this.model,
463
+ timestamp,
464
+ message: message || "Unknown error",
465
+ code,
466
+ error: {
467
+ message: message || "Unknown error",
468
+ code
469
+ }
470
+ };
471
+ }
472
+ }
473
+ async structuredOutput(options) {
474
+ const { outputSchema, chatOptions } = options;
475
+ const { systemPrompts, messages, model, modelOptions } = chatOptions;
476
+ const extraBody = normalizeModelOptions(modelOptions);
477
+ const openAIMessages = buildOpenAIMessages(systemPrompts, messages, { includeToolMessages: false });
478
+ const response = await this.client.chat.completions.create({
479
+ ...extraBody,
480
+ model: model ?? this.model,
481
+ messages: openAIMessages,
482
+ stream: false,
483
+ response_format: {
484
+ type: "json_schema",
485
+ json_schema: {
486
+ name: "structured_output",
487
+ strict: true,
488
+ schema: outputSchema
489
+ }
490
+ }
491
+ });
492
+ const choice = response.choices?.[0];
493
+ if (!choice) throw new Error(`Workers AI structured output returned no choices: ${JSON.stringify(response)}`);
494
+ const rawContent = choice.message?.content ?? "";
495
+ let data;
496
+ let rawText;
497
+ if (typeof rawContent === "string") {
498
+ rawText = rawContent;
499
+ try {
500
+ data = JSON.parse(rawText);
501
+ } catch {
502
+ data = rawText;
503
+ }
504
+ } else {
505
+ data = rawContent;
506
+ rawText = JSON.stringify(rawContent);
507
+ }
508
+ return {
509
+ data,
510
+ rawText
511
+ };
512
+ }
513
+ };
514
+ function createWorkersAiChat(model, config) {
515
+ return new WorkersAiTextAdapter(model, config);
516
+ }
517
+ //#endregion
518
+ exports.WorkersAiTextAdapter = WorkersAiTextAdapter;
519
+ exports.createWorkersAiChat = createWorkersAiChat;
520
+
521
+ //# sourceMappingURL=workers-ai.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workers-ai.cjs","names":["isDirectBindingConfig","OpenAI","createWorkersAiBindingFetch","isDirectCredentialsConfig","createGatewayFetch","BaseTextAdapter","EventType"],"sources":["../../src/adapters/workers-ai.ts"],"sourcesContent":["import type { AiModels, BaseAiTextGeneration } from \"@cloudflare/workers-types\";\nimport type {\n\tContentPart,\n\tModelMessage,\n\tStreamChunk,\n\tSystemPrompt,\n\tTextOptions,\n} from \"@tanstack/ai\";\nimport { EventType } from \"@tanstack/ai\";\nimport {\n\tBaseTextAdapter,\n\ttype StructuredOutputOptions,\n\ttype StructuredOutputResult,\n} from \"@tanstack/ai/adapters\";\nimport OpenAI from \"openai\";\nimport {\n\ttype WorkersAiAdapterConfig,\n\ttype AiGatewayAdapterConfig,\n\tcreateGatewayFetch,\n\tcreateWorkersAiBindingFetch,\n\tisDirectBindingConfig,\n\tisDirectCredentialsConfig,\n\tvalidateWorkersAiConfig,\n} from \"../utils/create-fetcher\";\n\n// ---------------------------------------------------------------------------\n// Model types derived from @cloudflare/workers-types\n// ---------------------------------------------------------------------------\n\nexport type WorkersAiTextModel =\n\t| {\n\t\t\t[K in keyof AiModels]: AiModels[K] extends BaseAiTextGeneration ? K : never;\n\t }[keyof AiModels]\n\t| (string & {});\n\n// ---------------------------------------------------------------------------\n// Provider-specific options forwarded to Workers AI's chat completions inputs.\n//\n// These correspond to fields on `ChatCompletionsCommonOptions` in\n// `@cloudflare/workers-types`. They are passed verbatim into the request body\n// sent to the Workers AI binding / REST endpoint / AI Gateway, and ultimately\n// land on the `inputs` object of `binding.run(model, inputs)`.\n//\n// Pass via `modelOptions` on a per-call basis:\n//\n// await adapter.chatStream({\n// model, messages,\n// modelOptions: {\n// reasoning_effort: \"low\",\n// chat_template_kwargs: { enable_thinking: false },\n// },\n// });\n// ---------------------------------------------------------------------------\n\nexport interface WorkersAiTextModelOptions {\n\t/**\n\t * Controls the reasoning budget for reasoning-capable models\n\t * (e.g. `@cf/zai-org/glm-4.7-flash`, `@cf/moonshotai/kimi-k2.7-code`,\n\t * `@cf/openai/gpt-oss-120b`).\n\t *\n\t * `null` is a valid value and disables reasoning for models that support it.\n\t */\n\treasoning_effort?: \"low\" | \"medium\" | \"high\" | null;\n\t/**\n\t * Chat-template overrides for reasoning-capable models that expose\n\t * thinking toggles (e.g. GLM, Kimi).\n\t */\n\tchat_template_kwargs?: {\n\t\t/** Whether to enable reasoning. Enabled by default on reasoning models. */\n\t\tenable_thinking?: boolean;\n\t\t/** If false, preserves reasoning context between turns. */\n\t\tclear_thinking?: boolean;\n\t};\n\t/**\n\t * Escape hatch for other Workers AI inputs-level parameters.\n\t *\n\t * Keys placed here are merged into the outbound request body and forwarded\n\t * to the underlying transport (binding / REST / gateway). Only fields that\n\t * the binding shim knows about are extracted for direct `env.AI` bindings;\n\t * everything is passed through on REST and gateway paths.\n\t */\n\t[key: string]: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers: build the right OpenAI client depending on config mode\n// ---------------------------------------------------------------------------\n\nfunction buildWorkersAiClient(config: WorkersAiAdapterConfig): OpenAI {\n\tvalidateWorkersAiConfig(config);\n\n\tconst sessionHeaders: Record<string, string> | undefined = config.sessionAffinity\n\t\t? { \"x-session-affinity\": config.sessionAffinity }\n\t\t: undefined;\n\n\tif (isDirectBindingConfig(config)) {\n\t\t// Plain binding mode: shim translates OpenAI fetch calls to env.AI.run()\n\t\treturn new OpenAI({\n\t\t\tapiKey: \"unused\",\n\t\t\tfetch: createWorkersAiBindingFetch(\n\t\t\t\tconfig.binding,\n\t\t\t\tsessionHeaders ? { extraHeaders: sessionHeaders } : undefined,\n\t\t\t),\n\t\t});\n\t}\n\n\tif (isDirectCredentialsConfig(config)) {\n\t\t// Plain REST mode: point OpenAI SDK at Workers AI's OpenAI-compatible endpoint\n\t\treturn new OpenAI({\n\t\t\tbaseURL: `https://api.cloudflare.com/client/v4/accounts/${config.accountId}/ai/v1`,\n\t\t\tapiKey: config.apiKey,\n\t\t\tdefaultHeaders: sessionHeaders,\n\t\t});\n\t}\n\n\t// Gateway mode (existing): use createGatewayFetch\n\tconst gatewayConfig = config as AiGatewayAdapterConfig;\n\treturn new OpenAI({\n\t\tfetch: createGatewayFetch(\"workers-ai\", gatewayConfig, sessionHeaders),\n\t\tapiKey: gatewayConfig.apiKey ?? \"unused\",\n\t});\n}\n\n// ---------------------------------------------------------------------------\n// Shared message-building helpers\n// ---------------------------------------------------------------------------\n\nfunction extractTextContent(content: ModelMessage[\"content\"]): string {\n\tif (content === null) return \"\";\n\tif (typeof content === \"string\") return content;\n\treturn content.flatMap((p) => (p.type === \"text\" ? [p.content] : [])).join(\"\");\n}\n\n/**\n * Convert a single TanStack AI {@link ContentPart} to the OpenAI Chat\n * Completions multi-modal format.\n *\n * TODO: handle other content types (audio, video, document)\n */\nfunction convertContentPart(part: ContentPart): OpenAI.Chat.ChatCompletionContentPart | undefined {\n\tswitch (part.type) {\n\t\tcase \"text\":\n\t\t\tif (part.content) {\n\t\t\t\treturn { type: \"text\", text: part.content };\n\t\t\t}\n\t\t\treturn undefined;\n\t\tcase \"image\": {\n\t\t\tlet url: string;\n\t\t\tif (part.source.type === \"data\") {\n\t\t\t\turl = part.source.value.startsWith(\"data:\")\n\t\t\t\t\t? part.source.value\n\t\t\t\t\t: `data:${part.source.mimeType};base64,${part.source.value}`;\n\t\t\t} else {\n\t\t\t\turl = part.source.value;\n\t\t\t}\n\t\t\treturn { type: \"image_url\", image_url: { url } };\n\t\t}\n\t\tdefault:\n\t\t\t// audio, video, document — not supported for now\n\t\t\tconsole.warn(\n\t\t\t\t`[@cloudflare/tanstack-ai] Unsupported content part type \"${part.type}\" — skipping`,\n\t\t\t);\n\t\t\treturn undefined;\n\t}\n}\n\n/**\n * Build OpenAI-compatible user message content from TanStack AI content.\n *\n * If the content has only text parts, returns a plain string.\n * If it includes image parts, returns an array of content parts in\n * OpenAI's multi-modal format (text + image_url).\n */\nfunction buildUserContent(\n\tcontent: ModelMessage[\"content\"],\n): string | OpenAI.Chat.ChatCompletionContentPart[] {\n\tif (content === null) return \"\";\n\tif (typeof content === \"string\") return content;\n\n\tconst hasImages = content.some((p) => p.type === \"image\");\n\tif (!hasImages) {\n\t\treturn content.flatMap((p) => (p.type === \"text\" ? [p.content] : [])).join(\"\");\n\t}\n\n\tconst parts: OpenAI.Chat.ChatCompletionContentPart[] = [];\n\tfor (const part of content) {\n\t\tconst converted = convertContentPart(part);\n\t\tif (converted) {\n\t\t\tparts.push(converted);\n\t\t}\n\t}\n\treturn parts;\n}\n\nfunction buildOpenAIMessages(\n\tsystemPrompts: SystemPrompt[] | undefined,\n\tmessages: ModelMessage[],\n\toptions?: { includeToolMessages?: boolean },\n): OpenAI.Chat.ChatCompletionMessageParam[] {\n\tconst includeTools = options?.includeToolMessages ?? true;\n\tconst openAIMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [];\n\n\tif (systemPrompts && systemPrompts.length > 0) {\n\t\topenAIMessages.push({\n\t\t\trole: \"system\",\n\t\t\tcontent: systemPrompts\n\t\t\t\t.map((prompt) => (typeof prompt === \"string\" ? prompt : prompt.content))\n\t\t\t\t.join(\"\\n\"),\n\t\t});\n\t}\n\n\tfor (const message of messages) {\n\t\tif (message.role === \"user\") {\n\t\t\topenAIMessages.push({\n\t\t\t\trole: \"user\",\n\t\t\t\tcontent: buildUserContent(message.content),\n\t\t\t});\n\t\t} else if (message.role === \"assistant\") {\n\t\t\tconst assistantMessage: OpenAI.Chat.ChatCompletionAssistantMessageParam = {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tcontent: extractTextContent(message.content),\n\t\t\t};\n\t\t\tif (includeTools && message.toolCalls && message.toolCalls.length > 0) {\n\t\t\t\tassistantMessage.tool_calls = message.toolCalls.map((tc) => ({\n\t\t\t\t\tid: tc.id,\n\t\t\t\t\ttype: \"function\" as const,\n\t\t\t\t\tfunction: {\n\t\t\t\t\t\tname: tc.function.name,\n\t\t\t\t\t\targuments: tc.function.arguments,\n\t\t\t\t\t},\n\t\t\t\t}));\n\t\t\t}\n\t\t\topenAIMessages.push(assistantMessage);\n\t\t} else if (includeTools && message.role === \"tool\") {\n\t\t\tlet toolContent: string;\n\t\t\tif (typeof message.content === \"string\") {\n\t\t\t\ttry {\n\t\t\t\t\tJSON.parse(message.content);\n\t\t\t\t\ttoolContent = message.content;\n\t\t\t\t} catch {\n\t\t\t\t\ttoolContent = JSON.stringify(message.content);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttoolContent = JSON.stringify(message.content);\n\t\t\t}\n\t\t\topenAIMessages.push({\n\t\t\t\trole: \"tool\",\n\t\t\t\ttool_call_id: message.toolCallId || `tool_${crypto.randomUUID().slice(0, 8)}`,\n\t\t\t\tcontent: toolContent,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn openAIMessages;\n}\n\nfunction buildOpenAITools(\n\ttools: Array<{ name: string; description: string; inputSchema?: unknown }> | undefined,\n): OpenAI.Chat.ChatCompletionTool[] | undefined {\n\tif (!tools) return undefined;\n\treturn tools.map((tool) => ({\n\t\ttype: \"function\" as const,\n\t\tfunction: {\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tparameters: tool.inputSchema as Record<string, unknown>,\n\t\t},\n\t}));\n}\n\n// ---------------------------------------------------------------------------\n// ID generation\n// ---------------------------------------------------------------------------\n\nfunction generateId(prefix = \"chatcmpl\"): string {\n\treturn `${prefix}-${crypto.randomUUID().replace(/-/g, \"\").slice(0, 16)}`;\n}\n\n// ---------------------------------------------------------------------------\n// modelOptions normalization\n//\n// Users pass Workers AI-specific chat params (e.g. `reasoning_effort`,\n// `chat_template_kwargs`) via `modelOptions`. We merge these into the outbound\n// request body so they reach the binding / REST / gateway transports.\n//\n// Spread order matters: these go FIRST in the request body so that TanStack-AI\n// managed fields (`model`, `messages`, `temperature`, `max_tokens`, `stream`,\n// `tools`, `response_format`, ...) always win if a user accidentally sets\n// them both at the top level and inside `modelOptions`.\n//\n// `undefined` values are stripped so that JSON.stringify (and our binding shim\n// which does `!== undefined` checks) see them as absent. `null` values are\n// preserved — they're meaningful for fields like `reasoning_effort: null`\n// which explicitly disables reasoning on some models.\n// ---------------------------------------------------------------------------\nfunction normalizeModelOptions(\n\tmodelOptions: WorkersAiTextModelOptions | undefined,\n): Record<string, unknown> {\n\t// Guard against runtime misuse. TanStack AI types this as an object, but\n\t// users can always bypass with `as any`. `Object.entries` on a string\n\t// surprisingly returns per-character tuples (e.g. `Object.entries(\"ab\") →\n\t// [[\"0\",\"a\"],[\"1\",\"b\"]]`), which would leak spurious keys into the body.\n\t// Arrays similarly become index-keyed. Only accept plain objects.\n\tif (modelOptions === null || typeof modelOptions !== \"object\" || Array.isArray(modelOptions)) {\n\t\treturn {};\n\t}\n\tconst out: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(modelOptions)) {\n\t\tif (value !== undefined) out[key] = value;\n\t}\n\treturn out;\n}\n\n// ---------------------------------------------------------------------------\n// WorkersAiTextAdapter: chat / structured output via OpenAI Chat Completions\n// ---------------------------------------------------------------------------\n\nexport class WorkersAiTextAdapter<TModel extends WorkersAiTextModel> extends BaseTextAdapter<\n\tTModel,\n\tWorkersAiTextModelOptions,\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any -- remaining BaseTextAdapter generics are opaque\n\tany,\n\tany\n> {\n\tname = \"workers-ai\" as const;\n\n\tprivate client: OpenAI;\n\n\tconstructor(model: TModel, config: WorkersAiAdapterConfig) {\n\t\tsuper({ apiKey: \"unused\" }, model);\n\t\tthis.client = buildWorkersAiClient(config);\n\t}\n\n\tasync *chatStream(options: TextOptions<WorkersAiTextModelOptions>): AsyncIterable<StreamChunk> {\n\t\tconst { systemPrompts, messages, tools, model, modelOptions } = options;\n\t\tconst extraBody = normalizeModelOptions(modelOptions);\n\n\t\tconst openAIMessages = buildOpenAIMessages(systemPrompts, messages);\n\t\tconst openAITools = buildOpenAITools(tools);\n\n\t\tconst timestamp = Date.now();\n\t\tconst runId = options.runId ?? generateId();\n\t\tconst threadId = options.threadId ?? generateId(\"thread\");\n\t\tconst messageId = generateId();\n\t\tlet hasEmittedRunStarted = false;\n\t\tlet hasEmittedTextMessageStart = false;\n\t\tlet accumulatedContent = \"\";\n\t\tlet hasEmittedStepStarted = false;\n\t\tlet accumulatedReasoning = \"\";\n\t\tconst stepId = generateId();\n\t\tlet hasReceivedFinishReason = false;\n\t\tconst toolCallsInProgress = new Map<\n\t\t\tnumber,\n\t\t\t{\n\t\t\t\tid: string;\n\t\t\t\tname: string;\n\t\t\t\targuments: string;\n\t\t\t\tstarted: boolean;\n\t\t\t\t/** Number of `arguments` chars already forwarded via TOOL_CALL_ARGS. */\n\t\t\t\temittedArgsLength: number;\n\t\t\t}\n\t\t>();\n\n\t\ttry {\n\t\t\tlet stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>;\n\t\t\ttry {\n\t\t\t\tstream = await this.client.chat.completions.create({\n\t\t\t\t\t...extraBody,\n\t\t\t\t\tmodel: model ?? this.model,\n\t\t\t\t\tmessages: openAIMessages,\n\t\t\t\t\ttools: openAITools,\n\t\t\t\t\tstream: true,\n\t\t\t\t\tstream_options: { include_usage: true },\n\t\t\t\t} as OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming);\n\t\t\t} catch (streamError: unknown) {\n\t\t\t\t// Some models (e.g. GPT-OSS) don't support streaming via the REST API.\n\t\t\t\t// Fall back to a non-streaming call and yield the result as a single chunk.\n\t\t\t\tconsole.warn(\n\t\t\t\t\t\"[tanstack-ai] Streaming failed, falling back to non-streaming:\",\n\t\t\t\t\tstreamError instanceof Error ? streamError.message : streamError,\n\t\t\t\t);\n\t\t\t\tconst nonStreamResult = await this.client.chat.completions.create({\n\t\t\t\t\t...extraBody,\n\t\t\t\t\tmodel: model ?? this.model,\n\t\t\t\t\tmessages: openAIMessages,\n\t\t\t\t\ttools: openAITools,\n\t\t\t\t} as OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming);\n\n\t\t\t\tyield {\n\t\t\t\t\ttype: EventType.RUN_STARTED,\n\t\t\t\t\trunId,\n\t\t\t\t\tthreadId,\n\t\t\t\t\tmodel: nonStreamResult.model || model || this.model,\n\t\t\t\t\ttimestamp,\n\t\t\t\t} satisfies StreamChunk;\n\n\t\t\t\tconst msg = nonStreamResult.choices[0]?.message;\n\t\t\t\tif (msg?.content) {\n\t\t\t\t\tyield {\n\t\t\t\t\t\ttype: EventType.TEXT_MESSAGE_START,\n\t\t\t\t\t\tmessageId,\n\t\t\t\t\t\tmodel: nonStreamResult.model || model || this.model,\n\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t\tyield {\n\t\t\t\t\t\ttype: EventType.TEXT_MESSAGE_CONTENT,\n\t\t\t\t\t\tmessageId,\n\t\t\t\t\t\tmodel: nonStreamResult.model || model || this.model,\n\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\tdelta: msg.content,\n\t\t\t\t\t\tcontent: msg.content,\n\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t\tyield {\n\t\t\t\t\t\ttype: EventType.TEXT_MESSAGE_END,\n\t\t\t\t\t\tmessageId,\n\t\t\t\t\t\tmodel: nonStreamResult.model || model || this.model,\n\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t}\n\n\t\t\t\tif (msg?.tool_calls) {\n\t\t\t\t\tfor (const tc of msg.tool_calls) {\n\t\t\t\t\t\tif (tc.type !== \"function\") continue;\n\t\t\t\t\t\tconst fn = tc.function;\n\t\t\t\t\t\tlet parsedInput: unknown = {};\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tparsedInput = fn.arguments ? JSON.parse(fn.arguments) : {};\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tparsedInput = {};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\ttype: EventType.TOOL_CALL_START,\n\t\t\t\t\t\t\ttoolCallId: tc.id,\n\t\t\t\t\t\t\ttoolCallName: fn.name,\n\t\t\t\t\t\t\ttoolName: fn.name,\n\t\t\t\t\t\t\tmodel: nonStreamResult.model || model || this.model,\n\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\tindex: 0,\n\t\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\ttype: EventType.TOOL_CALL_END,\n\t\t\t\t\t\t\ttoolCallId: tc.id,\n\t\t\t\t\t\t\ttoolName: fn.name,\n\t\t\t\t\t\t\tmodel: nonStreamResult.model || model || this.model,\n\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\tinput: parsedInput,\n\t\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst finishReason = nonStreamResult.choices[0]?.finish_reason;\n\t\t\t\tyield {\n\t\t\t\t\ttype: EventType.RUN_FINISHED,\n\t\t\t\t\trunId,\n\t\t\t\t\tthreadId,\n\t\t\t\t\tmodel: nonStreamResult.model || model || this.model,\n\t\t\t\t\ttimestamp,\n\t\t\t\t\tusage: nonStreamResult.usage\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tpromptTokens: nonStreamResult.usage.prompt_tokens,\n\t\t\t\t\t\t\t\tcompletionTokens: nonStreamResult.usage.completion_tokens,\n\t\t\t\t\t\t\t\ttotalTokens: nonStreamResult.usage.total_tokens,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\tfinishReason:\n\t\t\t\t\t\tfinishReason === \"tool_calls\" || finishReason === \"function_call\"\n\t\t\t\t\t\t\t? \"tool_calls\"\n\t\t\t\t\t\t\t: ((finishReason as \"stop\" | \"length\" | \"content_filter\") ?? \"stop\"),\n\t\t\t\t} satisfies StreamChunk;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor await (const chunk of stream) {\n\t\t\t\tif (!chunk.choices || chunk.choices.length === 0) continue;\n\t\t\t\tconst choice = chunk.choices[0];\n\t\t\t\tif (!choice) continue;\n\n\t\t\t\t// Emit RUN_STARTED on first chunk\n\t\t\t\tif (!hasEmittedRunStarted) {\n\t\t\t\t\thasEmittedRunStarted = true;\n\t\t\t\t\tyield {\n\t\t\t\t\t\ttype: EventType.RUN_STARTED,\n\t\t\t\t\t\trunId,\n\t\t\t\t\t\tthreadId,\n\t\t\t\t\t\tmodel: chunk.model || model || this.model,\n\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t}\n\n\t\t\t\tconst delta = choice.delta;\n\n\t\t\t\t// Reasoning content (used by models like QwQ, DeepSeek R1, Kimi K2.5)\n\t\t\t\t// The OpenAI SDK doesn't type this field, but models send it as an extension.\n\t\t\t\tconst reasoningContent = ((delta as Record<string, unknown>).reasoning_content ??\n\t\t\t\t\t(delta as Record<string, unknown>).reasoning) as string | undefined;\n\t\t\t\tif (reasoningContent) {\n\t\t\t\t\t// RUN_STARTED is already guaranteed by the guard above\n\t\t\t\t\tif (!hasEmittedStepStarted) {\n\t\t\t\t\t\thasEmittedStepStarted = true;\n\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\ttype: EventType.STEP_STARTED,\n\t\t\t\t\t\t\tstepName: \"thinking\",\n\t\t\t\t\t\t\tstepId,\n\t\t\t\t\t\t\tstepType: \"thinking\",\n\t\t\t\t\t\t\tmodel: chunk.model || model || this.model,\n\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t\t}\n\t\t\t\t\taccumulatedReasoning += reasoningContent;\n\t\t\t\t\t// TODO: TanStack AI's StreamProcessor currently treats STEP_FINISHED as an\n\t\t\t\t\t// incremental reasoning event (with `delta` + accumulated `content`), so we\n\t\t\t\t\t// emit one per token. If TanStack AI adds a dedicated STEP_CONTENT event\n\t\t\t\t\t// type, this should be updated to emit STEP_CONTENT per token and a single\n\t\t\t\t\t// STEP_FINISHED when reasoning ends (i.e. when the first non-reasoning\n\t\t\t\t\t// content or finish_reason arrives).\n\t\t\t\t\tyield {\n\t\t\t\t\t\ttype: EventType.STEP_FINISHED,\n\t\t\t\t\t\tstepName: \"thinking\",\n\t\t\t\t\t\tstepId,\n\t\t\t\t\t\tdelta: reasoningContent,\n\t\t\t\t\t\tcontent: accumulatedReasoning,\n\t\t\t\t\t\tmodel: chunk.model || model || this.model,\n\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t}\n\n\t\t\t\t// Text content\n\t\t\t\tif (delta.content) {\n\t\t\t\t\tif (!hasEmittedTextMessageStart) {\n\t\t\t\t\t\thasEmittedTextMessageStart = true;\n\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\ttype: EventType.TEXT_MESSAGE_START,\n\t\t\t\t\t\t\tmessageId,\n\t\t\t\t\t\t\tmodel: chunk.model || model || this.model,\n\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t\t}\n\n\t\t\t\t\taccumulatedContent += delta.content;\n\t\t\t\t\tyield {\n\t\t\t\t\t\ttype: EventType.TEXT_MESSAGE_CONTENT,\n\t\t\t\t\t\tmessageId,\n\t\t\t\t\t\tmodel: chunk.model || model || this.model,\n\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\tdelta: delta.content,\n\t\t\t\t\t\tcontent: accumulatedContent,\n\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t}\n\n\t\t\t\t// Tool calls\n\t\t\t\tif (delta.tool_calls) {\n\t\t\t\t\tfor (const toolCallDelta of delta.tool_calls) {\n\t\t\t\t\t\tconst index = toolCallDelta.index;\n\n\t\t\t\t\t\tif (!toolCallsInProgress.has(index)) {\n\t\t\t\t\t\t\t// Always generate a unique ID per tool call index.\n\t\t\t\t\t\t\t// The backend may send the same ID for multiple tool calls,\n\t\t\t\t\t\t\t// so we cannot trust toolCallDelta.id to be unique.\n\t\t\t\t\t\t\ttoolCallsInProgress.set(index, {\n\t\t\t\t\t\t\t\tid: generateId(\"chatcmpl-tool\"),\n\t\t\t\t\t\t\t\tname: toolCallDelta.function?.name || \"\",\n\t\t\t\t\t\t\t\targuments: \"\",\n\t\t\t\t\t\t\t\tstarted: false,\n\t\t\t\t\t\t\t\temittedArgsLength: 0,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst toolCall = toolCallsInProgress.get(index)!;\n\n\t\t\t\t\t\t// Only update name if provided (ID is already set at creation time\n\t\t\t\t\t\t// and should not be overwritten by subsequent chunks that may have\n\t\t\t\t\t\t// duplicate/shared IDs from the backend)\n\t\t\t\t\t\tif (toolCallDelta.function?.name) {\n\t\t\t\t\t\t\ttoolCall.name = toolCallDelta.function.name;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (toolCallDelta.function?.arguments) {\n\t\t\t\t\t\t\ttoolCall.arguments += toolCallDelta.function.arguments;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Emit TOOL_CALL_START once we have id and name. We must wait\n\t\t\t\t\t\t// for the name: TanStack AI's StreamProcessor reads the tool\n\t\t\t\t\t\t// name ONLY from TOOL_CALL_START (it is never updated by later\n\t\t\t\t\t\t// events), so emitting early with an empty name produces a\n\t\t\t\t\t\t// tool-call part with no `name`, breaking dispatch (issue #523).\n\t\t\t\t\t\tif (toolCall.id && toolCall.name && !toolCall.started) {\n\t\t\t\t\t\t\ttoolCall.started = true;\n\t\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\t\ttype: EventType.TOOL_CALL_START,\n\t\t\t\t\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\t\t\t\t\ttoolCallName: toolCall.name,\n\t\t\t\t\t\t\t\ttoolName: toolCall.name,\n\t\t\t\t\t\t\t\tmodel: chunk.model || model || this.model,\n\t\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\t\tindex,\n\t\t\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Stream any argument fragments that haven't been forwarded\n\t\t\t\t\t\t// yet. We track the emitted length rather than forwarding the\n\t\t\t\t\t\t// raw per-chunk delta because some models stream argument\n\t\t\t\t\t\t// fragments BEFORE the name arrives; those are buffered in\n\t\t\t\t\t\t// `arguments` while we wait for the name, and must be flushed\n\t\t\t\t\t\t// once START is emitted so the full argument string reaches\n\t\t\t\t\t\t// the consumer (issue #523).\n\t\t\t\t\t\tif (toolCall.started && toolCall.arguments.length > toolCall.emittedArgsLength) {\n\t\t\t\t\t\t\tconst argsDelta = toolCall.arguments.slice(toolCall.emittedArgsLength);\n\t\t\t\t\t\t\ttoolCall.emittedArgsLength = toolCall.arguments.length;\n\t\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\t\ttype: EventType.TOOL_CALL_ARGS,\n\t\t\t\t\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\t\t\t\t\tmodel: chunk.model || model || this.model,\n\t\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\t\tdelta: argsDelta,\n\t\t\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Finish\n\t\t\t\tif (choice.finish_reason) {\n\t\t\t\t\thasReceivedFinishReason = true;\n\n\t\t\t\t\t// End tool calls\n\t\t\t\t\tif (choice.finish_reason === \"tool_calls\" || toolCallsInProgress.size > 0) {\n\t\t\t\t\t\tfor (const [, toolCall] of toolCallsInProgress) {\n\t\t\t\t\t\t\tlet parsedInput: unknown = {};\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tparsedInput = toolCall.arguments\n\t\t\t\t\t\t\t\t\t? JSON.parse(toolCall.arguments)\n\t\t\t\t\t\t\t\t\t: {};\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\tparsedInput = {};\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\t\ttype: EventType.TOOL_CALL_END,\n\t\t\t\t\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\t\t\t\t\ttoolName: toolCall.name,\n\t\t\t\t\t\t\t\tmodel: chunk.model || model || this.model,\n\t\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\t\tinput: parsedInput,\n\t\t\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst computedFinishReason =\n\t\t\t\t\t\tchoice.finish_reason === \"tool_calls\" ||\n\t\t\t\t\t\tchoice.finish_reason === \"function_call\" ||\n\t\t\t\t\t\ttoolCallsInProgress.size > 0\n\t\t\t\t\t\t\t? \"tool_calls\"\n\t\t\t\t\t\t\t: (choice.finish_reason as \"stop\" | \"length\" | \"content_filter\");\n\n\t\t\t\t\t// End text message if started\n\t\t\t\t\tif (hasEmittedTextMessageStart) {\n\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\ttype: EventType.TEXT_MESSAGE_END,\n\t\t\t\t\t\t\tmessageId,\n\t\t\t\t\t\t\tmodel: chunk.model || model || this.model,\n\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Emit RUN_FINISHED\n\t\t\t\t\tyield {\n\t\t\t\t\t\ttype: EventType.RUN_FINISHED,\n\t\t\t\t\t\trunId,\n\t\t\t\t\t\tthreadId,\n\t\t\t\t\t\tmodel: chunk.model || model || this.model,\n\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\tusage: chunk.usage\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tpromptTokens: chunk.usage.prompt_tokens,\n\t\t\t\t\t\t\t\t\tcompletionTokens: chunk.usage.completion_tokens,\n\t\t\t\t\t\t\t\t\ttotalTokens: chunk.usage.total_tokens,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\tfinishReason: computedFinishReason,\n\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Premature stream termination: the stream ended without a finish_reason.\n\t\t\t// This can happen when Workers AI truncates a response or the connection drops.\n\t\t\t// Emit proper closing events so the consumer doesn't hang.\n\t\t\tif (hasEmittedRunStarted && !hasReceivedFinishReason) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t\"[tanstack-ai] Stream ended without finish_reason — possible truncation or connection drop\",\n\t\t\t\t);\n\n\t\t\t\t// Close any open tool calls\n\t\t\t\tfor (const [, toolCall] of toolCallsInProgress) {\n\t\t\t\t\tif (toolCall.started) {\n\t\t\t\t\t\tlet parsedInput: unknown = {};\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tparsedInput = toolCall.arguments ? JSON.parse(toolCall.arguments) : {};\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tparsedInput = {};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\ttype: EventType.TOOL_CALL_END,\n\t\t\t\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\t\t\t\ttoolName: toolCall.name,\n\t\t\t\t\t\t\tmodel: model ?? this.model,\n\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\tinput: parsedInput,\n\t\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Close text message if open\n\t\t\t\tif (hasEmittedTextMessageStart) {\n\t\t\t\t\tyield {\n\t\t\t\t\t\ttype: EventType.TEXT_MESSAGE_END,\n\t\t\t\t\t\tmessageId,\n\t\t\t\t\t\tmodel: model ?? this.model,\n\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t} satisfies StreamChunk;\n\t\t\t\t}\n\n\t\t\t\tyield {\n\t\t\t\t\ttype: EventType.RUN_FINISHED,\n\t\t\t\t\trunId,\n\t\t\t\t\tthreadId,\n\t\t\t\t\tmodel: model ?? this.model,\n\t\t\t\t\ttimestamp,\n\t\t\t\t\tfinishReason: \"stop\",\n\t\t\t\t} satisfies StreamChunk;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tconst code =\n\t\t\t\terror instanceof Error ? (error as Error & { code?: string }).code : undefined;\n\t\t\tif (!hasEmittedRunStarted) {\n\t\t\t\tyield {\n\t\t\t\t\ttype: EventType.RUN_STARTED,\n\t\t\t\t\trunId,\n\t\t\t\t\tthreadId,\n\t\t\t\t\tmodel: model ?? this.model,\n\t\t\t\t\ttimestamp,\n\t\t\t\t} satisfies StreamChunk;\n\t\t\t}\n\t\t\tyield {\n\t\t\t\ttype: EventType.RUN_ERROR,\n\t\t\t\trunId,\n\t\t\t\tthreadId,\n\t\t\t\tmodel: model ?? this.model,\n\t\t\t\ttimestamp,\n\t\t\t\tmessage: message || \"Unknown error\",\n\t\t\t\tcode,\n\t\t\t\terror: {\n\t\t\t\t\tmessage: message || \"Unknown error\",\n\t\t\t\t\tcode,\n\t\t\t\t},\n\t\t\t} satisfies StreamChunk;\n\t\t}\n\t}\n\n\tasync structuredOutput(\n\t\toptions: StructuredOutputOptions<WorkersAiTextModelOptions>,\n\t): Promise<StructuredOutputResult<unknown>> {\n\t\tconst { outputSchema, chatOptions } = options;\n\t\tconst { systemPrompts, messages, model, modelOptions } = chatOptions;\n\t\tconst extraBody = normalizeModelOptions(modelOptions);\n\n\t\tconst openAIMessages = buildOpenAIMessages(systemPrompts, messages, {\n\t\t\tincludeToolMessages: false,\n\t\t});\n\n\t\tconst response = await this.client.chat.completions.create({\n\t\t\t...extraBody,\n\t\t\tmodel: model ?? this.model,\n\t\t\tmessages: openAIMessages,\n\t\t\tstream: false,\n\t\t\tresponse_format: {\n\t\t\t\ttype: \"json_schema\",\n\t\t\t\tjson_schema: {\n\t\t\t\t\tname: \"structured_output\",\n\t\t\t\t\tstrict: true,\n\t\t\t\t\tschema: outputSchema,\n\t\t\t\t},\n\t\t\t},\n\t\t} as OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming);\n\n\t\tconst choice = response.choices?.[0];\n\n\t\tif (!choice) {\n\t\t\tthrow new Error(\n\t\t\t\t`Workers AI structured output returned no choices: ${JSON.stringify(response)}`,\n\t\t\t);\n\t\t}\n\n\t\tconst rawContent = choice.message?.content ?? \"\";\n\n\t\t// Workers AI REST endpoint may return `content` as an already-parsed object\n\t\t// when using json_schema response format, so normalise both cases.\n\t\tlet data: unknown;\n\t\tlet rawText: string;\n\n\t\tif (typeof rawContent === \"string\") {\n\t\t\trawText = rawContent;\n\t\t\ttry {\n\t\t\t\tdata = JSON.parse(rawText);\n\t\t\t} catch {\n\t\t\t\tdata = rawText;\n\t\t\t}\n\t\t} else {\n\t\t\t// Already an object — stringify for rawText, use directly for data\n\t\t\tdata = rawContent;\n\t\t\trawText = JSON.stringify(rawContent);\n\t\t}\n\n\t\treturn { data, rawText };\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Factory functions\n// ---------------------------------------------------------------------------\n\nexport function createWorkersAiChat(model: WorkersAiTextModel, config: WorkersAiAdapterConfig) {\n\treturn new WorkersAiTextAdapter(model, config);\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { i as WorkersAiAdapterConfig } from "../create-fetcher-vAQ8WW-p.cjs";
1
+ import { i as WorkersAiAdapterConfig } from "../create-fetcher-Bp5yCNaO.cjs";
2
2
  import { StreamChunk, TextOptions } from "@tanstack/ai";
3
3
  import { BaseTextAdapter, StructuredOutputOptions, StructuredOutputResult } from "@tanstack/ai/adapters";
4
4
  import { AiModels, BaseAiTextGeneration } from "@cloudflare/workers-types";
@@ -8,7 +8,7 @@ type WorkersAiTextModel = { [K in keyof AiModels]: AiModels[K] extends BaseAiTex
8
8
  interface WorkersAiTextModelOptions {
9
9
  /**
10
10
  * Controls the reasoning budget for reasoning-capable models
11
- * (e.g. `@cf/zai-org/glm-4.7-flash`, `@cf/moonshotai/kimi-k2.5`,
11
+ * (e.g. `@cf/zai-org/glm-4.7-flash`, `@cf/moonshotai/kimi-k2.7-code`,
12
12
  * `@cf/openai/gpt-oss-120b`).
13
13
  *
14
14
  * `null` is a valid value and disables reasoning for models that support it.
@@ -1,6 +1,6 @@
1
- import { i as WorkersAiAdapterConfig } from "../create-fetcher-6p6heb85.mjs";
2
- import { BaseTextAdapter, StructuredOutputOptions, StructuredOutputResult } from "@tanstack/ai/adapters";
1
+ import { i as WorkersAiAdapterConfig } from "../create-fetcher-Bp5yCNaO.mjs";
3
2
  import { StreamChunk, TextOptions } from "@tanstack/ai";
3
+ import { BaseTextAdapter, StructuredOutputOptions, StructuredOutputResult } from "@tanstack/ai/adapters";
4
4
  import { AiModels, BaseAiTextGeneration } from "@cloudflare/workers-types";
5
5
 
6
6
  //#region src/adapters/workers-ai.d.ts
@@ -8,7 +8,7 @@ type WorkersAiTextModel = { [K in keyof AiModels]: AiModels[K] extends BaseAiTex
8
8
  interface WorkersAiTextModelOptions {
9
9
  /**
10
10
  * Controls the reasoning budget for reasoning-capable models
11
- * (e.g. `@cf/zai-org/glm-4.7-flash`, `@cf/moonshotai/kimi-k2.5`,
11
+ * (e.g. `@cf/zai-org/glm-4.7-flash`, `@cf/moonshotai/kimi-k2.7-code`,
12
12
  * `@cf/openai/gpt-oss-120b`).
13
13
  *
14
14
  * `null` is a valid value and disables reasoning for models that support it.