@everworker/oneringai 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,7 +5,9 @@ import * as fs16 from 'fs';
5
5
  import { promises, existsSync } from 'fs';
6
6
  import { EventEmitter } from 'eventemitter3';
7
7
  import * as path2 from 'path';
8
- import { join, resolve, dirname, relative, isAbsolute, normalize, extname } from 'path';
8
+ import { join, resolve, extname, dirname, relative, isAbsolute, normalize, sep } from 'path';
9
+ import TurndownService from 'turndown';
10
+ import { Readability } from '@mozilla/readability';
9
11
  import * as os2 from 'os';
10
12
  import { homedir } from 'os';
11
13
  import OpenAI3 from 'openai';
@@ -14,6 +16,7 @@ import { GoogleGenAI } from '@google/genai';
14
16
  import 'zod/v3';
15
17
  import * as z4mini from 'zod/v4-mini';
16
18
  import * as z from 'zod/v4';
19
+ import spawn$1 from 'cross-spawn';
17
20
  import process2 from 'process';
18
21
  import { PassThrough } from 'stream';
19
22
  import * as fs15 from 'fs/promises';
@@ -22,8 +25,6 @@ import * as simpleIcons from 'simple-icons';
22
25
  import { exec, spawn } from 'child_process';
23
26
  import { promisify } from 'util';
24
27
  import { load } from 'cheerio';
25
- import TurndownService from 'turndown';
26
- import { Readability } from '@mozilla/readability';
27
28
  import * as vm from 'vm';
28
29
 
29
30
  var __create = Object.create;
@@ -2231,6 +2232,66 @@ var init_Connector = __esm({
2231
2232
  }
2232
2233
  });
2233
2234
 
2235
+ // src/core/constants.ts
2236
+ var AGENT_DEFAULTS, TOKEN_ESTIMATION, DOCUMENT_DEFAULTS;
2237
+ var init_constants = __esm({
2238
+ "src/core/constants.ts"() {
2239
+ AGENT_DEFAULTS = {
2240
+ /** Default maximum iterations for agentic loop */
2241
+ MAX_ITERATIONS: 50,
2242
+ /** Default temperature for LLM calls */
2243
+ DEFAULT_TEMPERATURE: 0.7,
2244
+ /** Message injected when max iterations is reached */
2245
+ MAX_ITERATIONS_MESSAGE: `You have reached the maximum iteration limit for this execution. Please:
2246
+ 1. Summarize what you have accomplished so far
2247
+ 2. Explain what remains to be done (if anything)
2248
+ 3. Ask the user if they would like you to continue
2249
+
2250
+ Do NOT use any tools in this response - just provide a clear summary and ask for confirmation to proceed.`
2251
+ };
2252
+ TOKEN_ESTIMATION = {
2253
+ /** Characters per token for code */
2254
+ CODE_CHARS_PER_TOKEN: 3,
2255
+ /** Characters per token for prose */
2256
+ PROSE_CHARS_PER_TOKEN: 4,
2257
+ /** Characters per token for mixed content */
2258
+ MIXED_CHARS_PER_TOKEN: 3.5,
2259
+ /** Default characters per token */
2260
+ DEFAULT_CHARS_PER_TOKEN: 4
2261
+ };
2262
+ DOCUMENT_DEFAULTS = {
2263
+ /** Maximum estimated tokens in output */
2264
+ MAX_OUTPUT_TOKENS: 1e5,
2265
+ /** Maximum output size in bytes (5MB) */
2266
+ MAX_OUTPUT_BYTES: 5 * 1024 * 1024,
2267
+ /** Maximum download size for URL sources (50MB) */
2268
+ MAX_DOWNLOAD_SIZE_BYTES: 50 * 1024 * 1024,
2269
+ /** Download timeout for URL sources */
2270
+ DOWNLOAD_TIMEOUT_MS: 6e4,
2271
+ /** Maximum extracted images from a single document */
2272
+ MAX_EXTRACTED_IMAGES: 50,
2273
+ /** Maximum Excel rows per sheet */
2274
+ MAX_EXCEL_ROWS: 1e3,
2275
+ /** Maximum Excel columns per sheet */
2276
+ MAX_EXCEL_COLUMNS: 50,
2277
+ /** Maximum HTML content length */
2278
+ MAX_HTML_LENGTH: 5e4,
2279
+ /** Characters per token estimate */
2280
+ CHARS_PER_TOKEN: 4,
2281
+ /** Estimated tokens for an image with auto detail */
2282
+ IMAGE_TOKENS_AUTO: 765,
2283
+ /** Estimated tokens for an image with low detail */
2284
+ IMAGE_TOKENS_LOW: 85,
2285
+ /** Image filter defaults */
2286
+ IMAGE_FILTER: {
2287
+ MIN_WIDTH: 50,
2288
+ MIN_HEIGHT: 50,
2289
+ MIN_SIZE_BYTES: 1024
2290
+ }
2291
+ };
2292
+ }
2293
+ });
2294
+
2234
2295
  // node_modules/@modelcontextprotocol/sdk/node_modules/ajv/dist/compile/codegen/code.js
2235
2296
  var require_code = __commonJS({
2236
2297
  "node_modules/@modelcontextprotocol/sdk/node_modules/ajv/dist/compile/codegen/code.js"(exports$1) {
@@ -14544,491 +14605,961 @@ var require_dist = __commonJS({
14544
14605
  }
14545
14606
  });
14546
14607
 
14547
- // node_modules/isexe/windows.js
14548
- var require_windows = __commonJS({
14549
- "node_modules/isexe/windows.js"(exports$1, module) {
14550
- module.exports = isexe;
14551
- isexe.sync = sync;
14552
- var fs17 = __require("fs");
14553
- function checkPathExt(path6, options) {
14554
- var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
14555
- if (!pathext) {
14556
- return true;
14557
- }
14558
- pathext = pathext.split(";");
14559
- if (pathext.indexOf("") !== -1) {
14560
- return true;
14608
+ // src/capabilities/documents/handlers/TextHandler.ts
14609
+ var CODE_FENCE_FORMATS, TextHandler;
14610
+ var init_TextHandler = __esm({
14611
+ "src/capabilities/documents/handlers/TextHandler.ts"() {
14612
+ init_constants();
14613
+ CODE_FENCE_FORMATS = {
14614
+ json: "json",
14615
+ xml: "xml",
14616
+ yaml: "yaml",
14617
+ yml: "yaml"
14618
+ };
14619
+ TextHandler = class {
14620
+ name = "TextHandler";
14621
+ supportedFormats = ["txt", "md", "json", "xml", "yaml", "yml"];
14622
+ async handle(buffer, filename, format, _options) {
14623
+ const text = buffer.toString("utf-8");
14624
+ const fenceLanguage = CODE_FENCE_FORMATS[format];
14625
+ const content = fenceLanguage ? `\`\`\`${fenceLanguage}
14626
+ ${text}
14627
+ \`\`\`` : text;
14628
+ const sizeBytes = Buffer.byteLength(content, "utf-8");
14629
+ return [
14630
+ {
14631
+ type: "text",
14632
+ content,
14633
+ metadata: {
14634
+ sourceFilename: filename,
14635
+ format,
14636
+ index: 0,
14637
+ sizeBytes,
14638
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
14639
+ }
14640
+ }
14641
+ ];
14561
14642
  }
14562
- for (var i = 0; i < pathext.length; i++) {
14563
- var p = pathext[i].toLowerCase();
14564
- if (p && path6.substr(-p.length).toLowerCase() === p) {
14565
- return true;
14643
+ };
14644
+ }
14645
+ });
14646
+
14647
+ // src/capabilities/documents/handlers/ImageHandler.ts
14648
+ var MIME_TYPES, ImageHandler;
14649
+ var init_ImageHandler = __esm({
14650
+ "src/capabilities/documents/handlers/ImageHandler.ts"() {
14651
+ init_constants();
14652
+ MIME_TYPES = {
14653
+ png: "image/png",
14654
+ jpg: "image/jpeg",
14655
+ jpeg: "image/jpeg",
14656
+ gif: "image/gif",
14657
+ webp: "image/webp",
14658
+ svg: "image/svg+xml"
14659
+ };
14660
+ ImageHandler = class {
14661
+ name = "ImageHandler";
14662
+ supportedFormats = ["png", "jpg", "jpeg", "gif", "webp", "svg"];
14663
+ async handle(buffer, filename, format, _options) {
14664
+ const pieces = [];
14665
+ const mimeType = MIME_TYPES[format] || "application/octet-stream";
14666
+ pieces.push({
14667
+ type: "image",
14668
+ base64: buffer.toString("base64"),
14669
+ mimeType,
14670
+ metadata: {
14671
+ sourceFilename: filename,
14672
+ format,
14673
+ index: 0,
14674
+ sizeBytes: buffer.length,
14675
+ estimatedTokens: DOCUMENT_DEFAULTS.IMAGE_TOKENS_AUTO,
14676
+ label: filename
14677
+ }
14678
+ });
14679
+ if (format === "svg") {
14680
+ const svgText = buffer.toString("utf-8");
14681
+ const sizeBytes = Buffer.byteLength(svgText, "utf-8");
14682
+ pieces.push({
14683
+ type: "text",
14684
+ content: `\`\`\`svg
14685
+ ${svgText}
14686
+ \`\`\``,
14687
+ metadata: {
14688
+ sourceFilename: filename,
14689
+ format,
14690
+ index: 1,
14691
+ section: "SVG source",
14692
+ sizeBytes,
14693
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
14694
+ }
14695
+ });
14566
14696
  }
14697
+ return pieces;
14567
14698
  }
14568
- return false;
14569
- }
14570
- function checkStat(stat6, path6, options) {
14571
- if (!stat6.isSymbolicLink() && !stat6.isFile()) {
14572
- return false;
14573
- }
14574
- return checkPathExt(path6, options);
14575
- }
14576
- function isexe(path6, options, cb) {
14577
- fs17.stat(path6, function(er, stat6) {
14578
- cb(er, er ? false : checkStat(stat6, path6, options));
14579
- });
14580
- }
14581
- function sync(path6, options) {
14582
- return checkStat(fs17.statSync(path6), path6, options);
14583
- }
14699
+ };
14584
14700
  }
14585
14701
  });
14586
-
14587
- // node_modules/isexe/mode.js
14588
- var require_mode = __commonJS({
14589
- "node_modules/isexe/mode.js"(exports$1, module) {
14590
- module.exports = isexe;
14591
- isexe.sync = sync;
14592
- var fs17 = __require("fs");
14593
- function isexe(path6, options, cb) {
14594
- fs17.stat(path6, function(er, stat6) {
14595
- cb(er, er ? false : checkStat(stat6, options));
14596
- });
14597
- }
14598
- function sync(path6, options) {
14599
- return checkStat(fs17.statSync(path6), options);
14702
+ async function getJSDOM() {
14703
+ if (!JSDOM) {
14704
+ const jsdom = await import('jsdom');
14705
+ JSDOM = jsdom.JSDOM;
14706
+ }
14707
+ return JSDOM;
14708
+ }
14709
+ async function htmlToMarkdown(html, url2, maxLength = 5e4) {
14710
+ const JSDOMClass = await getJSDOM();
14711
+ const dom = new JSDOMClass(html, { url: url2 });
14712
+ const document = dom.window.document;
14713
+ let title = document.title || "";
14714
+ let byline;
14715
+ let excerpt;
14716
+ let contentHtml = html;
14717
+ let wasReadabilityUsed = false;
14718
+ try {
14719
+ const clonedDoc = document.cloneNode(true);
14720
+ const reader = new Readability(clonedDoc);
14721
+ const article = reader.parse();
14722
+ if (article && article.content && article.content.length > 100) {
14723
+ contentHtml = article.content;
14724
+ title = article.title || title;
14725
+ byline = article.byline || void 0;
14726
+ excerpt = article.excerpt || void 0;
14727
+ wasReadabilityUsed = true;
14600
14728
  }
14601
- function checkStat(stat6, options) {
14602
- return stat6.isFile() && checkMode(stat6, options);
14729
+ } catch {
14730
+ }
14731
+ const turndown = new TurndownService({
14732
+ headingStyle: "atx",
14733
+ codeBlockStyle: "fenced",
14734
+ bulletListMarker: "-",
14735
+ emDelimiter: "_"
14736
+ });
14737
+ turndown.remove(["script", "style", "nav", "footer", "aside", "iframe", "noscript"]);
14738
+ turndown.addRule("pre", {
14739
+ filter: ["pre"],
14740
+ replacement: (content, node) => {
14741
+ const element = node;
14742
+ const code = element.querySelector?.("code");
14743
+ const lang = code?.className?.match(/language-(\w+)/)?.[1] || "";
14744
+ const text = code?.textContent || content;
14745
+ return `
14746
+ \`\`\`${lang}
14747
+ ${text}
14748
+ \`\`\`
14749
+ `;
14603
14750
  }
14604
- function checkMode(stat6, options) {
14605
- var mod = stat6.mode;
14606
- var uid = stat6.uid;
14607
- var gid = stat6.gid;
14608
- var myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid();
14609
- var myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid();
14610
- var u = parseInt("100", 8);
14611
- var g = parseInt("010", 8);
14612
- var o = parseInt("001", 8);
14613
- var ug = u | g;
14614
- var ret = mod & o || mod & g && gid === myGid || mod & u && uid === myUid || mod & ug && myUid === 0;
14615
- return ret;
14751
+ });
14752
+ let markdown = turndown.turndown(contentHtml);
14753
+ markdown = markdown.replace(/\n{3,}/g, "\n\n").replace(/^\s+|\s+$/g, "").replace(/[ \t]+$/gm, "");
14754
+ let wasTruncated = false;
14755
+ if (markdown.length > maxLength) {
14756
+ const truncateAt = markdown.lastIndexOf("\n\n", maxLength);
14757
+ if (truncateAt > maxLength * 0.5) {
14758
+ markdown = markdown.slice(0, truncateAt) + "\n\n...[content truncated]";
14759
+ } else {
14760
+ markdown = markdown.slice(0, maxLength) + "...[truncated]";
14616
14761
  }
14762
+ wasTruncated = true;
14763
+ }
14764
+ return {
14765
+ markdown,
14766
+ title,
14767
+ byline,
14768
+ excerpt,
14769
+ wasReadabilityUsed,
14770
+ wasTruncated
14771
+ };
14772
+ }
14773
+ var JSDOM;
14774
+ var init_htmlToMarkdown = __esm({
14775
+ "src/tools/web/htmlToMarkdown.ts"() {
14776
+ JSDOM = null;
14777
+ }
14778
+ });
14779
+
14780
+ // src/capabilities/documents/handlers/HTMLHandler.ts
14781
+ var HTMLHandler;
14782
+ var init_HTMLHandler = __esm({
14783
+ "src/capabilities/documents/handlers/HTMLHandler.ts"() {
14784
+ init_constants();
14785
+ init_htmlToMarkdown();
14786
+ HTMLHandler = class {
14787
+ name = "HTMLHandler";
14788
+ supportedFormats = ["html"];
14789
+ async handle(buffer, filename, format, options) {
14790
+ const html = buffer.toString("utf-8");
14791
+ const maxLength = options.formatOptions?.html?.maxLength ?? DOCUMENT_DEFAULTS.MAX_HTML_LENGTH;
14792
+ const result = await htmlToMarkdown(html, `file://${filename}`, maxLength);
14793
+ const content = result.markdown;
14794
+ const sizeBytes = Buffer.byteLength(content, "utf-8");
14795
+ return [
14796
+ {
14797
+ type: "text",
14798
+ content,
14799
+ metadata: {
14800
+ sourceFilename: filename,
14801
+ format,
14802
+ index: 0,
14803
+ sizeBytes,
14804
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN),
14805
+ label: result.title || void 0
14806
+ }
14807
+ }
14808
+ ];
14809
+ }
14810
+ };
14617
14811
  }
14618
14812
  });
14619
14813
 
14620
- // node_modules/isexe/index.js
14621
- var require_isexe = __commonJS({
14622
- "node_modules/isexe/index.js"(exports$1, module) {
14623
- __require("fs");
14624
- var core;
14625
- if (process.platform === "win32" || global.TESTING_WINDOWS) {
14626
- core = require_windows();
14627
- } else {
14628
- core = require_mode();
14629
- }
14630
- module.exports = isexe;
14631
- isexe.sync = sync;
14632
- function isexe(path6, options, cb) {
14633
- if (typeof options === "function") {
14634
- cb = options;
14635
- options = {};
14636
- }
14637
- if (!cb) {
14638
- if (typeof Promise !== "function") {
14639
- throw new TypeError("callback not provided");
14640
- }
14641
- return new Promise(function(resolve4, reject) {
14642
- isexe(path6, options || {}, function(er, is) {
14643
- if (er) {
14644
- reject(er);
14645
- } else {
14646
- resolve4(is);
14647
- }
14648
- });
14814
+ // src/capabilities/documents/handlers/OfficeHandler.ts
14815
+ async function getParseOffice() {
14816
+ if (!parseOffice) {
14817
+ const mod = await import('officeparser');
14818
+ parseOffice = mod.parseOffice;
14819
+ }
14820
+ return parseOffice;
14821
+ }
14822
+ var parseOffice, OfficeHandler;
14823
+ var init_OfficeHandler = __esm({
14824
+ "src/capabilities/documents/handlers/OfficeHandler.ts"() {
14825
+ init_constants();
14826
+ parseOffice = null;
14827
+ OfficeHandler = class {
14828
+ name = "OfficeHandler";
14829
+ supportedFormats = ["docx", "pptx", "odt", "odp", "ods", "rtf"];
14830
+ async handle(buffer, filename, format, options) {
14831
+ const parse = await getParseOffice();
14832
+ const extractImages = options.extractImages !== false;
14833
+ const includeSpeakerNotes = options.formatOptions?.office?.includeSpeakerNotes !== false;
14834
+ const ast = await parse(buffer, {
14835
+ extractAttachments: extractImages,
14836
+ ignoreNotes: !includeSpeakerNotes
14649
14837
  });
14838
+ const pieces = [];
14839
+ let pieceIndex = 0;
14840
+ const content = ast.content || [];
14841
+ const markdown = this.astToMarkdown(content, format);
14842
+ if (format === "pptx" || format === "odp") {
14843
+ const slides = this.splitBySlides(content);
14844
+ for (let i = 0; i < slides.length; i++) {
14845
+ const slideContent = this.astToMarkdown(slides[i] ?? [], format);
14846
+ if (slideContent.trim()) {
14847
+ const sizeBytes = Buffer.byteLength(slideContent, "utf-8");
14848
+ pieces.push({
14849
+ type: "text",
14850
+ content: slideContent,
14851
+ metadata: {
14852
+ sourceFilename: filename,
14853
+ format,
14854
+ index: pieceIndex++,
14855
+ section: `Slide ${i + 1}`,
14856
+ sizeBytes,
14857
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
14858
+ }
14859
+ });
14860
+ }
14861
+ }
14862
+ } else {
14863
+ if (markdown.trim()) {
14864
+ const sizeBytes = Buffer.byteLength(markdown, "utf-8");
14865
+ pieces.push({
14866
+ type: "text",
14867
+ content: markdown,
14868
+ metadata: {
14869
+ sourceFilename: filename,
14870
+ format,
14871
+ index: pieceIndex++,
14872
+ sizeBytes,
14873
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
14874
+ }
14875
+ });
14876
+ }
14877
+ }
14878
+ if (extractImages && ast.attachments?.length > 0) {
14879
+ for (const attachment of ast.attachments) {
14880
+ if (attachment.type === "image" && attachment.data) {
14881
+ const imageData = attachment.data;
14882
+ const sizeBytes = Math.ceil(imageData.length * 0.75);
14883
+ pieces.push({
14884
+ type: "image",
14885
+ base64: imageData,
14886
+ mimeType: attachment.mimeType || "image/png",
14887
+ metadata: {
14888
+ sourceFilename: filename,
14889
+ format,
14890
+ index: pieceIndex++,
14891
+ sizeBytes,
14892
+ estimatedTokens: DOCUMENT_DEFAULTS.IMAGE_TOKENS_AUTO,
14893
+ label: attachment.altText || attachment.name || void 0
14894
+ }
14895
+ });
14896
+ }
14897
+ }
14898
+ }
14899
+ return pieces;
14650
14900
  }
14651
- core(path6, options || {}, function(er, is) {
14652
- if (er) {
14653
- if (er.code === "EACCES" || options && options.ignoreErrors) {
14654
- er = null;
14655
- is = false;
14901
+ /**
14902
+ * Split AST content into slide groups
14903
+ */
14904
+ splitBySlides(content) {
14905
+ const slides = [];
14906
+ let currentSlide = [];
14907
+ for (const node of content) {
14908
+ if (node.type === "slide") {
14909
+ if (currentSlide.length > 0) {
14910
+ slides.push(currentSlide);
14911
+ }
14912
+ currentSlide = [node];
14913
+ } else {
14914
+ currentSlide.push(node);
14656
14915
  }
14657
14916
  }
14658
- cb(er, is);
14659
- });
14660
- }
14661
- function sync(path6, options) {
14662
- try {
14663
- return core.sync(path6, options || {});
14664
- } catch (er) {
14665
- if (options && options.ignoreErrors || er.code === "EACCES") {
14666
- return false;
14667
- } else {
14668
- throw er;
14917
+ if (currentSlide.length > 0) {
14918
+ slides.push(currentSlide);
14669
14919
  }
14920
+ if (slides.length === 0 && content.length > 0) {
14921
+ slides.push(content);
14922
+ }
14923
+ return slides;
14670
14924
  }
14671
- }
14672
- }
14673
- });
14674
-
14675
- // node_modules/which/which.js
14676
- var require_which = __commonJS({
14677
- "node_modules/which/which.js"(exports$1, module) {
14678
- var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
14679
- var path6 = __require("path");
14680
- var COLON = isWindows ? ";" : ":";
14681
- var isexe = require_isexe();
14682
- var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
14683
- var getPathInfo = (cmd, opt) => {
14684
- const colon = opt.colon || COLON;
14685
- const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? [""] : [
14686
- // windows always checks the cwd first
14687
- ...isWindows ? [process.cwd()] : [],
14688
- ...(opt.path || process.env.PATH || /* istanbul ignore next: very unusual */
14689
- "").split(colon)
14690
- ];
14691
- const pathExtExe = isWindows ? opt.pathExt || process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM" : "";
14692
- const pathExt = isWindows ? pathExtExe.split(colon) : [""];
14693
- if (isWindows) {
14694
- if (cmd.indexOf(".") !== -1 && pathExt[0] !== "")
14695
- pathExt.unshift("");
14925
+ /**
14926
+ * Convert AST nodes to markdown
14927
+ */
14928
+ astToMarkdown(nodes, format) {
14929
+ const parts = [];
14930
+ for (const node of nodes) {
14931
+ const md = this.nodeToMarkdown(node, format);
14932
+ if (md) parts.push(md);
14933
+ }
14934
+ return parts.join("\n\n");
14696
14935
  }
14697
- return {
14698
- pathEnv,
14699
- pathExt,
14700
- pathExtExe
14701
- };
14702
- };
14703
- var which = (cmd, opt, cb) => {
14704
- if (typeof opt === "function") {
14705
- cb = opt;
14706
- opt = {};
14707
- }
14708
- if (!opt)
14709
- opt = {};
14710
- const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
14711
- const found = [];
14712
- const step = (i) => new Promise((resolve4, reject) => {
14713
- if (i === pathEnv.length)
14714
- return opt.all && found.length ? resolve4(found) : reject(getNotFoundError(cmd));
14715
- const ppRaw = pathEnv[i];
14716
- const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
14717
- const pCmd = path6.join(pathPart, cmd);
14718
- const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
14719
- resolve4(subStep(p, i, 0));
14720
- });
14721
- const subStep = (p, i, ii) => new Promise((resolve4, reject) => {
14722
- if (ii === pathExt.length)
14723
- return resolve4(step(i + 1));
14724
- const ext = pathExt[ii];
14725
- isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
14726
- if (!er && is) {
14727
- if (opt.all)
14728
- found.push(p + ext);
14729
- else
14730
- return resolve4(p + ext);
14936
+ /**
14937
+ * Convert a single AST node to markdown
14938
+ */
14939
+ nodeToMarkdown(node, format) {
14940
+ if (!node) return "";
14941
+ switch (node.type) {
14942
+ case "heading": {
14943
+ const level = node.metadata?.level || 1;
14944
+ const prefix = "#".repeat(Math.min(level, 6));
14945
+ return `${prefix} ${node.text || ""}`;
14946
+ }
14947
+ case "paragraph":
14948
+ return this.formatText(node);
14949
+ case "text":
14950
+ return this.formatText(node);
14951
+ case "list": {
14952
+ const items = node.children || [];
14953
+ return items.map((item, i) => {
14954
+ const indent = " ".repeat(node.metadata?.indentation || 0);
14955
+ const prefix = node.metadata?.listType === "ordered" ? `${i + 1}.` : "-";
14956
+ return `${indent}${prefix} ${item.text || this.getNodeText(item)}`;
14957
+ }).join("\n");
14958
+ }
14959
+ case "table": {
14960
+ return this.tableToMarkdown(node);
14961
+ }
14962
+ case "slide": {
14963
+ const slideNum = node.metadata?.slideNumber || "";
14964
+ const childContent = node.children ? node.children.map((c) => this.nodeToMarkdown(c, format)).filter(Boolean).join("\n\n") : node.text || "";
14965
+ return slideNum ? `### Slide ${slideNum}
14966
+
14967
+ ${childContent}` : childContent;
14968
+ }
14969
+ case "note":
14970
+ return `> **Note:** ${node.text || this.getNodeText(node)}`;
14971
+ case "sheet": {
14972
+ const sheetName = node.metadata?.sheetName || "Sheet";
14973
+ const childContent = node.children ? node.children.map((c) => this.nodeToMarkdown(c, format)).filter(Boolean).join("\n") : "";
14974
+ return `## Sheet: ${sheetName}
14975
+
14976
+ ${childContent}`;
14977
+ }
14978
+ case "page": {
14979
+ const pageNum = node.metadata?.pageNumber || "";
14980
+ const childContent = node.children ? node.children.map((c) => this.nodeToMarkdown(c, format)).filter(Boolean).join("\n\n") : node.text || "";
14981
+ return pageNum ? `--- Page ${pageNum} ---
14982
+
14983
+ ${childContent}` : childContent;
14984
+ }
14985
+ case "image":
14986
+ return `[Image: ${node.metadata?.altText || node.metadata?.attachmentName || "embedded image"}]`;
14987
+ case "chart":
14988
+ return `[Chart: ${node.metadata?.attachmentName || "embedded chart"}]`;
14989
+ default:
14990
+ return node.text || this.getNodeText(node);
14991
+ }
14992
+ }
14993
+ /**
14994
+ * Get text from a node recursively
14995
+ */
14996
+ getNodeText(node) {
14997
+ if (node.text) return node.text;
14998
+ if (node.children) {
14999
+ return node.children.map((c) => this.getNodeText(c)).join("");
15000
+ }
15001
+ return "";
15002
+ }
15003
+ /**
15004
+ * Format text with markdown formatting
15005
+ */
15006
+ formatText(node) {
15007
+ if (!node.children || node.children.length === 0) {
15008
+ return node.text || "";
15009
+ }
15010
+ return node.children.map((child) => {
15011
+ let text = child.text || this.getNodeText(child);
15012
+ if (!text) return "";
15013
+ const fmt = child.formatting;
15014
+ if (fmt) {
15015
+ if (fmt.bold) text = `**${text}**`;
15016
+ if (fmt.italic) text = `_${text}_`;
15017
+ if (fmt.strikethrough) text = `~~${text}~~`;
14731
15018
  }
14732
- return resolve4(subStep(p, i, ii + 1));
14733
- });
14734
- });
14735
- return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
14736
- };
14737
- var whichSync = (cmd, opt) => {
14738
- opt = opt || {};
14739
- const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
14740
- const found = [];
14741
- for (let i = 0; i < pathEnv.length; i++) {
14742
- const ppRaw = pathEnv[i];
14743
- const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
14744
- const pCmd = path6.join(pathPart, cmd);
14745
- const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
14746
- for (let j = 0; j < pathExt.length; j++) {
14747
- const cur = p + pathExt[j];
14748
- try {
14749
- const is = isexe.sync(cur, { pathExt: pathExtExe });
14750
- if (is) {
14751
- if (opt.all)
14752
- found.push(cur);
14753
- else
14754
- return cur;
14755
- }
14756
- } catch (ex) {
15019
+ if (child.metadata?.link && child.metadata?.linkType === "external") {
15020
+ text = `[${text}](${child.metadata.link})`;
14757
15021
  }
14758
- }
15022
+ return text;
15023
+ }).join("");
14759
15024
  }
14760
- if (opt.all && found.length)
14761
- return found;
14762
- if (opt.nothrow)
14763
- return null;
14764
- throw getNotFoundError(cmd);
14765
- };
14766
- module.exports = which;
14767
- which.sync = whichSync;
14768
- }
14769
- });
15025
+ /**
15026
+ * Convert table node to markdown table
15027
+ */
15028
+ tableToMarkdown(node) {
15029
+ if (!node.children || node.children.length === 0) return "";
15030
+ const rows = [];
15031
+ for (const row of node.children) {
15032
+ if (row.type === "row" && row.children) {
15033
+ rows.push(row.children.map((cell) => {
15034
+ const text = cell.text || this.getNodeText(cell);
15035
+ return text.replace(/\|/g, "\\|").trim();
15036
+ }));
15037
+ }
15038
+ }
15039
+ if (rows.length === 0) return "";
15040
+ const maxCols = Math.max(...rows.map((r) => r.length));
15041
+ const normalizedRows = rows.map((r) => {
15042
+ while (r.length < maxCols) r.push("");
15043
+ return r;
15044
+ });
15045
+ const firstRow = normalizedRows[0] ?? [];
15046
+ const header = `| ${firstRow.join(" | ")} |`;
15047
+ const separator = `| ${firstRow.map(() => "---").join(" | ")} |`;
15048
+ const body = normalizedRows.slice(1).map((r) => `| ${r.join(" | ")} |`).join("\n");
15049
+ return body ? `${header}
15050
+ ${separator}
15051
+ ${body}` : `${header}
15052
+ ${separator}`;
15053
+ }
15054
+ };
15055
+ }
15056
+ });
15057
+
15058
+ // src/capabilities/documents/handlers/ExcelHandler.ts
15059
+ async function getExcelJS() {
15060
+ if (!ExcelJS) {
15061
+ ExcelJS = await import('exceljs');
15062
+ }
15063
+ return ExcelJS;
15064
+ }
15065
+ var ExcelJS, ExcelHandler;
15066
+ var init_ExcelHandler = __esm({
15067
+ "src/capabilities/documents/handlers/ExcelHandler.ts"() {
15068
+ init_constants();
15069
+ ExcelJS = null;
15070
+ ExcelHandler = class {
15071
+ name = "ExcelHandler";
15072
+ supportedFormats = ["xlsx", "csv"];
15073
+ async handle(buffer, filename, format, options) {
15074
+ const exceljs = await getExcelJS();
15075
+ const Workbook = exceljs.Workbook || exceljs.default?.Workbook;
15076
+ const excelOpts = {
15077
+ maxRows: options.formatOptions?.excel?.maxRows ?? DOCUMENT_DEFAULTS.MAX_EXCEL_ROWS,
15078
+ maxColumns: options.formatOptions?.excel?.maxColumns ?? DOCUMENT_DEFAULTS.MAX_EXCEL_COLUMNS,
15079
+ tableFormat: options.formatOptions?.excel?.tableFormat ?? "markdown",
15080
+ includeFormulas: options.formatOptions?.excel?.includeFormulas ?? false
15081
+ };
15082
+ const workbook = new Workbook();
15083
+ if (format === "csv") {
15084
+ await workbook.csv.read(
15085
+ new (await import('stream')).Readable({
15086
+ read() {
15087
+ this.push(buffer);
15088
+ this.push(null);
15089
+ }
15090
+ })
15091
+ );
15092
+ } else {
15093
+ await workbook.xlsx.load(buffer);
15094
+ }
15095
+ const pieces = [];
15096
+ let pieceIndex = 0;
15097
+ const requestedSheets = options.pages;
15098
+ workbook.eachSheet((worksheet, sheetId) => {
15099
+ if (requestedSheets && requestedSheets.length > 0) {
15100
+ const isRequested = requestedSheets.some((p) => {
15101
+ if (typeof p === "number") return sheetId === p;
15102
+ return worksheet.name === p || String(sheetId) === p;
15103
+ });
15104
+ if (!isRequested) return;
15105
+ }
15106
+ const content = this.sheetToContent(worksheet, excelOpts);
15107
+ if (!content.trim()) return;
15108
+ const sheetContent = format === "csv" ? content : `## Sheet: ${worksheet.name}
14770
15109
 
14771
- // node_modules/path-key/index.js
14772
- var require_path_key = __commonJS({
14773
- "node_modules/path-key/index.js"(exports$1, module) {
14774
- var pathKey = (options = {}) => {
14775
- const environment = options.env || process.env;
14776
- const platform2 = options.platform || process.platform;
14777
- if (platform2 !== "win32") {
14778
- return "PATH";
15110
+ ${content}`;
15111
+ const sizeBytes = Buffer.byteLength(sheetContent, "utf-8");
15112
+ pieces.push({
15113
+ type: "text",
15114
+ content: sheetContent,
15115
+ metadata: {
15116
+ sourceFilename: filename,
15117
+ format,
15118
+ index: pieceIndex++,
15119
+ section: format === "csv" ? void 0 : worksheet.name,
15120
+ sizeBytes,
15121
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
15122
+ }
15123
+ });
15124
+ });
15125
+ return pieces;
14779
15126
  }
14780
- return Object.keys(environment).reverse().find((key) => key.toUpperCase() === "PATH") || "Path";
14781
- };
14782
- module.exports = pathKey;
14783
- module.exports.default = pathKey;
14784
- }
14785
- });
14786
-
14787
- // node_modules/cross-spawn/lib/util/resolveCommand.js
14788
- var require_resolveCommand = __commonJS({
14789
- "node_modules/cross-spawn/lib/util/resolveCommand.js"(exports$1, module) {
14790
- var path6 = __require("path");
14791
- var which = require_which();
14792
- var getPathKey = require_path_key();
14793
- function resolveCommandAttempt(parsed, withoutPathExt) {
14794
- const env = parsed.options.env || process.env;
14795
- const cwd = process.cwd();
14796
- const hasCustomCwd = parsed.options.cwd != null;
14797
- const shouldSwitchCwd = hasCustomCwd && process.chdir !== void 0 && !process.chdir.disabled;
14798
- if (shouldSwitchCwd) {
14799
- try {
14800
- process.chdir(parsed.options.cwd);
14801
- } catch (err) {
15127
+ /**
15128
+ * Convert a worksheet to the configured format
15129
+ */
15130
+ sheetToContent(worksheet, opts) {
15131
+ switch (opts.tableFormat) {
15132
+ case "csv":
15133
+ return this.sheetToCSV(worksheet, opts);
15134
+ case "json":
15135
+ return this.sheetToJSON(worksheet, opts);
15136
+ default:
15137
+ return this.sheetToMarkdownTable(worksheet, opts);
14802
15138
  }
14803
15139
  }
14804
- let resolved;
14805
- try {
14806
- resolved = which.sync(parsed.command, {
14807
- path: env[getPathKey({ env })],
14808
- pathExt: withoutPathExt ? path6.delimiter : void 0
15140
+ /**
15141
+ * Convert worksheet to markdown table
15142
+ */
15143
+ sheetToMarkdownTable(worksheet, opts) {
15144
+ const rows = this.extractRows(worksheet, opts);
15145
+ if (rows.length === 0) return "";
15146
+ const maxCols = Math.min(
15147
+ Math.max(...rows.map((r) => r.length)),
15148
+ opts.maxColumns
15149
+ );
15150
+ const normalizedRows = rows.map((r) => {
15151
+ const truncated = r.slice(0, maxCols);
15152
+ while (truncated.length < maxCols) truncated.push("");
15153
+ return truncated;
14809
15154
  });
14810
- } catch (e) {
14811
- } finally {
14812
- if (shouldSwitchCwd) {
14813
- process.chdir(cwd);
15155
+ const firstRow = normalizedRows[0] ?? [];
15156
+ const header = `| ${firstRow.join(" | ")} |`;
15157
+ const separator = `| ${firstRow.map(() => "---").join(" | ")} |`;
15158
+ const body = normalizedRows.slice(1).map((r) => `| ${r.join(" | ")} |`).join("\n");
15159
+ let result = `${header}
15160
+ ${separator}`;
15161
+ if (body) result += `
15162
+ ${body}`;
15163
+ if (worksheet.rowCount > opts.maxRows) {
15164
+ result += `
15165
+
15166
+ _...truncated (${worksheet.rowCount - opts.maxRows} more rows)_`;
14814
15167
  }
15168
+ return result;
14815
15169
  }
14816
- if (resolved) {
14817
- resolved = path6.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
15170
+ /**
15171
+ * Convert worksheet to CSV
15172
+ */
15173
+ sheetToCSV(worksheet, opts) {
15174
+ const rows = this.extractRows(worksheet, opts);
15175
+ return rows.map(
15176
+ (row) => row.slice(0, opts.maxColumns).map((cell) => {
15177
+ if (cell.includes(",") || cell.includes('"') || cell.includes("\n")) {
15178
+ return `"${cell.replace(/"/g, '""')}"`;
15179
+ }
15180
+ return cell;
15181
+ }).join(",")
15182
+ ).join("\n");
14818
15183
  }
14819
- return resolved;
14820
- }
14821
- function resolveCommand(parsed) {
14822
- return resolveCommandAttempt(parsed) || resolveCommandAttempt(parsed, true);
14823
- }
14824
- module.exports = resolveCommand;
14825
- }
14826
- });
14827
-
14828
- // node_modules/cross-spawn/lib/util/escape.js
14829
- var require_escape = __commonJS({
14830
- "node_modules/cross-spawn/lib/util/escape.js"(exports$1, module) {
14831
- var metaCharsRegExp = /([()\][%!^"`<>&|;, *?])/g;
14832
- function escapeCommand(arg) {
14833
- arg = arg.replace(metaCharsRegExp, "^$1");
14834
- return arg;
14835
- }
14836
- function escapeArgument(arg, doubleEscapeMetaChars) {
14837
- arg = `${arg}`;
14838
- arg = arg.replace(/(?=(\\+?)?)\1"/g, '$1$1\\"');
14839
- arg = arg.replace(/(?=(\\+?)?)\1$/, "$1$1");
14840
- arg = `"${arg}"`;
14841
- arg = arg.replace(metaCharsRegExp, "^$1");
14842
- if (doubleEscapeMetaChars) {
14843
- arg = arg.replace(metaCharsRegExp, "^$1");
15184
+ /**
15185
+ * Convert worksheet to JSON
15186
+ */
15187
+ sheetToJSON(worksheet, opts) {
15188
+ const rows = this.extractRows(worksheet, opts);
15189
+ if (rows.length < 2) return "[]";
15190
+ const headers = (rows[0] ?? []).slice(0, opts.maxColumns);
15191
+ const data = rows.slice(1).map((row) => {
15192
+ const obj = {};
15193
+ headers.forEach((header, i) => {
15194
+ if (header && i < row.length) {
15195
+ obj[header] = row[i] ?? "";
15196
+ }
15197
+ });
15198
+ return obj;
15199
+ });
15200
+ return "```json\n" + JSON.stringify(data, null, 2) + "\n```";
14844
15201
  }
14845
- return arg;
14846
- }
14847
- module.exports.command = escapeCommand;
14848
- module.exports.argument = escapeArgument;
14849
- }
14850
- });
14851
-
14852
- // node_modules/shebang-regex/index.js
14853
- var require_shebang_regex = __commonJS({
14854
- "node_modules/shebang-regex/index.js"(exports$1, module) {
14855
- module.exports = /^#!(.*)/;
14856
- }
14857
- });
14858
-
14859
- // node_modules/shebang-command/index.js
14860
- var require_shebang_command = __commonJS({
14861
- "node_modules/shebang-command/index.js"(exports$1, module) {
14862
- var shebangRegex = require_shebang_regex();
14863
- module.exports = (string3 = "") => {
14864
- const match = string3.match(shebangRegex);
14865
- if (!match) {
14866
- return null;
15202
+ /**
15203
+ * Extract rows from worksheet as string arrays
15204
+ */
15205
+ extractRows(worksheet, opts) {
15206
+ const rows = [];
15207
+ let rowCount = 0;
15208
+ worksheet.eachRow({ includeEmpty: false }, (row) => {
15209
+ if (rowCount >= opts.maxRows) return;
15210
+ rowCount++;
15211
+ const cells = [];
15212
+ row.eachCell({ includeEmpty: true }, (cell, colNumber) => {
15213
+ if (colNumber > opts.maxColumns) return;
15214
+ let value = "";
15215
+ if (opts.includeFormulas && cell.formula) {
15216
+ value = `${this.getCellValue(cell)} (=${cell.formula})`;
15217
+ } else {
15218
+ value = this.getCellValue(cell);
15219
+ }
15220
+ while (cells.length < colNumber - 1) cells.push("");
15221
+ cells.push(value);
15222
+ });
15223
+ rows.push(cells);
15224
+ });
15225
+ return rows;
14867
15226
  }
14868
- const [path6, argument] = match[0].replace(/#! ?/, "").split(" ");
14869
- const binary = path6.split("/").pop();
14870
- if (binary === "env") {
14871
- return argument;
15227
+ /**
15228
+ * Get cell value as string
15229
+ */
15230
+ getCellValue(cell) {
15231
+ if (cell.value === null || cell.value === void 0) return "";
15232
+ if (typeof cell.value === "object") {
15233
+ if (cell.value.richText) {
15234
+ return cell.value.richText.map((rt) => rt.text || "").join("");
15235
+ }
15236
+ if (cell.value.hyperlink) {
15237
+ return cell.value.text || cell.value.hyperlink;
15238
+ }
15239
+ if ("result" in cell.value) {
15240
+ return String(cell.value.result ?? "");
15241
+ }
15242
+ if (cell.value instanceof Date) {
15243
+ return cell.value.toISOString().split("T")[0];
15244
+ }
15245
+ return String(cell.value);
15246
+ }
15247
+ return String(cell.value).replace(/\|/g, "\\|");
14872
15248
  }
14873
- return argument ? `${binary} ${argument}` : binary;
14874
15249
  };
14875
15250
  }
14876
15251
  });
14877
15252
 
14878
- // node_modules/cross-spawn/lib/util/readShebang.js
14879
- var require_readShebang = __commonJS({
14880
- "node_modules/cross-spawn/lib/util/readShebang.js"(exports$1, module) {
14881
- var fs17 = __require("fs");
14882
- var shebangCommand = require_shebang_command();
14883
- function readShebang(command) {
14884
- const size = 150;
14885
- const buffer = Buffer.alloc(size);
14886
- let fd;
14887
- try {
14888
- fd = fs17.openSync(command, "r");
14889
- fs17.readSync(fd, buffer, 0, size, 0);
14890
- fs17.closeSync(fd);
14891
- } catch (e) {
14892
- }
14893
- return shebangCommand(buffer.toString());
14894
- }
14895
- module.exports = readShebang;
14896
- }
14897
- });
14898
-
14899
- // node_modules/cross-spawn/lib/parse.js
14900
- var require_parse = __commonJS({
14901
- "node_modules/cross-spawn/lib/parse.js"(exports$1, module) {
14902
- var path6 = __require("path");
14903
- var resolveCommand = require_resolveCommand();
14904
- var escape2 = require_escape();
14905
- var readShebang = require_readShebang();
14906
- var isWin = process.platform === "win32";
14907
- var isExecutableRegExp = /\.(?:com|exe)$/i;
14908
- var isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
14909
- function detectShebang(parsed) {
14910
- parsed.file = resolveCommand(parsed);
14911
- const shebang = parsed.file && readShebang(parsed.file);
14912
- if (shebang) {
14913
- parsed.args.unshift(parsed.file);
14914
- parsed.command = shebang;
14915
- return resolveCommand(parsed);
14916
- }
14917
- return parsed.file;
14918
- }
14919
- function parseNonShell(parsed) {
14920
- if (!isWin) {
14921
- return parsed;
14922
- }
14923
- const commandFile = detectShebang(parsed);
14924
- const needsShell = !isExecutableRegExp.test(commandFile);
14925
- if (parsed.options.forceShell || needsShell) {
14926
- const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
14927
- parsed.command = path6.normalize(parsed.command);
14928
- parsed.command = escape2.command(parsed.command);
14929
- parsed.args = parsed.args.map((arg) => escape2.argument(arg, needsDoubleEscapeMetaChars));
14930
- const shellCommand = [parsed.command].concat(parsed.args).join(" ");
14931
- parsed.args = ["/d", "/s", "/c", `"${shellCommand}"`];
14932
- parsed.command = process.env.comspec || "cmd.exe";
14933
- parsed.options.windowsVerbatimArguments = true;
15253
+ // src/capabilities/documents/handlers/PDFHandler.ts
15254
+ async function getUnpdf() {
15255
+ if (!unpdfModule) {
15256
+ const mod = await import('unpdf');
15257
+ unpdfModule = {
15258
+ extractText: mod.extractText,
15259
+ extractImages: mod.extractImages,
15260
+ getMeta: mod.getMeta
15261
+ };
15262
+ }
15263
+ return unpdfModule;
15264
+ }
15265
+ var unpdfModule, PDFHandler;
15266
+ var init_PDFHandler = __esm({
15267
+ "src/capabilities/documents/handlers/PDFHandler.ts"() {
15268
+ init_constants();
15269
+ unpdfModule = null;
15270
+ PDFHandler = class {
15271
+ name = "PDFHandler";
15272
+ supportedFormats = ["pdf"];
15273
+ async handle(buffer, filename, format, options) {
15274
+ const unpdf = await getUnpdf();
15275
+ const pieces = [];
15276
+ let pieceIndex = 0;
15277
+ let metadata = {};
15278
+ const includeMetadata = options.formatOptions?.pdf?.includeMetadata !== false;
15279
+ if (includeMetadata) {
15280
+ try {
15281
+ metadata = await unpdf.getMeta(buffer);
15282
+ } catch {
15283
+ }
15284
+ }
15285
+ const textResult = await unpdf.extractText(buffer, { mergePages: false });
15286
+ const pages = textResult?.pages || textResult?.text ? Array.isArray(textResult.text) ? textResult.text : [textResult.text] : [];
15287
+ const requestedPages = options.pages;
15288
+ const pageEntries = pages.map((text, i) => ({ text, pageNum: i + 1 }));
15289
+ const filteredPages = requestedPages && requestedPages.length > 0 ? pageEntries.filter(
15290
+ (p) => requestedPages.some((rp) => {
15291
+ const num = typeof rp === "string" ? parseInt(rp, 10) : rp;
15292
+ return num === p.pageNum;
15293
+ })
15294
+ ) : pageEntries;
15295
+ if (includeMetadata && metadata?.info) {
15296
+ const metaParts = [];
15297
+ if (metadata.info.Title) metaParts.push(`**Title:** ${metadata.info.Title}`);
15298
+ if (metadata.info.Author) metaParts.push(`**Author:** ${metadata.info.Author}`);
15299
+ if (metadata.info.Subject) metaParts.push(`**Subject:** ${metadata.info.Subject}`);
15300
+ if (metadata.info.Creator) metaParts.push(`**Creator:** ${metadata.info.Creator}`);
15301
+ if (pages.length) metaParts.push(`**Pages:** ${pages.length}`);
15302
+ if (metaParts.length > 0) {
15303
+ const metaContent = metaParts.join("\n");
15304
+ const sizeBytes = Buffer.byteLength(metaContent, "utf-8");
15305
+ pieces.push({
15306
+ type: "text",
15307
+ content: metaContent,
15308
+ metadata: {
15309
+ sourceFilename: filename,
15310
+ format,
15311
+ index: pieceIndex++,
15312
+ section: "Metadata",
15313
+ sizeBytes,
15314
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
15315
+ }
15316
+ });
15317
+ }
15318
+ }
15319
+ for (const page of filteredPages) {
15320
+ const text = page.text.trim();
15321
+ if (!text) continue;
15322
+ const sizeBytes = Buffer.byteLength(text, "utf-8");
15323
+ pieces.push({
15324
+ type: "text",
15325
+ content: text,
15326
+ metadata: {
15327
+ sourceFilename: filename,
15328
+ format,
15329
+ index: pieceIndex++,
15330
+ section: `Page ${page.pageNum}`,
15331
+ sizeBytes,
15332
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
15333
+ }
15334
+ });
15335
+ }
15336
+ if (options.extractImages !== false) {
15337
+ try {
15338
+ const imagesResult = await unpdf.extractImages(buffer, {});
15339
+ const images = imagesResult?.images || [];
15340
+ for (const img of images) {
15341
+ if (!img.data) continue;
15342
+ const base64 = typeof img.data === "string" ? img.data : Buffer.from(img.data).toString("base64");
15343
+ const sizeBytes = Math.ceil(base64.length * 0.75);
15344
+ pieces.push({
15345
+ type: "image",
15346
+ base64,
15347
+ mimeType: img.mimeType || "image/png",
15348
+ width: img.width,
15349
+ height: img.height,
15350
+ metadata: {
15351
+ sourceFilename: filename,
15352
+ format,
15353
+ index: pieceIndex++,
15354
+ sizeBytes,
15355
+ estimatedTokens: DOCUMENT_DEFAULTS.IMAGE_TOKENS_AUTO,
15356
+ label: img.name || void 0
15357
+ }
15358
+ });
15359
+ }
15360
+ } catch {
15361
+ }
15362
+ }
15363
+ return pieces;
15364
+ }
15365
+ };
15366
+ }
15367
+ });
15368
+
15369
+ // src/capabilities/documents/handlers/index.ts
15370
+ var handlers_exports = {};
15371
+ __export(handlers_exports, {
15372
+ ExcelHandler: () => ExcelHandler,
15373
+ HTMLHandler: () => HTMLHandler,
15374
+ ImageHandler: () => ImageHandler,
15375
+ OfficeHandler: () => OfficeHandler,
15376
+ PDFHandler: () => PDFHandler,
15377
+ TextHandler: () => TextHandler,
15378
+ getDefaultHandlers: () => getDefaultHandlers
15379
+ });
15380
+ function getDefaultHandlers() {
15381
+ return /* @__PURE__ */ new Map([
15382
+ ["text", new TextHandler()],
15383
+ ["image", new ImageHandler()],
15384
+ ["html", new HTMLHandler()],
15385
+ ["office", new OfficeHandler()],
15386
+ ["spreadsheet", new ExcelHandler()],
15387
+ ["pdf", new PDFHandler()]
15388
+ ]);
15389
+ }
15390
+ var init_handlers = __esm({
15391
+ "src/capabilities/documents/handlers/index.ts"() {
15392
+ init_TextHandler();
15393
+ init_ImageHandler();
15394
+ init_HTMLHandler();
15395
+ init_OfficeHandler();
15396
+ init_ExcelHandler();
15397
+ init_PDFHandler();
15398
+ init_TextHandler();
15399
+ init_ImageHandler();
15400
+ init_HTMLHandler();
15401
+ init_OfficeHandler();
15402
+ init_ExcelHandler();
15403
+ init_PDFHandler();
15404
+ }
15405
+ });
15406
+
15407
+ // src/capabilities/documents/transformers/DefaultTransformers.ts
15408
+ function normalizeTable(table) {
15409
+ const lines = table.trim().split("\n");
15410
+ if (lines.length < 2) return table;
15411
+ const rows = lines.map(
15412
+ (line) => line.split("|").slice(1, -1).map((cell) => cell.trim())
15413
+ );
15414
+ const colCount = Math.max(...rows.map((r) => r.length));
15415
+ const colWidths = new Array(colCount).fill(3);
15416
+ for (const row of rows) {
15417
+ for (let i = 0; i < row.length; i++) {
15418
+ const cell = row[i] ?? "";
15419
+ if (cell.match(/^[-:]+$/)) continue;
15420
+ colWidths[i] = Math.max(colWidths[i] ?? 3, cell.length);
15421
+ }
15422
+ }
15423
+ const result = rows.map((row, rowIndex) => {
15424
+ const cells = [];
15425
+ for (let i = 0; i < colCount; i++) {
15426
+ const cell = row[i] || "";
15427
+ if (rowIndex === 1) {
15428
+ cells.push("-".repeat(colWidths[i]));
15429
+ } else {
15430
+ cells.push(cell.padEnd(colWidths[i]));
14934
15431
  }
14935
- return parsed;
14936
15432
  }
14937
- function parse(command, args, options) {
14938
- if (args && !Array.isArray(args)) {
14939
- options = args;
14940
- args = null;
15433
+ return `| ${cells.join(" | ")} |`;
15434
+ });
15435
+ return result.join("\n");
15436
+ }
15437
+ function getDefaultTransformers() {
15438
+ return [
15439
+ documentHeaderTransformer,
15440
+ tableFormattingTransformer,
15441
+ truncationTransformer
15442
+ ];
15443
+ }
15444
+ var documentHeaderTransformer, tableFormattingTransformer, truncationTransformer;
15445
+ var init_DefaultTransformers = __esm({
15446
+ "src/capabilities/documents/transformers/DefaultTransformers.ts"() {
15447
+ init_constants();
15448
+ documentHeaderTransformer = {
15449
+ name: "documentHeaderTransformer",
15450
+ appliesTo: [],
15451
+ // applies to all formats
15452
+ priority: 10,
15453
+ async transform(pieces, context) {
15454
+ if (pieces.length === 0) return pieces;
15455
+ const totalSize = pieces.reduce((sum, p) => sum + p.metadata.sizeBytes, 0);
15456
+ const sizeStr = totalSize > 1024 * 1024 ? `${(totalSize / 1024 / 1024).toFixed(1)}MB` : `${(totalSize / 1024).toFixed(1)}KB`;
15457
+ const header = `# Document: ${context.filename}
15458
+ _Format: ${context.format.toUpperCase()} | Size: ${sizeStr}_`;
15459
+ const headerBytes = Buffer.byteLength(header, "utf-8");
15460
+ const headerPiece = {
15461
+ type: "text",
15462
+ content: header,
15463
+ metadata: {
15464
+ sourceFilename: context.filename,
15465
+ format: context.format,
15466
+ index: -1,
15467
+ // will be re-indexed
15468
+ section: "Header",
15469
+ sizeBytes: headerBytes,
15470
+ estimatedTokens: Math.ceil(headerBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
15471
+ }
15472
+ };
15473
+ const result = [headerPiece, ...pieces];
15474
+ result.forEach((p, i) => {
15475
+ p.metadata.index = i;
15476
+ });
15477
+ return result;
14941
15478
  }
14942
- args = args ? args.slice(0) : [];
14943
- options = Object.assign({}, options);
14944
- const parsed = {
14945
- command,
14946
- args,
14947
- options,
14948
- file: void 0,
14949
- original: {
14950
- command,
14951
- args
14952
- }
14953
- };
14954
- return options.shell ? parsed : parseNonShell(parsed);
14955
- }
14956
- module.exports = parse;
14957
- }
14958
- });
14959
-
14960
- // node_modules/cross-spawn/lib/enoent.js
14961
- var require_enoent = __commonJS({
14962
- "node_modules/cross-spawn/lib/enoent.js"(exports$1, module) {
14963
- var isWin = process.platform === "win32";
14964
- function notFoundError(original, syscall) {
14965
- return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), {
14966
- code: "ENOENT",
14967
- errno: "ENOENT",
14968
- syscall: `${syscall} ${original.command}`,
14969
- path: original.command,
14970
- spawnargs: original.args
14971
- });
14972
- }
14973
- function hookChildProcess(cp, parsed) {
14974
- if (!isWin) {
14975
- return;
15479
+ };
15480
+ tableFormattingTransformer = {
15481
+ name: "tableFormattingTransformer",
15482
+ appliesTo: ["xlsx", "csv"],
15483
+ priority: 50,
15484
+ async transform(pieces, _context) {
15485
+ return pieces.map((piece) => {
15486
+ if (piece.type !== "text") return piece;
15487
+ let content = piece.content;
15488
+ content = content.replace(
15489
+ /(\|[^\n]+\|\n\|[\s\-:|]+\|\n(?:\|[^\n]+\|\n?)*)/g,
15490
+ (table) => normalizeTable(table)
15491
+ );
15492
+ if (content === piece.content) return piece;
15493
+ const sizeBytes = Buffer.byteLength(content, "utf-8");
15494
+ return {
15495
+ ...piece,
15496
+ content,
15497
+ metadata: {
15498
+ ...piece.metadata,
15499
+ sizeBytes,
15500
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
15501
+ }
15502
+ };
15503
+ });
14976
15504
  }
14977
- const originalEmit = cp.emit;
14978
- cp.emit = function(name, arg1) {
14979
- if (name === "exit") {
14980
- const err = verifyENOENT(arg1, parsed);
14981
- if (err) {
14982
- return originalEmit.call(cp, "error", err);
15505
+ };
15506
+ truncationTransformer = {
15507
+ name: "truncationTransformer",
15508
+ appliesTo: [],
15509
+ // applies to all formats
15510
+ priority: 1e3,
15511
+ // runs last
15512
+ async transform(pieces, context) {
15513
+ const maxTokens = context.options.maxTokens ?? DOCUMENT_DEFAULTS.MAX_OUTPUT_TOKENS;
15514
+ const maxBytes = context.options.maxOutputBytes ?? DOCUMENT_DEFAULTS.MAX_OUTPUT_BYTES;
15515
+ let totalTokens = 0;
15516
+ let totalBytes = 0;
15517
+ const result = [];
15518
+ for (const piece of pieces) {
15519
+ totalTokens += piece.metadata.estimatedTokens;
15520
+ totalBytes += piece.metadata.sizeBytes;
15521
+ if (totalTokens > maxTokens || totalBytes > maxBytes) {
15522
+ if (piece.type === "text") {
15523
+ const remainingTokens = maxTokens - (totalTokens - piece.metadata.estimatedTokens);
15524
+ const remainingChars = remainingTokens * DOCUMENT_DEFAULTS.CHARS_PER_TOKEN;
15525
+ if (remainingChars > 100) {
15526
+ const content = piece.content;
15527
+ const truncateAt = content.lastIndexOf("\n\n", remainingChars);
15528
+ const cutPoint = truncateAt > remainingChars * 0.3 ? truncateAt : remainingChars;
15529
+ const truncated = content.slice(0, cutPoint) + "\n\n..._[content truncated]_";
15530
+ const sizeBytes = Buffer.byteLength(truncated, "utf-8");
15531
+ result.push({
15532
+ ...piece,
15533
+ content: truncated,
15534
+ metadata: {
15535
+ ...piece.metadata,
15536
+ sizeBytes,
15537
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
15538
+ }
15539
+ });
15540
+ }
15541
+ }
15542
+ break;
14983
15543
  }
15544
+ result.push(piece);
14984
15545
  }
14985
- return originalEmit.apply(cp, arguments);
14986
- };
14987
- }
14988
- function verifyENOENT(status, parsed) {
14989
- if (isWin && status === 1 && !parsed.file) {
14990
- return notFoundError(parsed.original, "spawn");
14991
- }
14992
- return null;
14993
- }
14994
- function verifyENOENTSync(status, parsed) {
14995
- if (isWin && status === 1 && !parsed.file) {
14996
- return notFoundError(parsed.original, "spawnSync");
15546
+ return result;
14997
15547
  }
14998
- return null;
14999
- }
15000
- module.exports = {
15001
- hookChildProcess,
15002
- verifyENOENT,
15003
- verifyENOENTSync,
15004
- notFoundError
15005
- };
15006
- }
15007
- });
15008
-
15009
- // node_modules/cross-spawn/index.js
15010
- var require_cross_spawn = __commonJS({
15011
- "node_modules/cross-spawn/index.js"(exports$1, module) {
15012
- var cp = __require("child_process");
15013
- var parse = require_parse();
15014
- var enoent = require_enoent();
15015
- function spawn3(command, args, options) {
15016
- const parsed = parse(command, args, options);
15017
- const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
15018
- enoent.hookChildProcess(spawned, parsed);
15019
- return spawned;
15020
- }
15021
- function spawnSync(command, args, options) {
15022
- const parsed = parse(command, args, options);
15023
- const result = cp.spawnSync(parsed.command, parsed.args, parsed.options);
15024
- result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
15025
- return result;
15026
- }
15027
- module.exports = spawn3;
15028
- module.exports.spawn = spawn3;
15029
- module.exports.sync = spawnSync;
15030
- module.exports._parse = parse;
15031
- module.exports._enoent = enoent;
15548
+ };
15549
+ }
15550
+ });
15551
+
15552
+ // src/capabilities/documents/transformers/index.ts
15553
+ var transformers_exports = {};
15554
+ __export(transformers_exports, {
15555
+ documentHeaderTransformer: () => documentHeaderTransformer,
15556
+ getDefaultTransformers: () => getDefaultTransformers,
15557
+ tableFormattingTransformer: () => tableFormattingTransformer,
15558
+ truncationTransformer: () => truncationTransformer
15559
+ });
15560
+ var init_transformers = __esm({
15561
+ "src/capabilities/documents/transformers/index.ts"() {
15562
+ init_DefaultTransformers();
15032
15563
  }
15033
15564
  });
15034
15565
 
@@ -15743,6 +16274,32 @@ var ParallelTasksError = class _ParallelTasksError extends AIError {
15743
16274
  return this.failures.map((f) => f.taskId);
15744
16275
  }
15745
16276
  };
16277
+ var DocumentReadError = class _DocumentReadError extends AIError {
16278
+ constructor(source, message, originalError) {
16279
+ super(
16280
+ `Failed to read document '${source}': ${message}`,
16281
+ "DOCUMENT_READ_ERROR",
16282
+ 500,
16283
+ originalError
16284
+ );
16285
+ this.source = source;
16286
+ this.name = "DocumentReadError";
16287
+ Object.setPrototypeOf(this, _DocumentReadError.prototype);
16288
+ }
16289
+ };
16290
+ var UnsupportedFormatError = class _UnsupportedFormatError extends AIError {
16291
+ constructor(format, family) {
16292
+ super(
16293
+ `Unsupported document format: '${format}'${family ? ` (family: ${family})` : ""}`,
16294
+ "UNSUPPORTED_FORMAT",
16295
+ 400
16296
+ );
16297
+ this.format = format;
16298
+ this.family = family;
16299
+ this.name = "UnsupportedFormatError";
16300
+ Object.setPrototypeOf(this, _UnsupportedFormatError.prototype);
16301
+ }
16302
+ };
15746
16303
  var ContextOverflowError = class _ContextOverflowError extends AIError {
15747
16304
  constructor(message, budget) {
15748
16305
  super(
@@ -18146,24 +18703,9 @@ var ContentType = /* @__PURE__ */ ((ContentType2) => {
18146
18703
  ContentType2["TOOL_RESULT"] = "tool_result";
18147
18704
  return ContentType2;
18148
18705
  })(ContentType || {});
18149
- var AGENT_DEFAULTS = {
18150
- /** Default maximum iterations for agentic loop */
18151
- MAX_ITERATIONS: 50,
18152
- /** Default temperature for LLM calls */
18153
- DEFAULT_TEMPERATURE: 0.7,
18154
- /** Message injected when max iterations is reached */
18155
- MAX_ITERATIONS_MESSAGE: `You have reached the maximum iteration limit for this execution. Please:
18156
- 1. Summarize what you have accomplished so far
18157
- 2. Explain what remains to be done (if anything)
18158
- 3. Ask the user if they would like you to continue
18159
-
18160
- Do NOT use any tools in this response - just provide a clear summary and ask for confirmation to proceed.`
18161
- };
18162
- var TOKEN_ESTIMATION = {
18163
- /** Characters per token for mixed content */
18164
- MIXED_CHARS_PER_TOKEN: 3.5};
18165
18706
 
18166
18707
  // src/core/context-nextgen/BasePluginNextGen.ts
18708
+ init_constants();
18167
18709
  var simpleTokenEstimator = {
18168
18710
  estimateTokens(text) {
18169
18711
  if (!text || text.length === 0) return 0;
@@ -18172,6 +18714,14 @@ var simpleTokenEstimator = {
18172
18714
  estimateDataTokens(data) {
18173
18715
  const text = typeof data === "string" ? data : JSON.stringify(data);
18174
18716
  return this.estimateTokens(text);
18717
+ },
18718
+ estimateImageTokens(width, height, detail) {
18719
+ if (detail === "low") return 85;
18720
+ if (width && height) {
18721
+ const tiles = Math.ceil(width / 512) * Math.ceil(height / 512);
18722
+ return 85 + 170 * tiles;
18723
+ }
18724
+ return 1e3;
18175
18725
  }
18176
18726
  };
18177
18727
  var BasePluginNextGen = class {
@@ -21419,12 +21969,26 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
21419
21969
  return "";
21420
21970
  }
21421
21971
  const id = this.generateId();
21422
- const contentArray = results.map((r) => ({
21423
- type: "tool_result" /* TOOL_RESULT */,
21424
- tool_use_id: r.tool_use_id,
21425
- content: typeof r.content === "string" ? r.content : JSON.stringify(r.content),
21426
- error: r.error
21427
- }));
21972
+ const contentArray = results.map((r) => {
21973
+ let contentStr;
21974
+ let images;
21975
+ if (typeof r.content === "string") {
21976
+ contentStr = r.content;
21977
+ } else if (r.content && Array.isArray(r.content.__images) && r.content.__images.length > 0) {
21978
+ images = r.content.__images;
21979
+ const { __images: _, base64: __, ...rest } = r.content;
21980
+ contentStr = JSON.stringify(rest);
21981
+ } else {
21982
+ contentStr = JSON.stringify(r.content);
21983
+ }
21984
+ return {
21985
+ type: "tool_result" /* TOOL_RESULT */,
21986
+ tool_use_id: r.tool_use_id,
21987
+ content: contentStr,
21988
+ error: r.error,
21989
+ ...images ? { __images: images } : {}
21990
+ };
21991
+ });
21428
21992
  const message = {
21429
21993
  type: "message",
21430
21994
  id,
@@ -21685,12 +22249,29 @@ ${content}`);
21685
22249
  total += this._estimator.estimateDataTokens(c.input || {});
21686
22250
  } else if (c.type === "tool_result" /* TOOL_RESULT */) {
21687
22251
  total += this._estimator.estimateTokens(c.content || "");
22252
+ const images = c.__images;
22253
+ if (images?.length) {
22254
+ for (const _img of images) {
22255
+ total += this._estimateImageTokens();
22256
+ }
22257
+ }
21688
22258
  } else if (c.type === "input_image_url" /* INPUT_IMAGE_URL */) {
21689
- total += 200;
22259
+ const imgContent = c;
22260
+ const detail = imgContent.image_url?.detail;
22261
+ total += this._estimateImageTokens(void 0, void 0, detail);
21690
22262
  }
21691
22263
  }
21692
22264
  return total;
21693
22265
  }
22266
+ /**
22267
+ * Estimate tokens for a single image, using the estimator's image method if available.
22268
+ */
22269
+ _estimateImageTokens(width, height, detail) {
22270
+ if (this._estimator.estimateImageTokens) {
22271
+ return this._estimator.estimateImageTokens(width, height, detail);
22272
+ }
22273
+ return 1e3;
22274
+ }
21694
22275
  // ============================================================================
21695
22276
  // Compaction
21696
22277
  // ============================================================================
@@ -21923,7 +22504,8 @@ ${content}`);
21923
22504
  if (c.type === "tool_result" /* TOOL_RESULT */) {
21924
22505
  const toolResult = c;
21925
22506
  const content = toolResult.content || "";
21926
- if (this.isBinaryContent(content)) {
22507
+ const images = toolResult.__images;
22508
+ if (!images?.length && this.isBinaryContent(content)) {
21927
22509
  truncatedContent.push({
21928
22510
  type: "tool_result" /* TOOL_RESULT */,
21929
22511
  tool_use_id: toolResult.tool_use_id,
@@ -21940,7 +22522,9 @@ ${content}`);
21940
22522
  tool_use_id: toolResult.tool_use_id,
21941
22523
  content: `${truncated}
21942
22524
 
21943
- [TRUNCATED: Original output was ${Math.round(content.length / 1024)}KB. Only first ${Math.round(availableChars / 1024)}KB shown. Consider using more targeted queries.]`
22525
+ [TRUNCATED: Original output was ${Math.round(content.length / 1024)}KB. Only first ${Math.round(availableChars / 1024)}KB shown. Consider using more targeted queries.]`,
22526
+ // Preserve images even when text is truncated — they're handled natively by providers
22527
+ ...images ? { __images: images } : {}
21944
22528
  });
21945
22529
  totalCharsUsed += truncated.length + 150;
21946
22530
  } else if (availableChars > 0) {
@@ -21951,7 +22535,9 @@ ${content}`);
21951
22535
  type: "tool_result" /* TOOL_RESULT */,
21952
22536
  tool_use_id: toolResult.tool_use_id,
21953
22537
  content: "[Output too large - skipped due to context limits. Try a more targeted query.]",
21954
- error: "Output too large"
22538
+ error: "Output too large",
22539
+ // Preserve images even when text is dropped
22540
+ ...images ? { __images: images } : {}
21955
22541
  });
21956
22542
  totalCharsUsed += 100;
21957
22543
  }
@@ -22480,14 +23066,41 @@ var OpenAIResponsesConverter = class {
22480
23066
  arguments: content.arguments
22481
23067
  });
22482
23068
  break;
22483
- case "tool_result":
22484
- const output = typeof content.content === "string" ? content.content : JSON.stringify(content.content);
23069
+ case "tool_result": {
23070
+ const contentImages = content.__images;
23071
+ let outputText;
23072
+ let images;
23073
+ if (contentImages?.length) {
23074
+ outputText = typeof content.content === "string" ? content.content : JSON.stringify(content.content);
23075
+ images = contentImages;
23076
+ } else {
23077
+ const rawOutput = typeof content.content === "string" ? content.content : JSON.stringify(content.content);
23078
+ const extracted = this.extractImagesFromOutput(rawOutput);
23079
+ outputText = extracted.text;
23080
+ images = extracted.images;
23081
+ }
22485
23082
  items.push({
22486
23083
  type: "function_call_output",
22487
23084
  call_id: content.tool_use_id,
22488
- output
23085
+ output: outputText
22489
23086
  });
23087
+ if (images.length > 0) {
23088
+ const imageContent = images.map((img) => ({
23089
+ type: "input_image",
23090
+ image_url: `data:${img.mediaType};base64,${img.base64}`
23091
+ }));
23092
+ items.push({
23093
+ type: "message",
23094
+ role: "user",
23095
+ content: [
23096
+ { type: "input_text", text: "[Screenshot from tool result]" },
23097
+ ...imageContent
23098
+ ],
23099
+ status: "completed"
23100
+ });
23101
+ }
22490
23102
  break;
23103
+ }
22491
23104
  }
22492
23105
  }
22493
23106
  if (messageContent.length > 0) {
@@ -22655,6 +23268,22 @@ var OpenAIResponsesConverter = class {
22655
23268
  }
22656
23269
  };
22657
23270
  }
23271
+ /**
23272
+ * Extract __images from a JSON tool result and return cleaned text + images.
23273
+ * Used by the __images convention for multimodal tool results.
23274
+ */
23275
+ extractImagesFromOutput(output) {
23276
+ try {
23277
+ const parsed = JSON.parse(output);
23278
+ if (parsed && Array.isArray(parsed.__images) && parsed.__images.length > 0) {
23279
+ const images = parsed.__images;
23280
+ const { __images: _, base64: __, ...rest } = parsed;
23281
+ return { text: JSON.stringify(rest), images };
23282
+ }
23283
+ } catch {
23284
+ }
23285
+ return { text: output, images: [] };
23286
+ }
22658
23287
  };
22659
23288
 
22660
23289
  // src/domain/entities/StreamEvent.ts
@@ -23460,6 +24089,7 @@ var AnthropicConverter = class extends BaseConverter {
23460
24089
  /**
23461
24090
  * Convert tool result to Anthropic block
23462
24091
  * Anthropic requires non-empty content when is_error is true
24092
+ * Supports __images convention: tool results with __images get multimodal content
23463
24093
  */
23464
24094
  convertToolResultToAnthropicBlock(resultContent) {
23465
24095
  const isError = !!resultContent.error;
@@ -23472,6 +24102,30 @@ var AnthropicConverter = class extends BaseConverter {
23472
24102
  if (isError && !toolResultContent) {
23473
24103
  toolResultContent = resultContent.error || "Tool execution failed";
23474
24104
  }
24105
+ const images = resultContent.__images?.length ? resultContent.__images : this.extractImages(toolResultContent);
24106
+ if (images) {
24107
+ const textContent = resultContent.__images?.length ? toolResultContent : this.stripImagesFromContent(toolResultContent);
24108
+ const contentBlocks = [];
24109
+ if (textContent.trim()) {
24110
+ contentBlocks.push({ type: "text", text: textContent });
24111
+ }
24112
+ for (const img of images) {
24113
+ contentBlocks.push({
24114
+ type: "image",
24115
+ source: {
24116
+ type: "base64",
24117
+ media_type: img.mediaType || "image/png",
24118
+ data: img.base64
24119
+ }
24120
+ });
24121
+ }
24122
+ return {
24123
+ type: "tool_result",
24124
+ tool_use_id: resultContent.tool_use_id,
24125
+ content: contentBlocks.length > 0 ? contentBlocks : textContent,
24126
+ is_error: isError
24127
+ };
24128
+ }
23475
24129
  return {
23476
24130
  type: "tool_result",
23477
24131
  tool_use_id: resultContent.tool_use_id,
@@ -23479,6 +24133,32 @@ var AnthropicConverter = class extends BaseConverter {
23479
24133
  is_error: isError
23480
24134
  };
23481
24135
  }
24136
+ /**
24137
+ * Extract __images from a JSON-stringified tool result content.
24138
+ * Returns null if no images found.
24139
+ */
24140
+ extractImages(content) {
24141
+ try {
24142
+ const parsed = JSON.parse(content);
24143
+ if (parsed && Array.isArray(parsed.__images) && parsed.__images.length > 0) {
24144
+ return parsed.__images;
24145
+ }
24146
+ } catch {
24147
+ }
24148
+ return null;
24149
+ }
24150
+ /**
24151
+ * Strip __images and base64 fields from JSON content to reduce token usage in text.
24152
+ */
24153
+ stripImagesFromContent(content) {
24154
+ try {
24155
+ const parsed = JSON.parse(content);
24156
+ const { __images: _, base64: __, ...rest } = parsed;
24157
+ return JSON.stringify(rest);
24158
+ } catch {
24159
+ return content;
24160
+ }
24161
+ }
23482
24162
  /**
23483
24163
  * Convert our Tool[] -> Anthropic tools
23484
24164
  * Uses shared conversion utilities (DRY)
@@ -24206,18 +24886,38 @@ var GoogleConverter = class {
24206
24886
  }
24207
24887
  parts.push(functionCallPart);
24208
24888
  break;
24209
- case "tool_result" /* TOOL_RESULT */:
24889
+ case "tool_result" /* TOOL_RESULT */: {
24210
24890
  const functionName = this.toolCallMapping.get(c.tool_use_id) || this.extractToolName(c.tool_use_id);
24891
+ const contentImages = c.__images;
24892
+ let resultText;
24893
+ let resultImages;
24894
+ if (contentImages?.length) {
24895
+ resultText = typeof c.content === "string" ? c.content : JSON.stringify(c.content);
24896
+ resultImages = contentImages;
24897
+ } else {
24898
+ const resultStr = typeof c.content === "string" ? c.content : JSON.stringify(c.content);
24899
+ const extracted = this.extractImagesFromResult(resultStr);
24900
+ resultText = extracted.text;
24901
+ resultImages = extracted.images;
24902
+ }
24211
24903
  parts.push({
24212
24904
  functionResponse: {
24213
24905
  name: functionName,
24214
- // Use actual function name from mapping
24215
24906
  response: {
24216
- result: typeof c.content === "string" ? c.content : c.content
24907
+ result: resultText
24217
24908
  }
24218
24909
  }
24219
24910
  });
24911
+ for (const img of resultImages) {
24912
+ parts.push({
24913
+ inlineData: {
24914
+ mimeType: img.mediaType || "image/png",
24915
+ data: img.base64
24916
+ }
24917
+ });
24918
+ }
24220
24919
  break;
24920
+ }
24221
24921
  }
24222
24922
  }
24223
24923
  return parts;
@@ -24353,6 +25053,22 @@ var GoogleConverter = class {
24353
25053
  reset() {
24354
25054
  this.clearMappings();
24355
25055
  }
25056
+ /**
25057
+ * Extract __images from a JSON tool result and return cleaned text + images.
25058
+ * Used by the __images convention for multimodal tool results.
25059
+ */
25060
+ extractImagesFromResult(content) {
25061
+ try {
25062
+ const parsed = JSON.parse(content);
25063
+ if (parsed && Array.isArray(parsed.__images) && parsed.__images.length > 0) {
25064
+ const images = parsed.__images;
25065
+ const { __images: _, base64: __, ...rest } = parsed;
25066
+ return { text: JSON.stringify(rest), images };
25067
+ }
25068
+ } catch {
25069
+ }
25070
+ return { text: content, images: [] };
25071
+ }
24356
25072
  };
24357
25073
  var GoogleStreamConverter = class {
24358
25074
  responseId = "";
@@ -26315,6 +27031,7 @@ function assertNotDestroyed(obj, operation) {
26315
27031
 
26316
27032
  // src/core/Agent.ts
26317
27033
  init_Metrics();
27034
+ init_constants();
26318
27035
  var Agent = class _Agent extends BaseAgent {
26319
27036
  // ===== Agent-specific State =====
26320
27037
  hookManager;
@@ -27522,6 +28239,9 @@ var Agent = class _Agent extends BaseAgent {
27522
28239
  this._logger.debug("Agent destroyed");
27523
28240
  }
27524
28241
  };
28242
+
28243
+ // src/core/index.ts
28244
+ init_constants();
27525
28245
  (class {
27526
28246
  static DEFAULT_PATHS = [
27527
28247
  "./oneringai.config.json",
@@ -30931,9 +31651,6 @@ var Client = class extends Protocol {
30931
31651
  }
30932
31652
  };
30933
31653
 
30934
- // node_modules/@modelcontextprotocol/sdk/dist/esm/client/stdio.js
30935
- var import_cross_spawn = __toESM(require_cross_spawn());
30936
-
30937
31654
  // node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
30938
31655
  var ReadBuffer = class {
30939
31656
  append(chunk) {
@@ -31011,7 +31728,7 @@ var StdioClientTransport = class {
31011
31728
  throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");
31012
31729
  }
31013
31730
  return new Promise((resolve4, reject) => {
31014
- this._process = (0, import_cross_spawn.default)(this._serverParams.command, this._serverParams.args ?? [], {
31731
+ this._process = spawn$1(this._serverParams.command, this._serverParams.args ?? [], {
31015
31732
  // merge default env with server env because mcp server needs some env vars
31016
31733
  env: {
31017
31734
  ...getDefaultEnvironment(),
@@ -38560,6 +39277,494 @@ var ZenRowsProvider = class {
38560
39277
  };
38561
39278
  registerScrapeProvider("zenrows", ZenRowsProvider);
38562
39279
 
39280
+ // src/capabilities/documents/DocumentReader.ts
39281
+ init_constants();
39282
+
39283
+ // src/capabilities/documents/FormatDetector.ts
39284
+ var EXTENSION_MAP = {
39285
+ // Office
39286
+ ".docx": { format: "docx", family: "office", mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document" },
39287
+ ".pptx": { format: "pptx", family: "office", mimeType: "application/vnd.openxmlformats-officedocument.presentationml.presentation" },
39288
+ ".odt": { format: "odt", family: "office", mimeType: "application/vnd.oasis.opendocument.text" },
39289
+ ".odp": { format: "odp", family: "office", mimeType: "application/vnd.oasis.opendocument.presentation" },
39290
+ ".ods": { format: "ods", family: "office", mimeType: "application/vnd.oasis.opendocument.spreadsheet" },
39291
+ ".rtf": { format: "rtf", family: "office", mimeType: "application/rtf" },
39292
+ // Spreadsheet
39293
+ ".xlsx": { format: "xlsx", family: "spreadsheet", mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" },
39294
+ ".csv": { format: "csv", family: "spreadsheet", mimeType: "text/csv" },
39295
+ // PDF
39296
+ ".pdf": { format: "pdf", family: "pdf", mimeType: "application/pdf" },
39297
+ // HTML
39298
+ ".html": { format: "html", family: "html", mimeType: "text/html" },
39299
+ ".htm": { format: "html", family: "html", mimeType: "text/html" },
39300
+ // Text
39301
+ ".txt": { format: "txt", family: "text", mimeType: "text/plain" },
39302
+ ".md": { format: "md", family: "text", mimeType: "text/markdown" },
39303
+ ".json": { format: "json", family: "text", mimeType: "application/json" },
39304
+ ".xml": { format: "xml", family: "text", mimeType: "application/xml" },
39305
+ ".yaml": { format: "yaml", family: "text", mimeType: "application/yaml" },
39306
+ ".yml": { format: "yml", family: "text", mimeType: "application/yaml" },
39307
+ // Image
39308
+ ".png": { format: "png", family: "image", mimeType: "image/png" },
39309
+ ".jpg": { format: "jpg", family: "image", mimeType: "image/jpeg" },
39310
+ ".jpeg": { format: "jpeg", family: "image", mimeType: "image/jpeg" },
39311
+ ".gif": { format: "gif", family: "image", mimeType: "image/gif" },
39312
+ ".webp": { format: "webp", family: "image", mimeType: "image/webp" },
39313
+ ".svg": { format: "svg", family: "image", mimeType: "image/svg+xml" }
39314
+ };
39315
+ var MIME_MAP = {
39316
+ "application/pdf": { format: "pdf", family: "pdf" },
39317
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": { format: "docx", family: "office" },
39318
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": { format: "pptx", family: "office" },
39319
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { format: "xlsx", family: "spreadsheet" },
39320
+ "application/vnd.oasis.opendocument.text": { format: "odt", family: "office" },
39321
+ "application/vnd.oasis.opendocument.presentation": { format: "odp", family: "office" },
39322
+ "application/vnd.oasis.opendocument.spreadsheet": { format: "ods", family: "office" },
39323
+ "application/rtf": { format: "rtf", family: "office" },
39324
+ "text/rtf": { format: "rtf", family: "office" },
39325
+ "text/csv": { format: "csv", family: "spreadsheet" },
39326
+ "application/csv": { format: "csv", family: "spreadsheet" }
39327
+ };
39328
+ var BINARY_DOCUMENT_EXTENSIONS = /* @__PURE__ */ new Set([
39329
+ ".docx",
39330
+ ".pptx",
39331
+ ".xlsx",
39332
+ ".odt",
39333
+ ".odp",
39334
+ ".ods",
39335
+ ".pdf",
39336
+ ".png",
39337
+ ".jpg",
39338
+ ".jpeg",
39339
+ ".gif",
39340
+ ".webp"
39341
+ ]);
39342
+ var FormatDetector = class _FormatDetector {
39343
+ /**
39344
+ * Detect format from filename and optional buffer
39345
+ */
39346
+ static detect(filename, _buffer) {
39347
+ const ext = _FormatDetector.getExtension(filename);
39348
+ const entry = EXTENSION_MAP[ext];
39349
+ if (!entry) {
39350
+ return {
39351
+ format: "txt",
39352
+ family: "text",
39353
+ mimeType: "text/plain",
39354
+ confidence: "low"
39355
+ };
39356
+ }
39357
+ return {
39358
+ format: entry.format,
39359
+ family: entry.family,
39360
+ mimeType: entry.mimeType,
39361
+ confidence: "high"
39362
+ };
39363
+ }
39364
+ /**
39365
+ * Check if an extension is a supported document format
39366
+ * Used by readFile to detect when to use DocumentReader
39367
+ */
39368
+ static isDocumentFormat(ext) {
39369
+ const normalizedExt = ext.startsWith(".") ? ext.toLowerCase() : `.${ext.toLowerCase()}`;
39370
+ return normalizedExt in EXTENSION_MAP;
39371
+ }
39372
+ /**
39373
+ * Check if an extension is a binary document format
39374
+ * (i.e., cannot be read as UTF-8)
39375
+ */
39376
+ static isBinaryDocumentFormat(ext) {
39377
+ const normalizedExt = ext.startsWith(".") ? ext.toLowerCase() : `.${ext.toLowerCase()}`;
39378
+ return BINARY_DOCUMENT_EXTENSIONS.has(normalizedExt);
39379
+ }
39380
+ /**
39381
+ * Check if a Content-Type header indicates a document format
39382
+ * Used by webFetch to detect downloadable documents
39383
+ */
39384
+ static isDocumentMimeType(contentType) {
39385
+ const mime = (contentType.split(";")[0] ?? "").trim().toLowerCase();
39386
+ return mime in MIME_MAP;
39387
+ }
39388
+ /**
39389
+ * Detect format from Content-Type header
39390
+ */
39391
+ static detectFromMimeType(contentType) {
39392
+ const mime = (contentType.split(";")[0] ?? "").trim().toLowerCase();
39393
+ const entry = MIME_MAP[mime];
39394
+ if (!entry) return null;
39395
+ const extEntry = Object.values(EXTENSION_MAP).find(
39396
+ (e) => e.format === entry.format
39397
+ );
39398
+ return {
39399
+ format: entry.format,
39400
+ family: entry.family,
39401
+ mimeType: extEntry?.mimeType || mime,
39402
+ confidence: "high"
39403
+ };
39404
+ }
39405
+ /**
39406
+ * Get all supported document extensions
39407
+ */
39408
+ static getSupportedExtensions() {
39409
+ return Object.keys(EXTENSION_MAP);
39410
+ }
39411
+ /**
39412
+ * Get the normalized extension from a filename
39413
+ */
39414
+ static getExtension(filename) {
39415
+ const lastDot = filename.lastIndexOf(".");
39416
+ if (lastDot === -1 || lastDot === filename.length - 1) return "";
39417
+ return filename.slice(lastDot).toLowerCase();
39418
+ }
39419
+ };
39420
+
39421
+ // src/capabilities/documents/DocumentReader.ts
39422
+ var DocumentReader = class _DocumentReader {
39423
+ handlers;
39424
+ config;
39425
+ constructor(config = {}) {
39426
+ this.config = config;
39427
+ this.handlers = config.handlers ? new Map(config.handlers) : /* @__PURE__ */ new Map();
39428
+ }
39429
+ /**
39430
+ * Create a new DocumentReader instance
39431
+ */
39432
+ static create(config = {}) {
39433
+ const reader = new _DocumentReader(config);
39434
+ reader.registerDefaultHandlers();
39435
+ return reader;
39436
+ }
39437
+ /**
39438
+ * Register all default format handlers (lazy-loaded)
39439
+ */
39440
+ registerDefaultHandlers() {
39441
+ }
39442
+ /**
39443
+ * Register a custom format handler
39444
+ */
39445
+ registerHandler(family, handler) {
39446
+ this.handlers.set(family, handler);
39447
+ }
39448
+ /**
39449
+ * Read a document from any source
39450
+ */
39451
+ async read(source, options = {}) {
39452
+ const startTime = Date.now();
39453
+ const warnings = [];
39454
+ const mergedOptions = {
39455
+ ...this.config.defaults,
39456
+ ...options,
39457
+ formatOptions: {
39458
+ ...this.config.defaults?.formatOptions,
39459
+ ...options.formatOptions
39460
+ },
39461
+ imageFilter: {
39462
+ ...this.config.defaults?.imageFilter,
39463
+ ...options.imageFilter
39464
+ }
39465
+ };
39466
+ try {
39467
+ const { buffer, filename } = await this.resolveSource(
39468
+ typeof source === "string" ? this.parseStringSource(source) : source
39469
+ );
39470
+ const detection = FormatDetector.detect(filename, buffer);
39471
+ const handler = await this.getHandler(detection.family);
39472
+ if (!handler) {
39473
+ throw new UnsupportedFormatError(detection.format, detection.family);
39474
+ }
39475
+ let pieces = await handler.handle(buffer, filename, detection.format, mergedOptions);
39476
+ if (mergedOptions.extractImages !== false) {
39477
+ pieces = this.filterImages(pieces, mergedOptions.imageFilter);
39478
+ } else {
39479
+ pieces = pieces.filter((p) => p.type !== "image");
39480
+ }
39481
+ const transformerContext = {
39482
+ filename,
39483
+ format: detection.format,
39484
+ family: detection.family,
39485
+ options: mergedOptions
39486
+ };
39487
+ pieces = await this.runTransformers(pieces, transformerContext, mergedOptions);
39488
+ const metadata = this.assembleMetadata(pieces, filename, detection, startTime);
39489
+ return {
39490
+ success: true,
39491
+ pieces,
39492
+ metadata,
39493
+ warnings
39494
+ };
39495
+ } catch (error) {
39496
+ if (error instanceof DocumentReadError || error instanceof UnsupportedFormatError) {
39497
+ throw error;
39498
+ }
39499
+ throw new DocumentReadError(
39500
+ typeof source === "string" ? source : "path" in source ? source.path : "filename" in source ? source.filename : "unknown",
39501
+ error instanceof Error ? error.message : String(error),
39502
+ error instanceof Error ? error : void 0
39503
+ );
39504
+ }
39505
+ }
39506
+ /**
39507
+ * Parse a string source (auto-detect path vs URL)
39508
+ */
39509
+ parseStringSource(source) {
39510
+ if (source.startsWith("http://") || source.startsWith("https://")) {
39511
+ return { type: "url", url: source };
39512
+ }
39513
+ return { type: "file", path: source };
39514
+ }
39515
+ /**
39516
+ * Resolve any source to a buffer and filename
39517
+ */
39518
+ async resolveSource(source) {
39519
+ switch (source.type) {
39520
+ case "file": {
39521
+ const buffer = await readFile(source.path);
39522
+ const filename = source.path.split("/").pop() || source.path;
39523
+ return { buffer, filename };
39524
+ }
39525
+ case "url": {
39526
+ const maxSize = this.config.maxDownloadSizeBytes ?? DOCUMENT_DEFAULTS.MAX_DOWNLOAD_SIZE_BYTES;
39527
+ const timeout = this.config.downloadTimeoutMs ?? DOCUMENT_DEFAULTS.DOWNLOAD_TIMEOUT_MS;
39528
+ const controller = new AbortController();
39529
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
39530
+ try {
39531
+ const response = await fetch(source.url, {
39532
+ headers: {
39533
+ ...source.headers,
39534
+ "User-Agent": "OneRingAI-DocumentReader/1.0"
39535
+ },
39536
+ signal: controller.signal
39537
+ });
39538
+ clearTimeout(timeoutId);
39539
+ if (!response.ok) {
39540
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
39541
+ }
39542
+ const contentLength = response.headers.get("content-length");
39543
+ if (contentLength && parseInt(contentLength, 10) > maxSize) {
39544
+ throw new Error(`File too large: ${contentLength} bytes (max: ${maxSize})`);
39545
+ }
39546
+ const arrayBuffer = await response.arrayBuffer();
39547
+ if (arrayBuffer.byteLength > maxSize) {
39548
+ throw new Error(`Downloaded file too large: ${arrayBuffer.byteLength} bytes (max: ${maxSize})`);
39549
+ }
39550
+ const filename = this.extractFilenameFromURL(source.url, response);
39551
+ return { buffer: Buffer.from(arrayBuffer), filename };
39552
+ } catch (error) {
39553
+ clearTimeout(timeoutId);
39554
+ if (error.name === "AbortError") {
39555
+ throw new Error(`Download timed out after ${timeout}ms`);
39556
+ }
39557
+ throw error;
39558
+ }
39559
+ }
39560
+ case "buffer": {
39561
+ const buffer = Buffer.isBuffer(source.buffer) ? source.buffer : Buffer.from(source.buffer);
39562
+ return { buffer, filename: source.filename };
39563
+ }
39564
+ case "blob": {
39565
+ const arrayBuffer = await source.blob.arrayBuffer();
39566
+ return { buffer: Buffer.from(arrayBuffer), filename: source.filename };
39567
+ }
39568
+ }
39569
+ }
39570
+ /**
39571
+ * Extract filename from URL and response headers
39572
+ */
39573
+ extractFilenameFromURL(url2, response) {
39574
+ const disposition = response.headers.get("content-disposition");
39575
+ if (disposition) {
39576
+ const match = disposition.match(/filename[^;=\n]*=(['"]?)([^'"\n;]*)\1/);
39577
+ if (match?.[2]) return match[2];
39578
+ }
39579
+ try {
39580
+ const pathname = new URL(url2).pathname;
39581
+ const basename = pathname.split("/").pop();
39582
+ if (basename && basename.includes(".")) return basename;
39583
+ } catch {
39584
+ }
39585
+ return "document";
39586
+ }
39587
+ /**
39588
+ * Get the handler for a format family, loading defaults lazily
39589
+ */
39590
+ async getHandler(family) {
39591
+ if (this.handlers.has(family)) {
39592
+ return this.handlers.get(family);
39593
+ }
39594
+ try {
39595
+ const { getDefaultHandlers: getDefaultHandlers2 } = await Promise.resolve().then(() => (init_handlers(), handlers_exports));
39596
+ const defaults = getDefaultHandlers2();
39597
+ const handler = defaults.get(family);
39598
+ if (handler) {
39599
+ this.handlers.set(family, handler);
39600
+ return handler;
39601
+ }
39602
+ } catch {
39603
+ }
39604
+ return null;
39605
+ }
39606
+ /**
39607
+ * Filter images based on options
39608
+ */
39609
+ filterImages(pieces, filterOptions) {
39610
+ const minWidth = filterOptions?.minWidth ?? DOCUMENT_DEFAULTS.IMAGE_FILTER.MIN_WIDTH;
39611
+ const minHeight = filterOptions?.minHeight ?? DOCUMENT_DEFAULTS.IMAGE_FILTER.MIN_HEIGHT;
39612
+ const minSizeBytes = filterOptions?.minSizeBytes ?? DOCUMENT_DEFAULTS.IMAGE_FILTER.MIN_SIZE_BYTES;
39613
+ const maxImages = filterOptions?.maxImages ?? DOCUMENT_DEFAULTS.MAX_EXTRACTED_IMAGES;
39614
+ const excludePatterns = filterOptions?.excludePatterns ?? [];
39615
+ let imageCount = 0;
39616
+ return pieces.filter((piece) => {
39617
+ if (piece.type !== "image") return true;
39618
+ const img = piece;
39619
+ if (img.width !== void 0 && img.width < minWidth) return false;
39620
+ if (img.height !== void 0 && img.height < minHeight) return false;
39621
+ if (img.metadata.sizeBytes < minSizeBytes) return false;
39622
+ const label = img.metadata.label || "";
39623
+ if (excludePatterns.some((p) => p.test(label))) return false;
39624
+ imageCount++;
39625
+ if (imageCount > maxImages) return false;
39626
+ return true;
39627
+ });
39628
+ }
39629
+ /**
39630
+ * Run the transformer pipeline
39631
+ */
39632
+ async runTransformers(pieces, context, options) {
39633
+ const transformers = [];
39634
+ if (!options.skipDefaultTransformers) {
39635
+ try {
39636
+ const { getDefaultTransformers: getDefaultTransformers2 } = await Promise.resolve().then(() => (init_transformers(), transformers_exports));
39637
+ transformers.push(...getDefaultTransformers2());
39638
+ } catch {
39639
+ }
39640
+ }
39641
+ if (options.transformers) {
39642
+ transformers.push(...options.transformers);
39643
+ }
39644
+ transformers.sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
39645
+ let result = pieces;
39646
+ for (const transformer of transformers) {
39647
+ if (transformer.appliesTo.length === 0 || transformer.appliesTo.includes(context.format)) {
39648
+ result = await transformer.transform(result, context);
39649
+ }
39650
+ }
39651
+ return result;
39652
+ }
39653
+ /**
39654
+ * Assemble metadata from pieces
39655
+ */
39656
+ assembleMetadata(pieces, filename, detection, startTime) {
39657
+ const textPieces = pieces.filter((p) => p.type === "text");
39658
+ const imagePieces = pieces.filter((p) => p.type === "image");
39659
+ const totalSizeBytes = pieces.reduce((sum, p) => sum + p.metadata.sizeBytes, 0);
39660
+ const estimatedTokens = pieces.reduce((sum, p) => sum + p.metadata.estimatedTokens, 0);
39661
+ return {
39662
+ filename,
39663
+ format: detection.format,
39664
+ family: detection.family,
39665
+ mimeType: detection.mimeType,
39666
+ totalPieces: pieces.length,
39667
+ totalTextPieces: textPieces.length,
39668
+ totalImagePieces: imagePieces.length,
39669
+ totalSizeBytes,
39670
+ estimatedTokens,
39671
+ processingTimeMs: Date.now() - startTime
39672
+ };
39673
+ }
39674
+ };
39675
+ function mergeTextPieces(pieces) {
39676
+ return pieces.filter((p) => p.type === "text").map((p) => p.content).join("\n\n");
39677
+ }
39678
+
39679
+ // src/capabilities/documents/index.ts
39680
+ init_handlers();
39681
+ init_transformers();
39682
+
39683
+ // src/utils/documentContentBridge.ts
39684
+ function documentToContent(result, options = {}) {
39685
+ const {
39686
+ imageDetail = "auto",
39687
+ imageFilter,
39688
+ maxImages = 20,
39689
+ mergeAdjacentText = true
39690
+ } = options;
39691
+ const minWidth = imageFilter?.minWidth ?? 0;
39692
+ const minHeight = imageFilter?.minHeight ?? 0;
39693
+ const minSizeBytes = imageFilter?.minSizeBytes ?? 0;
39694
+ const excludePatterns = imageFilter?.excludePatterns ?? [];
39695
+ const contents = [];
39696
+ let imageCount = 0;
39697
+ let pendingText = [];
39698
+ const flushText = () => {
39699
+ if (pendingText.length > 0) {
39700
+ const text = {
39701
+ type: "input_text" /* INPUT_TEXT */,
39702
+ text: pendingText.join("\n\n")
39703
+ };
39704
+ contents.push(text);
39705
+ pendingText = [];
39706
+ }
39707
+ };
39708
+ for (const piece of result.pieces) {
39709
+ if (piece.type === "text") {
39710
+ if (mergeAdjacentText) {
39711
+ pendingText.push(piece.content);
39712
+ } else {
39713
+ const text = {
39714
+ type: "input_text" /* INPUT_TEXT */,
39715
+ text: piece.content
39716
+ };
39717
+ contents.push(text);
39718
+ }
39719
+ } else if (piece.type === "image") {
39720
+ if (piece.width !== void 0 && piece.width < minWidth) continue;
39721
+ if (piece.height !== void 0 && piece.height < minHeight) continue;
39722
+ if (piece.metadata.sizeBytes < minSizeBytes) continue;
39723
+ const label = piece.metadata.label || "";
39724
+ if (excludePatterns.some((p) => p.test(label))) continue;
39725
+ imageCount++;
39726
+ if (imageCount > maxImages) continue;
39727
+ flushText();
39728
+ const imageContent = {
39729
+ type: "input_image_url" /* INPUT_IMAGE_URL */,
39730
+ image_url: {
39731
+ url: `data:${piece.mimeType};base64,${piece.base64}`,
39732
+ detail: imageDetail
39733
+ }
39734
+ };
39735
+ contents.push(imageContent);
39736
+ }
39737
+ }
39738
+ flushText();
39739
+ return contents;
39740
+ }
39741
+ async function readDocumentAsContent(source, options = {}) {
39742
+ const {
39743
+ imageDetail,
39744
+ maxImages,
39745
+ mergeAdjacentText,
39746
+ // imageFilter is shared between both
39747
+ ...readOptions
39748
+ } = options;
39749
+ const contentOptions = {
39750
+ imageDetail,
39751
+ imageFilter: options.imageFilter,
39752
+ maxImages,
39753
+ mergeAdjacentText
39754
+ };
39755
+ const reader = DocumentReader.create();
39756
+ const result = await reader.read(source, readOptions);
39757
+ if (!result.success) {
39758
+ return [
39759
+ {
39760
+ type: "input_text" /* INPUT_TEXT */,
39761
+ text: `[Document read error: ${result.error || "Unknown error"}]`
39762
+ }
39763
+ ];
39764
+ }
39765
+ return documentToContent(result, contentOptions);
39766
+ }
39767
+
38563
39768
  // src/domain/interfaces/IContextStorage.ts
38564
39769
  var CONTEXT_SESSION_FORMAT_VERSION = 1;
38565
39770
 
@@ -40500,6 +41705,21 @@ var ApproximateTokenEstimator = class {
40500
41705
  return 100;
40501
41706
  }
40502
41707
  }
41708
+ /**
41709
+ * Estimate tokens for an image using tile-based model (matches OpenAI pricing).
41710
+ *
41711
+ * - detail='low': 85 tokens
41712
+ * - detail='high' with known dimensions: 85 + 170 per 512×512 tile
41713
+ * - Unknown dimensions: 1000 tokens (conservative default)
41714
+ */
41715
+ estimateImageTokens(width, height, detail) {
41716
+ if (detail === "low") return 85;
41717
+ if (width && height) {
41718
+ const tiles = Math.ceil(width / 512) * Math.ceil(height / 512);
41719
+ return 85 + 170 * tiles;
41720
+ }
41721
+ return 1e3;
41722
+ }
40503
41723
  };
40504
41724
 
40505
41725
  // src/infrastructure/context/estimators/index.ts
@@ -40727,10 +41947,17 @@ var FileContextStorage = class {
40727
41947
  }
40728
41948
  /**
40729
41949
  * Get the storage path (for display/debugging)
41950
+ * @deprecated Use getLocation() instead
40730
41951
  */
40731
41952
  getPath() {
40732
41953
  return this.sessionsDirectory;
40733
41954
  }
41955
+ /**
41956
+ * Get a human-readable storage location string (for display/debugging)
41957
+ */
41958
+ getLocation() {
41959
+ return this.sessionsDirectory;
41960
+ }
40734
41961
  /**
40735
41962
  * Get the agent ID
40736
41963
  */
@@ -41102,7 +42329,7 @@ var FileAgentDefinitionStorage = class {
41102
42329
  function createFileAgentDefinitionStorage(config) {
41103
42330
  return new FileAgentDefinitionStorage(config);
41104
42331
  }
41105
- var MIME_TYPES = {
42332
+ var MIME_TYPES2 = {
41106
42333
  png: "image/png",
41107
42334
  jpeg: "image/jpeg",
41108
42335
  jpg: "image/jpeg",
@@ -41132,7 +42359,7 @@ var FileMediaStorage = class {
41132
42359
  const filePath = path2.join(dir, filename);
41133
42360
  await fs15.writeFile(filePath, data);
41134
42361
  const format = metadata.format.toLowerCase();
41135
- const mimeType = MIME_TYPES[format] ?? "application/octet-stream";
42362
+ const mimeType = MIME_TYPES2[format] ?? "application/octet-stream";
41136
42363
  return {
41137
42364
  location: filePath,
41138
42365
  mimeType,
@@ -41177,7 +42404,7 @@ var FileMediaStorage = class {
41177
42404
  const stat6 = await fs15.stat(filePath);
41178
42405
  if (!stat6.isFile()) continue;
41179
42406
  const ext = path2.extname(file).slice(1).toLowerCase();
41180
- const mimeType = MIME_TYPES[ext] ?? "application/octet-stream";
42407
+ const mimeType = MIME_TYPES2[ext] ?? "application/octet-stream";
41181
42408
  let type;
41182
42409
  for (const prefix of MEDIA_TYPE_PREFIXES) {
41183
42410
  if (file.startsWith(`${prefix}_`)) {
@@ -45454,13 +46681,30 @@ function extractNumber(text, patterns = [
45454
46681
  var tools_exports = {};
45455
46682
  __export(tools_exports, {
45456
46683
  ConnectorTools: () => ConnectorTools,
46684
+ DEFAULT_DESKTOP_CONFIG: () => DEFAULT_DESKTOP_CONFIG,
45457
46685
  DEFAULT_FILESYSTEM_CONFIG: () => DEFAULT_FILESYSTEM_CONFIG,
45458
46686
  DEFAULT_SHELL_CONFIG: () => DEFAULT_SHELL_CONFIG,
46687
+ DESKTOP_TOOL_NAMES: () => DESKTOP_TOOL_NAMES,
46688
+ DocumentReader: () => DocumentReader,
45459
46689
  FileMediaOutputHandler: () => FileMediaStorage,
46690
+ FormatDetector: () => FormatDetector,
46691
+ NutTreeDriver: () => NutTreeDriver,
45460
46692
  ToolRegistry: () => ToolRegistry,
46693
+ applyHumanDelay: () => applyHumanDelay,
45461
46694
  bash: () => bash,
45462
46695
  createBashTool: () => createBashTool,
45463
46696
  createCreatePRTool: () => createCreatePRTool,
46697
+ createDesktopGetCursorTool: () => createDesktopGetCursorTool,
46698
+ createDesktopGetScreenSizeTool: () => createDesktopGetScreenSizeTool,
46699
+ createDesktopKeyboardKeyTool: () => createDesktopKeyboardKeyTool,
46700
+ createDesktopKeyboardTypeTool: () => createDesktopKeyboardTypeTool,
46701
+ createDesktopMouseClickTool: () => createDesktopMouseClickTool,
46702
+ createDesktopMouseDragTool: () => createDesktopMouseDragTool,
46703
+ createDesktopMouseMoveTool: () => createDesktopMouseMoveTool,
46704
+ createDesktopMouseScrollTool: () => createDesktopMouseScrollTool,
46705
+ createDesktopScreenshotTool: () => createDesktopScreenshotTool,
46706
+ createDesktopWindowFocusTool: () => createDesktopWindowFocusTool,
46707
+ createDesktopWindowListTool: () => createDesktopWindowListTool,
45464
46708
  createEditFileTool: () => createEditFileTool,
45465
46709
  createExecuteJavaScriptTool: () => createExecuteJavaScriptTool,
45466
46710
  createGetPRTool: () => createGetPRTool,
@@ -45480,12 +46724,25 @@ __export(tools_exports, {
45480
46724
  createWebScrapeTool: () => createWebScrapeTool,
45481
46725
  createWebSearchTool: () => createWebSearchTool,
45482
46726
  createWriteFileTool: () => createWriteFileTool,
46727
+ desktopGetCursor: () => desktopGetCursor,
46728
+ desktopGetScreenSize: () => desktopGetScreenSize,
46729
+ desktopKeyboardKey: () => desktopKeyboardKey,
46730
+ desktopKeyboardType: () => desktopKeyboardType,
46731
+ desktopMouseClick: () => desktopMouseClick,
46732
+ desktopMouseDrag: () => desktopMouseDrag,
46733
+ desktopMouseMove: () => desktopMouseMove,
46734
+ desktopMouseScroll: () => desktopMouseScroll,
46735
+ desktopScreenshot: () => desktopScreenshot,
46736
+ desktopTools: () => desktopTools,
46737
+ desktopWindowFocus: () => desktopWindowFocus,
46738
+ desktopWindowList: () => desktopWindowList,
45483
46739
  developerTools: () => developerTools,
45484
46740
  editFile: () => editFile,
45485
46741
  executeJavaScript: () => executeJavaScript,
45486
46742
  expandTilde: () => expandTilde,
45487
46743
  getAllBuiltInTools: () => getAllBuiltInTools,
45488
46744
  getBackgroundOutput: () => getBackgroundOutput,
46745
+ getDesktopDriver: () => getDesktopDriver,
45489
46746
  getMediaOutputHandler: () => getMediaOutputHandler,
45490
46747
  getMediaStorage: () => getMediaStorage,
45491
46748
  getToolByName: () => getToolByName,
@@ -45500,8 +46757,11 @@ __export(tools_exports, {
45500
46757
  jsonManipulator: () => jsonManipulator,
45501
46758
  killBackgroundProcess: () => killBackgroundProcess,
45502
46759
  listDirectory: () => listDirectory,
46760
+ mergeTextPieces: () => mergeTextPieces,
46761
+ parseKeyCombo: () => parseKeyCombo,
45503
46762
  parseRepository: () => parseRepository,
45504
46763
  readFile: () => readFile5,
46764
+ resetDefaultDriver: () => resetDefaultDriver,
45505
46765
  resolveRepository: () => resolveRepository,
45506
46766
  setMediaOutputHandler: () => setMediaOutputHandler,
45507
46767
  setMediaStorage: () => setMediaStorage,
@@ -45547,13 +46807,11 @@ var DEFAULT_FILESYSTEM_CONFIG = {
45547
46807
  ".avi",
45548
46808
  ".mov",
45549
46809
  ".mkv",
45550
- ".pdf",
46810
+ // Note: .pdf, .docx, .xlsx, .pptx are NOT excluded — DocumentReader handles them
45551
46811
  ".doc",
45552
- ".docx",
45553
46812
  ".xls",
45554
- ".xlsx",
45555
46813
  ".ppt",
45556
- ".pptx",
46814
+ // Legacy Office formats not yet supported
45557
46815
  ".woff",
45558
46816
  ".woff2",
45559
46817
  ".ttf",
@@ -45561,6 +46819,9 @@ var DEFAULT_FILESYSTEM_CONFIG = {
45561
46819
  ".otf"
45562
46820
  ]
45563
46821
  };
46822
+ function toForwardSlash(p) {
46823
+ return sep === "\\" ? p.replace(/\\/g, "/") : p;
46824
+ }
45564
46825
  function validatePath(inputPath, config = {}) {
45565
46826
  const workingDir = config.workingDirectory || process.cwd();
45566
46827
  const allowedDirs = config.allowedDirectories || [];
@@ -45577,7 +46838,8 @@ function validatePath(inputPath, config = {}) {
45577
46838
  } else {
45578
46839
  resolvedPath = resolve(workingDir, expandedPath);
45579
46840
  }
45580
- const pathSegments = resolvedPath.split("/").filter(Boolean);
46841
+ const normalizedResolved = toForwardSlash(resolvedPath);
46842
+ const pathSegments = normalizedResolved.split("/").filter(Boolean);
45581
46843
  for (const blocked of blockedDirs) {
45582
46844
  if (!blocked.includes("/")) {
45583
46845
  if (pathSegments.includes(blocked)) {
@@ -45588,8 +46850,8 @@ function validatePath(inputPath, config = {}) {
45588
46850
  };
45589
46851
  }
45590
46852
  } else {
45591
- const blockedPath = isAbsolute(blocked) ? blocked : resolve(workingDir, blocked);
45592
- if (resolvedPath.startsWith(blockedPath + "/") || resolvedPath === blockedPath) {
46853
+ const blockedPath = toForwardSlash(isAbsolute(blocked) ? blocked : resolve(workingDir, blocked));
46854
+ if (normalizedResolved.startsWith(blockedPath + "/") || normalizedResolved === blockedPath) {
45593
46855
  return {
45594
46856
  valid: false,
45595
46857
  resolvedPath,
@@ -45601,8 +46863,8 @@ function validatePath(inputPath, config = {}) {
45601
46863
  if (allowedDirs.length > 0) {
45602
46864
  let isAllowed = false;
45603
46865
  for (const allowed of allowedDirs) {
45604
- const allowedPath = isAbsolute(allowed) ? allowed : resolve(workingDir, allowed);
45605
- if (resolvedPath.startsWith(allowedPath + "/") || resolvedPath === allowedPath) {
46866
+ const allowedPath = toForwardSlash(isAbsolute(allowed) ? allowed : resolve(workingDir, allowed));
46867
+ if (normalizedResolved.startsWith(allowedPath + "/") || normalizedResolved === allowedPath) {
45606
46868
  isAllowed = true;
45607
46869
  break;
45608
46870
  }
@@ -45636,7 +46898,7 @@ function createReadFileTool(config = {}) {
45636
46898
  type: "function",
45637
46899
  function: {
45638
46900
  name: "read_file",
45639
- description: `Read content from a file on the local filesystem.
46901
+ description: `Read content from a file on the local filesystem. Supports text files AND binary document formats \u2014 PDF, DOCX, PPTX, XLSX, ODS, ODT, ODP, and images (PNG, JPG, GIF, WEBP) are automatically converted to markdown text.
45640
46902
 
45641
46903
  USAGE:
45642
46904
  - The file_path parameter must be an absolute path, not a relative path
@@ -45645,20 +46907,34 @@ USAGE:
45645
46907
  - Any lines longer than 2000 characters will be truncated
45646
46908
  - Results are returned with line numbers starting at 1
45647
46909
 
46910
+ DOCUMENT SUPPORT:
46911
+ - PDF files: extracted as markdown text with per-page sections
46912
+ - Word documents (.docx): converted to markdown preserving headings, lists, tables
46913
+ - PowerPoint (.pptx): extracted slide-by-slide as markdown
46914
+ - Excel (.xlsx) / CSV / ODS: tables converted to markdown tables
46915
+ - OpenDocument (.odt, .odp, .ods): converted like their MS Office equivalents
46916
+ - Images (.png, .jpg, .gif, .webp): described as image metadata
46917
+ - Binary documents are auto-detected by extension \u2014 just pass the file path
46918
+
45648
46919
  WHEN TO USE:
45649
46920
  - To read source code files before making edits
45650
46921
  - To understand file contents and structure
45651
46922
  - To read configuration files
45652
46923
  - To examine log files or data files
46924
+ - To read PDF, Word, Excel, PowerPoint, or other document files as text
45653
46925
 
45654
46926
  IMPORTANT:
45655
46927
  - Always read a file before attempting to edit it
45656
46928
  - Use offset/limit for very large files to read in chunks
45657
46929
  - The tool will return an error if the file doesn't exist
46930
+ - offset/limit are ignored for binary document formats (full document is always returned)
45658
46931
 
45659
46932
  EXAMPLES:
45660
46933
  - Read entire file: { "file_path": "/path/to/file.ts" }
45661
- - Read lines 100-200: { "file_path": "/path/to/file.ts", "offset": 100, "limit": 100 }`,
46934
+ - Read lines 100-200: { "file_path": "/path/to/file.ts", "offset": 100, "limit": 100 }
46935
+ - Read a PDF: { "file_path": "/path/to/report.pdf" }
46936
+ - Read an Excel file: { "file_path": "/path/to/data.xlsx" }
46937
+ - Read a Word doc: { "file_path": "/path/to/document.docx" }`,
45662
46938
  parameters: {
45663
46939
  type: "object",
45664
46940
  properties: {
@@ -45720,6 +46996,32 @@ EXAMPLES:
45720
46996
  size: stats.size
45721
46997
  };
45722
46998
  }
46999
+ const ext = extname(resolvedPath).toLowerCase();
47000
+ if (FormatDetector.isBinaryDocumentFormat(ext)) {
47001
+ try {
47002
+ const reader = DocumentReader.create(mergedConfig.documentReaderConfig);
47003
+ const result2 = await reader.read(
47004
+ { type: "file", path: resolvedPath },
47005
+ {
47006
+ extractImages: false,
47007
+ ...mergedConfig.documentReaderConfig?.defaults
47008
+ }
47009
+ );
47010
+ if (result2.success) {
47011
+ const content2 = mergeTextPieces(result2.pieces);
47012
+ return {
47013
+ success: true,
47014
+ content: content2,
47015
+ lines: content2.split("\n").length,
47016
+ truncated: false,
47017
+ encoding: "document",
47018
+ size: stats.size,
47019
+ path: file_path
47020
+ };
47021
+ }
47022
+ } catch {
47023
+ }
47024
+ }
45723
47025
  const content = await readFile(resolvedPath, "utf-8");
45724
47026
  const allLines = content.split("\n");
45725
47027
  const totalLines = allLines.length;
@@ -46041,7 +47343,7 @@ async function findFiles(dir, pattern, baseDir, config, results = [], depth = 0)
46041
47343
  for (const entry of entries) {
46042
47344
  if (results.length >= config.maxResults) break;
46043
47345
  const fullPath = join(dir, entry.name);
46044
- const relativePath = relative(baseDir, fullPath);
47346
+ const relativePath = toForwardSlash(relative(baseDir, fullPath));
46045
47347
  if (entry.isDirectory()) {
46046
47348
  const isBlocked = config.blockedDirectories.some(
46047
47349
  (blocked) => entry.name === blocked || relativePath.includes(`/${blocked}/`) || relativePath.startsWith(`${blocked}/`)
@@ -46404,7 +47706,7 @@ WHEN TO USE:
46404
47706
  );
46405
47707
  if (matches.length > 0) {
46406
47708
  filesMatched++;
46407
- const relativePath = relative(resolvedPath, file) || file;
47709
+ const relativePath = toForwardSlash(relative(resolvedPath, file)) || file;
46408
47710
  for (const match of matches) {
46409
47711
  match.file = relativePath;
46410
47712
  }
@@ -46470,7 +47772,7 @@ async function listDir(dir, baseDir, config, recursive, filter, maxDepth = 3, cu
46470
47772
  for (const entry of dirEntries) {
46471
47773
  if (entries.length >= config.maxResults) break;
46472
47774
  const fullPath = join(dir, entry.name);
46473
- const relativePath = relative(baseDir, fullPath);
47775
+ const relativePath = toForwardSlash(relative(baseDir, fullPath));
46474
47776
  if (entry.isDirectory() && config.blockedDirectories.includes(entry.name)) {
46475
47777
  continue;
46476
47778
  }
@@ -46685,6 +47987,8 @@ function createBashTool(config = {}) {
46685
47987
  name: "bash",
46686
47988
  description: `Execute shell commands with optional timeout.
46687
47989
 
47990
+ SHELL: This tool uses ${mergedConfig.shell}${process.platform === "win32" ? " (Windows). Use Windows command syntax (dir, type, del, etc.), NOT Unix commands (ls, cat, rm, etc.). Use \\ as path separator or quote paths with forward slashes." : " (Unix). Use standard Unix command syntax."}
47991
+
46688
47992
  USAGE:
46689
47993
  - Execute any shell command
46690
47994
  - Working directory persists between commands
@@ -46701,9 +48005,11 @@ For file operations, prefer dedicated tools:
46701
48005
 
46702
48006
  BEST PRACTICES:
46703
48007
  - Always quote file paths with spaces: cd "/path with spaces"
46704
- - Use absolute paths when possible
48008
+ - Use absolute paths when possible${process.platform === "win32" ? `
48009
+ - Chain dependent commands with &&: git add . && git commit -m "msg"
48010
+ - Use PowerShell syntax if cmd.exe is insufficient` : `
46705
48011
  - Chain dependent commands with &&: git add . && git commit -m "msg"
46706
- - Use ; only when you don't care if earlier commands fail
48012
+ - Use ; only when you don't care if earlier commands fail`}
46707
48013
  - Avoid interactive commands (no -i flags)
46708
48014
 
46709
48015
  GIT SAFETY:
@@ -47420,92 +48726,30 @@ function detectContentQuality(html, text, $) {
47420
48726
  issues
47421
48727
  };
47422
48728
  }
47423
- var JSDOM = null;
47424
- async function getJSDOM() {
47425
- if (!JSDOM) {
47426
- const jsdom = await import('jsdom');
47427
- JSDOM = jsdom.JSDOM;
47428
- }
47429
- return JSDOM;
47430
- }
47431
- async function htmlToMarkdown(html, url2, maxLength = 5e4) {
47432
- const JSDOMClass = await getJSDOM();
47433
- const dom = new JSDOMClass(html, { url: url2 });
47434
- const document = dom.window.document;
47435
- let title = document.title || "";
47436
- let byline;
47437
- let excerpt;
47438
- let contentHtml = html;
47439
- let wasReadabilityUsed = false;
47440
- try {
47441
- const clonedDoc = document.cloneNode(true);
47442
- const reader = new Readability(clonedDoc);
47443
- const article = reader.parse();
47444
- if (article && article.content && article.content.length > 100) {
47445
- contentHtml = article.content;
47446
- title = article.title || title;
47447
- byline = article.byline || void 0;
47448
- excerpt = article.excerpt || void 0;
47449
- wasReadabilityUsed = true;
47450
- }
47451
- } catch {
47452
- }
47453
- const turndown = new TurndownService({
47454
- headingStyle: "atx",
47455
- codeBlockStyle: "fenced",
47456
- bulletListMarker: "-",
47457
- emDelimiter: "_"
47458
- });
47459
- turndown.remove(["script", "style", "nav", "footer", "aside", "iframe", "noscript"]);
47460
- turndown.addRule("pre", {
47461
- filter: ["pre"],
47462
- replacement: (content, node) => {
47463
- const element = node;
47464
- const code = element.querySelector?.("code");
47465
- const lang = code?.className?.match(/language-(\w+)/)?.[1] || "";
47466
- const text = code?.textContent || content;
47467
- return `
47468
- \`\`\`${lang}
47469
- ${text}
47470
- \`\`\`
47471
- `;
47472
- }
47473
- });
47474
- let markdown = turndown.turndown(contentHtml);
47475
- markdown = markdown.replace(/\n{3,}/g, "\n\n").replace(/^\s+|\s+$/g, "").replace(/[ \t]+$/gm, "");
47476
- let wasTruncated = false;
47477
- if (markdown.length > maxLength) {
47478
- const truncateAt = markdown.lastIndexOf("\n\n", maxLength);
47479
- if (truncateAt > maxLength * 0.5) {
47480
- markdown = markdown.slice(0, truncateAt) + "\n\n...[content truncated]";
47481
- } else {
47482
- markdown = markdown.slice(0, maxLength) + "...[truncated]";
47483
- }
47484
- wasTruncated = true;
47485
- }
47486
- return {
47487
- markdown,
47488
- title,
47489
- byline,
47490
- excerpt,
47491
- wasReadabilityUsed,
47492
- wasTruncated
47493
- };
47494
- }
47495
48729
 
47496
48730
  // src/tools/web/webFetch.ts
48731
+ init_htmlToMarkdown();
47497
48732
  var webFetch = {
47498
48733
  definition: {
47499
48734
  type: "function",
47500
48735
  function: {
47501
48736
  name: "web_fetch",
47502
- description: `Fetch and extract text content from a web page URL.
48737
+ description: `Fetch and extract content from a URL \u2014 works with web pages AND document files (PDF, DOCX, XLSX, PPTX, etc.). Document URLs are automatically detected and converted to markdown text.
47503
48738
 
47504
- IMPORTANT: This tool performs a simple HTTP fetch and HTML parsing. It works well for:
48739
+ WEB PAGES:
48740
+ This tool performs HTTP fetch and HTML parsing. It works well for:
47505
48741
  - Static websites (blogs, documentation, articles)
47506
48742
  - Server-rendered HTML pages
47507
48743
  - Content that doesn't require JavaScript
47508
48744
 
48745
+ DOCUMENT URLs:
48746
+ When the URL points to a document file (detected via Content-Type header or URL extension), the document is automatically downloaded and converted to markdown:
48747
+ - PDF files: extracted as markdown with per-page sections
48748
+ - Word (.docx), PowerPoint (.pptx): converted to structured markdown
48749
+ - Excel (.xlsx), CSV, ODS: tables converted to markdown tables
48750
+ - OpenDocument formats (.odt, .odp, .ods): converted like MS Office equivalents
48751
+ - Returns contentType: "document" and includes documentMetadata in the result
48752
+
47509
48753
  LIMITATIONS:
47510
48754
  - Cannot execute JavaScript
47511
48755
  - May fail on React/Vue/Angular sites (will return low quality score)
@@ -47525,8 +48769,8 @@ RETURNS:
47525
48769
  success: boolean,
47526
48770
  url: string,
47527
48771
  title: string,
47528
- content: string, // Clean markdown (converted from HTML via Readability + Turndown)
47529
- contentType: string, // 'html' | 'json' | 'text' | 'error'
48772
+ content: string, // Clean markdown (converted from HTML or document)
48773
+ contentType: string, // 'html' | 'json' | 'text' | 'document' | 'error'
47530
48774
  qualityScore: number, // 0-100 (quality of extraction)
47531
48775
  requiresJS: boolean, // True if site likely needs JavaScript
47532
48776
  suggestedAction: string, // Suggestion if quality is low
@@ -47534,20 +48778,24 @@ RETURNS:
47534
48778
  excerpt: string, // Short summary excerpt (if extracted)
47535
48779
  byline: string, // Author info (if extracted)
47536
48780
  wasTruncated: boolean, // True if content was truncated
48781
+ documentMetadata: object, // Document metadata (format, pages, etc.) \u2014 only for document URLs
47537
48782
  error: string // Error message if failed
47538
48783
  }
47539
48784
 
47540
- EXAMPLE:
47541
- To fetch a blog post:
48785
+ EXAMPLES:
48786
+ Fetch a blog post:
47542
48787
  {
47543
48788
  url: "https://example.com/blog/article"
47544
48789
  }
47545
48790
 
47546
- With custom user agent:
48791
+ Fetch a PDF document:
48792
+ {
48793
+ url: "https://example.com/reports/q4-2025.pdf"
48794
+ }
48795
+
48796
+ Fetch an Excel spreadsheet:
47547
48797
  {
47548
- url: "https://example.com/page",
47549
- userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
47550
- timeout: 15000
48798
+ url: "https://example.com/data/metrics.xlsx"
47551
48799
  }`,
47552
48800
  parameters: {
47553
48801
  type: "object",
@@ -47611,6 +48859,51 @@ With custom user agent:
47611
48859
  };
47612
48860
  }
47613
48861
  const contentType = response.headers.get("content-type") || "";
48862
+ const urlExt = (() => {
48863
+ try {
48864
+ const pathname = new URL(args.url).pathname;
48865
+ const ext = pathname.split(".").pop()?.toLowerCase();
48866
+ return ext ? `.${ext}` : "";
48867
+ } catch {
48868
+ return "";
48869
+ }
48870
+ })();
48871
+ if (FormatDetector.isDocumentMimeType(contentType) || FormatDetector.isBinaryDocumentFormat(urlExt)) {
48872
+ try {
48873
+ const arrayBuffer = await response.arrayBuffer();
48874
+ const buffer = Buffer.from(arrayBuffer);
48875
+ const disposition = response.headers.get("content-disposition");
48876
+ let filename = "document";
48877
+ if (disposition) {
48878
+ const match = disposition.match(/filename[^;=\n]*=(['"]?)([^'"\n;]*)\1/);
48879
+ if (match?.[2]) filename = match[2];
48880
+ } else {
48881
+ try {
48882
+ const basename = new URL(args.url).pathname.split("/").pop();
48883
+ if (basename && basename.includes(".")) filename = basename;
48884
+ } catch {
48885
+ }
48886
+ }
48887
+ const reader = DocumentReader.create();
48888
+ const result = await reader.read(
48889
+ { type: "buffer", buffer, filename },
48890
+ { extractImages: false }
48891
+ );
48892
+ if (result.success) {
48893
+ return {
48894
+ success: true,
48895
+ url: args.url,
48896
+ title: `Document: ${filename}`,
48897
+ content: mergeTextPieces(result.pieces),
48898
+ contentType: "document",
48899
+ qualityScore: 100,
48900
+ requiresJS: false,
48901
+ documentMetadata: result.metadata
48902
+ };
48903
+ }
48904
+ } catch {
48905
+ }
48906
+ }
47614
48907
  if (contentType.includes("application/json")) {
47615
48908
  const json = await response.json();
47616
48909
  return {
@@ -47877,6 +49170,10 @@ For JS-heavy sites:
47877
49170
  const api = await tryAPI(args, startTime, attemptedMethods);
47878
49171
  if (api.success) return api;
47879
49172
  if (native.success) return native;
49173
+ const errors = [];
49174
+ if (native.error) errors.push(`native: ${native.error}`);
49175
+ if (api.error) errors.push(`api(${connector.name}): ${api.error}`);
49176
+ const detail = errors.length > 0 ? errors.join(" | ") : "Unknown failure";
47880
49177
  return {
47881
49178
  success: false,
47882
49179
  url: args.url,
@@ -47885,7 +49182,7 @@ For JS-heavy sites:
47885
49182
  content: "",
47886
49183
  durationMs: Date.now() - startTime,
47887
49184
  attemptedMethods,
47888
- error: "All scraping methods failed. Site may have bot protection."
49185
+ error: `All scraping methods failed. ${detail}`
47889
49186
  };
47890
49187
  },
47891
49188
  describeCall: (args) => args.url
@@ -49549,6 +50846,819 @@ function registerGitHubTools() {
49549
50846
  // src/tools/github/index.ts
49550
50847
  registerGitHubTools();
49551
50848
 
50849
+ // src/tools/desktop/types.ts
50850
+ var DEFAULT_DESKTOP_CONFIG = {
50851
+ driver: null,
50852
+ // Lazy-initialized
50853
+ humanDelay: [50, 150],
50854
+ humanizeMovement: false
50855
+ };
50856
+ async function applyHumanDelay(config) {
50857
+ const [min, max] = config.humanDelay ?? DEFAULT_DESKTOP_CONFIG.humanDelay;
50858
+ if (min === 0 && max === 0) return;
50859
+ const delay = min + Math.random() * (max - min);
50860
+ await new Promise((resolve4) => setTimeout(resolve4, delay));
50861
+ }
50862
+ var DESKTOP_TOOL_NAMES = [
50863
+ "desktop_screenshot",
50864
+ "desktop_mouse_move",
50865
+ "desktop_mouse_click",
50866
+ "desktop_mouse_drag",
50867
+ "desktop_mouse_scroll",
50868
+ "desktop_get_cursor",
50869
+ "desktop_keyboard_type",
50870
+ "desktop_keyboard_key",
50871
+ "desktop_get_screen_size",
50872
+ "desktop_window_list",
50873
+ "desktop_window_focus"
50874
+ ];
50875
+
50876
+ // src/tools/desktop/driver/NutTreeDriver.ts
50877
+ var KEY_MAP = {
50878
+ // Modifiers
50879
+ ctrl: "LeftControl",
50880
+ control: "LeftControl",
50881
+ cmd: "LeftCmd",
50882
+ command: "LeftCmd",
50883
+ meta: "LeftCmd",
50884
+ super: "LeftCmd",
50885
+ alt: "LeftAlt",
50886
+ option: "LeftAlt",
50887
+ shift: "LeftShift",
50888
+ // Navigation
50889
+ enter: "Return",
50890
+ return: "Return",
50891
+ tab: "Tab",
50892
+ escape: "Escape",
50893
+ esc: "Escape",
50894
+ backspace: "Backspace",
50895
+ delete: "Delete",
50896
+ space: "Space",
50897
+ // Arrow keys
50898
+ up: "Up",
50899
+ down: "Down",
50900
+ left: "Left",
50901
+ right: "Right",
50902
+ // Function keys
50903
+ f1: "F1",
50904
+ f2: "F2",
50905
+ f3: "F3",
50906
+ f4: "F4",
50907
+ f5: "F5",
50908
+ f6: "F6",
50909
+ f7: "F7",
50910
+ f8: "F8",
50911
+ f9: "F9",
50912
+ f10: "F10",
50913
+ f11: "F11",
50914
+ f12: "F12",
50915
+ // Other
50916
+ home: "Home",
50917
+ end: "End",
50918
+ pageup: "PageUp",
50919
+ pagedown: "PageDown",
50920
+ insert: "Insert",
50921
+ printscreen: "Print",
50922
+ capslock: "CapsLock",
50923
+ numlock: "NumLock",
50924
+ scrolllock: "ScrollLock"
50925
+ };
50926
+ function parseKeyCombo(keys, KeyEnum) {
50927
+ const parts = keys.toLowerCase().split("+").map((k) => k.trim());
50928
+ const result = [];
50929
+ for (const part of parts) {
50930
+ const mapped = KEY_MAP[part];
50931
+ if (mapped && KeyEnum[mapped] !== void 0) {
50932
+ result.push(KeyEnum[mapped]);
50933
+ continue;
50934
+ }
50935
+ if (part.length === 1) {
50936
+ const upper = part.toUpperCase();
50937
+ if (KeyEnum[upper] !== void 0) {
50938
+ result.push(KeyEnum[upper]);
50939
+ continue;
50940
+ }
50941
+ }
50942
+ const pascal = part.charAt(0).toUpperCase() + part.slice(1);
50943
+ if (KeyEnum[pascal] !== void 0) {
50944
+ result.push(KeyEnum[pascal]);
50945
+ continue;
50946
+ }
50947
+ if (KeyEnum[part] !== void 0) {
50948
+ result.push(KeyEnum[part]);
50949
+ continue;
50950
+ }
50951
+ throw new Error(`Unknown key: "${part}". Available modifiers: ctrl, cmd, alt, shift. Common keys: enter, tab, escape, space, up, down, left, right, f1-f12, a-z, 0-9`);
50952
+ }
50953
+ return result;
50954
+ }
50955
+ async function encodeRGBAToPNG(data, width, height) {
50956
+ const { PNG } = await import('pngjs');
50957
+ const png = new PNG({ width, height });
50958
+ const sourceBuffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
50959
+ sourceBuffer.copy(png.data, 0, 0, width * height * 4);
50960
+ return PNG.sync.write(png);
50961
+ }
50962
+ var NutTreeDriver = class {
50963
+ _isInitialized = false;
50964
+ _scaleFactor = 1;
50965
+ // Lazy-loaded nut-tree modules
50966
+ _nut = null;
50967
+ // Cache of Window objects keyed by windowHandle, populated by getWindowList()
50968
+ _windowCache = /* @__PURE__ */ new Map();
50969
+ get isInitialized() {
50970
+ return this._isInitialized;
50971
+ }
50972
+ get scaleFactor() {
50973
+ return this._scaleFactor;
50974
+ }
50975
+ async initialize() {
50976
+ if (this._isInitialized) return;
50977
+ try {
50978
+ this._nut = await import('@nut-tree-fork/nut-js');
50979
+ } catch {
50980
+ throw new Error(
50981
+ "@nut-tree-fork/nut-js is not installed. Install it to use desktop automation tools:\n npm install @nut-tree-fork/nut-js"
50982
+ );
50983
+ }
50984
+ try {
50985
+ const { mouse, keyboard } = this._nut;
50986
+ if (mouse.config) {
50987
+ mouse.config.mouseSpeed = 1e4;
50988
+ mouse.config.autoDelayMs = 0;
50989
+ }
50990
+ if (keyboard.config) {
50991
+ keyboard.config.autoDelayMs = 0;
50992
+ }
50993
+ } catch {
50994
+ }
50995
+ try {
50996
+ const { screen } = this._nut;
50997
+ const logicalWidth = await screen.width();
50998
+ const screenshotImage = await screen.grab();
50999
+ const physicalWidth = screenshotImage.width;
51000
+ this._scaleFactor = physicalWidth / logicalWidth;
51001
+ } catch (err) {
51002
+ if (err.message?.includes("permission") || err.message?.includes("accessibility")) {
51003
+ throw new Error(
51004
+ "Desktop automation requires accessibility permissions.\nOn macOS: System Settings \u2192 Privacy & Security \u2192 Accessibility \u2192 Enable your terminal app."
51005
+ );
51006
+ }
51007
+ this._scaleFactor = 1;
51008
+ }
51009
+ this._isInitialized = true;
51010
+ }
51011
+ assertInitialized() {
51012
+ if (!this._isInitialized) {
51013
+ throw new Error("NutTreeDriver not initialized. Call initialize() first.");
51014
+ }
51015
+ }
51016
+ /** Convert physical (screenshot) coords to logical (OS) coords */
51017
+ toLogical(x, y) {
51018
+ return {
51019
+ x: Math.round(x / this._scaleFactor),
51020
+ y: Math.round(y / this._scaleFactor)
51021
+ };
51022
+ }
51023
+ /** Convert logical (OS) coords to physical (screenshot) coords */
51024
+ toPhysical(x, y) {
51025
+ return {
51026
+ x: Math.round(x * this._scaleFactor),
51027
+ y: Math.round(y * this._scaleFactor)
51028
+ };
51029
+ }
51030
+ // ===== Screen =====
51031
+ async screenshot(region) {
51032
+ this.assertInitialized();
51033
+ const { screen } = this._nut;
51034
+ let image;
51035
+ if (region) {
51036
+ const { Region } = this._nut;
51037
+ const logTopLeft = this.toLogical(region.x, region.y);
51038
+ const logicalWidth = Math.round(region.width / this._scaleFactor);
51039
+ const logicalHeight = Math.round(region.height / this._scaleFactor);
51040
+ const nutRegion = new Region(logTopLeft.x, logTopLeft.y, logicalWidth, logicalHeight);
51041
+ image = await screen.grabRegion(nutRegion);
51042
+ } else {
51043
+ image = await screen.grab();
51044
+ }
51045
+ const pngBuffer = await encodeRGBAToPNG(image.data, image.width, image.height);
51046
+ const base64 = pngBuffer.toString("base64");
51047
+ return {
51048
+ base64,
51049
+ width: image.width,
51050
+ height: image.height
51051
+ };
51052
+ }
51053
+ async getScreenSize() {
51054
+ this.assertInitialized();
51055
+ const { screen } = this._nut;
51056
+ const logicalWidth = await screen.width();
51057
+ const logicalHeight = await screen.height();
51058
+ return {
51059
+ physicalWidth: Math.round(logicalWidth * this._scaleFactor),
51060
+ physicalHeight: Math.round(logicalHeight * this._scaleFactor),
51061
+ logicalWidth,
51062
+ logicalHeight,
51063
+ scaleFactor: this._scaleFactor
51064
+ };
51065
+ }
51066
+ // ===== Mouse =====
51067
+ async mouseMove(x, y) {
51068
+ this.assertInitialized();
51069
+ const { mouse, straightTo, Point } = this._nut;
51070
+ const logical = this.toLogical(x, y);
51071
+ await mouse.move(straightTo(new Point(logical.x, logical.y)));
51072
+ }
51073
+ async mouseClick(x, y, button, clickCount) {
51074
+ this.assertInitialized();
51075
+ const { mouse, straightTo, Point, Button } = this._nut;
51076
+ const nutButton = button === "right" ? Button.RIGHT : button === "middle" ? Button.MIDDLE : Button.LEFT;
51077
+ const logical = this.toLogical(x, y);
51078
+ await mouse.move(straightTo(new Point(logical.x, logical.y)));
51079
+ for (let i = 0; i < clickCount; i++) {
51080
+ await mouse.click(nutButton);
51081
+ }
51082
+ }
51083
+ async mouseDrag(startX, startY, endX, endY, button) {
51084
+ this.assertInitialized();
51085
+ const { mouse, straightTo, Point, Button } = this._nut;
51086
+ const nutButton = button === "right" ? Button.RIGHT : button === "middle" ? Button.MIDDLE : Button.LEFT;
51087
+ const logicalStart = this.toLogical(startX, startY);
51088
+ const logicalEnd = this.toLogical(endX, endY);
51089
+ await mouse.move(straightTo(new Point(logicalStart.x, logicalStart.y)));
51090
+ await mouse.pressButton(nutButton);
51091
+ await mouse.move(straightTo(new Point(logicalEnd.x, logicalEnd.y)));
51092
+ await mouse.releaseButton(nutButton);
51093
+ }
51094
+ async mouseScroll(deltaX, deltaY, x, y) {
51095
+ this.assertInitialized();
51096
+ const { mouse, straightTo, Point } = this._nut;
51097
+ if (x !== void 0 && y !== void 0) {
51098
+ const logical = this.toLogical(x, y);
51099
+ await mouse.move(straightTo(new Point(logical.x, logical.y)));
51100
+ }
51101
+ if (deltaY !== 0) {
51102
+ if (deltaY > 0) {
51103
+ await mouse.scrollDown(Math.abs(deltaY));
51104
+ } else {
51105
+ await mouse.scrollUp(Math.abs(deltaY));
51106
+ }
51107
+ }
51108
+ if (deltaX !== 0) {
51109
+ if (deltaX > 0) {
51110
+ await mouse.scrollRight(Math.abs(deltaX));
51111
+ } else {
51112
+ await mouse.scrollLeft(Math.abs(deltaX));
51113
+ }
51114
+ }
51115
+ }
51116
+ async getCursorPosition() {
51117
+ this.assertInitialized();
51118
+ const { mouse } = this._nut;
51119
+ const pos = await mouse.getPosition();
51120
+ return this.toPhysical(pos.x, pos.y);
51121
+ }
51122
+ // ===== Keyboard =====
51123
+ async keyboardType(text, delay) {
51124
+ this.assertInitialized();
51125
+ const { keyboard } = this._nut;
51126
+ const prevDelay = keyboard.config.autoDelayMs;
51127
+ if (delay !== void 0) {
51128
+ keyboard.config.autoDelayMs = delay;
51129
+ }
51130
+ try {
51131
+ await keyboard.type(text);
51132
+ } finally {
51133
+ if (delay !== void 0) {
51134
+ keyboard.config.autoDelayMs = prevDelay;
51135
+ }
51136
+ }
51137
+ }
51138
+ async keyboardKey(keys) {
51139
+ this.assertInitialized();
51140
+ const { keyboard, Key } = this._nut;
51141
+ const parsedKeys = parseKeyCombo(keys, Key);
51142
+ if (parsedKeys.length === 1) {
51143
+ await keyboard.pressKey(parsedKeys[0]);
51144
+ await keyboard.releaseKey(parsedKeys[0]);
51145
+ } else {
51146
+ for (const key of parsedKeys) {
51147
+ await keyboard.pressKey(key);
51148
+ }
51149
+ for (const key of [...parsedKeys].reverse()) {
51150
+ await keyboard.releaseKey(key);
51151
+ }
51152
+ }
51153
+ }
51154
+ // ===== Windows =====
51155
+ async getWindowList() {
51156
+ this.assertInitialized();
51157
+ const { getWindows } = this._nut;
51158
+ try {
51159
+ const windows = await getWindows();
51160
+ const result = [];
51161
+ this._windowCache.clear();
51162
+ for (const win of windows) {
51163
+ try {
51164
+ const handle = win.windowHandle;
51165
+ if (handle === void 0 || handle === null) continue;
51166
+ const title = await win.title;
51167
+ const region = await win.region;
51168
+ this._windowCache.set(handle, win);
51169
+ result.push({
51170
+ id: handle,
51171
+ title: title || "",
51172
+ bounds: region ? {
51173
+ x: Math.round(region.left * this._scaleFactor),
51174
+ y: Math.round(region.top * this._scaleFactor),
51175
+ width: Math.round(region.width * this._scaleFactor),
51176
+ height: Math.round(region.height * this._scaleFactor)
51177
+ } : void 0
51178
+ });
51179
+ } catch {
51180
+ }
51181
+ }
51182
+ return result;
51183
+ } catch {
51184
+ return [];
51185
+ }
51186
+ }
51187
+ async focusWindow(windowId) {
51188
+ this.assertInitialized();
51189
+ let target = this._windowCache.get(windowId);
51190
+ if (!target) {
51191
+ const { getWindows } = this._nut;
51192
+ const windows = await getWindows();
51193
+ target = windows.find((w) => w.windowHandle === windowId);
51194
+ }
51195
+ if (!target) {
51196
+ throw new Error(`Window with ID ${windowId} not found. Call desktop_window_list first to get current window IDs.`);
51197
+ }
51198
+ await target.focus();
51199
+ }
51200
+ };
51201
+
51202
+ // src/tools/desktop/getDriver.ts
51203
+ var defaultDriver = null;
51204
+ async function getDesktopDriver(config) {
51205
+ if (config?.driver) {
51206
+ if (!config.driver.isInitialized) {
51207
+ await config.driver.initialize();
51208
+ }
51209
+ return config.driver;
51210
+ }
51211
+ if (!defaultDriver) {
51212
+ defaultDriver = new NutTreeDriver();
51213
+ }
51214
+ if (!defaultDriver.isInitialized) {
51215
+ await defaultDriver.initialize();
51216
+ }
51217
+ return defaultDriver;
51218
+ }
51219
+ function resetDefaultDriver() {
51220
+ defaultDriver = null;
51221
+ }
51222
+
51223
+ // src/tools/desktop/screenshot.ts
51224
+ function createDesktopScreenshotTool(config) {
51225
+ return {
51226
+ definition: {
51227
+ type: "function",
51228
+ function: {
51229
+ name: "desktop_screenshot",
51230
+ description: `Take a screenshot of the entire screen or a specific region. Returns the screenshot image for visual analysis. Use this to see what's on screen before performing actions. IMPORTANT: If you capture a region, element positions in the image are relative to the region's top-left corner. To click an element at image position (ix, iy), you must use screen coordinates (ix + region.x, iy + region.y). Prefer full-screen screenshots to avoid coordinate offset errors.`,
51231
+ parameters: {
51232
+ type: "object",
51233
+ properties: {
51234
+ region: {
51235
+ type: "object",
51236
+ description: "Optional region to capture (in physical pixel coordinates). Omit to capture full screen.",
51237
+ properties: {
51238
+ x: { type: "number", description: "Left edge X coordinate" },
51239
+ y: { type: "number", description: "Top edge Y coordinate" },
51240
+ width: { type: "number", description: "Width in pixels" },
51241
+ height: { type: "number", description: "Height in pixels" }
51242
+ },
51243
+ required: ["x", "y", "width", "height"]
51244
+ }
51245
+ },
51246
+ required: []
51247
+ }
51248
+ }
51249
+ },
51250
+ describeCall: (args) => {
51251
+ if (args.region) {
51252
+ return `region (${args.region.x},${args.region.y}) ${args.region.width}x${args.region.height}`;
51253
+ }
51254
+ return "full screen";
51255
+ },
51256
+ execute: async (args) => {
51257
+ try {
51258
+ const driver = await getDesktopDriver(config);
51259
+ const screenshot = await driver.screenshot(args.region);
51260
+ return {
51261
+ success: true,
51262
+ width: screenshot.width,
51263
+ height: screenshot.height,
51264
+ base64: screenshot.base64,
51265
+ __images: [{ base64: screenshot.base64, mediaType: "image/png" }],
51266
+ // Include region info so the agent can compute screen coordinates:
51267
+ // screen_x = image_x + regionOffsetX, screen_y = image_y + regionOffsetY
51268
+ ...args.region ? { regionOffsetX: args.region.x, regionOffsetY: args.region.y } : {}
51269
+ };
51270
+ } catch (err) {
51271
+ return { success: false, error: err.message };
51272
+ }
51273
+ }
51274
+ };
51275
+ }
51276
+ var desktopScreenshot = createDesktopScreenshotTool();
51277
+
51278
+ // src/tools/desktop/mouseMove.ts
51279
+ function createDesktopMouseMoveTool(config) {
51280
+ return {
51281
+ definition: {
51282
+ type: "function",
51283
+ function: {
51284
+ name: "desktop_mouse_move",
51285
+ description: `Move the mouse cursor to the specified (x, y) position. Coordinates are in screenshot pixel space (full screen). Returns the actual cursor position after the move for verification.`,
51286
+ parameters: {
51287
+ type: "object",
51288
+ properties: {
51289
+ x: { type: "number", description: "X coordinate (in screenshot pixels)" },
51290
+ y: { type: "number", description: "Y coordinate (in screenshot pixels)" }
51291
+ },
51292
+ required: ["x", "y"]
51293
+ }
51294
+ }
51295
+ },
51296
+ describeCall: (args) => `(${args.x}, ${args.y})`,
51297
+ execute: async (args) => {
51298
+ try {
51299
+ const driver = await getDesktopDriver(config);
51300
+ await driver.mouseMove(args.x, args.y);
51301
+ await applyHumanDelay(config ?? {});
51302
+ const actual = await driver.getCursorPosition();
51303
+ return { success: true, x: actual.x, y: actual.y };
51304
+ } catch (err) {
51305
+ return { success: false, error: err.message };
51306
+ }
51307
+ }
51308
+ };
51309
+ }
51310
+ var desktopMouseMove = createDesktopMouseMoveTool();
51311
+
51312
+ // src/tools/desktop/mouseClick.ts
51313
+ function createDesktopMouseClickTool(config) {
51314
+ return {
51315
+ definition: {
51316
+ type: "function",
51317
+ function: {
51318
+ name: "desktop_mouse_click",
51319
+ description: `Click the mouse at the specified position or at the current cursor position. Supports left/right/middle button and single/double/triple click.`,
51320
+ parameters: {
51321
+ type: "object",
51322
+ properties: {
51323
+ x: { type: "number", description: "X coordinate to click (in screenshot pixels). Omit to click at current position." },
51324
+ y: { type: "number", description: "Y coordinate to click (in screenshot pixels). Omit to click at current position." },
51325
+ button: {
51326
+ type: "string",
51327
+ enum: ["left", "right", "middle"],
51328
+ description: 'Mouse button to click. Default: "left"'
51329
+ },
51330
+ clickCount: {
51331
+ type: "number",
51332
+ description: "Number of clicks (1=single, 2=double, 3=triple). Default: 1"
51333
+ }
51334
+ },
51335
+ required: []
51336
+ }
51337
+ }
51338
+ },
51339
+ describeCall: (args) => {
51340
+ const pos = args.x !== void 0 ? `(${args.x}, ${args.y})` : "current position";
51341
+ const btn = args.button && args.button !== "left" ? ` ${args.button}` : "";
51342
+ const count = args.clickCount && args.clickCount > 1 ? ` x${args.clickCount}` : "";
51343
+ return `${pos}${btn}${count}`;
51344
+ },
51345
+ execute: async (args) => {
51346
+ try {
51347
+ const driver = await getDesktopDriver(config);
51348
+ const button = args.button ?? "left";
51349
+ const clickCount = args.clickCount ?? 1;
51350
+ if (args.x !== void 0 && args.y !== void 0) {
51351
+ await driver.mouseClick(args.x, args.y, button, clickCount);
51352
+ } else {
51353
+ const pos = await driver.getCursorPosition();
51354
+ await driver.mouseClick(pos.x, pos.y, button, clickCount);
51355
+ }
51356
+ await applyHumanDelay(config ?? {});
51357
+ const actual = await driver.getCursorPosition();
51358
+ return { success: true, x: actual.x, y: actual.y, button, clickCount };
51359
+ } catch (err) {
51360
+ return { success: false, error: err.message };
51361
+ }
51362
+ }
51363
+ };
51364
+ }
51365
+ var desktopMouseClick = createDesktopMouseClickTool();
51366
+
51367
+ // src/tools/desktop/mouseDrag.ts
51368
+ function createDesktopMouseDragTool(config) {
51369
+ return {
51370
+ definition: {
51371
+ type: "function",
51372
+ function: {
51373
+ name: "desktop_mouse_drag",
51374
+ description: `Drag the mouse from one position to another. Presses the button at the start position, moves to the end position, then releases.`,
51375
+ parameters: {
51376
+ type: "object",
51377
+ properties: {
51378
+ startX: { type: "number", description: "Start X coordinate (in screenshot pixels)" },
51379
+ startY: { type: "number", description: "Start Y coordinate (in screenshot pixels)" },
51380
+ endX: { type: "number", description: "End X coordinate (in screenshot pixels)" },
51381
+ endY: { type: "number", description: "End Y coordinate (in screenshot pixels)" },
51382
+ button: {
51383
+ type: "string",
51384
+ enum: ["left", "right", "middle"],
51385
+ description: 'Mouse button to use for dragging. Default: "left"'
51386
+ }
51387
+ },
51388
+ required: ["startX", "startY", "endX", "endY"]
51389
+ }
51390
+ }
51391
+ },
51392
+ describeCall: (args) => `(${args.startX},${args.startY}) \u2192 (${args.endX},${args.endY})`,
51393
+ execute: async (args) => {
51394
+ try {
51395
+ const driver = await getDesktopDriver(config);
51396
+ await driver.mouseDrag(args.startX, args.startY, args.endX, args.endY, args.button ?? "left");
51397
+ await applyHumanDelay(config ?? {});
51398
+ return { success: true };
51399
+ } catch (err) {
51400
+ return { success: false, error: err.message };
51401
+ }
51402
+ }
51403
+ };
51404
+ }
51405
+ var desktopMouseDrag = createDesktopMouseDragTool();
51406
+
51407
+ // src/tools/desktop/mouseScroll.ts
51408
+ function createDesktopMouseScrollTool(config) {
51409
+ return {
51410
+ definition: {
51411
+ type: "function",
51412
+ function: {
51413
+ name: "desktop_mouse_scroll",
51414
+ description: `Scroll the mouse wheel. Positive deltaY scrolls down, negative scrolls up. Positive deltaX scrolls right, negative scrolls left. Optionally specify position to scroll at.`,
51415
+ parameters: {
51416
+ type: "object",
51417
+ properties: {
51418
+ deltaX: { type: "number", description: "Horizontal scroll amount. Positive=right, negative=left. Default: 0" },
51419
+ deltaY: { type: "number", description: "Vertical scroll amount. Positive=down, negative=up. Default: 0" },
51420
+ x: { type: "number", description: "X coordinate to scroll at (in screenshot pixels). Omit to scroll at current position." },
51421
+ y: { type: "number", description: "Y coordinate to scroll at (in screenshot pixels). Omit to scroll at current position." }
51422
+ },
51423
+ required: []
51424
+ }
51425
+ }
51426
+ },
51427
+ describeCall: (args) => {
51428
+ const parts = [];
51429
+ if (args.deltaY) parts.push(args.deltaY > 0 ? `down ${args.deltaY}` : `up ${Math.abs(args.deltaY)}`);
51430
+ if (args.deltaX) parts.push(args.deltaX > 0 ? `right ${args.deltaX}` : `left ${Math.abs(args.deltaX)}`);
51431
+ if (args.x !== void 0) parts.push(`at (${args.x},${args.y})`);
51432
+ return parts.join(", ") || "no-op";
51433
+ },
51434
+ execute: async (args) => {
51435
+ try {
51436
+ const driver = await getDesktopDriver(config);
51437
+ await driver.mouseScroll(args.deltaX ?? 0, args.deltaY ?? 0, args.x, args.y);
51438
+ await applyHumanDelay(config ?? {});
51439
+ return { success: true };
51440
+ } catch (err) {
51441
+ return { success: false, error: err.message };
51442
+ }
51443
+ }
51444
+ };
51445
+ }
51446
+ var desktopMouseScroll = createDesktopMouseScrollTool();
51447
+
51448
+ // src/tools/desktop/getCursor.ts
51449
+ function createDesktopGetCursorTool(config) {
51450
+ return {
51451
+ definition: {
51452
+ type: "function",
51453
+ function: {
51454
+ name: "desktop_get_cursor",
51455
+ description: `Get the current mouse cursor position in screenshot pixel coordinates.`,
51456
+ parameters: {
51457
+ type: "object",
51458
+ properties: {},
51459
+ required: []
51460
+ }
51461
+ }
51462
+ },
51463
+ describeCall: () => "get cursor position",
51464
+ execute: async () => {
51465
+ try {
51466
+ const driver = await getDesktopDriver(config);
51467
+ const pos = await driver.getCursorPosition();
51468
+ return { success: true, x: pos.x, y: pos.y };
51469
+ } catch (err) {
51470
+ return { success: false, error: err.message };
51471
+ }
51472
+ }
51473
+ };
51474
+ }
51475
+ var desktopGetCursor = createDesktopGetCursorTool();
51476
+
51477
+ // src/tools/desktop/keyboardType.ts
51478
+ function createDesktopKeyboardTypeTool(config) {
51479
+ return {
51480
+ definition: {
51481
+ type: "function",
51482
+ function: {
51483
+ name: "desktop_keyboard_type",
51484
+ description: `Type text using the keyboard. Each character is typed as a keypress. Use this for entering text into focused input fields.`,
51485
+ parameters: {
51486
+ type: "object",
51487
+ properties: {
51488
+ text: { type: "string", description: "The text to type" },
51489
+ delay: { type: "number", description: "Delay in ms between each keystroke. Default: uses system default." }
51490
+ },
51491
+ required: ["text"]
51492
+ }
51493
+ }
51494
+ },
51495
+ describeCall: (args) => {
51496
+ const preview = args.text.length > 30 ? args.text.slice(0, 27) + "..." : args.text;
51497
+ return `"${preview}"`;
51498
+ },
51499
+ execute: async (args) => {
51500
+ try {
51501
+ const driver = await getDesktopDriver(config);
51502
+ await driver.keyboardType(args.text, args.delay);
51503
+ await applyHumanDelay(config ?? {});
51504
+ return { success: true };
51505
+ } catch (err) {
51506
+ return { success: false, error: err.message };
51507
+ }
51508
+ }
51509
+ };
51510
+ }
51511
+ var desktopKeyboardType = createDesktopKeyboardTypeTool();
51512
+
51513
+ // src/tools/desktop/keyboardKey.ts
51514
+ function createDesktopKeyboardKeyTool(config) {
51515
+ return {
51516
+ definition: {
51517
+ type: "function",
51518
+ function: {
51519
+ name: "desktop_keyboard_key",
51520
+ description: `Press a keyboard shortcut or special key. Use "+" to combine keys (e.g., "ctrl+c", "cmd+shift+s", "enter", "tab", "escape"). Modifiers: ctrl, cmd/command, alt/option, shift. Special keys: enter, tab, escape, backspace, delete, space, up, down, left, right, f1-f12, home, end, pageup, pagedown.`,
51521
+ parameters: {
51522
+ type: "object",
51523
+ properties: {
51524
+ keys: {
51525
+ type: "string",
51526
+ description: 'Key combo string (e.g., "ctrl+c", "enter", "cmd+shift+s")'
51527
+ }
51528
+ },
51529
+ required: ["keys"]
51530
+ }
51531
+ }
51532
+ },
51533
+ describeCall: (args) => args.keys,
51534
+ execute: async (args) => {
51535
+ try {
51536
+ const driver = await getDesktopDriver(config);
51537
+ await driver.keyboardKey(args.keys);
51538
+ await applyHumanDelay(config ?? {});
51539
+ return { success: true };
51540
+ } catch (err) {
51541
+ return { success: false, error: err.message };
51542
+ }
51543
+ }
51544
+ };
51545
+ }
51546
+ var desktopKeyboardKey = createDesktopKeyboardKeyTool();
51547
+
51548
+ // src/tools/desktop/getScreenSize.ts
51549
+ function createDesktopGetScreenSizeTool(config) {
51550
+ return {
51551
+ definition: {
51552
+ type: "function",
51553
+ function: {
51554
+ name: "desktop_get_screen_size",
51555
+ description: `Get the screen dimensions. Returns physical pixel size (screenshot space), logical size (OS coordinates), and the scale factor (e.g., 2.0 on Retina displays). All desktop tool coordinates use physical pixel space.`,
51556
+ parameters: {
51557
+ type: "object",
51558
+ properties: {},
51559
+ required: []
51560
+ }
51561
+ }
51562
+ },
51563
+ describeCall: () => "get screen size",
51564
+ execute: async () => {
51565
+ try {
51566
+ const driver = await getDesktopDriver(config);
51567
+ const size = await driver.getScreenSize();
51568
+ return {
51569
+ success: true,
51570
+ physicalWidth: size.physicalWidth,
51571
+ physicalHeight: size.physicalHeight,
51572
+ logicalWidth: size.logicalWidth,
51573
+ logicalHeight: size.logicalHeight,
51574
+ scaleFactor: size.scaleFactor
51575
+ };
51576
+ } catch (err) {
51577
+ return { success: false, error: err.message };
51578
+ }
51579
+ }
51580
+ };
51581
+ }
51582
+ var desktopGetScreenSize = createDesktopGetScreenSizeTool();
51583
+
51584
+ // src/tools/desktop/windowList.ts
51585
+ function createDesktopWindowListTool(config) {
51586
+ return {
51587
+ definition: {
51588
+ type: "function",
51589
+ function: {
51590
+ name: "desktop_window_list",
51591
+ description: `List all visible windows on the desktop. Returns window IDs, titles, application names, and bounds. Use the window ID with desktop_window_focus to bring a window to the foreground.`,
51592
+ parameters: {
51593
+ type: "object",
51594
+ properties: {},
51595
+ required: []
51596
+ }
51597
+ }
51598
+ },
51599
+ describeCall: () => "list windows",
51600
+ execute: async () => {
51601
+ try {
51602
+ const driver = await getDesktopDriver(config);
51603
+ const windows = await driver.getWindowList();
51604
+ return { success: true, windows };
51605
+ } catch (err) {
51606
+ return { success: false, error: err.message };
51607
+ }
51608
+ }
51609
+ };
51610
+ }
51611
+ var desktopWindowList = createDesktopWindowListTool();
51612
+
51613
+ // src/tools/desktop/windowFocus.ts
51614
+ function createDesktopWindowFocusTool(config) {
51615
+ return {
51616
+ definition: {
51617
+ type: "function",
51618
+ function: {
51619
+ name: "desktop_window_focus",
51620
+ description: `Focus (bring to front) a window by its ID. Use desktop_window_list to get available window IDs.`,
51621
+ parameters: {
51622
+ type: "object",
51623
+ properties: {
51624
+ windowId: {
51625
+ type: "number",
51626
+ description: "The window ID from desktop_window_list"
51627
+ }
51628
+ },
51629
+ required: ["windowId"]
51630
+ }
51631
+ }
51632
+ },
51633
+ describeCall: (args) => `window ${args.windowId}`,
51634
+ execute: async (args) => {
51635
+ try {
51636
+ const driver = await getDesktopDriver(config);
51637
+ await driver.focusWindow(args.windowId);
51638
+ return { success: true };
51639
+ } catch (err) {
51640
+ return { success: false, error: err.message };
51641
+ }
51642
+ }
51643
+ };
51644
+ }
51645
+ var desktopWindowFocus = createDesktopWindowFocusTool();
51646
+
51647
+ // src/tools/desktop/index.ts
51648
+ var desktopTools = [
51649
+ desktopScreenshot,
51650
+ desktopMouseMove,
51651
+ desktopMouseClick,
51652
+ desktopMouseDrag,
51653
+ desktopMouseScroll,
51654
+ desktopGetCursor,
51655
+ desktopKeyboardType,
51656
+ desktopKeyboardKey,
51657
+ desktopGetScreenSize,
51658
+ desktopWindowList,
51659
+ desktopWindowFocus
51660
+ ];
51661
+
49552
51662
  // src/tools/registry.generated.ts
49553
51663
  var toolRegistry = [
49554
51664
  {
@@ -49560,6 +51670,105 @@ var toolRegistry = [
49560
51670
  tool: executeJavaScript,
49561
51671
  safeByDefault: false
49562
51672
  },
51673
+ {
51674
+ name: "desktop_get_cursor",
51675
+ exportName: "desktopGetCursor",
51676
+ displayName: "Desktop Get Cursor",
51677
+ category: "desktop",
51678
+ description: "Get the current mouse cursor position in screenshot pixel coordinates.",
51679
+ tool: desktopGetCursor,
51680
+ safeByDefault: false
51681
+ },
51682
+ {
51683
+ name: "desktop_get_screen_size",
51684
+ exportName: "desktopGetScreenSize",
51685
+ displayName: "Desktop Get Screen Size",
51686
+ category: "desktop",
51687
+ description: "Get the screen dimensions. Returns physical pixel size (screenshot space), logical size (OS coordinates), and the scale factor (e.g., 2.0 on Retina displays). All desktop tool coordinates use physical",
51688
+ tool: desktopGetScreenSize,
51689
+ safeByDefault: false
51690
+ },
51691
+ {
51692
+ name: "desktop_keyboard_key",
51693
+ exportName: "desktopKeyboardKey",
51694
+ displayName: "Desktop Keyboard Key",
51695
+ category: "desktop",
51696
+ description: 'Press a keyboard shortcut or special key. Use "+" to combine keys (e.g., "ctrl+c", "cmd+shift+s", "enter", "tab", "escape"). Modifiers: ctrl, cmd/command, alt/option, shift. Special keys: enter, tab, ',
51697
+ tool: desktopKeyboardKey,
51698
+ safeByDefault: false
51699
+ },
51700
+ {
51701
+ name: "desktop_keyboard_type",
51702
+ exportName: "desktopKeyboardType",
51703
+ displayName: "Desktop Keyboard Type",
51704
+ category: "desktop",
51705
+ description: "Type text using the keyboard. Each character is typed as a keypress. Use this for entering text into focused input fields.",
51706
+ tool: desktopKeyboardType,
51707
+ safeByDefault: false
51708
+ },
51709
+ {
51710
+ name: "desktop_mouse_click",
51711
+ exportName: "desktopMouseClick",
51712
+ displayName: "Desktop Mouse Click",
51713
+ category: "desktop",
51714
+ description: "Click the mouse at the specified position or at the current cursor position. Supports left/right/middle button and single/double/triple click.",
51715
+ tool: desktopMouseClick,
51716
+ safeByDefault: false
51717
+ },
51718
+ {
51719
+ name: "desktop_mouse_drag",
51720
+ exportName: "desktopMouseDrag",
51721
+ displayName: "Desktop Mouse Drag",
51722
+ category: "desktop",
51723
+ description: "Drag the mouse from one position to another. Presses the button at the start position, moves to the end position, then releases.",
51724
+ tool: desktopMouseDrag,
51725
+ safeByDefault: false
51726
+ },
51727
+ {
51728
+ name: "desktop_mouse_move",
51729
+ exportName: "desktopMouseMove",
51730
+ displayName: "Desktop Mouse Move",
51731
+ category: "desktop",
51732
+ description: "Move the mouse cursor to the specified (x, y) position. Coordinates are in screenshot pixel space (full screen). Returns the actual cursor position after the move for verification.",
51733
+ tool: desktopMouseMove,
51734
+ safeByDefault: false
51735
+ },
51736
+ {
51737
+ name: "desktop_mouse_scroll",
51738
+ exportName: "desktopMouseScroll",
51739
+ displayName: "Desktop Mouse Scroll",
51740
+ category: "desktop",
51741
+ description: "Scroll the mouse wheel. Positive deltaY scrolls down, negative scrolls up. Positive deltaX scrolls right, negative scrolls left. Optionally specify position to scroll at.",
51742
+ tool: desktopMouseScroll,
51743
+ safeByDefault: false
51744
+ },
51745
+ {
51746
+ name: "desktop_screenshot",
51747
+ exportName: "desktopScreenshot",
51748
+ displayName: "Desktop Screenshot",
51749
+ category: "desktop",
51750
+ description: "Take a screenshot of the entire screen or a specific region. Returns the screenshot image for visual analysis. Use this to see what's on screen before performing actions. IMPORTANT: If you capture a r",
51751
+ tool: desktopScreenshot,
51752
+ safeByDefault: false
51753
+ },
51754
+ {
51755
+ name: "desktop_window_focus",
51756
+ exportName: "desktopWindowFocus",
51757
+ displayName: "Desktop Window Focus",
51758
+ category: "desktop",
51759
+ description: "Focus (bring to front) a window by its ID. Use desktop_window_list to get available window IDs.",
51760
+ tool: desktopWindowFocus,
51761
+ safeByDefault: false
51762
+ },
51763
+ {
51764
+ name: "desktop_window_list",
51765
+ exportName: "desktopWindowList",
51766
+ displayName: "Desktop Window List",
51767
+ category: "desktop",
51768
+ description: "List all visible windows on the desktop. Returns window IDs, titles, application names, and bounds. Use the window ID with desktop_window_focus to bring a window to the foreground.",
51769
+ tool: desktopWindowList,
51770
+ safeByDefault: false
51771
+ },
49563
51772
  {
49564
51773
  name: "edit_file",
49565
51774
  exportName: "editFile",
@@ -49601,7 +51810,7 @@ var toolRegistry = [
49601
51810
  exportName: "readFile",
49602
51811
  displayName: "Read File",
49603
51812
  category: "filesystem",
49604
- description: "Read content from a file on the local filesystem.",
51813
+ description: "Read content from a file on the local filesystem. Supports text files AND binary document formats \u2014 PDF, DOCX, PPTX, XLSX, ODS, ODT, ODP, and images (PNG, JPG, GIF, WEBP) are automatically converted t",
49605
51814
  tool: readFile5,
49606
51815
  safeByDefault: true
49607
51816
  },
@@ -49637,7 +51846,7 @@ var toolRegistry = [
49637
51846
  exportName: "webFetch",
49638
51847
  displayName: "Web Fetch",
49639
51848
  category: "web",
49640
- description: "Fetch and extract text content from a web page URL.",
51849
+ description: "Fetch and extract content from a URL \u2014 works with web pages AND document files (PDF, DOCX, XLSX, PPTX, etc.). Document URLs are automatically detected and converted to markdown text.",
49641
51850
  tool: webFetch,
49642
51851
  safeByDefault: true
49643
51852
  }
@@ -49997,6 +52206,6 @@ REMEMBER: Keep it conversational, ask one question at a time, and only output th
49997
52206
  }
49998
52207
  };
49999
52208
 
50000
- export { AGENT_DEFINITION_FORMAT_VERSION, AIError, APPROVAL_STATE_VERSION, Agent, AgentContextNextGen, ApproximateTokenEstimator, BaseMediaProvider, BasePluginNextGen, BaseProvider, BaseTextProvider, BraveProvider, CONNECTOR_CONFIG_VERSION, CONTEXT_SESSION_FORMAT_VERSION, CheckpointManager, CircuitBreaker, CircuitOpenError, Connector, ConnectorConfigStore, ConnectorTools, ConsoleMetrics, ContentType, ContextOverflowError, DEFAULT_ALLOWLIST, DEFAULT_BACKOFF_CONFIG, DEFAULT_BASE_DELAY_MS, DEFAULT_CHECKPOINT_STRATEGY, DEFAULT_CIRCUIT_BREAKER_CONFIG, DEFAULT_CONFIG2 as DEFAULT_CONFIG, DEFAULT_CONNECTOR_TIMEOUT, DEFAULT_CONTEXT_CONFIG, DEFAULT_FEATURES, DEFAULT_FILESYSTEM_CONFIG, DEFAULT_HISTORY_MANAGER_CONFIG, DEFAULT_MAX_DELAY_MS, DEFAULT_MAX_RETRIES, DEFAULT_MEMORY_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_RATE_LIMITER_CONFIG, DEFAULT_RETRYABLE_STATUSES, DEFAULT_SHELL_CONFIG, DefaultCompactionStrategy, DependencyCycleError, ErrorHandler, ExecutionContext, ExternalDependencyHandler, FileAgentDefinitionStorage, FileConnectorStorage, FileContextStorage, FileMediaStorage as FileMediaOutputHandler, FileMediaStorage, FilePersistentInstructionsStorage, FileStorage, FrameworkLogger, HookManager, IMAGE_MODELS, IMAGE_MODEL_REGISTRY, ImageGeneration, InContextMemoryPluginNextGen, InMemoryAgentStateStorage, InMemoryHistoryStorage, InMemoryMetrics, InMemoryPlanStorage, InMemoryStorage, InvalidConfigError, InvalidToolArgumentsError, LLM_MODELS, LoggingPlugin, MCPClient, MCPConnectionError, MCPError, MCPProtocolError, MCPRegistry, MCPResourceError, MCPTimeoutError, MCPToolError, MEMORY_PRIORITY_VALUES, MODEL_REGISTRY, MemoryConnectorStorage, MemoryEvictionCompactor, MemoryStorage, MessageBuilder, MessageRole, ModelNotSupportedError, NoOpMetrics, OAuthManager, ParallelTasksError, PersistentInstructionsPluginNextGen, PlanningAgent, ProviderAuthError, ProviderConfigAgent, ProviderContextLengthError, ProviderError, ProviderErrorMapper, ProviderNotFoundError, ProviderRateLimitError, RapidAPIProvider, RateLimitError, SERVICE_DEFINITIONS, SERVICE_INFO, SERVICE_URL_PATTERNS, SIMPLE_ICONS_CDN, STT_MODELS, STT_MODEL_REGISTRY, ScopedConnectorRegistry, ScrapeProvider, SearchProvider, SerperProvider, Services, SpeechToText, StrategyRegistry, StreamEventType, StreamHelpers, StreamState, SummarizeCompactor, TERMINAL_TASK_STATUSES, TTS_MODELS, TTS_MODEL_REGISTRY, TaskTimeoutError, TaskValidationError, TavilyProvider, TextToSpeech, TokenBucketRateLimiter, ToolCallState, ToolExecutionError, ToolExecutionPipeline, ToolManager, ToolNotFoundError, ToolPermissionManager, ToolRegistry, ToolTimeoutError, TruncateCompactor, VENDORS, VENDOR_ICON_MAP, VIDEO_MODELS, VIDEO_MODEL_REGISTRY, Vendor, VideoGeneration, WorkingMemory, WorkingMemoryPluginNextGen, addJitter, allVendorTemplates, assertNotDestroyed, authenticatedFetch, backoffSequence, backoffWait, bash, buildAuthConfig, buildEndpointWithQuery, buildQueryString, calculateBackoff, calculateCost, calculateEntrySize, calculateImageCost, calculateSTTCost, calculateTTSCost, calculateVideoCost, canTaskExecute, createAgentStorage, createAuthenticatedFetch, createBashTool, createConnectorFromTemplate, createCreatePRTool, createEditFileTool, createEstimator, createExecuteJavaScriptTool, createFileAgentDefinitionStorage, createFileContextStorage, createFileMediaStorage, createGetPRTool, createGitHubReadFileTool, createGlobTool, createGrepTool, createImageGenerationTool, createImageProvider, createListDirectoryTool, createMessageWithImages, createMetricsCollector, createPRCommentsTool, createPRFilesTool, createPlan, createProvider, createReadFileTool, createSearchCodeTool, createSearchFilesTool, createSpeechToTextTool, createTask, createTextMessage, createTextToSpeechTool, createVideoProvider, createVideoTools, createWriteFileTool, defaultDescribeCall, detectDependencyCycle, detectServiceFromURL, developerTools, editFile, evaluateCondition, extractJSON, extractJSONField, extractNumber, findConnectorByServiceTypes, forPlan, forTasks, generateEncryptionKey, generateSimplePlan, generateWebAPITool, getActiveImageModels, getActiveModels, getActiveSTTModels, getActiveTTSModels, getActiveVideoModels, getAllBuiltInTools, getAllServiceIds, getAllVendorLogos, getAllVendorTemplates, getBackgroundOutput, getConnectorTools, getCredentialsSetupURL, getDocsURL, getImageModelInfo, getImageModelsByVendor, getImageModelsWithFeature, getMediaOutputHandler, getMediaStorage, getModelInfo, getModelsByVendor, getNextExecutableTasks, getRegisteredScrapeProviders, getSTTModelInfo, getSTTModelsByVendor, getSTTModelsWithFeature, getServiceDefinition, getServiceInfo, getServicesByCategory, getTTSModelInfo, getTTSModelsByVendor, getTTSModelsWithFeature, getTaskDependencies, getToolByName, getToolCallDescription, getToolCategories, getToolRegistry, getToolsByCategory, getToolsRequiringConnector, getVendorAuthTemplate, getVendorColor, getVendorDefaultBaseURL, getVendorInfo, getVendorLogo, getVendorLogoCdnUrl, getVendorLogoSvg, getVendorTemplate, getVideoModelInfo, getVideoModelsByVendor, getVideoModelsWithAudio, getVideoModelsWithFeature, glob, globalErrorHandler, grep, hasClipboardImage, hasVendorLogo, isBlockedCommand, isErrorEvent, isExcludedExtension, isKnownService, isOutputTextDelta, isResponseComplete, isSimpleScope, isStreamEvent, isTaskAwareScope, isTaskBlocked, isTerminalMemoryStatus, isTerminalStatus, isToolCallArgumentsDelta, isToolCallArgumentsDone, isToolCallStart, isVendor, killBackgroundProcess, listConnectorsByServiceTypes, listDirectory, listVendorIds, listVendors, listVendorsByAuthType, listVendorsByCategory, listVendorsWithLogos, logger, metrics, parseRepository, readClipboardImage, readFile5 as readFile, registerScrapeProvider, resolveConnector, resolveDependencies, resolveRepository, retryWithBackoff, scopeEquals, scopeMatches, setMediaOutputHandler, setMediaStorage, setMetricsCollector, simpleTokenEstimator, toConnectorOptions, toolRegistry, tools_exports as tools, updateTaskStatus, validatePath, writeFile5 as writeFile };
52209
+ export { AGENT_DEFINITION_FORMAT_VERSION, AIError, APPROVAL_STATE_VERSION, Agent, AgentContextNextGen, ApproximateTokenEstimator, BaseMediaProvider, BasePluginNextGen, BaseProvider, BaseTextProvider, BraveProvider, CONNECTOR_CONFIG_VERSION, CONTEXT_SESSION_FORMAT_VERSION, CheckpointManager, CircuitBreaker, CircuitOpenError, Connector, ConnectorConfigStore, ConnectorTools, ConsoleMetrics, ContentType, ContextOverflowError, DEFAULT_ALLOWLIST, DEFAULT_BACKOFF_CONFIG, DEFAULT_BASE_DELAY_MS, DEFAULT_CHECKPOINT_STRATEGY, DEFAULT_CIRCUIT_BREAKER_CONFIG, DEFAULT_CONFIG2 as DEFAULT_CONFIG, DEFAULT_CONNECTOR_TIMEOUT, DEFAULT_CONTEXT_CONFIG, DEFAULT_DESKTOP_CONFIG, DEFAULT_FEATURES, DEFAULT_FILESYSTEM_CONFIG, DEFAULT_HISTORY_MANAGER_CONFIG, DEFAULT_MAX_DELAY_MS, DEFAULT_MAX_RETRIES, DEFAULT_MEMORY_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_RATE_LIMITER_CONFIG, DEFAULT_RETRYABLE_STATUSES, DEFAULT_SHELL_CONFIG, DESKTOP_TOOL_NAMES, DefaultCompactionStrategy, DependencyCycleError, DocumentReader, ErrorHandler, ExecutionContext, ExternalDependencyHandler, FileAgentDefinitionStorage, FileConnectorStorage, FileContextStorage, FileMediaStorage as FileMediaOutputHandler, FileMediaStorage, FilePersistentInstructionsStorage, FileStorage, FormatDetector, FrameworkLogger, HookManager, IMAGE_MODELS, IMAGE_MODEL_REGISTRY, ImageGeneration, InContextMemoryPluginNextGen, InMemoryAgentStateStorage, InMemoryHistoryStorage, InMemoryMetrics, InMemoryPlanStorage, InMemoryStorage, InvalidConfigError, InvalidToolArgumentsError, LLM_MODELS, LoggingPlugin, MCPClient, MCPConnectionError, MCPError, MCPProtocolError, MCPRegistry, MCPResourceError, MCPTimeoutError, MCPToolError, MEMORY_PRIORITY_VALUES, MODEL_REGISTRY, MemoryConnectorStorage, MemoryEvictionCompactor, MemoryStorage, MessageBuilder, MessageRole, ModelNotSupportedError, NoOpMetrics, NutTreeDriver, OAuthManager, ParallelTasksError, PersistentInstructionsPluginNextGen, PlanningAgent, ProviderAuthError, ProviderConfigAgent, ProviderContextLengthError, ProviderError, ProviderErrorMapper, ProviderNotFoundError, ProviderRateLimitError, RapidAPIProvider, RateLimitError, SERVICE_DEFINITIONS, SERVICE_INFO, SERVICE_URL_PATTERNS, SIMPLE_ICONS_CDN, STT_MODELS, STT_MODEL_REGISTRY, ScopedConnectorRegistry, ScrapeProvider, SearchProvider, SerperProvider, Services, SpeechToText, StrategyRegistry, StreamEventType, StreamHelpers, StreamState, SummarizeCompactor, TERMINAL_TASK_STATUSES, TTS_MODELS, TTS_MODEL_REGISTRY, TaskTimeoutError, TaskValidationError, TavilyProvider, TextToSpeech, TokenBucketRateLimiter, ToolCallState, ToolExecutionError, ToolExecutionPipeline, ToolManager, ToolNotFoundError, ToolPermissionManager, ToolRegistry, ToolTimeoutError, TruncateCompactor, VENDORS, VENDOR_ICON_MAP, VIDEO_MODELS, VIDEO_MODEL_REGISTRY, Vendor, VideoGeneration, WorkingMemory, WorkingMemoryPluginNextGen, addJitter, allVendorTemplates, assertNotDestroyed, authenticatedFetch, backoffSequence, backoffWait, bash, buildAuthConfig, buildEndpointWithQuery, buildQueryString, calculateBackoff, calculateCost, calculateEntrySize, calculateImageCost, calculateSTTCost, calculateTTSCost, calculateVideoCost, canTaskExecute, createAgentStorage, createAuthenticatedFetch, createBashTool, createConnectorFromTemplate, createCreatePRTool, createDesktopGetCursorTool, createDesktopGetScreenSizeTool, createDesktopKeyboardKeyTool, createDesktopKeyboardTypeTool, createDesktopMouseClickTool, createDesktopMouseDragTool, createDesktopMouseMoveTool, createDesktopMouseScrollTool, createDesktopScreenshotTool, createDesktopWindowFocusTool, createDesktopWindowListTool, createEditFileTool, createEstimator, createExecuteJavaScriptTool, createFileAgentDefinitionStorage, createFileContextStorage, createFileMediaStorage, createGetPRTool, createGitHubReadFileTool, createGlobTool, createGrepTool, createImageGenerationTool, createImageProvider, createListDirectoryTool, createMessageWithImages, createMetricsCollector, createPRCommentsTool, createPRFilesTool, createPlan, createProvider, createReadFileTool, createSearchCodeTool, createSearchFilesTool, createSpeechToTextTool, createTask, createTextMessage, createTextToSpeechTool, createVideoProvider, createVideoTools, createWriteFileTool, defaultDescribeCall, desktopGetCursor, desktopGetScreenSize, desktopKeyboardKey, desktopKeyboardType, desktopMouseClick, desktopMouseDrag, desktopMouseMove, desktopMouseScroll, desktopScreenshot, desktopTools, desktopWindowFocus, desktopWindowList, detectDependencyCycle, detectServiceFromURL, developerTools, documentToContent, editFile, evaluateCondition, extractJSON, extractJSONField, extractNumber, findConnectorByServiceTypes, forPlan, forTasks, generateEncryptionKey, generateSimplePlan, generateWebAPITool, getActiveImageModels, getActiveModels, getActiveSTTModels, getActiveTTSModels, getActiveVideoModels, getAllBuiltInTools, getAllServiceIds, getAllVendorLogos, getAllVendorTemplates, getBackgroundOutput, getConnectorTools, getCredentialsSetupURL, getDesktopDriver, getDocsURL, getImageModelInfo, getImageModelsByVendor, getImageModelsWithFeature, getMediaOutputHandler, getMediaStorage, getModelInfo, getModelsByVendor, getNextExecutableTasks, getRegisteredScrapeProviders, getSTTModelInfo, getSTTModelsByVendor, getSTTModelsWithFeature, getServiceDefinition, getServiceInfo, getServicesByCategory, getTTSModelInfo, getTTSModelsByVendor, getTTSModelsWithFeature, getTaskDependencies, getToolByName, getToolCallDescription, getToolCategories, getToolRegistry, getToolsByCategory, getToolsRequiringConnector, getVendorAuthTemplate, getVendorColor, getVendorDefaultBaseURL, getVendorInfo, getVendorLogo, getVendorLogoCdnUrl, getVendorLogoSvg, getVendorTemplate, getVideoModelInfo, getVideoModelsByVendor, getVideoModelsWithAudio, getVideoModelsWithFeature, glob, globalErrorHandler, grep, hasClipboardImage, hasVendorLogo, isBlockedCommand, isErrorEvent, isExcludedExtension, isKnownService, isOutputTextDelta, isResponseComplete, isSimpleScope, isStreamEvent, isTaskAwareScope, isTaskBlocked, isTerminalMemoryStatus, isTerminalStatus, isToolCallArgumentsDelta, isToolCallArgumentsDone, isToolCallStart, isVendor, killBackgroundProcess, listConnectorsByServiceTypes, listDirectory, listVendorIds, listVendors, listVendorsByAuthType, listVendorsByCategory, listVendorsWithLogos, logger, mergeTextPieces, metrics, parseKeyCombo, parseRepository, readClipboardImage, readDocumentAsContent, readFile5 as readFile, registerScrapeProvider, resetDefaultDriver, resolveConnector, resolveDependencies, resolveRepository, retryWithBackoff, scopeEquals, scopeMatches, setMediaOutputHandler, setMediaStorage, setMetricsCollector, simpleTokenEstimator, toConnectorOptions, toolRegistry, tools_exports as tools, updateTaskStatus, validatePath, writeFile5 as writeFile };
50001
52210
  //# sourceMappingURL=index.js.map
50002
52211
  //# sourceMappingURL=index.js.map