pi2dsh 0.3.4 → 0.4.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.
Files changed (74) hide show
  1. package/dist/{all-Rt4K68QA.mjs → all-DSpxKvHa.mjs} +10 -10
  2. package/dist/{all-Rt4K68QA.mjs.map → all-DSpxKvHa.mjs.map} +1 -1
  3. package/dist/{anthropic-messages-Beym0_aC.mjs → anthropic-messages-BL9N1Idv.mjs} +3 -3
  4. package/dist/{anthropic-messages-Beym0_aC.mjs.map → anthropic-messages-BL9N1Idv.mjs.map} +1 -1
  5. package/dist/{azure-openai-responses-cHqZTgLD.mjs → azure-openai-responses-A67VbaZ1.mjs} +3 -3
  6. package/dist/{azure-openai-responses-cHqZTgLD.mjs.map → azure-openai-responses-A67VbaZ1.mjs.map} +1 -1
  7. package/dist/cli.mjs +1 -1
  8. package/dist/compat/pi-ai.d.mts +3 -38
  9. package/dist/compat/pi-ai.d.mts.map +1 -1
  10. package/dist/compat/pi-ai.mjs +3 -3
  11. package/dist/compat/pi-coding-agent.d.mts +71 -32
  12. package/dist/compat/pi-coding-agent.d.mts.map +1 -1
  13. package/dist/compat/pi-coding-agent.mjs +2 -2
  14. package/dist/credentials-oauth.mjs +2 -2
  15. package/dist/{dist-QBBA-dL_.mjs → dist-BYA74yh_.mjs} +2 -2
  16. package/dist/{dist-QBBA-dL_.mjs.map → dist-BYA74yh_.mjs.map} +1 -1
  17. package/dist/dist-DeonWo7m.mjs +1089 -0
  18. package/dist/dist-DeonWo7m.mjs.map +1 -0
  19. package/dist/{google-generative-ai-B7OZs5lu.mjs → google-generative-ai-DT5S8D8y.mjs} +2 -2
  20. package/dist/{google-generative-ai-B7OZs5lu.mjs.map → google-generative-ai-DT5S8D8y.mjs.map} +1 -1
  21. package/dist/{google-shared-CRsAUItF.mjs → google-shared-DYP_9cnK.mjs} +4 -4
  22. package/dist/{google-shared-CRsAUItF.mjs.map → google-shared-DYP_9cnK.mjs.map} +1 -1
  23. package/dist/{google-vertex-DmdaHQtB.mjs → google-vertex-Dpq7O7Be.mjs} +3 -3
  24. package/dist/{google-vertex-DmdaHQtB.mjs.map → google-vertex-Dpq7O7Be.mjs.map} +1 -1
  25. package/dist/host.mjs +1 -1
  26. package/dist/index.d.mts.map +1 -1
  27. package/dist/index.mjs +1 -1
  28. package/dist/{json-parse-CFyFZSLJ.mjs → json-parse-Dz5sKMTv.mjs} +2 -2
  29. package/dist/{json-parse-CFyFZSLJ.mjs.map → json-parse-Dz5sKMTv.mjs.map} +1 -1
  30. package/dist/{mcp-config-D2B3kv-Z.mjs → mcp-config-B3h5jTBb.mjs} +9 -8
  31. package/dist/mcp-config-B3h5jTBb.mjs.map +1 -0
  32. package/dist/{mistral-conversations-HHZCcFv_.mjs → mistral-conversations-BsxbCCWx.mjs} +4 -4
  33. package/dist/{mistral-conversations-HHZCcFv_.mjs.map → mistral-conversations-BsxbCCWx.mjs.map} +1 -1
  34. package/dist/{multipart-parser-CIa5BbwO.mjs → multipart-parser-woKCuALW.mjs} +3 -3
  35. package/dist/{multipart-parser-CIa5BbwO.mjs.map → multipart-parser-woKCuALW.mjs.map} +1 -1
  36. package/dist/{openai-codex-responses-vmovNu-q.mjs → openai-codex-responses-C7vviVT2.mjs} +3 -3
  37. package/dist/{openai-codex-responses-vmovNu-q.mjs.map → openai-codex-responses-C7vviVT2.mjs.map} +1 -1
  38. package/dist/{openai-completions-fXHhRolF.mjs → openai-completions-By8QNX1P.mjs} +3 -3
  39. package/dist/{openai-completions-fXHhRolF.mjs.map → openai-completions-By8QNX1P.mjs.map} +1 -1
  40. package/dist/{openai-responses-DKdCYf3h.mjs → openai-responses-DboJUcFN.mjs} +3 -3
  41. package/dist/{openai-responses-DKdCYf3h.mjs.map → openai-responses-DboJUcFN.mjs.map} +1 -1
  42. package/dist/{openai-responses-shared-D0Jq7yVP.mjs → openai-responses-shared-BDzn7nJY.mjs} +2 -2
  43. package/dist/{openai-responses-shared-D0Jq7yVP.mjs.map → openai-responses-shared-BDzn7nJY.mjs.map} +1 -1
  44. package/dist/{otel-BQSQRBLF.mjs → otel-PimLMoiV.mjs} +3 -3
  45. package/dist/{otel-BQSQRBLF.mjs.map → otel-PimLMoiV.mjs.map} +1 -1
  46. package/dist/{pi-ai-DhYGgq4Y.mjs → pi-ai-B_88Wb0r.mjs} +49 -6
  47. package/dist/{pi-ai-DhYGgq4Y.mjs.map → pi-ai-B_88Wb0r.mjs.map} +1 -1
  48. package/dist/{pi-coding-agent-fPHwKP4d.mjs → pi-coding-agent-COMX0KHL.mjs} +109 -34
  49. package/dist/pi-coding-agent-COMX0KHL.mjs.map +1 -0
  50. package/dist/{pi-messages-CV-Ts8An.mjs → pi-messages-B-7Xo_I0.mjs} +3 -3
  51. package/dist/{pi-messages-CV-Ts8An.mjs.map → pi-messages-B-7Xo_I0.mjs.map} +1 -1
  52. package/dist/pi-types-KazmR2O5.d.mts +62 -0
  53. package/dist/pi-types-KazmR2O5.d.mts.map +1 -0
  54. package/dist/pi-uuid-Db8ShZsK.mjs +47 -0
  55. package/dist/pi-uuid-Db8ShZsK.mjs.map +1 -0
  56. package/dist/{provider-env-C72pF4vP.mjs → provider-env-D-cCRWzv.mjs} +2 -2
  57. package/dist/{provider-env-C72pF4vP.mjs.map → provider-env-D-cCRWzv.mjs.map} +1 -1
  58. package/dist/{runtime-B9R7bDWT.mjs → runtime-B7mEIRf-.mjs} +1183 -52
  59. package/dist/runtime-B7mEIRf-.mjs.map +1 -0
  60. package/dist/runtime.d.mts.map +1 -1
  61. package/dist/runtime.mjs +1 -1
  62. package/dist/{src-C3WBfOks.mjs → src-BEl3QrGL.mjs} +3 -3
  63. package/dist/{src-C3WBfOks.mjs.map → src-BEl3QrGL.mjs.map} +1 -1
  64. package/package.json +2 -2
  65. package/dist/build-BG7p2Lbr.mjs +0 -4416
  66. package/dist/build-BG7p2Lbr.mjs.map +0 -1
  67. package/dist/dist-IQKOgQyt.mjs +0 -10035
  68. package/dist/dist-IQKOgQyt.mjs.map +0 -1
  69. package/dist/mcp-config-D2B3kv-Z.mjs.map +0 -1
  70. package/dist/pi-coding-agent-fPHwKP4d.mjs.map +0 -1
  71. package/dist/pi-types-BLt46jaf.d.mts +0 -2494
  72. package/dist/pi-types-BLt46jaf.d.mts.map +0 -1
  73. package/dist/rolldown-runtime-CTfmNlz1.mjs +0 -44
  74. package/dist/runtime-B9R7bDWT.mjs.map +0 -1
@@ -0,0 +1,1089 @@
1
+
2
+ import { a as AssistantMessageEventStream, i as formatThrownValue, n as createAssistantMessageDiagnostic, o as EventStream, r as extractDiagnosticError, s as createAssistantMessageEventStream, t as appendAssistantMessageDiagnostic } from "./diagnostics-CJye1UFh.mjs";
3
+ import { _ as lazyStream, a as calculateCost, c as createProvider, d as modelsAreEqual, f as InMemoryModelsStore, g as lazyApi, h as defaultProviderAuthContext, i as lazyOAuth, l as getSupportedThinkingLevels, m as InMemoryCredentialStore, n as createImagesProvider, o as clampThinkingLevel, p as ModelsError, r as envApiKeyAuth, s as createModels, t as createImagesModels, u as hasApi } from "./images-models-DJtHo9Rp.mjs";
4
+ import { n as parseStreamingJson, r as repairJson, t as parseJsonWithRepair } from "./json-parse-Dz5sKMTv.mjs";
5
+ import { n as cleanupSessionResources, r as registerSessionResourceCleanup, t as uuidv7 } from "./uuid-DtFT7tOE.mjs";
6
+ import { Type, Type as Type$1 } from "typebox";
7
+ import { Compile } from "typebox/compile";
8
+ import { Value } from "typebox/value";
9
+ //#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/providers/faux.js
10
+ const DEFAULT_API = "faux";
11
+ const DEFAULT_PROVIDER = "faux";
12
+ const DEFAULT_MODEL_ID = "faux-1";
13
+ const DEFAULT_MODEL_NAME = "Faux Model";
14
+ const DEFAULT_BASE_URL = "http://localhost:0";
15
+ const DEFAULT_MIN_TOKEN_SIZE = 3;
16
+ const DEFAULT_MAX_TOKEN_SIZE = 5;
17
+ const DEFAULT_USAGE = {
18
+ input: 0,
19
+ output: 0,
20
+ cacheRead: 0,
21
+ cacheWrite: 0,
22
+ totalTokens: 0,
23
+ cost: {
24
+ input: 0,
25
+ output: 0,
26
+ cacheRead: 0,
27
+ cacheWrite: 0,
28
+ total: 0
29
+ }
30
+ };
31
+ function fauxText(text) {
32
+ return {
33
+ type: "text",
34
+ text
35
+ };
36
+ }
37
+ function fauxThinking(thinking) {
38
+ return {
39
+ type: "thinking",
40
+ thinking
41
+ };
42
+ }
43
+ function fauxToolCall(name, arguments_, options = {}) {
44
+ return {
45
+ type: "toolCall",
46
+ id: options.id ?? randomId("tool"),
47
+ name,
48
+ arguments: arguments_
49
+ };
50
+ }
51
+ function normalizeFauxAssistantContent(content) {
52
+ if (typeof content === "string") return [fauxText(content)];
53
+ return Array.isArray(content) ? content : [content];
54
+ }
55
+ function fauxAssistantMessage(content, options = {}) {
56
+ return {
57
+ role: "assistant",
58
+ content: normalizeFauxAssistantContent(content),
59
+ api: DEFAULT_API,
60
+ provider: DEFAULT_PROVIDER,
61
+ model: DEFAULT_MODEL_ID,
62
+ usage: DEFAULT_USAGE,
63
+ stopReason: options.stopReason ?? "stop",
64
+ deferred: options.deferred,
65
+ errorMessage: options.errorMessage,
66
+ responseId: options.responseId,
67
+ timestamp: options.timestamp ?? Date.now()
68
+ };
69
+ }
70
+ function estimateTokens(text) {
71
+ return Math.ceil(text.length / 4);
72
+ }
73
+ function randomId(prefix) {
74
+ return `${prefix}:${Date.now()}:${Math.random().toString(36).slice(2)}`;
75
+ }
76
+ function contentToText(content) {
77
+ if (typeof content === "string") return content;
78
+ return content.map((block) => {
79
+ if (block.type === "text") return block.text;
80
+ return `[image:${block.mimeType}:${block.data.length}]`;
81
+ }).join("\n");
82
+ }
83
+ function assistantContentToText(content) {
84
+ return content.map((block) => {
85
+ if (block.type === "text") return block.text;
86
+ if (block.type === "thinking") return block.thinking;
87
+ return `${block.name}:${JSON.stringify(block.arguments)}`;
88
+ }).join("\n");
89
+ }
90
+ function toolResultToText(message) {
91
+ return [message.toolName, ...message.content.map((block) => contentToText([block]))].join("\n");
92
+ }
93
+ function messageToText(message) {
94
+ if (message.role === "user") return contentToText(message.content);
95
+ if (message.role === "assistant") return assistantContentToText(message.content);
96
+ return toolResultToText(message);
97
+ }
98
+ function serializeContext(context) {
99
+ const parts = [];
100
+ if (context.systemPrompt) parts.push(`system:${context.systemPrompt}`);
101
+ for (const message of context.messages) parts.push(`${message.role}:${messageToText(message)}`);
102
+ if (context.tools?.length) parts.push(`tools:${JSON.stringify(context.tools)}`);
103
+ return parts.join("\n\n");
104
+ }
105
+ function commonPrefixLength(a, b) {
106
+ const length = Math.min(a.length, b.length);
107
+ let index = 0;
108
+ while (index < length && a[index] === b[index]) index++;
109
+ return index;
110
+ }
111
+ function withUsageEstimate(message, context, options, promptCache) {
112
+ const promptText = serializeContext(context);
113
+ const promptTokens = estimateTokens(promptText);
114
+ const outputTokens = estimateTokens(assistantContentToText(message.content));
115
+ let input = promptTokens;
116
+ let cacheRead = 0;
117
+ let cacheWrite = 0;
118
+ const sessionId = options?.sessionId;
119
+ if (sessionId && options?.cacheRetention !== "none") {
120
+ const previousPrompt = promptCache.get(sessionId);
121
+ if (previousPrompt) {
122
+ const cachedChars = commonPrefixLength(previousPrompt, promptText);
123
+ cacheRead = estimateTokens(previousPrompt.slice(0, cachedChars));
124
+ cacheWrite = estimateTokens(promptText.slice(cachedChars));
125
+ input = Math.max(0, promptTokens - cacheRead);
126
+ } else cacheWrite = promptTokens;
127
+ promptCache.set(sessionId, promptText);
128
+ }
129
+ return {
130
+ ...message,
131
+ usage: {
132
+ input,
133
+ output: outputTokens,
134
+ cacheRead,
135
+ cacheWrite,
136
+ totalTokens: input + outputTokens + cacheRead + cacheWrite,
137
+ cost: {
138
+ input: 0,
139
+ output: 0,
140
+ cacheRead: 0,
141
+ cacheWrite: 0,
142
+ total: 0
143
+ }
144
+ }
145
+ };
146
+ }
147
+ function splitStringByTokenSize(text, minTokenSize, maxTokenSize) {
148
+ const chunks = [];
149
+ let index = 0;
150
+ while (index < text.length) {
151
+ const tokenSize = minTokenSize + Math.floor(Math.random() * (maxTokenSize - minTokenSize + 1));
152
+ const charSize = Math.max(1, tokenSize * 4);
153
+ chunks.push(text.slice(index, index + charSize));
154
+ index += charSize;
155
+ }
156
+ return chunks.length > 0 ? chunks : [""];
157
+ }
158
+ function cloneMessage(message, api, provider, modelId) {
159
+ const cloned = structuredClone(message);
160
+ return {
161
+ ...cloned,
162
+ api,
163
+ provider,
164
+ model: modelId,
165
+ timestamp: cloned.timestamp ?? Date.now(),
166
+ usage: cloned.usage ?? DEFAULT_USAGE
167
+ };
168
+ }
169
+ function createDeferredMessage(model, handle) {
170
+ return {
171
+ role: "assistant",
172
+ content: [],
173
+ api: model.api,
174
+ provider: model.provider,
175
+ model: model.id,
176
+ usage: DEFAULT_USAGE,
177
+ stopReason: "deferred",
178
+ deferred: handle,
179
+ timestamp: Date.now()
180
+ };
181
+ }
182
+ function createErrorMessage(error, api, provider, modelId) {
183
+ return {
184
+ role: "assistant",
185
+ content: [],
186
+ api,
187
+ provider,
188
+ model: modelId,
189
+ usage: DEFAULT_USAGE,
190
+ stopReason: "error",
191
+ errorMessage: error instanceof Error ? error.message : String(error),
192
+ timestamp: Date.now()
193
+ };
194
+ }
195
+ function createAbortedMessage(partial) {
196
+ return {
197
+ ...partial,
198
+ stopReason: "aborted",
199
+ errorMessage: "Request was aborted",
200
+ timestamp: Date.now()
201
+ };
202
+ }
203
+ function scheduleChunk(chunk, tokensPerSecond) {
204
+ if (!tokensPerSecond || tokensPerSecond <= 0) return new Promise((resolve) => queueMicrotask(resolve));
205
+ const delayMs = estimateTokens(chunk) / tokensPerSecond * 1e3;
206
+ return new Promise((resolve) => setTimeout(resolve, delayMs));
207
+ }
208
+ async function streamWithDeltas(stream, message, minTokenSize, maxTokenSize, tokensPerSecond, signal) {
209
+ const partial = {
210
+ ...message,
211
+ content: [],
212
+ stopReason: "pending"
213
+ };
214
+ if (signal?.aborted) {
215
+ const aborted = createAbortedMessage(partial);
216
+ stream.push({
217
+ type: "error",
218
+ reason: "aborted",
219
+ error: aborted
220
+ });
221
+ stream.end(aborted);
222
+ return;
223
+ }
224
+ stream.push({
225
+ type: "start",
226
+ partial: { ...partial }
227
+ });
228
+ for (let index = 0; index < message.content.length; index++) {
229
+ if (signal?.aborted) {
230
+ const aborted = createAbortedMessage(partial);
231
+ stream.push({
232
+ type: "error",
233
+ reason: "aborted",
234
+ error: aborted
235
+ });
236
+ stream.end(aborted);
237
+ return;
238
+ }
239
+ const block = message.content[index];
240
+ if (block.type === "thinking") {
241
+ partial.content = [...partial.content, {
242
+ type: "thinking",
243
+ thinking: ""
244
+ }];
245
+ stream.push({
246
+ type: "thinking_start",
247
+ contentIndex: index,
248
+ partial: { ...partial }
249
+ });
250
+ for (const chunk of splitStringByTokenSize(block.thinking, minTokenSize, maxTokenSize)) {
251
+ await scheduleChunk(chunk, tokensPerSecond);
252
+ if (signal?.aborted) {
253
+ const aborted = createAbortedMessage(partial);
254
+ stream.push({
255
+ type: "error",
256
+ reason: "aborted",
257
+ error: aborted
258
+ });
259
+ stream.end(aborted);
260
+ return;
261
+ }
262
+ partial.content[index].thinking += chunk;
263
+ stream.push({
264
+ type: "thinking_delta",
265
+ contentIndex: index,
266
+ delta: chunk,
267
+ partial: { ...partial }
268
+ });
269
+ }
270
+ stream.push({
271
+ type: "thinking_end",
272
+ contentIndex: index,
273
+ content: block.thinking,
274
+ partial: { ...partial }
275
+ });
276
+ continue;
277
+ }
278
+ if (block.type === "text") {
279
+ partial.content = [...partial.content, {
280
+ type: "text",
281
+ text: ""
282
+ }];
283
+ stream.push({
284
+ type: "text_start",
285
+ contentIndex: index,
286
+ partial: { ...partial }
287
+ });
288
+ for (const chunk of splitStringByTokenSize(block.text, minTokenSize, maxTokenSize)) {
289
+ await scheduleChunk(chunk, tokensPerSecond);
290
+ if (signal?.aborted) {
291
+ const aborted = createAbortedMessage(partial);
292
+ stream.push({
293
+ type: "error",
294
+ reason: "aborted",
295
+ error: aborted
296
+ });
297
+ stream.end(aborted);
298
+ return;
299
+ }
300
+ partial.content[index].text += chunk;
301
+ stream.push({
302
+ type: "text_delta",
303
+ contentIndex: index,
304
+ delta: chunk,
305
+ partial: { ...partial }
306
+ });
307
+ }
308
+ stream.push({
309
+ type: "text_end",
310
+ contentIndex: index,
311
+ content: block.text,
312
+ partial: { ...partial }
313
+ });
314
+ continue;
315
+ }
316
+ partial.content = [...partial.content, {
317
+ type: "toolCall",
318
+ id: block.id,
319
+ name: block.name,
320
+ arguments: {}
321
+ }];
322
+ stream.push({
323
+ type: "toolcall_start",
324
+ contentIndex: index,
325
+ partial: { ...partial }
326
+ });
327
+ for (const chunk of splitStringByTokenSize(JSON.stringify(block.arguments), minTokenSize, maxTokenSize)) {
328
+ await scheduleChunk(chunk, tokensPerSecond);
329
+ if (signal?.aborted) {
330
+ const aborted = createAbortedMessage(partial);
331
+ stream.push({
332
+ type: "error",
333
+ reason: "aborted",
334
+ error: aborted
335
+ });
336
+ stream.end(aborted);
337
+ return;
338
+ }
339
+ stream.push({
340
+ type: "toolcall_delta",
341
+ contentIndex: index,
342
+ delta: chunk,
343
+ partial: { ...partial }
344
+ });
345
+ }
346
+ partial.content[index].arguments = block.arguments;
347
+ stream.push({
348
+ type: "toolcall_end",
349
+ contentIndex: index,
350
+ toolCall: block,
351
+ partial: { ...partial }
352
+ });
353
+ }
354
+ if (message.stopReason === "pending") throw new Error("Faux response ended without a stop reason");
355
+ if (message.stopReason === "error" || message.stopReason === "aborted") {
356
+ stream.push({
357
+ type: "error",
358
+ reason: message.stopReason,
359
+ error: message
360
+ });
361
+ stream.end(message);
362
+ return;
363
+ }
364
+ stream.push({
365
+ type: "done",
366
+ reason: message.stopReason,
367
+ message
368
+ });
369
+ stream.end(message);
370
+ }
371
+ function createFauxCore(options) {
372
+ const api = options.api ?? randomId(DEFAULT_API);
373
+ const provider = options.provider ?? DEFAULT_PROVIDER;
374
+ const minTokenSize = Math.max(1, Math.min(options.tokenSize?.min ?? DEFAULT_MIN_TOKEN_SIZE, options.tokenSize?.max ?? DEFAULT_MAX_TOKEN_SIZE));
375
+ const maxTokenSize = Math.max(minTokenSize, options.tokenSize?.max ?? DEFAULT_MAX_TOKEN_SIZE);
376
+ let pendingResponses = [];
377
+ const tokensPerSecond = options.tokensPerSecond;
378
+ const state = {
379
+ callCount: 0,
380
+ deferredFetchCount: 0,
381
+ cancelledDeferred: []
382
+ };
383
+ const promptCache = /* @__PURE__ */ new Map();
384
+ const deferredResponses = /* @__PURE__ */ new Map();
385
+ const models = (options.models?.length ? options.models : [{
386
+ id: DEFAULT_MODEL_ID,
387
+ name: DEFAULT_MODEL_NAME,
388
+ reasoning: false,
389
+ input: ["text", "image"],
390
+ cost: {
391
+ input: 0,
392
+ output: 0,
393
+ cacheRead: 0,
394
+ cacheWrite: 0
395
+ },
396
+ contextWindow: 128e3,
397
+ maxTokens: 16384
398
+ }]).map((definition) => ({
399
+ id: definition.id,
400
+ name: definition.name ?? definition.id,
401
+ api,
402
+ provider,
403
+ baseUrl: DEFAULT_BASE_URL,
404
+ reasoning: definition.reasoning ?? false,
405
+ input: definition.input ?? ["text", "image"],
406
+ cost: definition.cost ?? {
407
+ input: 0,
408
+ output: 0,
409
+ cacheRead: 0,
410
+ cacheWrite: 0
411
+ },
412
+ contextWindow: definition.contextWindow ?? 128e3,
413
+ maxTokens: definition.maxTokens ?? 16384
414
+ }));
415
+ const resolveResponse = async (step, context, streamOptions, requestModel) => {
416
+ return withUsageEstimate(cloneMessage(typeof step === "function" ? await step(context, streamOptions, state, requestModel) : step, api, provider, requestModel.id), context, streamOptions, promptCache);
417
+ };
418
+ const stream = (requestModel, context, streamOptions) => {
419
+ const outer = createAssistantMessageEventStream();
420
+ const step = pendingResponses.shift();
421
+ state.callCount++;
422
+ queueMicrotask(async () => {
423
+ try {
424
+ await streamOptions?.onResponse?.({
425
+ status: 200,
426
+ headers: {}
427
+ }, requestModel);
428
+ if (!step) {
429
+ let message = createErrorMessage(/* @__PURE__ */ new Error("No more faux responses queued"), api, provider, requestModel.id);
430
+ message = withUsageEstimate(message, context, streamOptions, promptCache);
431
+ outer.push({
432
+ type: "error",
433
+ reason: "error",
434
+ error: message
435
+ });
436
+ outer.end(message);
437
+ return;
438
+ }
439
+ if (streamOptions?.deferred) {
440
+ const handle = {
441
+ provider: requestModel.provider,
442
+ modelId: requestModel.id,
443
+ api: requestModel.api,
444
+ id: randomId("deferred"),
445
+ ...options.deferred?.pollAfterMs !== void 0 ? { pollAfterMs: options.deferred.pollAfterMs } : {}
446
+ };
447
+ deferredResponses.set(handle.id, {
448
+ handle,
449
+ step,
450
+ context,
451
+ options: streamOptions,
452
+ model: requestModel,
453
+ pendingFetches: Math.max(0, Math.floor(options.deferred?.pendingFetches ?? 0)),
454
+ cancelled: false
455
+ });
456
+ await streamWithDeltas(outer, createDeferredMessage(requestModel, handle), minTokenSize, maxTokenSize, tokensPerSecond, streamOptions.signal);
457
+ return;
458
+ }
459
+ const message = await resolveResponse(step, context, streamOptions, requestModel);
460
+ await streamWithDeltas(outer, message, minTokenSize, maxTokenSize, tokensPerSecond, streamOptions?.signal);
461
+ } catch (error) {
462
+ const message = createErrorMessage(error, api, provider, requestModel.id);
463
+ outer.push({
464
+ type: "error",
465
+ reason: "error",
466
+ error: message
467
+ });
468
+ outer.end(message);
469
+ }
470
+ });
471
+ return outer;
472
+ };
473
+ const streamSimple = (streamModel, context, streamOptions) => stream(streamModel, context, streamOptions);
474
+ const fetchDeferred = (requestModel, handle, fetchOptions) => {
475
+ const outer = createAssistantMessageEventStream();
476
+ state.deferredFetchCount++;
477
+ queueMicrotask(async () => {
478
+ try {
479
+ await fetchOptions?.onResponse?.({
480
+ status: 200,
481
+ headers: {}
482
+ }, requestModel);
483
+ const entry = deferredResponses.get(handle.id);
484
+ if (!entry || entry.handle.provider !== handle.provider || entry.handle.modelId !== handle.modelId || entry.handle.api !== handle.api) throw new Error(`Unknown faux deferred response: ${handle.id}`);
485
+ if (entry.cancelled) throw new Error(`Faux deferred response was cancelled: ${handle.id}`);
486
+ if (entry.pendingFetches > 0) {
487
+ entry.pendingFetches--;
488
+ await streamWithDeltas(outer, createDeferredMessage(requestModel, entry.handle), minTokenSize, maxTokenSize, tokensPerSecond, fetchOptions?.signal);
489
+ return;
490
+ }
491
+ if (!entry.final) {
492
+ const { deferred: _deferred, signal: _submissionSignal, onResponse: _submissionOnResponse, ...submissionOptions } = entry.options ?? {};
493
+ try {
494
+ entry.final = await resolveResponse(entry.step, entry.context, submissionOptions, entry.model);
495
+ } catch (error) {
496
+ entry.final = createErrorMessage(error, api, provider, entry.model.id);
497
+ }
498
+ }
499
+ await streamWithDeltas(outer, entry.final, minTokenSize, maxTokenSize, tokensPerSecond, fetchOptions?.signal);
500
+ } catch (error) {
501
+ const message = createErrorMessage(error, api, provider, requestModel.id);
502
+ outer.push({
503
+ type: "error",
504
+ reason: "error",
505
+ error: message
506
+ });
507
+ outer.end(message);
508
+ }
509
+ });
510
+ return outer;
511
+ };
512
+ const cancelDeferred = async (requestModel, handle, cancelOptions) => {
513
+ state.cancelledDeferred.push(structuredClone(handle));
514
+ const entry = deferredResponses.get(handle.id);
515
+ if (entry) entry.cancelled = true;
516
+ await cancelOptions?.onResponse?.({
517
+ status: 200,
518
+ headers: {}
519
+ }, requestModel);
520
+ };
521
+ function getModel(requestedModelId) {
522
+ if (!requestedModelId) return models[0];
523
+ return models.find((candidate) => candidate.id === requestedModelId);
524
+ }
525
+ return {
526
+ api,
527
+ provider,
528
+ models,
529
+ stream,
530
+ streamSimple,
531
+ fetchDeferred,
532
+ cancelDeferred,
533
+ getModel,
534
+ state,
535
+ setResponses(responses) {
536
+ pendingResponses = [...responses];
537
+ },
538
+ appendResponses(responses) {
539
+ pendingResponses.push(...responses);
540
+ },
541
+ getPendingResponseCount() {
542
+ return pendingResponses.length;
543
+ }
544
+ };
545
+ }
546
+ /**
547
+ * Faux provider for tests built on explicit `Models` collections:
548
+ *
549
+ * ```ts
550
+ * const faux = fauxProvider();
551
+ * const models = createModels();
552
+ * models.setProvider(faux.provider);
553
+ * faux.setResponses([fauxAssistantMessage("hi")]);
554
+ * ```
555
+ */
556
+ function fauxProvider(options = {}) {
557
+ const core = createFauxCore(options);
558
+ return {
559
+ provider: createProvider({
560
+ id: core.provider,
561
+ auth: { apiKey: {
562
+ name: "Faux",
563
+ resolve: async () => ({ auth: {} })
564
+ } },
565
+ models: core.models,
566
+ api: {
567
+ stream: core.stream,
568
+ streamSimple: core.streamSimple,
569
+ fetchDeferred: core.fetchDeferred,
570
+ cancelDeferred: core.cancelDeferred
571
+ }
572
+ }),
573
+ api: core.api,
574
+ models: core.models,
575
+ getModel: core.getModel,
576
+ state: core.state,
577
+ setResponses: core.setResponses,
578
+ appendResponses: core.appendResponses,
579
+ getPendingResponseCount: core.getPendingResponseCount
580
+ };
581
+ }
582
+ //#endregion
583
+ //#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js
584
+ /**
585
+ * Regex patterns to detect context overflow errors from different providers.
586
+ *
587
+ * These patterns match error messages returned when the input exceeds
588
+ * the model's context window.
589
+ *
590
+ * Provider-specific patterns (with example error messages):
591
+ *
592
+ * - Anthropic: "prompt is too long: 213462 tokens > 200000 maximum"
593
+ * - Anthropic: "413 {\"error\":{\"type\":\"request_too_large\",\"message\":\"Request exceeds the maximum size\"}}"
594
+ * - OpenAI: "Your input exceeds the context window of this model"
595
+ * - OpenAI/LiteLLM: "Requested token count exceeds the model's maximum context length of 131072 tokens"
596
+ * - OpenAI-compatible: "Input length (265330) exceeds model's maximum context length (262144)."
597
+ * - Google: "The input token count (1196265) exceeds the maximum number of tokens allowed (1048575)"
598
+ * - xAI: "This model's maximum prompt length is 131072 but the request contains 537812 tokens"
599
+ * - Groq: "Please reduce the length of the messages or completion"
600
+ * - OpenRouter: "This endpoint's maximum context length is X tokens. However, you requested about Y tokens"
601
+ * - OpenRouter/Poolside: "Input length X exceeds the maximum allowed input length of Y tokens."
602
+ * - Together AI: "The input (X tokens) is longer than the model's context length (Y tokens)."
603
+ * - llama.cpp: "the request exceeds the available context size, try increasing it"
604
+ * - LM Studio: "tokens to keep from the initial prompt is greater than the context length"
605
+ * - GitHub Copilot: "prompt token count of X exceeds the limit of Y"
606
+ * - MiniMax: "invalid params, context window exceeds limit"
607
+ * - Kimi For Coding: "Your request exceeded model token limit: X (requested: Y)"
608
+ * - DS4: "Prompt has X tokens, but the configured context size is Y tokens"
609
+ * - Cerebras: "400/413 status code (no body)"
610
+ * - Mistral: "Prompt contains X tokens ... too large for model with Y maximum context length"
611
+ * - z.ai: Does NOT error, accepts overflow silently - handled via usage.input > contextWindow
612
+ * - Xiaomi MiMo: Truncates input to fill contextWindow exactly, then returns finish_reason "length"
613
+ * with output=0 (no room left to generate). Detected via stopReason "length" + zero output +
614
+ * input filling the context window.
615
+ * - DashScope/Qwen: "Range of input length should be [1, X]" (HTTP 400 invalid_parameter_error)
616
+ * - Ollama: Some deployments truncate silently, others return errors like "prompt too long; exceeded max context length by X tokens"
617
+ */
618
+ const OVERFLOW_PATTERNS = [
619
+ /prompt is too long/i,
620
+ /request_too_large/i,
621
+ /input is too long for requested model/i,
622
+ /exceeds the context window/i,
623
+ /exceeds (?:the )?(?:model'?s )?maximum context length(?: of [\d,]+ tokens?|\s*\([\d,]+\))/i,
624
+ /input token count.*exceeds the maximum/i,
625
+ /maximum prompt length is \d+/i,
626
+ /reduce the length of the messages/i,
627
+ /maximum context length is \d+ tokens/i,
628
+ /exceeds (?:the )?maximum allowed input length of [\d,]+ tokens?/i,
629
+ /input \(\d+ tokens\) is longer than the model'?s context length \(\d+ tokens\)/i,
630
+ /exceeds the limit of \d+/i,
631
+ /exceeds the available context size/i,
632
+ /greater than the context length/i,
633
+ /context window exceeds limit/i,
634
+ /exceeded model token limit/i,
635
+ /too large for model with \d+ maximum context length/i,
636
+ /prompt has [\d,]+ tokens?, but the configured context size is [\d,]+ tokens?/i,
637
+ /model_context_window_exceeded/i,
638
+ /prompt too long; exceeded (?:max )?context length/i,
639
+ /range of input length should be/i,
640
+ /context[_ ]length[_ ]exceeded/i,
641
+ /too many tokens/i,
642
+ /token limit exceeded/i,
643
+ /^4(?:00|13)\s*(?:status code)?\s*\(no body\)/i
644
+ ];
645
+ /**
646
+ * Patterns that indicate non-overflow errors (e.g. rate limiting, server errors).
647
+ * Error messages matching any of these are excluded from overflow detection
648
+ * even if they also match an OVERFLOW_PATTERN.
649
+ *
650
+ * Example: Bedrock formats throttling errors as "ThrottlingException: Too many tokens,
651
+ * please wait before trying again." which would match the /too many tokens/i overflow
652
+ * pattern without this exclusion.
653
+ */
654
+ const NON_OVERFLOW_PATTERNS = [
655
+ /^(Throttling error|Service unavailable):/i,
656
+ /rate limit/i,
657
+ /too many requests/i
658
+ ];
659
+ /**
660
+ * Check if an assistant message represents a context overflow error.
661
+ *
662
+ * This handles three cases:
663
+ * 1. Error-based overflow: Most providers return stopReason "error" with a
664
+ * specific error message pattern.
665
+ * 2. Silent overflow: Some providers accept overflow requests and return
666
+ * successfully. For these, we check if usage.input exceeds the context window.
667
+ * 3. Length-stop overflow: Xiaomi MiMo can return "length" with zero output when
668
+ * the input fills the context window.
669
+ *
670
+ * ## Reliability by Provider
671
+ *
672
+ * **Reliable detection (returns error with detectable message):**
673
+ * - Anthropic: "prompt is too long: X tokens > Y maximum" or "request_too_large"
674
+ * - OpenAI (Completions & Responses): "exceeds the context window", "exceeds the model's maximum context length of X tokens", or "exceeds model's maximum context length (X)"
675
+ * - Google Gemini: "input token count exceeds the maximum"
676
+ * - xAI (Grok): "maximum prompt length is X but request contains Y"
677
+ * - Groq: "reduce the length of the messages"
678
+ * - Cerebras: 400/413 status code (no body)
679
+ * - Mistral: "Prompt contains X tokens ... too large for model with Y maximum context length"
680
+ * - OpenRouter (most backends): "maximum context length is X tokens"
681
+ * - OpenRouter/Poolside: "Input length X exceeds the maximum allowed input length of Y tokens."
682
+ * - Together AI: "The input (X tokens) is longer than the model's context length (Y tokens)."
683
+ * - llama.cpp: "exceeds the available context size"
684
+ * - LM Studio: "greater than the context length"
685
+ * - Kimi For Coding: "exceeded model token limit: X (requested: Y)"
686
+ * - DS4: "Prompt has X tokens, but the configured context size is Y tokens"
687
+ * - DashScope/Qwen: "Range of input length should be [1, X]"
688
+ *
689
+ * **Unreliable detection:**
690
+ * - z.ai: Sometimes accepts overflow silently (detectable via usage.input > contextWindow),
691
+ * sometimes returns rate limit errors. Pass contextWindow param to detect silent overflow.
692
+ * - Xiaomi MiMo: Truncates input to fit contextWindow then returns stopReason "length" with
693
+ * output=0. Pass contextWindow param to detect via the "filled context + zero output" signal.
694
+ * - Ollama: May truncate input silently for some setups, but may also return explicit
695
+ * overflow errors that match the patterns above. Silent truncation still cannot be
696
+ * detected here because we do not know the expected token count.
697
+ *
698
+ * ## Custom Providers
699
+ *
700
+ * If you've added custom models via settings.json, this function may not detect
701
+ * overflow errors from those providers. To add support:
702
+ *
703
+ * 1. Send a request that exceeds the model's context window
704
+ * 2. Check the errorMessage in the response
705
+ * 3. Create a regex pattern that matches the error
706
+ * 4. The pattern should be added to OVERFLOW_PATTERNS in this file, or
707
+ * check the errorMessage yourself before calling this function
708
+ *
709
+ * @param message - The assistant message to check
710
+ * @param contextWindow - Optional context window size for detecting silent overflow (z.ai)
711
+ * @returns true if the message indicates a context overflow
712
+ */
713
+ function isContextOverflow(message, contextWindow) {
714
+ if (message.stopReason === "error" && message.errorMessage) {
715
+ if (!NON_OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage)) && OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage))) return true;
716
+ }
717
+ if (contextWindow && message.stopReason === "stop") {
718
+ if (message.usage.input + message.usage.cacheRead > contextWindow) return true;
719
+ }
720
+ if (contextWindow && message.stopReason === "length" && message.usage.output === 0) {
721
+ if (message.usage.input + message.usage.cacheRead >= contextWindow * .99) return true;
722
+ }
723
+ return false;
724
+ }
725
+ /**
726
+ * Check whether a length stop ended below the caller or model's intended output limit.
727
+ * Such responses may be caused by context pressure or provider-side truncation, so callers
728
+ * can make one bounded compact-and-retry attempt. `desiredMaxOutput` must be the original
729
+ * limit before any context-based clamping.
730
+ */
731
+ function isRecoverableLength(message, desiredMaxOutput) {
732
+ return message.stopReason === "length" && desiredMaxOutput > 0 && message.usage.output < desiredMaxOutput;
733
+ }
734
+ /**
735
+ * Get the overflow patterns for testing purposes.
736
+ */
737
+ function getOverflowPatterns() {
738
+ return [...OVERFLOW_PATTERNS];
739
+ }
740
+ //#endregion
741
+ //#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/utils/retry.js
742
+ function buildProviderErrorPattern(patterns) {
743
+ return new RegExp(patterns.join("|"), "i");
744
+ }
745
+ const NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN = buildProviderErrorPattern([
746
+ "GoUsageLimitError",
747
+ "FreeUsageLimitError",
748
+ "Monthly usage limit reached",
749
+ "available balance",
750
+ "insufficient_quota",
751
+ "out of budget",
752
+ "quota exceeded",
753
+ "billing"
754
+ ]);
755
+ const RETRYABLE_PROVIDER_ERROR_PATTERN = buildProviderErrorPattern([
756
+ "overloaded",
757
+ "rate.?limit",
758
+ "too many requests",
759
+ "429",
760
+ "500",
761
+ "502",
762
+ "503",
763
+ "504",
764
+ "524",
765
+ "service.?unavailable",
766
+ "server.?error",
767
+ "internal.?error",
768
+ "provider.?returned.?error",
769
+ "network.?error",
770
+ "connection.?error",
771
+ "connection.?refused",
772
+ "connection.?lost",
773
+ "other side closed",
774
+ "fetch failed",
775
+ "getaddrinfo",
776
+ "ENOTFOUND",
777
+ "EAI_AGAIN",
778
+ "upstream.?connect",
779
+ "reset before headers",
780
+ "socket hang up",
781
+ "socket connection was closed",
782
+ "timed? out",
783
+ "timeout",
784
+ "terminated",
785
+ "websocket.?closed",
786
+ "websocket.?error",
787
+ "ended without",
788
+ "stream ended before message_stop",
789
+ "stream ended before a terminal response event",
790
+ "http2 request did not get a response",
791
+ "retry delay",
792
+ "you can retry your request",
793
+ "try your request again",
794
+ "please retry your request",
795
+ "ResourceExhausted"
796
+ ]);
797
+ var RetrySleepAbortError = class extends Error {
798
+ constructor() {
799
+ super("Aborted");
800
+ }
801
+ };
802
+ function sleep(ms, signal) {
803
+ return new Promise((resolve, reject) => {
804
+ if (signal?.aborted) {
805
+ reject(new RetrySleepAbortError());
806
+ return;
807
+ }
808
+ const timeout = setTimeout(resolve, ms);
809
+ signal?.addEventListener("abort", () => {
810
+ clearTimeout(timeout);
811
+ reject(new RetrySleepAbortError());
812
+ }, { once: true });
813
+ });
814
+ }
815
+ /**
816
+ * Run a single assistant-producing call with bounded retry on transient errors.
817
+ *
818
+ * Behavior:
819
+ * - A successful response is returned immediately. Aborts are terminal and never
820
+ * retried, but reported as unsuccessful if they happen after a retry was scheduled.
821
+ * Aborts during the backoff sleep are normalized to an aborted `AssistantMessage`
822
+ * too, so callers do not need to care when cancellation happened.
823
+ * - A non-retryable error (per {@link isRetryableAssistantError}, including quota/
824
+ * billing exhaustion) is returned immediately so deterministic errors fail fast.
825
+ * - Otherwise retries up to `maxRetries` times with exponential backoff, emitting
826
+ * `onRetryScheduled` before each sleep, `onRetryAttemptStart` after each sleep before
827
+ * the retried call starts, and `onRetryFinished` once at the end (whether the loop
828
+ * ends in success, exhausted retries, or an aborted backoff).
829
+ *
830
+ * When `policy` is undefined or disabled, the first response is returned unchanged
831
+ * (equivalent to calling `produce()` directly).
832
+ */
833
+ async function retryAssistantCall(produce, policy, signal, callbacks) {
834
+ const maxAttempts = policy?.enabled ? policy.maxRetries : 0;
835
+ let attempt = 0;
836
+ let lastRetry;
837
+ for (;;) {
838
+ const response = await produce();
839
+ if (response.stopReason === "aborted") {
840
+ if (lastRetry) await callbacks?.onRetryFinished?.(false, lastRetry.attempt);
841
+ return response;
842
+ }
843
+ if (response.stopReason !== "error") {
844
+ if (lastRetry) await callbacks?.onRetryFinished?.(true, lastRetry.attempt);
845
+ return response;
846
+ }
847
+ if (attempt >= maxAttempts || !isRetryableAssistantError(response)) {
848
+ if (lastRetry) await callbacks?.onRetryFinished?.(false, lastRetry.attempt, response.errorMessage);
849
+ return response;
850
+ }
851
+ attempt++;
852
+ lastRetry = {
853
+ attempt,
854
+ errorMessage: response.errorMessage || "Unknown error"
855
+ };
856
+ const delayMs = policy.baseDelayMs * 2 ** (attempt - 1);
857
+ await callbacks?.onRetryScheduled?.(attempt, maxAttempts, delayMs, lastRetry.errorMessage);
858
+ try {
859
+ await sleep(delayMs, signal);
860
+ } catch (error) {
861
+ await callbacks?.onRetryFinished?.(false, attempt, lastRetry.errorMessage);
862
+ if (error instanceof RetrySleepAbortError) return {
863
+ ...response,
864
+ stopReason: "aborted",
865
+ errorMessage: void 0
866
+ };
867
+ throw error;
868
+ }
869
+ await callbacks?.onRetryAttemptStart?.();
870
+ }
871
+ }
872
+ /**
873
+ * Classifies whether a failed assistant message looks like a transient provider
874
+ * or transport error, so callers can decide if the last assistant turn should be
875
+ * restarted.
876
+ *
877
+ * This does not implement retry policy. Callers should first handle context
878
+ * overflow separately, then apply their own retry budget, backoff, and reporting
879
+ * before restarting the assistant turn.
880
+ */
881
+ function isRetryableAssistantError(message) {
882
+ if (message.stopReason !== "error" || !message.errorMessage) return false;
883
+ const errorMessage = message.errorMessage;
884
+ if (NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN.test(errorMessage)) return false;
885
+ return RETRYABLE_PROVIDER_ERROR_PATTERN.test(errorMessage);
886
+ }
887
+ //#endregion
888
+ //#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/utils/text.js
889
+ /** Extract and join text from message content. */
890
+ function contentText(content, separator = "\n") {
891
+ if (typeof content === "string") return content;
892
+ return content.filter((block) => block.type === "text").map((block) => block.text).join(separator);
893
+ }
894
+ //#endregion
895
+ //#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/utils/typebox-helpers.js
896
+ /**
897
+ * Creates a string enum schema compatible with Google's API and other providers
898
+ * that don't support anyOf/const patterns.
899
+ *
900
+ * @example
901
+ * const OperationSchema = StringEnum(["add", "subtract", "multiply", "divide"], {
902
+ * description: "The operation to perform"
903
+ * });
904
+ *
905
+ * type Operation = Static<typeof OperationSchema>; // "add" | "subtract" | "multiply" | "divide"
906
+ */
907
+ function StringEnum(values, options) {
908
+ return Type$1.Unsafe({
909
+ type: "string",
910
+ enum: values,
911
+ ...options?.description && { description: options.description },
912
+ ...options?.default && { default: options.default }
913
+ });
914
+ }
915
+ //#endregion
916
+ //#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/utils/validation.js
917
+ const validatorCache = /* @__PURE__ */ new WeakMap();
918
+ const TYPEBOX_KIND = Symbol.for("TypeBox.Kind");
919
+ function getSchemaTypes(schema) {
920
+ if (typeof schema.type === "string") return [schema.type];
921
+ if (Array.isArray(schema.type)) return schema.type.filter((type) => typeof type === "string");
922
+ return [];
923
+ }
924
+ function matchesJsonType(value, type) {
925
+ switch (type) {
926
+ case "number": return typeof value === "number";
927
+ case "integer": return typeof value === "number" && Number.isInteger(value);
928
+ case "boolean": return typeof value === "boolean";
929
+ case "string": return typeof value === "string";
930
+ case "null": return value === null;
931
+ case "array": return Array.isArray(value);
932
+ case "object": return typeof value === "object" && value !== null && !Array.isArray(value);
933
+ default: return false;
934
+ }
935
+ }
936
+ function getSubSchemaValidator(schema) {
937
+ try {
938
+ return getValidator(schema);
939
+ } catch {
940
+ return;
941
+ }
942
+ }
943
+ function coercePrimitiveByType(value, type) {
944
+ switch (type) {
945
+ case "number":
946
+ if (value === null) return 0;
947
+ if (typeof value === "string" && value.trim() !== "") {
948
+ const parsed = Number(value);
949
+ if (Number.isFinite(parsed)) return parsed;
950
+ }
951
+ if (typeof value === "boolean") return value ? 1 : 0;
952
+ return value;
953
+ case "integer":
954
+ if (value === null) return 0;
955
+ if (typeof value === "string" && value.trim() !== "") {
956
+ const parsed = Number(value);
957
+ if (Number.isInteger(parsed)) return parsed;
958
+ }
959
+ if (typeof value === "boolean") return value ? 1 : 0;
960
+ return value;
961
+ case "boolean":
962
+ if (value === null) return false;
963
+ if (typeof value === "string") {
964
+ if (value === "true") return true;
965
+ if (value === "false") return false;
966
+ }
967
+ if (typeof value === "number") {
968
+ if (value === 1) return true;
969
+ if (value === 0) return false;
970
+ }
971
+ return value;
972
+ case "string":
973
+ if (value === null) return "";
974
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
975
+ return value;
976
+ case "null":
977
+ if (value === "" || value === 0 || value === false) return null;
978
+ return value;
979
+ default: return value;
980
+ }
981
+ }
982
+ function applySchemaObjectCoercion(value, schema) {
983
+ const properties = schema.properties;
984
+ const definedKeys = new Set(properties ? Object.keys(properties) : []);
985
+ if (properties) for (const [key, propertySchema] of Object.entries(properties)) {
986
+ if (!(key in value)) continue;
987
+ value[key] = coerceWithJsonSchema(value[key], propertySchema);
988
+ }
989
+ if (schema.additionalProperties && typeof schema.additionalProperties === "object") for (const [key, propertyValue] of Object.entries(value)) {
990
+ if (definedKeys.has(key)) continue;
991
+ value[key] = coerceWithJsonSchema(propertyValue, schema.additionalProperties);
992
+ }
993
+ }
994
+ function applySchemaArrayCoercion(value, schema) {
995
+ if (Array.isArray(schema.items)) {
996
+ for (let index = 0; index < value.length; index++) {
997
+ const itemSchema = schema.items[index];
998
+ if (!itemSchema) continue;
999
+ value[index] = coerceWithJsonSchema(value[index], itemSchema);
1000
+ }
1001
+ return;
1002
+ }
1003
+ if (schema.items && typeof schema.items === "object") for (let index = 0; index < value.length; index++) value[index] = coerceWithJsonSchema(value[index], schema.items);
1004
+ }
1005
+ function coerceWithUnionSchema(value, schemas) {
1006
+ for (const schema of schemas) if (getSubSchemaValidator(schema)?.Check(value)) return value;
1007
+ for (const schema of schemas) {
1008
+ const coerced = coerceWithJsonSchema(structuredClone(value), schema);
1009
+ if (getSubSchemaValidator(schema)?.Check(coerced)) return coerced;
1010
+ }
1011
+ return value;
1012
+ }
1013
+ function coerceWithJsonSchema(value, schema) {
1014
+ let nextValue = value;
1015
+ if (Array.isArray(schema.allOf)) for (const nested of schema.allOf) nextValue = coerceWithJsonSchema(nextValue, nested);
1016
+ if (Array.isArray(schema.anyOf)) nextValue = coerceWithUnionSchema(nextValue, schema.anyOf);
1017
+ if (Array.isArray(schema.oneOf)) nextValue = coerceWithUnionSchema(nextValue, schema.oneOf);
1018
+ const schemaTypes = getSchemaTypes(schema);
1019
+ const matchesUnionMember = schemaTypes.length > 1 && schemaTypes.some((schemaType) => matchesJsonType(nextValue, schemaType));
1020
+ if (schemaTypes.length > 0 && !matchesUnionMember) for (const schemaType of schemaTypes) {
1021
+ const candidate = coercePrimitiveByType(nextValue, schemaType);
1022
+ if (candidate !== nextValue) {
1023
+ nextValue = candidate;
1024
+ break;
1025
+ }
1026
+ }
1027
+ if (schemaTypes.includes("object") && typeof nextValue === "object" && nextValue !== null && !Array.isArray(nextValue)) applySchemaObjectCoercion(nextValue, schema);
1028
+ if (schemaTypes.includes("array") && Array.isArray(nextValue)) applySchemaArrayCoercion(nextValue, schema);
1029
+ return nextValue;
1030
+ }
1031
+ function getValidator(schema) {
1032
+ const key = schema;
1033
+ const cached = validatorCache.get(key);
1034
+ if (cached) return cached;
1035
+ const validator = Compile(schema);
1036
+ validatorCache.set(key, validator);
1037
+ return validator;
1038
+ }
1039
+ function formatValidationPath(error) {
1040
+ if (error.keyword === "required") {
1041
+ const requiredProperty = error.params.requiredProperties?.[0];
1042
+ if (requiredProperty) {
1043
+ const basePath = error.instancePath.replace(/^\//, "").replace(/\//g, ".");
1044
+ return basePath ? `${basePath}.${requiredProperty}` : requiredProperty;
1045
+ }
1046
+ }
1047
+ return error.instancePath.replace(/^\//, "").replace(/\//g, ".") || "root";
1048
+ }
1049
+ /**
1050
+ * Finds a tool by name and validates the tool call arguments against its TypeBox schema
1051
+ * @param tools Array of tool definitions
1052
+ * @param toolCall The tool call from the LLM
1053
+ * @returns The validated arguments
1054
+ * @throws Error if tool is not found or validation fails
1055
+ */
1056
+ function validateToolCall(tools, toolCall) {
1057
+ const tool = tools.find((t) => t.name === toolCall.name);
1058
+ if (!tool) throw new Error(`Tool "${toolCall.name}" not found`);
1059
+ return validateToolArguments(tool, toolCall);
1060
+ }
1061
+ /**
1062
+ * Validates tool call arguments against the tool's TypeBox schema
1063
+ * @param tool The tool definition with TypeBox schema
1064
+ * @param toolCall The tool call from the LLM
1065
+ * @returns The validated (and potentially coerced) arguments
1066
+ * @throws Error with formatted message if validation fails
1067
+ */
1068
+ function validateToolArguments(tool, toolCall) {
1069
+ const args = structuredClone(toolCall.arguments);
1070
+ Value.Convert(tool.parameters, args);
1071
+ const validator = getValidator(tool.parameters);
1072
+ if (!Object.getOwnPropertySymbols(tool.parameters).includes(TYPEBOX_KIND)) {
1073
+ const coerced = coerceWithJsonSchema(args, tool.parameters);
1074
+ if (coerced !== args) {
1075
+ if (typeof args === "object" && args !== null && typeof coerced === "object" && coerced !== null) {
1076
+ for (const key of Object.keys(args)) delete args[key];
1077
+ Object.assign(args, coerced);
1078
+ } else return validator.Check(coerced) ? coerced : args;
1079
+ }
1080
+ }
1081
+ if (validator.Check(args)) return args;
1082
+ const errors = validator.Errors(args).map((error) => ` - ${formatValidationPath(error)}: ${error.message}`).join("\n") || "Unknown validation error";
1083
+ const errorMessage = `Validation failed for tool "${toolCall.name}":\n${errors}\n\nReceived arguments:\n${JSON.stringify(toolCall.arguments, null, 2)}`;
1084
+ throw new Error(errorMessage);
1085
+ }
1086
+ //#endregion
1087
+ export { AssistantMessageEventStream, EventStream, InMemoryCredentialStore, InMemoryModelsStore, ModelsError, StringEnum, Type, appendAssistantMessageDiagnostic, calculateCost, clampThinkingLevel, cleanupSessionResources, contentText, createAssistantMessageDiagnostic, createAssistantMessageEventStream, createFauxCore, createImagesModels, createImagesProvider, createModels, createProvider, defaultProviderAuthContext, envApiKeyAuth, extractDiagnosticError, fauxAssistantMessage, fauxProvider, fauxText, fauxThinking, fauxToolCall, formatThrownValue, getOverflowPatterns, getSupportedThinkingLevels, hasApi, isContextOverflow, isRecoverableLength, isRetryableAssistantError, lazyApi, lazyOAuth, lazyStream, modelsAreEqual, parseJsonWithRepair, parseStreamingJson, registerSessionResourceCleanup, repairJson, retryAssistantCall, uuidv7, validateToolArguments, validateToolCall };
1088
+
1089
+ //# sourceMappingURL=dist-DeonWo7m.mjs.map