openfox 2.0.76 → 2.0.77

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 (44) hide show
  1. package/dist/{chat-handler-3BZ4PDL2.js → chat-handler-FNRKORKP.js} +8 -8
  2. package/dist/{chunk-XTK6E2QR.js → chunk-3TQN25OM.js} +2 -2
  3. package/dist/{chunk-J7VCI5EX.js → chunk-BX3VJP2D.js} +96 -44
  4. package/dist/{chunk-OMWVB2XC.js → chunk-CI5BWHW7.js} +5 -5
  5. package/dist/{chunk-OCVRIPQP.js → chunk-CJDYSUU5.js} +3 -3
  6. package/dist/{chunk-HAQV6AJP.js → chunk-CPTC2MD5.js} +2 -2
  7. package/dist/chunk-NUXS5OQB.js +7 -0
  8. package/dist/{chunk-EZK7CGJ7.js → chunk-RMXPVQP4.js} +315 -45
  9. package/dist/{chunk-HLHGNHMV.js → chunk-VMYDUZWI.js} +5 -5
  10. package/dist/{chunk-KVRSAC4Z.js → chunk-VPFUXGMM.js} +6 -1
  11. package/dist/{chunk-W4ZEG3LX.js → chunk-WL2WEJAK.js} +2 -2
  12. package/dist/{chunk-7772ENZN.js → chunk-XNCHOD2X.js} +2 -2
  13. package/dist/{chunk-D6CI2B7B.js → chunk-YDV7RIQ6.js} +115 -72
  14. package/dist/{chunk-WGAAQASA.js → chunk-YFVSSMA3.js} +3 -2
  15. package/dist/{chunk-HHUIXHHX.js → chunk-YPHLCRFP.js} +7 -7
  16. package/dist/cli/dev.js +1 -1
  17. package/dist/cli/index.js +1 -1
  18. package/dist/{client-TDPQVBQ7.js → client-V5DZRO2D.js} +3 -3
  19. package/dist/{client-pure-NMLDKRDN.js → client-pure-5YE5WFJP.js} +2 -2
  20. package/dist/{compactor-BB3YYVRP.js → compactor-BJXFE5PL.js} +4 -4
  21. package/dist/{config-EUMVEFHU.js → config-MD74ETY5.js} +2 -2
  22. package/dist/{orchestrator-5IMCWX5P.js → orchestrator-67BZJEOO.js} +7 -7
  23. package/dist/package.json +3 -1
  24. package/dist/{processor-3R4GS6VB.js → processor-BCOSEMZK.js} +8 -8
  25. package/dist/{protocol-Sr6Jr4ZS.d.ts → protocol-Ceapo3jt.d.ts} +1 -1
  26. package/dist/provider/index.d.ts +4 -4
  27. package/dist/{provider-G2YC2IC4.js → provider-PI3RDDE4.js} +6 -6
  28. package/dist/{provider-manager-SQIELYLK.js → provider-manager-PD3BXUHY.js} +4 -4
  29. package/dist/{serve-MXKMKZYY.js → serve-BD44GN7N.js} +13 -13
  30. package/dist/server/index.d.ts +3 -3
  31. package/dist/server/index.js +12 -12
  32. package/dist/{server-SPYFMFQE.js → server-OLRW27DH.js} +9 -9
  33. package/dist/shared/index.d.ts +3 -3
  34. package/dist/{tools-JRCUWPJO.js → tools-T7S45DOQ.js} +6 -6
  35. package/dist/{types-C4cG9CtC.d.ts → types-DABVUbUu.d.ts} +1 -0
  36. package/dist/{types-DSZhFA8O.d.ts → types-pssMT-oY.d.ts} +1 -1
  37. package/dist/{update-OXDQ75M7.js → update-56VZOLQJ.js} +2 -2
  38. package/dist/{update-server-4MTM7M5P.js → update-server-V6GJ43WH.js} +2 -2
  39. package/dist/web/assets/index-BuUd6IgK.js +305 -0
  40. package/dist/web/index.html +1 -1
  41. package/dist/web/sw.js +1 -1
  42. package/package.json +3 -1
  43. package/dist/chunk-KQEVAO2Q.js +0 -7
  44. package/dist/web/assets/index-ghDkIdlf.js +0 -305
@@ -19,6 +19,7 @@ var OUTPUT_LIMITS = {
19
19
  maxImageBytes: 2097152,
20
20
  // 2MB for images
21
21
  maxPdfPages: 50,
22
+ maxPdfImages: 20,
22
23
  maxFileBytes: 20971520
23
24
  // 20MB general file safety limit
24
25
  },
@@ -38,7 +39,8 @@ var OUTPUT_LIMITS = {
38
39
  };
39
40
 
40
41
  // src/server/tools/pdf-utils.ts
41
- import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
42
+ import { getDocument, OPS } from "pdfjs-dist/legacy/build/pdf.mjs";
43
+ import { PNG } from "pngjs";
42
44
  var PDF_HEADER = Buffer.from("%PDF");
43
45
  function isPdfBuffer(buffer) {
44
46
  return buffer.length > 4 && buffer.subarray(0, 4).equals(PDF_HEADER);
@@ -63,47 +65,278 @@ function processPdfContent(text, maxBytes) {
63
65
  const isScanned = output.replace(/\[Page \d+\/\d+\]\n/g, "").trim().length === 0;
64
66
  return { output, truncated, isScanned };
65
67
  }
66
- async function extractPdfText(buffer) {
68
+ var IMAGE_KIND_GRAYSCALE_1BPP = 1;
69
+ var IMAGE_KIND_RGB_24BPP = 2;
70
+ var IMAGE_KIND_RGBA_32BPP = 3;
71
+ function getRgbaPixel(data, width, x, y, kind) {
72
+ if (kind === IMAGE_KIND_RGBA_32BPP) {
73
+ const i = (y * width + x) * 4;
74
+ return [data[i] ?? 0, data[i + 1] ?? 0, data[i + 2] ?? 0, data[i + 3] ?? 255];
75
+ }
76
+ if (kind === IMAGE_KIND_RGB_24BPP) {
77
+ const i = (y * width + x) * 3;
78
+ return [data[i] ?? 0, data[i + 1] ?? 0, data[i + 2] ?? 0, 255];
79
+ }
80
+ if (kind === IMAGE_KIND_GRAYSCALE_1BPP) {
81
+ const bytesPerRow = Math.ceil(width / 8);
82
+ const byteIdx = y * bytesPerRow + Math.floor(x / 8);
83
+ const bitIdx = 7 - x % 8;
84
+ const val = (data[byteIdx] ?? 0) >> bitIdx & 1 ? 255 : 0;
85
+ return [val, val, val, 255];
86
+ }
87
+ return [0, 0, 0, 255];
88
+ }
89
+ function toRgbaBuffer(data, width, height, kind) {
90
+ const rgba = new Uint8Array(width * height * 4);
91
+ for (let y = 0; y < height; y++) {
92
+ for (let x = 0; x < width; x++) {
93
+ const [r, g, b, a] = getRgbaPixel(data, width, x, y, kind);
94
+ const i = (y * width + x) * 4;
95
+ rgba[i] = r;
96
+ rgba[i + 1] = g;
97
+ rgba[i + 2] = b;
98
+ rgba[i + 3] = a;
99
+ }
100
+ }
101
+ return rgba;
102
+ }
103
+ function extractBitmapToRawImageData(bitmap) {
104
+ const canvas = new globalThis.OffscreenCanvas(bitmap.width, bitmap.height);
105
+ const ctx = canvas.getContext("2d");
106
+ ctx.drawImage(bitmap, 0, 0);
107
+ const imageData = ctx.getImageData(0, 0, bitmap.width, bitmap.height);
108
+ return {
109
+ width: bitmap.width,
110
+ height: bitmap.height,
111
+ data: new Uint8Array(imageData.data.buffer),
112
+ kind: IMAGE_KIND_RGBA_32BPP
113
+ };
114
+ }
115
+ function encodeImageToDataUrl(imgData, maxDimension = 1024) {
116
+ try {
117
+ let { width, height } = imgData;
118
+ let { data, kind } = imgData;
119
+ if (imgData.bitmap && !data) {
120
+ const converted = extractBitmapToRawImageData(imgData.bitmap);
121
+ data = converted.data;
122
+ kind = converted.kind;
123
+ }
124
+ if (!data) return null;
125
+ if (width * height * 4 > 20971520) return null;
126
+ if (maxDimension > 0 && (width > maxDimension || height > maxDimension)) {
127
+ const scale = maxDimension / Math.max(width, height);
128
+ const newWidth = Math.round(width * scale);
129
+ const newHeight = Math.round(height * scale);
130
+ const scaled = new Uint8Array(newWidth * newHeight * 4);
131
+ for (let y = 0; y < newHeight; y++) {
132
+ for (let x = 0; x < newWidth; x++) {
133
+ const srcX = Math.floor(x / scale);
134
+ const srcY = Math.floor(y / scale);
135
+ const dstI = (y * newWidth + x) * 4;
136
+ const [r, g, b, a] = getRgbaPixel(data, width, srcX, srcY, kind);
137
+ scaled[dstI] = r;
138
+ scaled[dstI + 1] = g;
139
+ scaled[dstI + 2] = b;
140
+ scaled[dstI + 3] = a;
141
+ }
142
+ }
143
+ width = newWidth;
144
+ height = newHeight;
145
+ const png2 = new PNG({ width, height });
146
+ Buffer.from(scaled.buffer, scaled.byteOffset, scaled.byteLength).copy(png2.data);
147
+ const pngBuffer2 = PNG.sync.write(png2);
148
+ return `data:image/png;base64,${pngBuffer2.toString("base64")}`;
149
+ }
150
+ let rgba;
151
+ if (kind === IMAGE_KIND_RGBA_32BPP) {
152
+ rgba = Uint8Array.from(
153
+ data instanceof Uint8ClampedArray ? new Uint8Array(data.buffer, data.byteOffset, data.byteLength) : data
154
+ );
155
+ } else {
156
+ rgba = toRgbaBuffer(data, width, height, kind);
157
+ }
158
+ const png = new PNG({ width, height });
159
+ Buffer.from(rgba.buffer, rgba.byteOffset, rgba.byteLength).copy(png.data);
160
+ const pngBuffer = PNG.sync.write(png);
161
+ return `data:image/png;base64,${pngBuffer.toString("base64")}`;
162
+ } catch {
163
+ return null;
164
+ }
165
+ }
166
+ async function extractPageBlocks(page, pageIndex, pageCount, imageCounter, maxImages) {
167
+ const [textContent, opList] = await Promise.all([page.getTextContent(), page.getOperatorList()]);
168
+ const textItems = textContent.items.filter(
169
+ (item) => "str" in item
170
+ );
171
+ const textStr = textItems.map((t) => t.str).join(" ").trim();
172
+ const imageOpIndices = [];
173
+ for (let i = 0; i < opList.fnArray.length; i++) {
174
+ const op = opList.fnArray[i];
175
+ if (op === OPS.paintImageXObject || op === OPS.paintInlineImageXObject || op === OPS.paintImageMaskXObject || op === OPS.paintImageMaskXObjectGroup || op === OPS.paintImageXObjectRepeat || op === OPS.paintImageMaskXObjectRepeat || op === OPS.paintInlineImageXObjectGroup || op === OPS.paintSolidColorImageMask) {
176
+ imageOpIndices.push(i);
177
+ }
178
+ }
179
+ const blocks = [];
180
+ if (textStr) {
181
+ blocks.push({ type: "text", content: `[Page ${pageIndex}/${pageCount}]
182
+ ${textStr}` });
183
+ }
184
+ for (let imageOpIdx = 0; imageOpIdx < imageOpIndices.length; imageOpIdx++) {
185
+ if (imageCounter.count >= maxImages) {
186
+ imageCounter.limitReached = true;
187
+ break;
188
+ }
189
+ const opIdx = imageOpIndices[imageOpIdx];
190
+ if (opIdx === void 0) break;
191
+ const imgBlock = await extractImageBlock(page, opList, opIdx);
192
+ if (imgBlock) {
193
+ blocks.push(imgBlock);
194
+ imageCounter.count++;
195
+ }
196
+ }
197
+ return blocks;
198
+ }
199
+ function isValidPixelData(data) {
200
+ return data instanceof Uint8Array || data instanceof Uint8ClampedArray;
201
+ }
202
+ var IMAGE_RESOLVE_TIMEOUT_MS = 5e3;
203
+ async function getObjectWithFallback(objs, objId) {
204
+ try {
205
+ return objs.get(objId);
206
+ } catch {
207
+ }
208
+ return new Promise((resolve, reject) => {
209
+ const timeoutId = setTimeout(() => reject(new Error("timeout")), IMAGE_RESOLVE_TIMEOUT_MS);
210
+ try {
211
+ ;
212
+ objs.get(objId, (data) => {
213
+ clearTimeout(timeoutId);
214
+ resolve(data);
215
+ });
216
+ } catch (e) {
217
+ clearTimeout(timeoutId);
218
+ reject(e);
219
+ }
220
+ });
221
+ }
222
+ async function extractImageBlock(page, opList, opIdx) {
223
+ const args = opList.argsArray[opIdx];
224
+ const objId = Array.isArray(args) ? args[0] : void 0;
225
+ let imgData = null;
226
+ if (objId && typeof objId === "string") {
227
+ try {
228
+ const store = objId.startsWith("g_") ? page.commonObjs : page.objs;
229
+ const raw = await getObjectWithFallback(store, objId);
230
+ if (raw && typeof raw === "object" && "width" in raw && "height" in raw) {
231
+ const r = raw;
232
+ if (isValidPixelData(r["data"])) {
233
+ imgData = raw;
234
+ } else if (r["bitmap"] && !r["data"]) {
235
+ imgData = raw;
236
+ }
237
+ }
238
+ } catch {
239
+ }
240
+ } else if (Array.isArray(args) && args[0] && typeof args[0] === "object" && "width" in args[0]) {
241
+ const inline = args[0];
242
+ if (isValidPixelData(inline["data"])) {
243
+ imgData = args[0];
244
+ } else if (inline["bitmap"] && !inline["data"]) {
245
+ imgData = args[0];
246
+ }
247
+ }
248
+ if (imgData) {
249
+ const dataUrl = encodeImageToDataUrl(imgData);
250
+ if (dataUrl) {
251
+ return { type: "image", dataUrl };
252
+ }
253
+ }
254
+ return null;
255
+ }
256
+ async function extractPdfContent(buffer) {
67
257
  const doc = await getDocument({ data: Uint8Array.from(buffer) }).promise;
68
258
  const pageCount = doc.numPages;
69
- const rawMeta = await doc.getMetadata();
70
- const info = rawMeta.info;
71
- const title = info?.["Title"] || null;
72
- const author = info?.["Author"] || null;
73
- const pages = [];
259
+ const allBlocks = [];
74
260
  const limitedPageCount = Math.min(pageCount, OUTPUT_LIMITS.read_file.maxPdfPages);
261
+ const maxImages = OUTPUT_LIMITS.read_file.maxPdfImages;
262
+ const imageCounter = { count: 0, limitReached: false };
263
+ let title = null;
264
+ let author = null;
265
+ try {
266
+ const rawMeta = await doc.getMetadata();
267
+ const info = rawMeta.info;
268
+ title = info?.["Title"] || null;
269
+ author = info?.["Author"] || null;
270
+ } catch {
271
+ }
75
272
  try {
76
273
  for (let i = 1; i <= limitedPageCount; i++) {
77
274
  const page = await doc.getPage(i);
78
275
  try {
79
- const content = await page.getTextContent();
80
- const pageText = content.items.map((item) => "str" in item ? item.str : "").join(" ");
81
- pages.push(`[Page ${i}/${pageCount}]
82
- ${pageText}`);
276
+ const blocks = await extractPageBlocks(page, i, pageCount, imageCounter, maxImages);
277
+ allBlocks.push(...blocks);
83
278
  } finally {
84
279
  page.cleanup();
85
280
  }
86
281
  }
282
+ } catch {
87
283
  } finally {
88
284
  doc.cleanup();
89
285
  }
90
- let text = pages.join("\n\n");
91
286
  if (pageCount > limitedPageCount) {
92
- text += `
287
+ allBlocks.push({
288
+ type: "text",
289
+ content: `[PDF has ${pageCount} pages, showing first ${limitedPageCount}. Use a shell command to process more.]`
290
+ });
291
+ }
292
+ if (imageCounter.limitReached) {
293
+ allBlocks.push({
294
+ type: "text",
295
+ content: `[Image limit reached: showing first ${maxImages} images out of more in this document.]`
296
+ });
297
+ }
298
+ return {
299
+ blocks: allBlocks,
300
+ pageCount,
301
+ title,
302
+ author,
303
+ imageCount: imageCounter.count,
304
+ imageLimitReached: imageCounter.limitReached
305
+ };
306
+ }
307
+ async function extractPdfText(buffer) {
308
+ const result = await extractPdfContent(buffer);
309
+ const text = result.blocks.filter((b) => b.type === "text").map((b) => b.content ?? "").join("\n\n");
310
+ return { text, pageCount: result.pageCount, title: result.title, author: result.author };
311
+ }
93
312
 
94
- [PDF has ${pageCount} pages, showing first ${limitedPageCount}. Use a shell command to process more.]`;
313
+ // src/server/utils/cache.ts
314
+ import { createHash } from "crypto";
315
+ function contentHash(data) {
316
+ return createHash("sha256").update(data).digest("hex").slice(0, 16);
317
+ }
318
+ function cacheSet(cache, key, value) {
319
+ const max = 50;
320
+ if (cache.size >= max) {
321
+ const first = cache.keys().next().value;
322
+ if (first !== void 0) cache.delete(first);
95
323
  }
96
- return { text, pageCount, title, author };
324
+ cache.set(key, value);
97
325
  }
98
326
 
99
- // src/server/llm/resolve-attachments.ts
100
- function decodeDataUrlToText(data) {
327
+ // src/server/utils/data-url.ts
328
+ function decodeDataUrl(data) {
101
329
  const match = data.match(/^data:.*?;base64,(.+)$/);
102
- if (match?.[1]) {
103
- return Buffer.from(match[1], "base64").toString("utf8");
330
+ if (!match?.[1]) return null;
331
+ try {
332
+ return Buffer.from(match[1], "base64");
333
+ } catch {
334
+ return null;
104
335
  }
105
- return data;
106
336
  }
337
+
338
+ // src/server/llm/resolve-attachments.ts
339
+ var pdfBlockCache = /* @__PURE__ */ new Map();
107
340
  async function extractPdfFromDataUrl(data, filename) {
108
341
  const base64Match = data.match(/^data:.*?;base64,(.+)$/);
109
342
  if (base64Match?.[1]) {
@@ -118,14 +351,50 @@ ${result.text}`;
118
351
  }
119
352
  return `[PDF: ${filename}] (could not extract text)`;
120
353
  }
354
+ async function extractPdfBlocksFromDataUrl(data, filename) {
355
+ const cacheKey = contentHash(data);
356
+ const cached = pdfBlockCache.get(cacheKey);
357
+ if (cached) {
358
+ const result = [{ type: "text", text: `[PDF: ${filename}]` }];
359
+ result.push(...cached);
360
+ return result;
361
+ }
362
+ const base64Match = data.match(/^data:.*?;base64,(.+)$/);
363
+ if (!base64Match?.[1]) {
364
+ cacheSet(pdfBlockCache, cacheKey, []);
365
+ return [{ type: "text", text: `[PDF: ${filename}] (could not extract content)` }];
366
+ }
367
+ try {
368
+ const buffer = Buffer.from(base64Match[1], "base64");
369
+ const result = await extractPdfContent(buffer);
370
+ const body = [];
371
+ for (const block of result.blocks) {
372
+ if (block.type === "text" && block.content) {
373
+ body.push({ type: "text", text: block.content });
374
+ } else if (block.type === "image" && block.dataUrl) {
375
+ body.push({ type: "image_url", image_url: { url: block.dataUrl } });
376
+ }
377
+ }
378
+ cacheSet(pdfBlockCache, cacheKey, body);
379
+ const parts = [{ type: "text", text: `[PDF: ${filename}]` }];
380
+ parts.push(...body);
381
+ return parts;
382
+ } catch {
383
+ cacheSet(pdfBlockCache, cacheKey, []);
384
+ return [{ type: "text", text: `[PDF: ${filename}] (could not extract content)` }];
385
+ }
386
+ }
121
387
  async function resolveAttachmentToText(attachment, supportsVision) {
122
388
  const mimeType = attachment.mimeType;
123
389
  if (TEXT_MIME_EXACT.includes(mimeType) || TEXT_MIME_PREFIXES.some((p) => mimeType.startsWith(p))) {
124
- const text = decodeDataUrlToText(attachment.data);
390
+ const text = decodeDataUrl(attachment.data)?.toString("utf8") ?? attachment.data;
125
391
  return `[File: ${attachment.filename || "file"}]
126
392
  ${text}`;
127
393
  }
128
394
  if (mimeType === "application/pdf") {
395
+ if (attachment.pdfContent) {
396
+ return attachment.pdfContent;
397
+ }
129
398
  return extractPdfFromDataUrl(attachment.data, attachment.filename || "document.pdf");
130
399
  }
131
400
  if (supportsVision) {
@@ -136,6 +405,7 @@ ${text}`;
136
405
  }
137
406
  return `[Image: ${attachment.filename || "image"}] (vision not supported, cannot describe)`;
138
407
  }
408
+ var isVisionAttachment = (attachment) => attachment.mimeType.startsWith("image/") || attachment.mimeType === "application/pdf";
139
409
  async function resolveAttachmentsInMessages(messages, supportsVision) {
140
410
  const result = [];
141
411
  for (const msg of messages) {
@@ -143,7 +413,7 @@ async function resolveAttachmentsInMessages(messages, supportsVision) {
143
413
  result.push(msg);
144
414
  continue;
145
415
  }
146
- if (supportsVision && msg.attachments.every((a) => a.mimeType.startsWith("image/"))) {
416
+ if (supportsVision && msg.attachments.every(isVisionAttachment)) {
147
417
  result.push(msg);
148
418
  continue;
149
419
  }
@@ -151,7 +421,7 @@ async function resolveAttachmentsInMessages(messages, supportsVision) {
151
421
  if (msg.content?.trim()) parts.push(msg.content);
152
422
  const remainingImageAttachments = [];
153
423
  for (const attachment of msg.attachments) {
154
- if (supportsVision && attachment.mimeType.startsWith("image/")) {
424
+ if (supportsVision && isVisionAttachment(attachment)) {
155
425
  remainingImageAttachments.push(attachment);
156
426
  continue;
157
427
  }
@@ -197,8 +467,8 @@ async function buildAttachmentContent(msgContent, attachments, modelSupportsVisi
197
467
  content.push({ type: "text", text: msgContent });
198
468
  }
199
469
  for (const attachment of attachments) {
200
- const converted = await convertAttachment(attachment, modelSupportsVision);
201
- content.push(converted);
470
+ const parts = await convertAttachment(attachment, modelSupportsVision);
471
+ content.push(...parts);
202
472
  }
203
473
  return content;
204
474
  }
@@ -222,7 +492,7 @@ function getThinking(msg, override) {
222
492
  function buildAssistantMessage(msg, thinkingField) {
223
493
  const result = {
224
494
  role: "assistant",
225
- content: msg.content || null
495
+ content: msg.toolCalls?.length ? msg.content || "" : msg.content || null
226
496
  };
227
497
  if (msg.toolCalls?.length) {
228
498
  result["tool_calls"] = convertToolCalls(msg.toolCalls);
@@ -235,32 +505,28 @@ function buildAssistantMessage(msg, thinkingField) {
235
505
  async function convertAttachment(attachment, modelSupportsVision) {
236
506
  const mimeType = attachment.mimeType;
237
507
  if (TEXT_MIME_EXACT.includes(mimeType) || TEXT_MIME_PREFIXES.some((p) => mimeType.startsWith(p))) {
238
- return {
239
- type: "text",
240
- text: `[File: ${attachment.filename || "file"}]
241
- ${attachment.data}`
242
- };
508
+ return [{ type: "text", text: `[File: ${attachment.filename || "file"}]
509
+ ${attachment.data}` }];
243
510
  }
244
511
  if (mimeType === "application/pdf") {
512
+ if (modelSupportsVision) {
513
+ return extractPdfBlocksFromDataUrl(attachment.data, attachment.filename || "document.pdf");
514
+ }
515
+ if (attachment.pdfContent) {
516
+ return [{ type: "text", text: attachment.pdfContent }];
517
+ }
245
518
  const text = await extractPdfFromDataUrl(attachment.data, attachment.filename || "document.pdf");
246
- return { type: "text", text };
519
+ return [{ type: "text", text }];
247
520
  }
248
521
  if (modelSupportsVision) {
249
- return {
250
- type: "image_url",
251
- image_url: { url: attachment.data }
252
- };
522
+ return [{ type: "image_url", image_url: { url: attachment.data } }];
253
523
  }
254
524
  if (attachment.description) {
255
- return {
256
- type: "text",
257
- text: `[Image: ${attachment.filename || "image"} - description: ${attachment.description}]`
258
- };
525
+ return [
526
+ { type: "text", text: `[Image: ${attachment.filename || "image"} - description: ${attachment.description}]` }
527
+ ];
259
528
  }
260
- return {
261
- type: "text",
262
- text: `[Image: ${attachment.filename || "image"}] (vision not supported, cannot describe)`
263
- };
529
+ return [{ type: "text", text: `[Image: ${attachment.filename || "image"}] (vision not supported, cannot describe)` }];
264
530
  }
265
531
  async function convertMessages(messages, modelSupportsVision, thinkingField) {
266
532
  const filtered = messages.filter((msg) => {
@@ -398,7 +664,11 @@ export {
398
664
  isPdfBuffer,
399
665
  formatPdfErrorMessage,
400
666
  processPdfContent,
667
+ extractPdfContent,
401
668
  extractPdfText,
669
+ contentHash,
670
+ cacheSet,
671
+ decodeDataUrl,
402
672
  resolveAttachmentsInMessages,
403
673
  parseToolArguments,
404
674
  buildModelParams,
@@ -409,4 +679,4 @@ export {
409
679
  buildStreamingCreateParams,
410
680
  mapFinishReason
411
681
  };
412
- //# sourceMappingURL=chunk-EZK7CGJ7.js.map
682
+ //# sourceMappingURL=chunk-RMXPVQP4.js.map
@@ -9,7 +9,7 @@ import {
9
9
  loadAllAgentsDefault,
10
10
  processEventsForConversation,
11
11
  runTopLevelAgentLoop
12
- } from "./chunk-D6CI2B7B.js";
12
+ } from "./chunk-YDV7RIQ6.js";
13
13
  import {
14
14
  TurnMetrics,
15
15
  buildAgentReminder,
@@ -17,7 +17,7 @@ import {
17
17
  buildTopLevelSystemPrompt,
18
18
  createChatDoneEvent,
19
19
  createMessageStartEvent
20
- } from "./chunk-7772ENZN.js";
20
+ } from "./chunk-XNCHOD2X.js";
21
21
  import {
22
22
  PathAccessDeniedError
23
23
  } from "./chunk-46RORSKU.js";
@@ -66,7 +66,7 @@ function resolveAgentDef(sessionManager, sessionId) {
66
66
  }
67
67
  async function buildCachedPrompt(sessionManager, sessionId, agentDef) {
68
68
  const { instructionContent, skills } = await loadSessionContext(sessionManager, sessionId);
69
- const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-JRCUWPJO.js");
69
+ const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-T7S45DOQ.js");
70
70
  const tools = getToolRegistryForAgent2(agentDef).definitions;
71
71
  const toolFingerprint = getToolFingerprint(tools);
72
72
  const allAgents = await loadAllAgentsDefault();
@@ -79,7 +79,7 @@ async function buildCachedPrompt(sessionManager, sessionId, agentDef) {
79
79
  async function computeSessionHash(sessionManager, sessionId) {
80
80
  const { instructionContent, skills } = await loadSessionContext(sessionManager, sessionId);
81
81
  const agentDef = await resolveAgentDef(sessionManager, sessionId);
82
- const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-JRCUWPJO.js");
82
+ const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-T7S45DOQ.js");
83
83
  const tools = getToolRegistryForAgent2(agentDef).definitions;
84
84
  const toolFingerprint = getToolFingerprint(tools);
85
85
  return computeDynamicContextHash(instructionContent, skills, toolFingerprint);
@@ -359,4 +359,4 @@ export {
359
359
  runChatTurn,
360
360
  runAgentTurn
361
361
  };
362
- //# sourceMappingURL=chunk-HLHGNHMV.js.map
362
+ //# sourceMappingURL=chunk-VMYDUZWI.js.map
@@ -8,6 +8,10 @@ function buildUpdatedServerConfig(patch, existing, persistedCfg) {
8
8
  const mergedEnv = patch.env !== void 0 ? patch.env : transportChanged ? void 0 : existing.config.env;
9
9
  const mergedUrl = patch.url !== void 0 ? patch.url : transportChanged ? void 0 : existing.config.url;
10
10
  const mergedHeaders = patch.headers !== void 0 ? patch.headers : transportChanged ? void 0 : existing.config.headers;
11
+ const mergedTimeout = patch.timeout !== void 0 ? patch.timeout : existing.config.timeout;
12
+ if (patch.timeout !== void 0 && (typeof patch.timeout !== "number" || patch.timeout <= 0)) {
13
+ return { serverCfg: {}, error: "timeout must be a positive number" };
14
+ }
11
15
  if (resolvedTransport === "http" && !mergedUrl) {
12
16
  return { serverCfg: {}, error: "url is required for http transport" };
13
17
  }
@@ -21,6 +25,7 @@ function buildUpdatedServerConfig(patch, existing, persistedCfg) {
21
25
  ...mergedEnv && Object.keys(mergedEnv).length > 0 ? { env: mergedEnv } : {},
22
26
  ...mergedUrl ? { url: mergedUrl } : {},
23
27
  ...mergedHeaders && Object.keys(mergedHeaders).length > 0 ? { headers: mergedHeaders } : {},
28
+ ...mergedTimeout !== void 0 ? { timeout: mergedTimeout } : {},
24
29
  ...persistedCfg?.disabledTools && persistedCfg.disabledTools.length > 0 ? { disabledTools: persistedCfg.disabledTools } : {},
25
30
  ...persistedCfg?.cachedTools && persistedCfg.cachedTools.length > 0 ? { cachedTools: persistedCfg.cachedTools } : {}
26
31
  };
@@ -51,4 +56,4 @@ export {
51
56
  buildUpdatedServerConfig,
52
57
  applyMcpServerUpdate
53
58
  };
54
- //# sourceMappingURL=chunk-KVRSAC4Z.js.map
59
+ //# sourceMappingURL=chunk-VPFUXGMM.js.map
@@ -13,7 +13,7 @@ import {
13
13
  getThinking,
14
14
  mapFinishReason,
15
15
  parseToolArguments
16
- } from "./chunk-EZK7CGJ7.js";
16
+ } from "./chunk-RMXPVQP4.js";
17
17
  import {
18
18
  LLMError,
19
19
  OpenAIHttpClient
@@ -268,4 +268,4 @@ function createLLMClient(config, initialBackend = "unknown") {
268
268
  export {
269
269
  createLLMClient
270
270
  };
271
- //# sourceMappingURL=chunk-W4ZEG3LX.js.map
271
+ //# sourceMappingURL=chunk-WL2WEJAK.js.map
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-YHEQTVFV.js";
13
13
  import {
14
14
  buildModelParams
15
- } from "./chunk-EZK7CGJ7.js";
15
+ } from "./chunk-RMXPVQP4.js";
16
16
  import {
17
17
  logger
18
18
  } from "./chunk-K44MW7JJ.js";
@@ -679,4 +679,4 @@ export {
679
679
  createChatDoneEvent,
680
680
  consumeStreamGenerator
681
681
  };
682
- //# sourceMappingURL=chunk-7772ENZN.js.map
682
+ //# sourceMappingURL=chunk-XNCHOD2X.js.map