@everworker/oneringai 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  var crypto2 = require('crypto');
4
4
  var jose = require('jose');
5
- var fs15 = require('fs');
5
+ var fs16 = require('fs');
6
6
  var eventemitter3 = require('eventemitter3');
7
- var path3 = require('path');
8
- var os = require('os');
9
- var OpenAI2 = require('openai');
7
+ var path2 = require('path');
8
+ var os2 = require('os');
9
+ var OpenAI3 = require('openai');
10
10
  var Anthropic = require('@anthropic-ai/sdk');
11
11
  var genai = require('@google/genai');
12
12
  require('zod/v3');
@@ -14,7 +14,7 @@ var z4mini = require('zod/v4-mini');
14
14
  var z = require('zod/v4');
15
15
  var process2 = require('process');
16
16
  var stream = require('stream');
17
- var fs14 = require('fs/promises');
17
+ var fs15 = require('fs/promises');
18
18
  var simpleIcons = require('simple-icons');
19
19
  var child_process = require('child_process');
20
20
  var util = require('util');
@@ -44,15 +44,15 @@ function _interopNamespace(e) {
44
44
  }
45
45
 
46
46
  var crypto2__namespace = /*#__PURE__*/_interopNamespace(crypto2);
47
- var fs15__namespace = /*#__PURE__*/_interopNamespace(fs15);
48
- var path3__namespace = /*#__PURE__*/_interopNamespace(path3);
49
- var os__namespace = /*#__PURE__*/_interopNamespace(os);
50
- var OpenAI2__default = /*#__PURE__*/_interopDefault(OpenAI2);
47
+ var fs16__namespace = /*#__PURE__*/_interopNamespace(fs16);
48
+ var path2__namespace = /*#__PURE__*/_interopNamespace(path2);
49
+ var os2__namespace = /*#__PURE__*/_interopNamespace(os2);
50
+ var OpenAI3__default = /*#__PURE__*/_interopDefault(OpenAI3);
51
51
  var Anthropic__default = /*#__PURE__*/_interopDefault(Anthropic);
52
52
  var z4mini__namespace = /*#__PURE__*/_interopNamespace(z4mini);
53
53
  var z__namespace = /*#__PURE__*/_interopNamespace(z);
54
54
  var process2__default = /*#__PURE__*/_interopDefault(process2);
55
- var fs14__namespace = /*#__PURE__*/_interopNamespace(fs14);
55
+ var fs15__namespace = /*#__PURE__*/_interopNamespace(fs15);
56
56
  var simpleIcons__namespace = /*#__PURE__*/_interopNamespace(simpleIcons);
57
57
  var TurndownService__default = /*#__PURE__*/_interopDefault(TurndownService);
58
58
  var vm__namespace = /*#__PURE__*/_interopNamespace(vm);
@@ -631,7 +631,7 @@ var init_JWTBearer = __esm({
631
631
  this.privateKey = config.privateKey;
632
632
  } else if (config.privateKeyPath) {
633
633
  try {
634
- this.privateKey = fs15__namespace.readFileSync(config.privateKeyPath, "utf8");
634
+ this.privateKey = fs16__namespace.readFileSync(config.privateKeyPath, "utf8");
635
635
  } catch (error) {
636
636
  throw new Error(`Failed to read private key from ${config.privateKeyPath}: ${error.message}`);
637
637
  }
@@ -1281,11 +1281,11 @@ var init_Logger = __esm({
1281
1281
  */
1282
1282
  initFileStream(filePath) {
1283
1283
  try {
1284
- const dir = path3__namespace.dirname(filePath);
1285
- if (!fs15__namespace.existsSync(dir)) {
1286
- fs15__namespace.mkdirSync(dir, { recursive: true });
1284
+ const dir = path2__namespace.dirname(filePath);
1285
+ if (!fs16__namespace.existsSync(dir)) {
1286
+ fs16__namespace.mkdirSync(dir, { recursive: true });
1287
1287
  }
1288
- this.fileStream = fs15__namespace.createWriteStream(filePath, {
1288
+ this.fileStream = fs16__namespace.createWriteStream(filePath, {
1289
1289
  flags: "a",
1290
1290
  // append mode
1291
1291
  encoding: "utf8"
@@ -2034,7 +2034,14 @@ var init_Connector = __esm({
2034
2034
  }
2035
2035
  const startTime = Date.now();
2036
2036
  this.requestCount++;
2037
- const url2 = endpoint.startsWith("http") ? endpoint : `${this.baseURL}${endpoint}`;
2037
+ let url2;
2038
+ if (endpoint.startsWith("http")) {
2039
+ url2 = endpoint;
2040
+ } else {
2041
+ const base = (this.baseURL ?? "").replace(/\/+$/, "");
2042
+ const path6 = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
2043
+ url2 = `${base}${path6}`;
2044
+ }
2038
2045
  const timeout = options?.timeout ?? this.config.timeout ?? exports.DEFAULT_CONNECTOR_TIMEOUT;
2039
2046
  if (this.config.logging?.enabled) {
2040
2047
  this.logRequest(url2, options);
@@ -14555,12 +14562,12 @@ var require_dist = __commonJS({
14555
14562
  throw new Error(`Unknown format "${name}"`);
14556
14563
  return f;
14557
14564
  };
14558
- function addFormats(ajv, list, fs18, exportName) {
14565
+ function addFormats(ajv, list, fs17, exportName) {
14559
14566
  var _a;
14560
14567
  var _b;
14561
14568
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
14562
14569
  for (const f of list)
14563
- ajv.addFormat(f, fs18[f]);
14570
+ ajv.addFormat(f, fs17[f]);
14564
14571
  }
14565
14572
  module.exports = exports$1 = formatsPlugin;
14566
14573
  Object.defineProperty(exports$1, "__esModule", { value: true });
@@ -14573,7 +14580,7 @@ var require_windows = __commonJS({
14573
14580
  "node_modules/isexe/windows.js"(exports$1, module) {
14574
14581
  module.exports = isexe;
14575
14582
  isexe.sync = sync;
14576
- var fs18 = __require("fs");
14583
+ var fs17 = __require("fs");
14577
14584
  function checkPathExt(path6, options) {
14578
14585
  var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
14579
14586
  if (!pathext) {
@@ -14591,19 +14598,19 @@ var require_windows = __commonJS({
14591
14598
  }
14592
14599
  return false;
14593
14600
  }
14594
- function checkStat(stat5, path6, options) {
14595
- if (!stat5.isSymbolicLink() && !stat5.isFile()) {
14601
+ function checkStat(stat6, path6, options) {
14602
+ if (!stat6.isSymbolicLink() && !stat6.isFile()) {
14596
14603
  return false;
14597
14604
  }
14598
14605
  return checkPathExt(path6, options);
14599
14606
  }
14600
14607
  function isexe(path6, options, cb) {
14601
- fs18.stat(path6, function(er, stat5) {
14602
- cb(er, er ? false : checkStat(stat5, path6, options));
14608
+ fs17.stat(path6, function(er, stat6) {
14609
+ cb(er, er ? false : checkStat(stat6, path6, options));
14603
14610
  });
14604
14611
  }
14605
14612
  function sync(path6, options) {
14606
- return checkStat(fs18.statSync(path6), path6, options);
14613
+ return checkStat(fs17.statSync(path6), path6, options);
14607
14614
  }
14608
14615
  }
14609
14616
  });
@@ -14613,22 +14620,22 @@ var require_mode = __commonJS({
14613
14620
  "node_modules/isexe/mode.js"(exports$1, module) {
14614
14621
  module.exports = isexe;
14615
14622
  isexe.sync = sync;
14616
- var fs18 = __require("fs");
14623
+ var fs17 = __require("fs");
14617
14624
  function isexe(path6, options, cb) {
14618
- fs18.stat(path6, function(er, stat5) {
14619
- cb(er, er ? false : checkStat(stat5, options));
14625
+ fs17.stat(path6, function(er, stat6) {
14626
+ cb(er, er ? false : checkStat(stat6, options));
14620
14627
  });
14621
14628
  }
14622
14629
  function sync(path6, options) {
14623
- return checkStat(fs18.statSync(path6), options);
14630
+ return checkStat(fs17.statSync(path6), options);
14624
14631
  }
14625
- function checkStat(stat5, options) {
14626
- return stat5.isFile() && checkMode(stat5, options);
14632
+ function checkStat(stat6, options) {
14633
+ return stat6.isFile() && checkMode(stat6, options);
14627
14634
  }
14628
- function checkMode(stat5, options) {
14629
- var mod = stat5.mode;
14630
- var uid = stat5.uid;
14631
- var gid = stat5.gid;
14635
+ function checkMode(stat6, options) {
14636
+ var mod = stat6.mode;
14637
+ var uid = stat6.uid;
14638
+ var gid = stat6.gid;
14632
14639
  var myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid();
14633
14640
  var myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid();
14634
14641
  var u = parseInt("100", 8);
@@ -14902,16 +14909,16 @@ var require_shebang_command = __commonJS({
14902
14909
  // node_modules/cross-spawn/lib/util/readShebang.js
14903
14910
  var require_readShebang = __commonJS({
14904
14911
  "node_modules/cross-spawn/lib/util/readShebang.js"(exports$1, module) {
14905
- var fs18 = __require("fs");
14912
+ var fs17 = __require("fs");
14906
14913
  var shebangCommand = require_shebang_command();
14907
14914
  function readShebang(command) {
14908
14915
  const size = 150;
14909
14916
  const buffer = Buffer.alloc(size);
14910
14917
  let fd;
14911
14918
  try {
14912
- fd = fs18.openSync(command, "r");
14913
- fs18.readSync(fd, buffer, 0, size, 0);
14914
- fs18.closeSync(fd);
14919
+ fd = fs17.openSync(command, "r");
14920
+ fs17.readSync(fd, buffer, 0, size, 0);
14921
+ fs17.closeSync(fd);
14915
14922
  } catch (e) {
14916
14923
  }
14917
14924
  return shebangCommand(buffer.toString());
@@ -16020,13 +16027,26 @@ var ToolManager = class extends eventemitter3.EventEmitter {
16020
16027
  pipeline;
16021
16028
  /** Optional tool context for execution (set by agent before runs) */
16022
16029
  _toolContext;
16023
- constructor() {
16030
+ /** Hard timeout for tool execution (0 = disabled) */
16031
+ _toolExecutionTimeout;
16032
+ constructor(config) {
16024
16033
  super();
16034
+ this._toolExecutionTimeout = config?.toolExecutionTimeout ?? 0;
16025
16035
  this.namespaceIndex.set("default", /* @__PURE__ */ new Set());
16026
16036
  this.toolLogger = exports.logger.child({ component: "ToolManager" });
16027
16037
  this.pipeline = new ToolExecutionPipeline();
16028
16038
  this.pipeline.use(new ResultNormalizerPlugin());
16029
16039
  }
16040
+ /**
16041
+ * Get or set the hard tool execution timeout in milliseconds.
16042
+ * 0 = disabled (relies on tool's own timeout).
16043
+ */
16044
+ get toolExecutionTimeout() {
16045
+ return this._toolExecutionTimeout;
16046
+ }
16047
+ set toolExecutionTimeout(value) {
16048
+ this._toolExecutionTimeout = Math.max(0, value);
16049
+ }
16030
16050
  /**
16031
16051
  * Access the execution pipeline for plugin management.
16032
16052
  *
@@ -16524,7 +16544,7 @@ var ToolManager = class extends eventemitter3.EventEmitter {
16524
16544
  const startTime = Date.now();
16525
16545
  exports.metrics.increment("tool.executed", 1, { tool: toolName });
16526
16546
  try {
16527
- const result = await breaker.execute(async () => {
16547
+ const executionPromise = breaker.execute(async () => {
16528
16548
  const toolWithContext = {
16529
16549
  ...registration.tool,
16530
16550
  execute: async (pipelineArgs) => {
@@ -16533,6 +16553,7 @@ var ToolManager = class extends eventemitter3.EventEmitter {
16533
16553
  };
16534
16554
  return await this.pipeline.execute(toolWithContext, args);
16535
16555
  });
16556
+ const result = this._toolExecutionTimeout > 0 ? await this.withHardTimeout(executionPromise, toolName, this._toolExecutionTimeout) : await executionPromise;
16536
16557
  const duration = Date.now() - startTime;
16537
16558
  this.recordExecution(toolName, duration, true);
16538
16559
  const resultSummary = this.summarizeResult(result);
@@ -16595,6 +16616,29 @@ var ToolManager = class extends eventemitter3.EventEmitter {
16595
16616
  return this.list();
16596
16617
  }
16597
16618
  // ==========================================================================
16619
+ // Hard Timeout
16620
+ // ==========================================================================
16621
+ /**
16622
+ * Wrap a promise with a hard timeout safety net.
16623
+ * If the promise doesn't resolve within the timeout, throws ToolExecutionError.
16624
+ */
16625
+ async withHardTimeout(promise, toolName, timeoutMs) {
16626
+ let timeoutId;
16627
+ const timeoutPromise = new Promise((_, reject) => {
16628
+ timeoutId = setTimeout(() => {
16629
+ reject(new ToolExecutionError(
16630
+ toolName,
16631
+ `Tool execution hard timeout after ${timeoutMs}ms (safety net - tool's own timeout may have failed)`
16632
+ ));
16633
+ }, timeoutMs);
16634
+ });
16635
+ try {
16636
+ return await Promise.race([promise, timeoutPromise]);
16637
+ } finally {
16638
+ clearTimeout(timeoutId);
16639
+ }
16640
+ }
16641
+ // ==========================================================================
16598
16642
  // Circuit Breaker Management
16599
16643
  // ==========================================================================
16600
16644
  /**
@@ -18400,6 +18444,9 @@ var BasePluginNextGen = class {
18400
18444
  }
18401
18445
  };
18402
18446
 
18447
+ // src/core/context-nextgen/AgentContextNextGen.ts
18448
+ init_Connector();
18449
+
18403
18450
  // src/domain/entities/Memory.ts
18404
18451
  function isTaskAwareScope(scope) {
18405
18452
  return typeof scope === "object" && scope !== null && "type" in scope;
@@ -19338,13 +19385,18 @@ Values are immediately visible - no retrieval needed.
19338
19385
  - \`high\`: Keep longer. Important state.
19339
19386
  - \`critical\`: Never auto-evicted.
19340
19387
 
19388
+ **UI Display:** Set \`showInUI: true\` in context_set to display the entry in the user's side panel.
19389
+ Values shown in the UI support the same rich markdown formatting as the chat window
19390
+ (see formatting instructions above). Use this for dashboards, progress displays, and results the user should see.
19391
+
19341
19392
  **Tools:** context_set, context_delete, context_list`;
19342
19393
  var contextSetDefinition = {
19343
19394
  type: "function",
19344
19395
  function: {
19345
19396
  name: "context_set",
19346
19397
  description: `Store or update a key-value pair in live context.
19347
- Value appears directly in context - no retrieval needed.`,
19398
+ Value appears directly in context - no retrieval needed.
19399
+ Set showInUI to true to also display the entry in the user's side panel.`,
19348
19400
  parameters: {
19349
19401
  type: "object",
19350
19402
  properties: {
@@ -19355,6 +19407,10 @@ Value appears directly in context - no retrieval needed.`,
19355
19407
  type: "string",
19356
19408
  enum: ["low", "normal", "high", "critical"],
19357
19409
  description: 'Eviction priority. Default: "normal"'
19410
+ },
19411
+ showInUI: {
19412
+ type: "boolean",
19413
+ description: "If true, display this entry in the user's side panel with full rich markdown rendering \u2014 same capabilities as the chat window (code blocks, tables, LaTeX, Mermaid diagrams, Vega-Lite charts, mindmaps, etc. \u2014 see formatting instructions in system prompt). Use this for dashboards, status displays, and structured results the user should see. Default: false"
19358
19414
  }
19359
19415
  },
19360
19416
  required: ["key", "description", "value"]
@@ -19395,6 +19451,7 @@ var InContextMemoryPluginNextGen = class {
19395
19451
  _destroyed = false;
19396
19452
  _tokenCache = null;
19397
19453
  _instructionsTokenCache = null;
19454
+ _notifyTimer = null;
19398
19455
  constructor(config = {}) {
19399
19456
  this.config = { ...DEFAULT_CONFIG, ...config };
19400
19457
  }
@@ -19435,15 +19492,18 @@ var InContextMemoryPluginNextGen = class {
19435
19492
  return a.updatedAt - b.updatedAt;
19436
19493
  });
19437
19494
  let freed = 0;
19495
+ let evicted = false;
19438
19496
  for (const entry of evictable) {
19439
19497
  if (freed >= targetTokensToFree) break;
19440
19498
  const entryTokens = this.estimator.estimateTokens(this.formatEntry(entry));
19441
19499
  this.entries.delete(entry.key);
19442
19500
  freed += entryTokens;
19501
+ evicted = true;
19443
19502
  }
19444
19503
  this._tokenCache = null;
19445
19504
  const content = await this.getContent();
19446
19505
  const after = content ? this.estimator.estimateTokens(content) : 0;
19506
+ if (evicted) this.notifyEntriesChanged();
19447
19507
  return Math.max(0, before - after);
19448
19508
  }
19449
19509
  getTools() {
@@ -19455,6 +19515,7 @@ var InContextMemoryPluginNextGen = class {
19455
19515
  }
19456
19516
  destroy() {
19457
19517
  if (this._destroyed) return;
19518
+ if (this._notifyTimer) clearTimeout(this._notifyTimer);
19458
19519
  this.entries.clear();
19459
19520
  this._destroyed = true;
19460
19521
  this._tokenCache = null;
@@ -19472,6 +19533,7 @@ var InContextMemoryPluginNextGen = class {
19472
19533
  this.entries.set(entry.key, entry);
19473
19534
  }
19474
19535
  this._tokenCache = null;
19536
+ this.notifyEntriesChanged();
19475
19537
  }
19476
19538
  // ============================================================================
19477
19539
  // Entry Management
@@ -19479,19 +19541,21 @@ var InContextMemoryPluginNextGen = class {
19479
19541
  /**
19480
19542
  * Store or update a key-value pair
19481
19543
  */
19482
- set(key, description, value, priority) {
19544
+ set(key, description, value, priority, showInUI) {
19483
19545
  this.assertNotDestroyed();
19484
19546
  const entry = {
19485
19547
  key,
19486
19548
  description,
19487
19549
  value,
19488
19550
  updatedAt: Date.now(),
19489
- priority: priority ?? this.config.defaultPriority
19551
+ priority: priority ?? this.config.defaultPriority,
19552
+ showInUI: showInUI ?? false
19490
19553
  };
19491
19554
  this.entries.set(key, entry);
19492
19555
  this.enforceMaxEntries();
19493
19556
  this.enforceTokenLimit();
19494
19557
  this._tokenCache = null;
19558
+ this.notifyEntriesChanged();
19495
19559
  }
19496
19560
  /**
19497
19561
  * Get a value by key
@@ -19513,7 +19577,10 @@ var InContextMemoryPluginNextGen = class {
19513
19577
  delete(key) {
19514
19578
  this.assertNotDestroyed();
19515
19579
  const deleted = this.entries.delete(key);
19516
- if (deleted) this._tokenCache = null;
19580
+ if (deleted) {
19581
+ this._tokenCache = null;
19582
+ this.notifyEntriesChanged();
19583
+ }
19517
19584
  return deleted;
19518
19585
  }
19519
19586
  /**
@@ -19525,7 +19592,8 @@ var InContextMemoryPluginNextGen = class {
19525
19592
  key: e.key,
19526
19593
  description: e.description,
19527
19594
  priority: e.priority,
19528
- updatedAt: e.updatedAt
19595
+ updatedAt: e.updatedAt,
19596
+ showInUI: e.showInUI ?? false
19529
19597
  }));
19530
19598
  }
19531
19599
  /**
@@ -19535,6 +19603,7 @@ var InContextMemoryPluginNextGen = class {
19535
19603
  this.assertNotDestroyed();
19536
19604
  this.entries.clear();
19537
19605
  this._tokenCache = null;
19606
+ this.notifyEntriesChanged();
19538
19607
  }
19539
19608
  // ============================================================================
19540
19609
  // Private Helpers
@@ -19598,6 +19667,20 @@ ${valueStr}
19598
19667
  return a.updatedAt - b.updatedAt;
19599
19668
  });
19600
19669
  }
19670
+ /**
19671
+ * Debounced notification when entries change.
19672
+ * Calls config.onEntriesChanged with all current entries.
19673
+ */
19674
+ notifyEntriesChanged() {
19675
+ if (!this.config.onEntriesChanged) return;
19676
+ if (this._notifyTimer) clearTimeout(this._notifyTimer);
19677
+ this._notifyTimer = setTimeout(() => {
19678
+ this._notifyTimer = null;
19679
+ if (!this._destroyed && this.config.onEntriesChanged) {
19680
+ this.config.onEntriesChanged(Array.from(this.entries.values()));
19681
+ }
19682
+ }, 100);
19683
+ }
19601
19684
  assertNotDestroyed() {
19602
19685
  if (this._destroyed) {
19603
19686
  throw new Error("InContextMemoryPluginNextGen is destroyed");
@@ -19614,16 +19697,18 @@ ${valueStr}
19614
19697
  args.key,
19615
19698
  args.description,
19616
19699
  args.value,
19617
- args.priority
19700
+ args.priority,
19701
+ args.showInUI
19618
19702
  );
19619
19703
  return {
19620
19704
  success: true,
19621
19705
  key: args.key,
19622
- message: `Stored "${args.key}" in live context`
19706
+ showInUI: args.showInUI ?? false,
19707
+ message: `Stored "${args.key}" in live context${args.showInUI ? " (visible in UI)" : ""}`
19623
19708
  };
19624
19709
  },
19625
19710
  permission: { scope: "always", riskLevel: "low" },
19626
- describeCall: (args) => `set ${args.key}`
19711
+ describeCall: (args) => `set ${args.key}${args.showInUI ? " [UI]" : ""}`
19627
19712
  };
19628
19713
  }
19629
19714
  createContextDeleteTool() {
@@ -19653,10 +19738,10 @@ function getDefaultBaseDirectory() {
19653
19738
  if (platform2 === "win32") {
19654
19739
  const appData = process.env.APPDATA || process.env.LOCALAPPDATA;
19655
19740
  if (appData) {
19656
- return path3.join(appData, "oneringai", "agents");
19741
+ return path2.join(appData, "oneringai", "agents");
19657
19742
  }
19658
19743
  }
19659
- return path3.join(os.homedir(), ".oneringai", "agents");
19744
+ return path2.join(os2.homedir(), ".oneringai", "agents");
19660
19745
  }
19661
19746
  function sanitizeAgentId(agentId) {
19662
19747
  return agentId.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase() || "default";
@@ -19671,9 +19756,9 @@ var FilePersistentInstructionsStorage = class {
19671
19756
  const sanitizedId = sanitizeAgentId(config.agentId);
19672
19757
  const baseDir = config.baseDirectory ?? getDefaultBaseDirectory();
19673
19758
  const filename = config.filename ?? "custom_instructions.json";
19674
- this.directory = path3.join(baseDir, sanitizedId);
19675
- this.filePath = path3.join(this.directory, filename);
19676
- this.legacyFilePath = path3.join(this.directory, "custom_instructions.md");
19759
+ this.directory = path2.join(baseDir, sanitizedId);
19760
+ this.filePath = path2.join(this.directory, filename);
19761
+ this.legacyFilePath = path2.join(this.directory, "custom_instructions.md");
19677
19762
  }
19678
19763
  /**
19679
19764
  * Load instruction entries from file.
@@ -19681,7 +19766,7 @@ var FilePersistentInstructionsStorage = class {
19681
19766
  */
19682
19767
  async load() {
19683
19768
  try {
19684
- const raw = await fs15.promises.readFile(this.filePath, "utf-8");
19769
+ const raw = await fs16.promises.readFile(this.filePath, "utf-8");
19685
19770
  const data = JSON.parse(raw);
19686
19771
  if (data.version === 2 && Array.isArray(data.entries)) {
19687
19772
  return data.entries.length > 0 ? data.entries : null;
@@ -19693,7 +19778,7 @@ var FilePersistentInstructionsStorage = class {
19693
19778
  }
19694
19779
  }
19695
19780
  try {
19696
- const content = await fs15.promises.readFile(this.legacyFilePath, "utf-8");
19781
+ const content = await fs16.promises.readFile(this.legacyFilePath, "utf-8");
19697
19782
  const trimmed = content.trim();
19698
19783
  if (!trimmed) return null;
19699
19784
  const now = Date.now();
@@ -19723,11 +19808,11 @@ var FilePersistentInstructionsStorage = class {
19723
19808
  };
19724
19809
  const tempPath = `${this.filePath}.tmp`;
19725
19810
  try {
19726
- await fs15.promises.writeFile(tempPath, JSON.stringify(data, null, 2), "utf-8");
19727
- await fs15.promises.rename(tempPath, this.filePath);
19811
+ await fs16.promises.writeFile(tempPath, JSON.stringify(data, null, 2), "utf-8");
19812
+ await fs16.promises.rename(tempPath, this.filePath);
19728
19813
  } catch (error) {
19729
19814
  try {
19730
- await fs15.promises.unlink(tempPath);
19815
+ await fs16.promises.unlink(tempPath);
19731
19816
  } catch {
19732
19817
  }
19733
19818
  throw error;
@@ -19739,7 +19824,7 @@ var FilePersistentInstructionsStorage = class {
19739
19824
  */
19740
19825
  async delete() {
19741
19826
  try {
19742
- await fs15.promises.unlink(this.filePath);
19827
+ await fs16.promises.unlink(this.filePath);
19743
19828
  } catch (error) {
19744
19829
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
19745
19830
  throw error;
@@ -19752,11 +19837,11 @@ var FilePersistentInstructionsStorage = class {
19752
19837
  */
19753
19838
  async exists() {
19754
19839
  try {
19755
- await fs15.promises.access(this.filePath);
19840
+ await fs16.promises.access(this.filePath);
19756
19841
  return true;
19757
19842
  } catch {
19758
19843
  try {
19759
- await fs15.promises.access(this.legacyFilePath);
19844
+ await fs16.promises.access(this.legacyFilePath);
19760
19845
  return true;
19761
19846
  } catch {
19762
19847
  return false;
@@ -19780,7 +19865,7 @@ var FilePersistentInstructionsStorage = class {
19780
19865
  */
19781
19866
  async ensureDirectory() {
19782
19867
  try {
19783
- await fs15.promises.mkdir(this.directory, { recursive: true });
19868
+ await fs16.promises.mkdir(this.directory, { recursive: true });
19784
19869
  } catch (error) {
19785
19870
  if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
19786
19871
  throw error;
@@ -19792,7 +19877,7 @@ var FilePersistentInstructionsStorage = class {
19792
19877
  */
19793
19878
  async removeLegacyFile() {
19794
19879
  try {
19795
- await fs15.promises.unlink(this.legacyFilePath);
19880
+ await fs16.promises.unlink(this.legacyFilePath);
19796
19881
  } catch (error) {
19797
19882
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
19798
19883
  console.warn(`Failed to remove legacy instructions file: ${this.legacyFilePath}`);
@@ -20935,6 +21020,10 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
20935
21020
  _sessionId = null;
20936
21021
  /** Agent ID */
20937
21022
  _agentId;
21023
+ /** User ID for multi-user scenarios */
21024
+ _userId;
21025
+ /** Allowed connector names (when agent is restricted to a subset) */
21026
+ _allowedConnectors;
20938
21027
  /** Storage backend */
20939
21028
  _storage;
20940
21029
  /** Destroyed flag */
@@ -20971,15 +21060,20 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
20971
21060
  };
20972
21061
  this._systemPrompt = config.systemPrompt;
20973
21062
  this._agentId = this._config.agentId;
21063
+ this._userId = config.userId;
21064
+ this._allowedConnectors = config.connectors;
20974
21065
  this._storage = config.storage;
20975
21066
  this._compactionStrategy = config.compactionStrategy ?? StrategyRegistry.create(this._config.strategy);
20976
- this._tools = new ToolManager();
21067
+ this._tools = new ToolManager(
21068
+ config.toolExecutionTimeout ? { toolExecutionTimeout: config.toolExecutionTimeout } : void 0
21069
+ );
20977
21070
  if (config.tools) {
20978
21071
  for (const tool of config.tools) {
20979
21072
  this._tools.register(tool);
20980
21073
  }
20981
21074
  }
20982
21075
  this.initializePlugins(config.plugins);
21076
+ this.syncToolContext();
20983
21077
  }
20984
21078
  /**
20985
21079
  * Initialize plugins based on feature flags.
@@ -21024,6 +21118,62 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
21024
21118
  );
21025
21119
  }
21026
21120
  }
21121
+ /**
21122
+ * Sync identity fields and connector registry to ToolContext.
21123
+ * Merges with existing ToolContext to preserve other fields (memory, signal, taskId).
21124
+ *
21125
+ * Connector registry resolution order:
21126
+ * 1. If `connectors` (allowed names) is set → filtered view of global registry
21127
+ * 2. If access policy + userId → scoped view via Connector.scoped()
21128
+ * 3. Otherwise → full global registry
21129
+ */
21130
+ syncToolContext() {
21131
+ const existing = this._tools.getToolContext();
21132
+ this._tools.setToolContext({
21133
+ ...existing,
21134
+ agentId: this._agentId,
21135
+ userId: this._userId,
21136
+ connectorRegistry: this.buildConnectorRegistry()
21137
+ });
21138
+ }
21139
+ /**
21140
+ * Build the connector registry appropriate for this agent's config.
21141
+ */
21142
+ buildConnectorRegistry() {
21143
+ if (this._allowedConnectors?.length) {
21144
+ const allowedSet = new Set(this._allowedConnectors);
21145
+ const base = this._userId && exports.Connector.getAccessPolicy() ? exports.Connector.scoped({ userId: this._userId }) : exports.Connector.asRegistry();
21146
+ return {
21147
+ get: (name) => {
21148
+ if (!allowedSet.has(name)) {
21149
+ const available = this._allowedConnectors.filter((n) => base.has(n)).join(", ") || "none";
21150
+ throw new Error(`Connector '${name}' not found. Available: ${available}`);
21151
+ }
21152
+ return base.get(name);
21153
+ },
21154
+ has: (name) => allowedSet.has(name) && base.has(name),
21155
+ list: () => base.list().filter((n) => allowedSet.has(n)),
21156
+ listAll: () => base.listAll().filter((c) => allowedSet.has(c.name)),
21157
+ size: () => base.listAll().filter((c) => allowedSet.has(c.name)).length,
21158
+ getDescriptionsForTools: () => {
21159
+ const connectors = base.listAll().filter((c) => allowedSet.has(c.name));
21160
+ if (connectors.length === 0) return "No connectors registered yet.";
21161
+ return connectors.map((c) => ` - "${c.name}": ${c.displayName} - ${c.config.description || "No description"}`).join("\n");
21162
+ },
21163
+ getInfo: () => {
21164
+ const info = {};
21165
+ for (const c of base.listAll().filter((c2) => allowedSet.has(c2.name))) {
21166
+ info[c.name] = { displayName: c.displayName, description: c.config.description || "", baseURL: c.baseURL };
21167
+ }
21168
+ return info;
21169
+ }
21170
+ };
21171
+ }
21172
+ if (this._userId && exports.Connector.getAccessPolicy()) {
21173
+ return exports.Connector.scoped({ userId: this._userId });
21174
+ }
21175
+ return exports.Connector.asRegistry();
21176
+ }
21027
21177
  // ============================================================================
21028
21178
  // Public Properties
21029
21179
  // ============================================================================
@@ -21039,6 +21189,24 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
21039
21189
  get agentId() {
21040
21190
  return this._agentId;
21041
21191
  }
21192
+ /** Get the current user ID */
21193
+ get userId() {
21194
+ return this._userId;
21195
+ }
21196
+ /** Set user ID. Automatically updates ToolContext for all tool executions. */
21197
+ set userId(value) {
21198
+ this._userId = value;
21199
+ this.syncToolContext();
21200
+ }
21201
+ /** Get the allowed connector names (undefined = all visible connectors) */
21202
+ get connectors() {
21203
+ return this._allowedConnectors;
21204
+ }
21205
+ /** Set allowed connector names. Updates ToolContext.connectorRegistry. */
21206
+ set connectors(value) {
21207
+ this._allowedConnectors = value;
21208
+ this.syncToolContext();
21209
+ }
21042
21210
  /** Get/set system prompt */
21043
21211
  get systemPrompt() {
21044
21212
  return this._systemPrompt;
@@ -21952,6 +22120,7 @@ ${content}`);
21952
22120
  metadata: {
21953
22121
  savedAt: Date.now(),
21954
22122
  agentId: this._agentId,
22123
+ userId: this._userId,
21955
22124
  model: this._config.model
21956
22125
  }
21957
22126
  };
@@ -22709,7 +22878,7 @@ var OpenAITextProvider = class extends BaseTextProvider {
22709
22878
  streamConverter;
22710
22879
  constructor(config) {
22711
22880
  super(config);
22712
- this.client = new OpenAI2__default.default({
22881
+ this.client = new OpenAI3__default.default({
22713
22882
  apiKey: this.getApiKey(),
22714
22883
  baseURL: this.getBaseURL(),
22715
22884
  organization: config.organization,
@@ -24439,7 +24608,9 @@ var GoogleTextProvider = class extends BaseTextProvider {
24439
24608
  constructor(config) {
24440
24609
  super(config);
24441
24610
  this.client = new genai.GoogleGenAI({
24442
- apiKey: this.getApiKey()
24611
+ apiKey: this.getApiKey(),
24612
+ // Pass custom baseURL for proxy support (e.g. when routing through EW proxy)
24613
+ ...config.baseURL ? { httpOptions: { baseUrl: config.baseURL } } : {}
24443
24614
  });
24444
24615
  this.converter = new GoogleConverter();
24445
24616
  this.streamConverter = new GoogleStreamConverter();
@@ -24736,6 +24907,30 @@ var GenericOpenAIProvider = class extends OpenAITextProvider {
24736
24907
  };
24737
24908
 
24738
24909
  // src/core/createProvider.ts
24910
+ var VENDOR_DEFAULT_URLS = (() => {
24911
+ const map = /* @__PURE__ */ new Map();
24912
+ try {
24913
+ map.set(Vendor.OpenAI, new OpenAI3__default.default({ apiKey: "_" }).baseURL);
24914
+ } catch {
24915
+ }
24916
+ try {
24917
+ map.set(Vendor.Anthropic, new Anthropic__default.default({ apiKey: "_" }).baseURL);
24918
+ } catch {
24919
+ }
24920
+ map.set(Vendor.Google, "https://generativelanguage.googleapis.com");
24921
+ map.set(Vendor.GoogleVertex, "https://us-central1-aiplatform.googleapis.com");
24922
+ map.set(Vendor.Groq, "https://api.groq.com/openai/v1");
24923
+ map.set(Vendor.Together, "https://api.together.xyz/v1");
24924
+ map.set(Vendor.Perplexity, "https://api.perplexity.ai");
24925
+ map.set(Vendor.Grok, "https://api.x.ai/v1");
24926
+ map.set(Vendor.DeepSeek, "https://api.deepseek.com/v1");
24927
+ map.set(Vendor.Mistral, "https://api.mistral.ai/v1");
24928
+ map.set(Vendor.Ollama, "http://localhost:11434/v1");
24929
+ return map;
24930
+ })();
24931
+ function getVendorDefaultBaseURL(vendor) {
24932
+ return VENDOR_DEFAULT_URLS.get(vendor);
24933
+ }
24739
24934
  function createProvider(connector) {
24740
24935
  const injectedProvider = connector.getOptions().provider;
24741
24936
  if (injectedProvider && typeof injectedProvider.generate === "function") {
@@ -24770,39 +24965,15 @@ function createProvider(connector) {
24770
24965
  });
24771
24966
  // OpenAI-compatible providers (use connector.name for unique identification)
24772
24967
  case Vendor.Groq:
24773
- return new GenericOpenAIProvider(connector.name, {
24774
- ...config,
24775
- baseURL: config.baseURL || "https://api.groq.com/openai/v1"
24776
- });
24777
24968
  case Vendor.Together:
24778
- return new GenericOpenAIProvider(connector.name, {
24779
- ...config,
24780
- baseURL: config.baseURL || "https://api.together.xyz/v1"
24781
- });
24782
24969
  case Vendor.Perplexity:
24783
- return new GenericOpenAIProvider(connector.name, {
24784
- ...config,
24785
- baseURL: config.baseURL || "https://api.perplexity.ai"
24786
- });
24787
24970
  case Vendor.Grok:
24788
- return new GenericOpenAIProvider(connector.name, {
24789
- ...config,
24790
- baseURL: config.baseURL || "https://api.x.ai/v1"
24791
- });
24792
24971
  case Vendor.DeepSeek:
24793
- return new GenericOpenAIProvider(connector.name, {
24794
- ...config,
24795
- baseURL: config.baseURL || "https://api.deepseek.com/v1"
24796
- });
24797
24972
  case Vendor.Mistral:
24798
- return new GenericOpenAIProvider(connector.name, {
24799
- ...config,
24800
- baseURL: config.baseURL || "https://api.mistral.ai/v1"
24801
- });
24802
24973
  case Vendor.Ollama:
24803
24974
  return new GenericOpenAIProvider(connector.name, {
24804
24975
  ...config,
24805
- baseURL: config.baseURL || "http://localhost:11434/v1"
24976
+ baseURL: config.baseURL || getVendorDefaultBaseURL(vendor)
24806
24977
  });
24807
24978
  case Vendor.Custom:
24808
24979
  if (!config.baseURL) {
@@ -24912,9 +25083,14 @@ var BaseAgent = class extends eventemitter3.EventEmitter {
24912
25083
  const contextConfig = {
24913
25084
  model: config.model,
24914
25085
  agentId: config.name,
25086
+ userId: config.userId,
25087
+ connectors: config.connectors,
24915
25088
  // Include storage and sessionId if session config is provided
24916
25089
  storage: config.session?.storage,
25090
+ // Thread tool execution timeout to ToolManager
25091
+ toolExecutionTimeout: config.toolExecutionTimeout,
24917
25092
  // Subclasses can add systemPrompt via their config
25093
+ // Note: context-level toolExecutionTimeout overrides agent-level if both set
24918
25094
  ...typeof config.context === "object" && config.context !== null ? config.context : {}
24919
25095
  };
24920
25096
  return AgentContextNextGen.create(contextConfig);
@@ -25065,6 +25241,30 @@ var BaseAgent = class extends eventemitter3.EventEmitter {
25065
25241
  get context() {
25066
25242
  return this._agentContext;
25067
25243
  }
25244
+ /**
25245
+ * Get the current user ID. Delegates to AgentContextNextGen.
25246
+ */
25247
+ get userId() {
25248
+ return this._agentContext.userId;
25249
+ }
25250
+ /**
25251
+ * Set user ID at runtime. Automatically updates ToolContext for all tool executions.
25252
+ */
25253
+ set userId(value) {
25254
+ this._agentContext.userId = value;
25255
+ }
25256
+ /**
25257
+ * Get the allowed connector names (undefined = all visible connectors).
25258
+ */
25259
+ get connectors() {
25260
+ return this._agentContext.connectors;
25261
+ }
25262
+ /**
25263
+ * Restrict this agent to a subset of connectors. Updates ToolContext.connectorRegistry.
25264
+ */
25265
+ set connectors(value) {
25266
+ this._agentContext.connectors = value;
25267
+ }
25068
25268
  /**
25069
25269
  * Permission management. Returns ToolPermissionManager for approval control.
25070
25270
  */
@@ -25116,9 +25316,10 @@ var BaseAgent = class extends eventemitter3.EventEmitter {
25116
25316
  * always sees up-to-date tool descriptions.
25117
25317
  */
25118
25318
  getEnabledToolDefinitions() {
25319
+ const toolContext = this._agentContext.tools.getToolContext();
25119
25320
  return this._agentContext.tools.getEnabled().map((tool) => {
25120
25321
  if (tool.descriptionFactory) {
25121
- const dynamicDescription = tool.descriptionFactory();
25322
+ const dynamicDescription = tool.descriptionFactory(toolContext);
25122
25323
  return {
25123
25324
  ...tool.definition,
25124
25325
  function: {
@@ -26164,6 +26365,7 @@ var Agent = class _Agent extends BaseAgent {
26164
26365
  * const agent = Agent.create({
26165
26366
  * connector: 'openai', // or Connector instance
26166
26367
  * model: 'gpt-4',
26368
+ * userId: 'user-123', // flows to all tool executions automatically
26167
26369
  * instructions: 'You are a helpful assistant',
26168
26370
  * tools: [myTool]
26169
26371
  * });
@@ -27354,18 +27556,18 @@ var Agent = class _Agent extends BaseAgent {
27354
27556
  (class {
27355
27557
  static DEFAULT_PATHS = [
27356
27558
  "./oneringai.config.json",
27357
- path3.join(os.homedir(), ".oneringai", "config.json")
27559
+ path2.join(os2.homedir(), ".oneringai", "config.json")
27358
27560
  ];
27359
27561
  /**
27360
27562
  * Load configuration from file
27361
27563
  */
27362
27564
  static async load(path6) {
27363
- const configPath = path6 ? path3.resolve(path6) : await this.findConfig();
27565
+ const configPath = path6 ? path2.resolve(path6) : await this.findConfig();
27364
27566
  if (!configPath) {
27365
27567
  throw new Error("Configuration file not found. Searched: " + this.DEFAULT_PATHS.join(", "));
27366
27568
  }
27367
27569
  try {
27368
- const content = await fs15.promises.readFile(configPath, "utf-8");
27570
+ const content = await fs16.promises.readFile(configPath, "utf-8");
27369
27571
  let config = JSON.parse(content);
27370
27572
  config = this.interpolateEnvVars(config);
27371
27573
  this.validate(config);
@@ -27381,13 +27583,13 @@ var Agent = class _Agent extends BaseAgent {
27381
27583
  * Load configuration synchronously
27382
27584
  */
27383
27585
  static loadSync(path6) {
27384
- const configPath = path6 ? path3.resolve(path6) : this.findConfigSync();
27586
+ const configPath = path6 ? path2.resolve(path6) : this.findConfigSync();
27385
27587
  if (!configPath) {
27386
27588
  throw new Error("Configuration file not found. Searched: " + this.DEFAULT_PATHS.join(", "));
27387
27589
  }
27388
27590
  try {
27389
- const fs18 = __require("fs");
27390
- const content = fs18.readFileSync(configPath, "utf-8");
27591
+ const fs17 = __require("fs");
27592
+ const content = fs17.readFileSync(configPath, "utf-8");
27391
27593
  let config = JSON.parse(content);
27392
27594
  config = this.interpolateEnvVars(config);
27393
27595
  this.validate(config);
@@ -27405,8 +27607,8 @@ var Agent = class _Agent extends BaseAgent {
27405
27607
  static async findConfig() {
27406
27608
  for (const path6 of this.DEFAULT_PATHS) {
27407
27609
  try {
27408
- await fs15.promises.access(path3.resolve(path6));
27409
- return path3.resolve(path6);
27610
+ await fs16.promises.access(path2.resolve(path6));
27611
+ return path2.resolve(path6);
27410
27612
  } catch {
27411
27613
  }
27412
27614
  }
@@ -27416,11 +27618,11 @@ var Agent = class _Agent extends BaseAgent {
27416
27618
  * Find configuration file synchronously
27417
27619
  */
27418
27620
  static findConfigSync() {
27419
- const fs18 = __require("fs");
27621
+ const fs17 = __require("fs");
27420
27622
  for (const path6 of this.DEFAULT_PATHS) {
27421
27623
  try {
27422
- fs18.accessSync(path3.resolve(path6));
27423
- return path3.resolve(path6);
27624
+ fs17.accessSync(path2.resolve(path6));
27625
+ return path2.resolve(path6);
27424
27626
  } catch {
27425
27627
  }
27426
27628
  }
@@ -32977,8 +33179,8 @@ var MCPRegistry = class {
32977
33179
  */
32978
33180
  static async loadFromConfigFile(path6) {
32979
33181
  try {
32980
- const configPath = path3.resolve(path6);
32981
- const content = await fs15.promises.readFile(configPath, "utf-8");
33182
+ const configPath = path2.resolve(path6);
33183
+ const content = await fs16.promises.readFile(configPath, "utf-8");
32982
33184
  const config = JSON.parse(content);
32983
33185
  if (!config.mcp) {
32984
33186
  throw new MCPError("Configuration file does not contain MCP section");
@@ -33366,7 +33568,7 @@ var OpenAITTSProvider = class extends BaseMediaProvider {
33366
33568
  client;
33367
33569
  constructor(config) {
33368
33570
  super({ apiKey: config.auth.apiKey, ...config });
33369
- this.client = new OpenAI2__default.default({
33571
+ this.client = new OpenAI3__default.default({
33370
33572
  apiKey: config.auth.apiKey,
33371
33573
  baseURL: config.baseURL,
33372
33574
  organization: config.organization,
@@ -33449,7 +33651,7 @@ var OpenAITTSProvider = class extends BaseMediaProvider {
33449
33651
  * Handle OpenAI API errors
33450
33652
  */
33451
33653
  handleError(error) {
33452
- if (error instanceof OpenAI2__default.default.APIError) {
33654
+ if (error instanceof OpenAI3__default.default.APIError) {
33453
33655
  const status = error.status;
33454
33656
  const message = error.message || "Unknown OpenAI API error";
33455
33657
  if (status === 401) {
@@ -33481,7 +33683,7 @@ var OpenAISTTProvider = class extends BaseMediaProvider {
33481
33683
  client;
33482
33684
  constructor(config) {
33483
33685
  super({ apiKey: config.auth.apiKey, ...config });
33484
- this.client = new OpenAI2__default.default({
33686
+ this.client = new OpenAI3__default.default({
33485
33687
  apiKey: config.auth.apiKey,
33486
33688
  baseURL: config.baseURL,
33487
33689
  organization: config.organization,
@@ -33583,7 +33785,7 @@ var OpenAISTTProvider = class extends BaseMediaProvider {
33583
33785
  if (Buffer.isBuffer(audio)) {
33584
33786
  return new File([new Uint8Array(audio)], "audio.wav", { type: "audio/wav" });
33585
33787
  } else if (typeof audio === "string") {
33586
- return fs15__namespace.createReadStream(audio);
33788
+ return fs16__namespace.createReadStream(audio);
33587
33789
  } else {
33588
33790
  throw new Error("Invalid audio input: must be Buffer or file path");
33589
33791
  }
@@ -33642,7 +33844,7 @@ var OpenAISTTProvider = class extends BaseMediaProvider {
33642
33844
  * Handle OpenAI API errors
33643
33845
  */
33644
33846
  handleError(error) {
33645
- if (error instanceof OpenAI2__default.default.APIError) {
33847
+ if (error instanceof OpenAI3__default.default.APIError) {
33646
33848
  const status = error.status;
33647
33849
  const message = error.message || "Unknown OpenAI API error";
33648
33850
  if (status === 401) {
@@ -34136,7 +34338,7 @@ var TextToSpeech = class _TextToSpeech {
34136
34338
  */
34137
34339
  async toFile(text, filePath, options) {
34138
34340
  const response = await this.synthesize(text, options);
34139
- await fs14__namespace.writeFile(filePath, response.audio);
34341
+ await fs15__namespace.writeFile(filePath, response.audio);
34140
34342
  }
34141
34343
  // ======================== Introspection Methods ========================
34142
34344
  /**
@@ -34484,7 +34686,7 @@ var SpeechToText = class _SpeechToText {
34484
34686
  * @param options - Optional transcription parameters
34485
34687
  */
34486
34688
  async transcribeFile(filePath, options) {
34487
- const audio = await fs14__namespace.readFile(filePath);
34689
+ const audio = await fs15__namespace.readFile(filePath);
34488
34690
  return this.transcribe(audio, options);
34489
34691
  }
34490
34692
  /**
@@ -34648,7 +34850,7 @@ var OpenAIImageProvider = class extends BaseMediaProvider {
34648
34850
  client;
34649
34851
  constructor(config) {
34650
34852
  super({ apiKey: config.auth.apiKey, ...config });
34651
- this.client = new OpenAI2__default.default({
34853
+ this.client = new OpenAI3__default.default({
34652
34854
  apiKey: config.auth.apiKey,
34653
34855
  baseURL: config.baseURL,
34654
34856
  organization: config.organization,
@@ -34810,7 +35012,7 @@ var OpenAIImageProvider = class extends BaseMediaProvider {
34810
35012
  if (Buffer.isBuffer(image)) {
34811
35013
  return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
34812
35014
  }
34813
- return fs15__namespace.createReadStream(image);
35015
+ return fs16__namespace.createReadStream(image);
34814
35016
  }
34815
35017
  /**
34816
35018
  * Handle OpenAI API errors
@@ -34957,8 +35159,8 @@ var GoogleImageProvider = class extends BaseMediaProvider {
34957
35159
  if (Buffer.isBuffer(image)) {
34958
35160
  imageBytes = image.toString("base64");
34959
35161
  } else {
34960
- const fs18 = await import('fs');
34961
- const buffer = fs18.readFileSync(image);
35162
+ const fs17 = await import('fs');
35163
+ const buffer = fs17.readFileSync(image);
34962
35164
  imageBytes = buffer.toString("base64");
34963
35165
  }
34964
35166
  return {
@@ -35008,7 +35210,7 @@ var GrokImageProvider = class extends BaseMediaProvider {
35008
35210
  client;
35009
35211
  constructor(config) {
35010
35212
  super({ apiKey: config.auth.apiKey, ...config });
35011
- this.client = new OpenAI2__default.default({
35213
+ this.client = new OpenAI3__default.default({
35012
35214
  apiKey: config.auth.apiKey,
35013
35215
  baseURL: config.baseURL || GROK_API_BASE_URL,
35014
35216
  timeout: config.timeout,
@@ -35119,7 +35321,7 @@ var GrokImageProvider = class extends BaseMediaProvider {
35119
35321
  if (Buffer.isBuffer(image)) {
35120
35322
  return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
35121
35323
  }
35122
- return fs15__namespace.createReadStream(image);
35324
+ return fs16__namespace.createReadStream(image);
35123
35325
  }
35124
35326
  /**
35125
35327
  * Handle API errors
@@ -36321,7 +36523,7 @@ var OpenAISoraProvider = class extends BaseMediaProvider {
36321
36523
  client;
36322
36524
  constructor(config) {
36323
36525
  super({ apiKey: config.auth.apiKey, ...config });
36324
- this.client = new OpenAI2__default.default({
36526
+ this.client = new OpenAI3__default.default({
36325
36527
  apiKey: config.auth.apiKey,
36326
36528
  baseURL: config.baseURL,
36327
36529
  organization: config.organization,
@@ -36569,8 +36771,8 @@ var OpenAISoraProvider = class extends BaseMediaProvider {
36569
36771
  return new File([new Uint8Array(image)], "input.png", { type: "image/png" });
36570
36772
  }
36571
36773
  if (!image.startsWith("http")) {
36572
- const fs18 = await import('fs');
36573
- const data = fs18.readFileSync(image);
36774
+ const fs17 = await import('fs');
36775
+ const data = fs17.readFileSync(image);
36574
36776
  return new File([new Uint8Array(data)], "input.png", { type: "image/png" });
36575
36777
  }
36576
36778
  const response = await fetch(image);
@@ -36748,7 +36950,7 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
36748
36950
  if (video.videoBytes) {
36749
36951
  buffer = Buffer.from(video.videoBytes, "base64");
36750
36952
  } else if (video.uri) {
36751
- const fs18 = await import('fs/promises');
36953
+ const fs17 = await import('fs/promises');
36752
36954
  const os3 = await import('os');
36753
36955
  const path6 = await import('path');
36754
36956
  const tempDir = os3.tmpdir();
@@ -36759,11 +36961,11 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
36759
36961
  // Pass as GeneratedVideo
36760
36962
  downloadPath: tempFile
36761
36963
  });
36762
- buffer = await fs18.readFile(tempFile);
36763
- await fs18.unlink(tempFile).catch(() => {
36964
+ buffer = await fs17.readFile(tempFile);
36965
+ await fs17.unlink(tempFile).catch(() => {
36764
36966
  });
36765
36967
  } catch (downloadError) {
36766
- await fs18.unlink(tempFile).catch(() => {
36968
+ await fs17.unlink(tempFile).catch(() => {
36767
36969
  });
36768
36970
  throw new ProviderError(
36769
36971
  "google",
@@ -36885,8 +37087,8 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
36885
37087
  if (image.startsWith("http://") || image.startsWith("https://")) {
36886
37088
  return { imageUri: image };
36887
37089
  }
36888
- const fs18 = await import('fs/promises');
36889
- const data = await fs18.readFile(image);
37090
+ const fs17 = await import('fs/promises');
37091
+ const data = await fs17.readFile(image);
36890
37092
  return {
36891
37093
  imageBytes: data.toString("base64")
36892
37094
  };
@@ -37193,8 +37395,8 @@ var GrokImagineProvider = class extends BaseMediaProvider {
37193
37395
  if (image.startsWith("http") || image.startsWith("data:")) {
37194
37396
  return image;
37195
37397
  }
37196
- const fs18 = await import('fs');
37197
- const data = fs18.readFileSync(image);
37398
+ const fs17 = await import('fs');
37399
+ const data = fs17.readFileSync(image);
37198
37400
  const base64 = data.toString("base64");
37199
37401
  const ext = image.split(".").pop()?.toLowerCase() || "png";
37200
37402
  const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext}`;
@@ -40399,10 +40601,10 @@ function getDefaultBaseDirectory2() {
40399
40601
  if (platform2 === "win32") {
40400
40602
  const appData = process.env.APPDATA || process.env.LOCALAPPDATA;
40401
40603
  if (appData) {
40402
- return path3.join(appData, "oneringai", "agents");
40604
+ return path2.join(appData, "oneringai", "agents");
40403
40605
  }
40404
40606
  }
40405
- return path3.join(os.homedir(), ".oneringai", "agents");
40607
+ return path2.join(os2.homedir(), ".oneringai", "agents");
40406
40608
  }
40407
40609
  function sanitizeId(id) {
40408
40610
  return id.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase() || "default";
@@ -40419,8 +40621,8 @@ var FileContextStorage = class {
40419
40621
  const sanitizedAgentId = sanitizeId(config.agentId);
40420
40622
  const baseDir = config.baseDirectory ?? getDefaultBaseDirectory2();
40421
40623
  this.prettyPrint = config.prettyPrint ?? true;
40422
- this.sessionsDirectory = path3.join(baseDir, sanitizedAgentId, "sessions");
40423
- this.indexPath = path3.join(this.sessionsDirectory, "_index.json");
40624
+ this.sessionsDirectory = path2.join(baseDir, sanitizedAgentId, "sessions");
40625
+ this.indexPath = path2.join(this.sessionsDirectory, "_index.json");
40424
40626
  }
40425
40627
  /**
40426
40628
  * Save context state to a session file
@@ -40446,11 +40648,11 @@ var FileContextStorage = class {
40446
40648
  const data = this.prettyPrint ? JSON.stringify(storedSession, null, 2) : JSON.stringify(storedSession);
40447
40649
  const tempPath = `${filePath}.tmp`;
40448
40650
  try {
40449
- await fs15.promises.writeFile(tempPath, data, "utf-8");
40450
- await fs15.promises.rename(tempPath, filePath);
40651
+ await fs16.promises.writeFile(tempPath, data, "utf-8");
40652
+ await fs16.promises.rename(tempPath, filePath);
40451
40653
  } catch (error) {
40452
40654
  try {
40453
- await fs15.promises.unlink(tempPath);
40655
+ await fs16.promises.unlink(tempPath);
40454
40656
  } catch {
40455
40657
  }
40456
40658
  throw error;
@@ -40471,7 +40673,7 @@ var FileContextStorage = class {
40471
40673
  const sanitizedSessionId = sanitizeId(sessionId);
40472
40674
  const filePath = this.getFilePath(sanitizedSessionId);
40473
40675
  try {
40474
- await fs15.promises.unlink(filePath);
40676
+ await fs16.promises.unlink(filePath);
40475
40677
  } catch (error) {
40476
40678
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
40477
40679
  throw error;
@@ -40486,7 +40688,7 @@ var FileContextStorage = class {
40486
40688
  const sanitizedSessionId = sanitizeId(sessionId);
40487
40689
  const filePath = this.getFilePath(sanitizedSessionId);
40488
40690
  try {
40489
- await fs15.promises.access(filePath);
40691
+ await fs16.promises.access(filePath);
40490
40692
  return true;
40491
40693
  } catch {
40492
40694
  return false;
@@ -40551,7 +40753,7 @@ var FileContextStorage = class {
40551
40753
  const sanitizedSessionId = sanitizeId(sessionId);
40552
40754
  const filePath = this.getFilePath(sanitizedSessionId);
40553
40755
  const data = this.prettyPrint ? JSON.stringify(stored, null, 2) : JSON.stringify(stored);
40554
- await fs15.promises.writeFile(filePath, data, "utf-8");
40756
+ await fs16.promises.writeFile(filePath, data, "utf-8");
40555
40757
  await this.updateIndex(stored);
40556
40758
  }
40557
40759
  /**
@@ -40572,13 +40774,13 @@ var FileContextStorage = class {
40572
40774
  */
40573
40775
  async rebuildIndex() {
40574
40776
  await this.ensureDirectory();
40575
- const files = await fs15.promises.readdir(this.sessionsDirectory);
40777
+ const files = await fs16.promises.readdir(this.sessionsDirectory);
40576
40778
  const sessionFiles = files.filter((f) => f.endsWith(".json") && !f.startsWith("_"));
40577
40779
  const entries = [];
40578
40780
  for (const file of sessionFiles) {
40579
40781
  try {
40580
- const filePath = path3.join(this.sessionsDirectory, file);
40581
- const data = await fs15.promises.readFile(filePath, "utf-8");
40782
+ const filePath = path2.join(this.sessionsDirectory, file);
40783
+ const data = await fs16.promises.readFile(filePath, "utf-8");
40582
40784
  const stored = JSON.parse(data);
40583
40785
  entries.push(this.storedToIndexEntry(stored));
40584
40786
  } catch {
@@ -40596,11 +40798,11 @@ var FileContextStorage = class {
40596
40798
  // Private Helpers
40597
40799
  // ==========================================================================
40598
40800
  getFilePath(sanitizedSessionId) {
40599
- return path3.join(this.sessionsDirectory, `${sanitizedSessionId}.json`);
40801
+ return path2.join(this.sessionsDirectory, `${sanitizedSessionId}.json`);
40600
40802
  }
40601
40803
  async ensureDirectory() {
40602
40804
  try {
40603
- await fs15.promises.mkdir(this.sessionsDirectory, { recursive: true });
40805
+ await fs16.promises.mkdir(this.sessionsDirectory, { recursive: true });
40604
40806
  } catch (error) {
40605
40807
  if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
40606
40808
  throw error;
@@ -40610,7 +40812,7 @@ var FileContextStorage = class {
40610
40812
  async loadRaw(sanitizedSessionId) {
40611
40813
  const filePath = this.getFilePath(sanitizedSessionId);
40612
40814
  try {
40613
- const data = await fs15.promises.readFile(filePath, "utf-8");
40815
+ const data = await fs16.promises.readFile(filePath, "utf-8");
40614
40816
  return JSON.parse(data);
40615
40817
  } catch (error) {
40616
40818
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -40628,7 +40830,7 @@ var FileContextStorage = class {
40628
40830
  return this.index;
40629
40831
  }
40630
40832
  try {
40631
- const data = await fs15.promises.readFile(this.indexPath, "utf-8");
40833
+ const data = await fs16.promises.readFile(this.indexPath, "utf-8");
40632
40834
  this.index = JSON.parse(data);
40633
40835
  return this.index;
40634
40836
  } catch (error) {
@@ -40649,7 +40851,7 @@ var FileContextStorage = class {
40649
40851
  await this.ensureDirectory();
40650
40852
  this.index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
40651
40853
  const data = this.prettyPrint ? JSON.stringify(this.index, null, 2) : JSON.stringify(this.index);
40652
- await fs15.promises.writeFile(this.indexPath, data, "utf-8");
40854
+ await fs16.promises.writeFile(this.indexPath, data, "utf-8");
40653
40855
  }
40654
40856
  async updateIndex(stored) {
40655
40857
  const index = await this.loadIndex();
@@ -40687,10 +40889,10 @@ function getDefaultBaseDirectory3() {
40687
40889
  if (platform2 === "win32") {
40688
40890
  const appData = process.env.APPDATA || process.env.LOCALAPPDATA;
40689
40891
  if (appData) {
40690
- return path3.join(appData, "oneringai", "agents");
40892
+ return path2.join(appData, "oneringai", "agents");
40691
40893
  }
40692
40894
  }
40693
- return path3.join(os.homedir(), ".oneringai", "agents");
40895
+ return path2.join(os2.homedir(), ".oneringai", "agents");
40694
40896
  }
40695
40897
  function sanitizeAgentId2(agentId) {
40696
40898
  return agentId.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase() || "default";
@@ -40703,15 +40905,15 @@ var FileAgentDefinitionStorage = class {
40703
40905
  constructor(config = {}) {
40704
40906
  this.baseDirectory = config.baseDirectory ?? getDefaultBaseDirectory3();
40705
40907
  this.prettyPrint = config.prettyPrint ?? true;
40706
- this.indexPath = path3.join(this.baseDirectory, "_agents_index.json");
40908
+ this.indexPath = path2.join(this.baseDirectory, "_agents_index.json");
40707
40909
  }
40708
40910
  /**
40709
40911
  * Save an agent definition
40710
40912
  */
40711
40913
  async save(definition) {
40712
40914
  const sanitizedId = sanitizeAgentId2(definition.agentId);
40713
- const agentDir = path3.join(this.baseDirectory, sanitizedId);
40714
- const filePath = path3.join(agentDir, "definition.json");
40915
+ const agentDir = path2.join(this.baseDirectory, sanitizedId);
40916
+ const filePath = path2.join(agentDir, "definition.json");
40715
40917
  await this.ensureDirectory(agentDir);
40716
40918
  const now = (/* @__PURE__ */ new Date()).toISOString();
40717
40919
  if (!definition.createdAt) {
@@ -40723,11 +40925,11 @@ var FileAgentDefinitionStorage = class {
40723
40925
  const data = this.prettyPrint ? JSON.stringify(definition, null, 2) : JSON.stringify(definition);
40724
40926
  const tempPath = `${filePath}.tmp`;
40725
40927
  try {
40726
- await fs15.promises.writeFile(tempPath, data, "utf-8");
40727
- await fs15.promises.rename(tempPath, filePath);
40928
+ await fs16.promises.writeFile(tempPath, data, "utf-8");
40929
+ await fs16.promises.rename(tempPath, filePath);
40728
40930
  } catch (error) {
40729
40931
  try {
40730
- await fs15.promises.unlink(tempPath);
40932
+ await fs16.promises.unlink(tempPath);
40731
40933
  } catch {
40732
40934
  }
40733
40935
  throw error;
@@ -40746,10 +40948,10 @@ var FileAgentDefinitionStorage = class {
40746
40948
  */
40747
40949
  async delete(agentId) {
40748
40950
  const sanitizedId = sanitizeAgentId2(agentId);
40749
- const agentDir = path3.join(this.baseDirectory, sanitizedId);
40750
- const filePath = path3.join(agentDir, "definition.json");
40951
+ const agentDir = path2.join(this.baseDirectory, sanitizedId);
40952
+ const filePath = path2.join(agentDir, "definition.json");
40751
40953
  try {
40752
- await fs15.promises.unlink(filePath);
40954
+ await fs16.promises.unlink(filePath);
40753
40955
  } catch (error) {
40754
40956
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
40755
40957
  throw error;
@@ -40762,9 +40964,9 @@ var FileAgentDefinitionStorage = class {
40762
40964
  */
40763
40965
  async exists(agentId) {
40764
40966
  const sanitizedId = sanitizeAgentId2(agentId);
40765
- const filePath = path3.join(this.baseDirectory, sanitizedId, "definition.json");
40967
+ const filePath = path2.join(this.baseDirectory, sanitizedId, "definition.json");
40766
40968
  try {
40767
- await fs15.promises.access(filePath);
40969
+ await fs16.promises.access(filePath);
40768
40970
  return true;
40769
40971
  } catch {
40770
40972
  return false;
@@ -40826,13 +41028,13 @@ var FileAgentDefinitionStorage = class {
40826
41028
  */
40827
41029
  async rebuildIndex() {
40828
41030
  await this.ensureDirectory(this.baseDirectory);
40829
- const entries = await fs15.promises.readdir(this.baseDirectory, { withFileTypes: true });
41031
+ const entries = await fs16.promises.readdir(this.baseDirectory, { withFileTypes: true });
40830
41032
  const agentDirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith("_"));
40831
41033
  const indexEntries = [];
40832
41034
  for (const dir of agentDirs) {
40833
41035
  try {
40834
- const filePath = path3.join(this.baseDirectory, dir.name, "definition.json");
40835
- const data = await fs15.promises.readFile(filePath, "utf-8");
41036
+ const filePath = path2.join(this.baseDirectory, dir.name, "definition.json");
41037
+ const data = await fs16.promises.readFile(filePath, "utf-8");
40836
41038
  const definition = JSON.parse(data);
40837
41039
  indexEntries.push(this.definitionToIndexEntry(definition));
40838
41040
  } catch {
@@ -40850,7 +41052,7 @@ var FileAgentDefinitionStorage = class {
40850
41052
  // ==========================================================================
40851
41053
  async ensureDirectory(dir) {
40852
41054
  try {
40853
- await fs15.promises.mkdir(dir, { recursive: true });
41055
+ await fs16.promises.mkdir(dir, { recursive: true });
40854
41056
  } catch (error) {
40855
41057
  if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
40856
41058
  throw error;
@@ -40858,9 +41060,9 @@ var FileAgentDefinitionStorage = class {
40858
41060
  }
40859
41061
  }
40860
41062
  async loadRaw(sanitizedId) {
40861
- const filePath = path3.join(this.baseDirectory, sanitizedId, "definition.json");
41063
+ const filePath = path2.join(this.baseDirectory, sanitizedId, "definition.json");
40862
41064
  try {
40863
- const data = await fs15.promises.readFile(filePath, "utf-8");
41065
+ const data = await fs16.promises.readFile(filePath, "utf-8");
40864
41066
  return JSON.parse(data);
40865
41067
  } catch (error) {
40866
41068
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -40878,7 +41080,7 @@ var FileAgentDefinitionStorage = class {
40878
41080
  return this.index;
40879
41081
  }
40880
41082
  try {
40881
- const data = await fs15.promises.readFile(this.indexPath, "utf-8");
41083
+ const data = await fs16.promises.readFile(this.indexPath, "utf-8");
40882
41084
  this.index = JSON.parse(data);
40883
41085
  return this.index;
40884
41086
  } catch (error) {
@@ -40898,7 +41100,7 @@ var FileAgentDefinitionStorage = class {
40898
41100
  await this.ensureDirectory(this.baseDirectory);
40899
41101
  this.index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
40900
41102
  const data = this.prettyPrint ? JSON.stringify(this.index, null, 2) : JSON.stringify(this.index);
40901
- await fs15.promises.writeFile(this.indexPath, data, "utf-8");
41103
+ await fs16.promises.writeFile(this.indexPath, data, "utf-8");
40902
41104
  }
40903
41105
  async updateIndex(definition) {
40904
41106
  const index = await this.loadIndex();
@@ -40931,6 +41133,126 @@ var FileAgentDefinitionStorage = class {
40931
41133
  function createFileAgentDefinitionStorage(config) {
40932
41134
  return new FileAgentDefinitionStorage(config);
40933
41135
  }
41136
+ var MIME_TYPES = {
41137
+ png: "image/png",
41138
+ jpeg: "image/jpeg",
41139
+ jpg: "image/jpeg",
41140
+ webp: "image/webp",
41141
+ gif: "image/gif",
41142
+ mp4: "video/mp4",
41143
+ webm: "video/webm",
41144
+ mp3: "audio/mpeg",
41145
+ wav: "audio/wav",
41146
+ opus: "audio/opus",
41147
+ ogg: "audio/ogg",
41148
+ aac: "audio/aac",
41149
+ flac: "audio/flac",
41150
+ pcm: "audio/pcm"
41151
+ };
41152
+ var MEDIA_TYPE_PREFIXES = ["image", "video", "audio"];
41153
+ var FileMediaStorage = class {
41154
+ outputDir;
41155
+ initialized = false;
41156
+ constructor(config) {
41157
+ this.outputDir = config?.outputDir ?? path2__namespace.join(os2__namespace.tmpdir(), "oneringai-media");
41158
+ }
41159
+ async save(data, metadata) {
41160
+ const dir = metadata.userId ? path2__namespace.join(this.outputDir, metadata.userId) : this.outputDir;
41161
+ await fs15__namespace.mkdir(dir, { recursive: true });
41162
+ const filename = metadata.suggestedFilename ?? this.generateFilename(metadata);
41163
+ const filePath = path2__namespace.join(dir, filename);
41164
+ await fs15__namespace.writeFile(filePath, data);
41165
+ const format = metadata.format.toLowerCase();
41166
+ const mimeType = MIME_TYPES[format] ?? "application/octet-stream";
41167
+ return {
41168
+ location: filePath,
41169
+ mimeType,
41170
+ size: data.length
41171
+ };
41172
+ }
41173
+ async read(location) {
41174
+ try {
41175
+ return await fs15__namespace.readFile(location);
41176
+ } catch (err) {
41177
+ if (err.code === "ENOENT") {
41178
+ return null;
41179
+ }
41180
+ throw err;
41181
+ }
41182
+ }
41183
+ async delete(location) {
41184
+ try {
41185
+ await fs15__namespace.unlink(location);
41186
+ } catch (err) {
41187
+ if (err.code === "ENOENT") {
41188
+ return;
41189
+ }
41190
+ throw err;
41191
+ }
41192
+ }
41193
+ async exists(location) {
41194
+ try {
41195
+ await fs15__namespace.access(location);
41196
+ return true;
41197
+ } catch {
41198
+ return false;
41199
+ }
41200
+ }
41201
+ async list(options) {
41202
+ await this.ensureDir();
41203
+ let entries = [];
41204
+ const files = await fs15__namespace.readdir(this.outputDir);
41205
+ for (const file of files) {
41206
+ const filePath = path2__namespace.join(this.outputDir, file);
41207
+ try {
41208
+ const stat6 = await fs15__namespace.stat(filePath);
41209
+ if (!stat6.isFile()) continue;
41210
+ const ext = path2__namespace.extname(file).slice(1).toLowerCase();
41211
+ const mimeType = MIME_TYPES[ext] ?? "application/octet-stream";
41212
+ let type;
41213
+ for (const prefix of MEDIA_TYPE_PREFIXES) {
41214
+ if (file.startsWith(`${prefix}_`)) {
41215
+ type = prefix;
41216
+ break;
41217
+ }
41218
+ }
41219
+ entries.push({
41220
+ location: filePath,
41221
+ mimeType,
41222
+ size: stat6.size,
41223
+ type,
41224
+ createdAt: stat6.birthtime
41225
+ });
41226
+ } catch {
41227
+ }
41228
+ }
41229
+ if (options?.type) {
41230
+ entries = entries.filter((e) => e.type === options.type);
41231
+ }
41232
+ entries.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
41233
+ const offset = options?.offset ?? 0;
41234
+ const limit = options?.limit ?? entries.length;
41235
+ return entries.slice(offset, offset + limit);
41236
+ }
41237
+ getPath() {
41238
+ return this.outputDir;
41239
+ }
41240
+ generateFilename(metadata) {
41241
+ const timestamp = Date.now();
41242
+ const random2 = crypto2__namespace.randomBytes(4).toString("hex");
41243
+ const indexSuffix = metadata.index != null ? `_${metadata.index}` : "";
41244
+ return `${metadata.type}_${timestamp}_${random2}${indexSuffix}.${metadata.format}`;
41245
+ }
41246
+ async ensureDir() {
41247
+ if (!this.initialized) {
41248
+ await fs15__namespace.mkdir(this.outputDir, { recursive: true });
41249
+ this.initialized = true;
41250
+ }
41251
+ }
41252
+ };
41253
+ function createFileMediaStorage(config) {
41254
+ return new FileMediaStorage(config);
41255
+ }
40934
41256
 
40935
41257
  // src/capabilities/agents/StreamHelpers.ts
40936
41258
  var StreamHelpers = class {
@@ -41621,6 +41943,32 @@ function filterProtectedHeaders(headers) {
41621
41943
  }
41622
41944
  return filtered;
41623
41945
  }
41946
+ function normalizeBody(body) {
41947
+ if (typeof body === "string") {
41948
+ try {
41949
+ return JSON.parse(body);
41950
+ } catch {
41951
+ return body;
41952
+ }
41953
+ }
41954
+ return body;
41955
+ }
41956
+ function detectAPIError(data) {
41957
+ if (!data || typeof data !== "object") return null;
41958
+ const obj = data;
41959
+ if (obj.ok === false && typeof obj.error === "string") {
41960
+ return obj.error;
41961
+ }
41962
+ if (obj.success === false) {
41963
+ if (typeof obj.error === "string") return obj.error;
41964
+ if (typeof obj.message === "string") return obj.message;
41965
+ }
41966
+ if (obj.error && typeof obj.error === "object") {
41967
+ const err = obj.error;
41968
+ if (typeof err.message === "string") return err.message;
41969
+ }
41970
+ return null;
41971
+ }
41624
41972
  var ConnectorTools = class {
41625
41973
  /** Registry of service-specific tool factories */
41626
41974
  static factories = /* @__PURE__ */ new Map();
@@ -41853,7 +42201,7 @@ var ConnectorTools = class {
41853
42201
  static createGenericAPITool(connector, options) {
41854
42202
  const toolName = options?.toolName ?? `${connector.name}_api`;
41855
42203
  const userId = options?.userId;
41856
- const description = options?.description ?? `Make an authenticated API call to ${connector.displayName}.` + (connector.baseURL ? ` Base URL: ${connector.baseURL}` : " Provide full URL in endpoint.");
42204
+ const description = options?.description ?? `Make an authenticated API call to ${connector.displayName}.` + (connector.baseURL ? ` Base URL: ${connector.baseURL}.` : " Provide full URL in endpoint.") + ' IMPORTANT: For POST/PUT/PATCH requests, pass data in the "body" parameter as a JSON object, NOT as query string parameters in the endpoint URL. The body is sent as application/json.';
41857
42205
  return {
41858
42206
  definition: {
41859
42207
  type: "function",
@@ -41870,15 +42218,15 @@ var ConnectorTools = class {
41870
42218
  },
41871
42219
  endpoint: {
41872
42220
  type: "string",
41873
- description: "API endpoint (relative to base URL) or full URL"
42221
+ description: 'API endpoint path (relative to base URL) or full URL. Do NOT put request data as query parameters here for POST/PUT/PATCH \u2014 use the "body" parameter instead.'
41874
42222
  },
41875
42223
  body: {
41876
42224
  type: "object",
41877
- description: "Request body (for POST/PUT/PATCH)"
42225
+ description: 'JSON request body for POST/PUT/PATCH requests. MUST be a JSON object (NOT a string). Example: {"channel": "C123", "text": "hello"}. Do NOT stringify this \u2014 pass it as a raw JSON object. Do NOT use query string parameters for POST data.'
41878
42226
  },
41879
42227
  queryParams: {
41880
42228
  type: "object",
41881
- description: "URL query parameters"
42229
+ description: 'URL query parameters (for filtering/pagination on GET requests). Do NOT use for POST/PUT/PATCH data \u2014 use "body" instead.'
41882
42230
  },
41883
42231
  headers: {
41884
42232
  type: "object",
@@ -41889,7 +42237,8 @@ var ConnectorTools = class {
41889
42237
  }
41890
42238
  }
41891
42239
  },
41892
- execute: async (args) => {
42240
+ execute: async (args, context) => {
42241
+ const effectiveUserId = context?.userId ?? userId;
41893
42242
  let url2 = args.endpoint;
41894
42243
  if (args.queryParams && Object.keys(args.queryParams).length > 0) {
41895
42244
  const params = new URLSearchParams();
@@ -41902,7 +42251,8 @@ var ConnectorTools = class {
41902
42251
  let bodyStr;
41903
42252
  if (args.body) {
41904
42253
  try {
41905
- bodyStr = safeStringify2(args.body);
42254
+ const normalized = normalizeBody(args.body);
42255
+ bodyStr = safeStringify2(normalized);
41906
42256
  } catch (e) {
41907
42257
  return {
41908
42258
  success: false,
@@ -41921,7 +42271,7 @@ var ConnectorTools = class {
41921
42271
  },
41922
42272
  body: bodyStr
41923
42273
  },
41924
- userId
42274
+ effectiveUserId
41925
42275
  );
41926
42276
  const text = await response.text();
41927
42277
  let data;
@@ -41930,11 +42280,12 @@ var ConnectorTools = class {
41930
42280
  } catch {
41931
42281
  data = text;
41932
42282
  }
42283
+ const apiError = detectAPIError(data);
41933
42284
  return {
41934
- success: response.ok,
42285
+ success: response.ok && !apiError,
41935
42286
  status: response.status,
41936
- data: response.ok ? data : void 0,
41937
- error: response.ok ? void 0 : typeof data === "string" ? data : safeStringify2(data)
42287
+ data: response.ok && !apiError ? data : void 0,
42288
+ error: apiError ? apiError : response.ok ? void 0 : typeof data === "string" ? data : safeStringify2(data)
41938
42289
  };
41939
42290
  } catch (error) {
41940
42291
  return {
@@ -41943,7 +42294,10 @@ var ConnectorTools = class {
41943
42294
  };
41944
42295
  }
41945
42296
  },
41946
- describeCall: (args) => `${args.method} ${args.endpoint}`,
42297
+ describeCall: (args) => {
42298
+ const bodyInfo = args.body ? ` body=${JSON.stringify(args.body).slice(0, 100)}` : "";
42299
+ return `${args.method} ${args.endpoint}${bodyInfo}`;
42300
+ },
41947
42301
  permission: options?.permission ?? {
41948
42302
  scope: "session",
41949
42303
  riskLevel: "medium",
@@ -41978,8 +42332,8 @@ var FileStorage = class {
41978
42332
  }
41979
42333
  async ensureDirectory() {
41980
42334
  try {
41981
- await fs14__namespace.mkdir(this.directory, { recursive: true });
41982
- await fs14__namespace.chmod(this.directory, 448);
42335
+ await fs15__namespace.mkdir(this.directory, { recursive: true });
42336
+ await fs15__namespace.chmod(this.directory, 448);
41983
42337
  } catch (error) {
41984
42338
  }
41985
42339
  }
@@ -41988,20 +42342,20 @@ var FileStorage = class {
41988
42342
  */
41989
42343
  getFilePath(key) {
41990
42344
  const hash = crypto2__namespace.createHash("sha256").update(key).digest("hex");
41991
- return path3__namespace.join(this.directory, `${hash}.token`);
42345
+ return path2__namespace.join(this.directory, `${hash}.token`);
41992
42346
  }
41993
42347
  async storeToken(key, token) {
41994
42348
  await this.ensureDirectory();
41995
42349
  const filePath = this.getFilePath(key);
41996
42350
  const plaintext = JSON.stringify(token);
41997
42351
  const encrypted = encrypt(plaintext, this.encryptionKey);
41998
- await fs14__namespace.writeFile(filePath, encrypted, "utf8");
41999
- await fs14__namespace.chmod(filePath, 384);
42352
+ await fs15__namespace.writeFile(filePath, encrypted, "utf8");
42353
+ await fs15__namespace.chmod(filePath, 384);
42000
42354
  }
42001
42355
  async getToken(key) {
42002
42356
  const filePath = this.getFilePath(key);
42003
42357
  try {
42004
- const encrypted = await fs14__namespace.readFile(filePath, "utf8");
42358
+ const encrypted = await fs15__namespace.readFile(filePath, "utf8");
42005
42359
  const decrypted = decrypt(encrypted, this.encryptionKey);
42006
42360
  return JSON.parse(decrypted);
42007
42361
  } catch (error) {
@@ -42010,7 +42364,7 @@ var FileStorage = class {
42010
42364
  }
42011
42365
  console.error("Failed to read/decrypt token file:", error);
42012
42366
  try {
42013
- await fs14__namespace.unlink(filePath);
42367
+ await fs15__namespace.unlink(filePath);
42014
42368
  } catch {
42015
42369
  }
42016
42370
  return null;
@@ -42019,7 +42373,7 @@ var FileStorage = class {
42019
42373
  async deleteToken(key) {
42020
42374
  const filePath = this.getFilePath(key);
42021
42375
  try {
42022
- await fs14__namespace.unlink(filePath);
42376
+ await fs15__namespace.unlink(filePath);
42023
42377
  } catch (error) {
42024
42378
  if (error.code !== "ENOENT") {
42025
42379
  throw error;
@@ -42029,7 +42383,7 @@ var FileStorage = class {
42029
42383
  async hasToken(key) {
42030
42384
  const filePath = this.getFilePath(key);
42031
42385
  try {
42032
- await fs14__namespace.access(filePath);
42386
+ await fs15__namespace.access(filePath);
42033
42387
  return true;
42034
42388
  } catch {
42035
42389
  return false;
@@ -42040,7 +42394,7 @@ var FileStorage = class {
42040
42394
  */
42041
42395
  async listTokens() {
42042
42396
  try {
42043
- const files = await fs14__namespace.readdir(this.directory);
42397
+ const files = await fs15__namespace.readdir(this.directory);
42044
42398
  return files.filter((f) => f.endsWith(".token")).map((f) => f.replace(".token", ""));
42045
42399
  } catch {
42046
42400
  return [];
@@ -42051,10 +42405,10 @@ var FileStorage = class {
42051
42405
  */
42052
42406
  async clearAll() {
42053
42407
  try {
42054
- const files = await fs14__namespace.readdir(this.directory);
42408
+ const files = await fs15__namespace.readdir(this.directory);
42055
42409
  const tokenFiles = files.filter((f) => f.endsWith(".token"));
42056
42410
  await Promise.all(
42057
- tokenFiles.map((f) => fs14__namespace.unlink(path3__namespace.join(this.directory, f)).catch(() => {
42411
+ tokenFiles.map((f) => fs15__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
42058
42412
  }))
42059
42413
  );
42060
42414
  } catch {
@@ -42322,22 +42676,26 @@ var ConnectorConfigStore = class {
42322
42676
  * Encrypt secrets in ConnectorAuth based on auth type
42323
42677
  */
42324
42678
  encryptAuthSecrets(auth2) {
42679
+ const encryptedExtra = this.encryptExtra(auth2.extra);
42325
42680
  switch (auth2.type) {
42326
42681
  case "api_key":
42327
42682
  return {
42328
42683
  ...auth2,
42329
- apiKey: this.encryptValue(auth2.apiKey)
42684
+ apiKey: this.encryptValue(auth2.apiKey),
42685
+ ...encryptedExtra ? { extra: encryptedExtra } : {}
42330
42686
  };
42331
42687
  case "oauth":
42332
42688
  return {
42333
42689
  ...auth2,
42334
42690
  clientSecret: auth2.clientSecret ? this.encryptValue(auth2.clientSecret) : void 0,
42335
- privateKey: auth2.privateKey ? this.encryptValue(auth2.privateKey) : void 0
42691
+ privateKey: auth2.privateKey ? this.encryptValue(auth2.privateKey) : void 0,
42692
+ ...encryptedExtra ? { extra: encryptedExtra } : {}
42336
42693
  };
42337
42694
  case "jwt":
42338
42695
  return {
42339
42696
  ...auth2,
42340
- privateKey: this.encryptValue(auth2.privateKey)
42697
+ privateKey: this.encryptValue(auth2.privateKey),
42698
+ ...encryptedExtra ? { extra: encryptedExtra } : {}
42341
42699
  };
42342
42700
  default:
42343
42701
  return auth2;
@@ -42347,27 +42705,53 @@ var ConnectorConfigStore = class {
42347
42705
  * Decrypt secrets in ConnectorAuth based on auth type
42348
42706
  */
42349
42707
  decryptAuthSecrets(auth2) {
42708
+ const decryptedExtra = this.decryptExtra(auth2.extra);
42350
42709
  switch (auth2.type) {
42351
42710
  case "api_key":
42352
42711
  return {
42353
42712
  ...auth2,
42354
- apiKey: this.decryptValue(auth2.apiKey)
42713
+ apiKey: this.decryptValue(auth2.apiKey),
42714
+ ...decryptedExtra ? { extra: decryptedExtra } : {}
42355
42715
  };
42356
42716
  case "oauth":
42357
42717
  return {
42358
42718
  ...auth2,
42359
42719
  clientSecret: auth2.clientSecret ? this.decryptValue(auth2.clientSecret) : void 0,
42360
- privateKey: auth2.privateKey ? this.decryptValue(auth2.privateKey) : void 0
42720
+ privateKey: auth2.privateKey ? this.decryptValue(auth2.privateKey) : void 0,
42721
+ ...decryptedExtra ? { extra: decryptedExtra } : {}
42361
42722
  };
42362
42723
  case "jwt":
42363
42724
  return {
42364
42725
  ...auth2,
42365
- privateKey: this.decryptValue(auth2.privateKey)
42726
+ privateKey: this.decryptValue(auth2.privateKey),
42727
+ ...decryptedExtra ? { extra: decryptedExtra } : {}
42366
42728
  };
42367
42729
  default:
42368
42730
  return auth2;
42369
42731
  }
42370
42732
  }
42733
+ /**
42734
+ * Encrypt all values in an extra Record (vendor-specific credentials)
42735
+ */
42736
+ encryptExtra(extra) {
42737
+ if (!extra || Object.keys(extra).length === 0) return void 0;
42738
+ const result = {};
42739
+ for (const [key, value] of Object.entries(extra)) {
42740
+ result[key] = this.encryptValue(value);
42741
+ }
42742
+ return result;
42743
+ }
42744
+ /**
42745
+ * Decrypt all values in an extra Record (vendor-specific credentials)
42746
+ */
42747
+ decryptExtra(extra) {
42748
+ if (!extra || Object.keys(extra).length === 0) return void 0;
42749
+ const result = {};
42750
+ for (const [key, value] of Object.entries(extra)) {
42751
+ result[key] = this.decryptValue(value);
42752
+ }
42753
+ return result;
42754
+ }
42371
42755
  /**
42372
42756
  * Encrypt a single value if not already encrypted
42373
42757
  */
@@ -42445,20 +42829,20 @@ var FileConnectorStorage = class {
42445
42829
  throw new Error("FileConnectorStorage requires a directory path");
42446
42830
  }
42447
42831
  this.directory = config.directory;
42448
- this.indexPath = path3__namespace.join(this.directory, "_index.json");
42832
+ this.indexPath = path2__namespace.join(this.directory, "_index.json");
42449
42833
  }
42450
42834
  async save(name, stored) {
42451
42835
  await this.ensureDirectory();
42452
42836
  const filePath = this.getFilePath(name);
42453
42837
  const json = JSON.stringify(stored, null, 2);
42454
- await fs14__namespace.writeFile(filePath, json, "utf8");
42455
- await fs14__namespace.chmod(filePath, 384);
42838
+ await fs15__namespace.writeFile(filePath, json, "utf8");
42839
+ await fs15__namespace.chmod(filePath, 384);
42456
42840
  await this.updateIndex(name, "add");
42457
42841
  }
42458
42842
  async get(name) {
42459
42843
  const filePath = this.getFilePath(name);
42460
42844
  try {
42461
- const json = await fs14__namespace.readFile(filePath, "utf8");
42845
+ const json = await fs15__namespace.readFile(filePath, "utf8");
42462
42846
  return JSON.parse(json);
42463
42847
  } catch (error) {
42464
42848
  const err = error;
@@ -42471,7 +42855,7 @@ var FileConnectorStorage = class {
42471
42855
  async delete(name) {
42472
42856
  const filePath = this.getFilePath(name);
42473
42857
  try {
42474
- await fs14__namespace.unlink(filePath);
42858
+ await fs15__namespace.unlink(filePath);
42475
42859
  await this.updateIndex(name, "remove");
42476
42860
  return true;
42477
42861
  } catch (error) {
@@ -42485,7 +42869,7 @@ var FileConnectorStorage = class {
42485
42869
  async has(name) {
42486
42870
  const filePath = this.getFilePath(name);
42487
42871
  try {
42488
- await fs14__namespace.access(filePath);
42872
+ await fs15__namespace.access(filePath);
42489
42873
  return true;
42490
42874
  } catch {
42491
42875
  return false;
@@ -42511,13 +42895,13 @@ var FileConnectorStorage = class {
42511
42895
  */
42512
42896
  async clear() {
42513
42897
  try {
42514
- const files = await fs14__namespace.readdir(this.directory);
42898
+ const files = await fs15__namespace.readdir(this.directory);
42515
42899
  const connectorFiles = files.filter(
42516
42900
  (f) => f.endsWith(".connector.json") || f === "_index.json"
42517
42901
  );
42518
42902
  await Promise.all(
42519
42903
  connectorFiles.map(
42520
- (f) => fs14__namespace.unlink(path3__namespace.join(this.directory, f)).catch(() => {
42904
+ (f) => fs15__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
42521
42905
  })
42522
42906
  )
42523
42907
  );
@@ -42530,7 +42914,7 @@ var FileConnectorStorage = class {
42530
42914
  */
42531
42915
  getFilePath(name) {
42532
42916
  const hash = this.hashName(name);
42533
- return path3__namespace.join(this.directory, `${hash}.connector.json`);
42917
+ return path2__namespace.join(this.directory, `${hash}.connector.json`);
42534
42918
  }
42535
42919
  /**
42536
42920
  * Hash connector name to prevent enumeration
@@ -42544,8 +42928,8 @@ var FileConnectorStorage = class {
42544
42928
  async ensureDirectory() {
42545
42929
  if (this.initialized) return;
42546
42930
  try {
42547
- await fs14__namespace.mkdir(this.directory, { recursive: true });
42548
- await fs14__namespace.chmod(this.directory, 448);
42931
+ await fs15__namespace.mkdir(this.directory, { recursive: true });
42932
+ await fs15__namespace.chmod(this.directory, 448);
42549
42933
  this.initialized = true;
42550
42934
  } catch {
42551
42935
  this.initialized = true;
@@ -42556,7 +42940,7 @@ var FileConnectorStorage = class {
42556
42940
  */
42557
42941
  async loadIndex() {
42558
42942
  try {
42559
- const json = await fs14__namespace.readFile(this.indexPath, "utf8");
42943
+ const json = await fs15__namespace.readFile(this.indexPath, "utf8");
42560
42944
  return JSON.parse(json);
42561
42945
  } catch {
42562
42946
  return { connectors: {} };
@@ -42574,8 +42958,8 @@ var FileConnectorStorage = class {
42574
42958
  delete index.connectors[hash];
42575
42959
  }
42576
42960
  const json = JSON.stringify(index, null, 2);
42577
- await fs14__namespace.writeFile(this.indexPath, json, "utf8");
42578
- await fs14__namespace.chmod(this.indexPath, 384);
42961
+ await fs15__namespace.writeFile(this.indexPath, json, "utf8");
42962
+ await fs15__namespace.chmod(this.indexPath, 384);
42579
42963
  }
42580
42964
  };
42581
42965
 
@@ -42620,11 +43004,19 @@ function buildAuthConfig(authTemplate, credentials) {
42620
43004
  if (!credentials.apiKey) {
42621
43005
  throw new Error("API key is required for api_key auth");
42622
43006
  }
43007
+ const standardApiKeyFields = /* @__PURE__ */ new Set(["apiKey", "headerName", "headerPrefix"]);
43008
+ const extra = {};
43009
+ for (const field of authTemplate.optionalFields ?? []) {
43010
+ if (!standardApiKeyFields.has(field) && credentials[field]) {
43011
+ extra[field] = credentials[field];
43012
+ }
43013
+ }
42623
43014
  return {
42624
43015
  type: "api_key",
42625
43016
  apiKey: credentials.apiKey,
42626
43017
  headerName: defaults.headerName ?? "Authorization",
42627
- headerPrefix: defaults.headerPrefix ?? "Bearer"
43018
+ headerPrefix: defaults.headerPrefix ?? "Bearer",
43019
+ ...Object.keys(extra).length > 0 ? { extra } : {}
42628
43020
  };
42629
43021
  }
42630
43022
  if (!authTemplate.flow) {
@@ -42894,8 +43286,9 @@ var slackTemplate = {
42894
43286
  id: "bot-token",
42895
43287
  name: "Bot Token",
42896
43288
  type: "api_key",
42897
- description: "Internal workspace bot - get from OAuth & Permissions page of your Slack app",
43289
+ description: "Internal workspace bot - get from OAuth & Permissions page of your Slack app. For Socket Mode bots, also provide appToken and signingSecret in extra fields.",
42898
43290
  requiredFields: ["apiKey"],
43291
+ optionalFields: ["appToken", "signingSecret"],
42899
43292
  defaults: {
42900
43293
  type: "api_key",
42901
43294
  headerName: "Authorization",
@@ -44733,14 +45126,14 @@ function createMessageWithImages(text, imageUrls, role = "user" /* USER */) {
44733
45126
  var execAsync = util.promisify(child_process.exec);
44734
45127
  function cleanupTempFile(filePath) {
44735
45128
  try {
44736
- if (fs15__namespace.existsSync(filePath)) {
44737
- fs15__namespace.unlinkSync(filePath);
45129
+ if (fs16__namespace.existsSync(filePath)) {
45130
+ fs16__namespace.unlinkSync(filePath);
44738
45131
  }
44739
45132
  } catch {
44740
45133
  }
44741
45134
  }
44742
45135
  async function readClipboardImage() {
44743
- const platform2 = os__namespace.platform();
45136
+ const platform2 = os2__namespace.platform();
44744
45137
  try {
44745
45138
  switch (platform2) {
44746
45139
  case "darwin":
@@ -44763,7 +45156,7 @@ async function readClipboardImage() {
44763
45156
  }
44764
45157
  }
44765
45158
  async function readClipboardImageMac() {
44766
- const tempFile = path3__namespace.join(os__namespace.tmpdir(), `clipboard-${Date.now()}.png`);
45159
+ const tempFile = path2__namespace.join(os2__namespace.tmpdir(), `clipboard-${Date.now()}.png`);
44767
45160
  try {
44768
45161
  try {
44769
45162
  await execAsync(`pngpaste "${tempFile}"`);
@@ -44785,7 +45178,7 @@ async function readClipboardImageMac() {
44785
45178
  end try
44786
45179
  `;
44787
45180
  const { stdout } = await execAsync(`osascript -e '${script}'`);
44788
- if (stdout.includes("success") || fs15__namespace.existsSync(tempFile)) {
45181
+ if (stdout.includes("success") || fs16__namespace.existsSync(tempFile)) {
44789
45182
  return await convertFileToDataUri(tempFile);
44790
45183
  }
44791
45184
  return {
@@ -44798,18 +45191,18 @@ async function readClipboardImageMac() {
44798
45191
  }
44799
45192
  }
44800
45193
  async function readClipboardImageLinux() {
44801
- const tempFile = path3__namespace.join(os__namespace.tmpdir(), `clipboard-${Date.now()}.png`);
45194
+ const tempFile = path2__namespace.join(os2__namespace.tmpdir(), `clipboard-${Date.now()}.png`);
44802
45195
  try {
44803
45196
  try {
44804
45197
  await execAsync(`xclip -selection clipboard -t image/png -o > "${tempFile}"`);
44805
- if (fs15__namespace.existsSync(tempFile) && fs15__namespace.statSync(tempFile).size > 0) {
45198
+ if (fs16__namespace.existsSync(tempFile) && fs16__namespace.statSync(tempFile).size > 0) {
44806
45199
  return await convertFileToDataUri(tempFile);
44807
45200
  }
44808
45201
  } catch {
44809
45202
  }
44810
45203
  try {
44811
45204
  await execAsync(`wl-paste -t image/png > "${tempFile}"`);
44812
- if (fs15__namespace.existsSync(tempFile) && fs15__namespace.statSync(tempFile).size > 0) {
45205
+ if (fs16__namespace.existsSync(tempFile) && fs16__namespace.statSync(tempFile).size > 0) {
44813
45206
  return await convertFileToDataUri(tempFile);
44814
45207
  }
44815
45208
  } catch {
@@ -44823,7 +45216,7 @@ async function readClipboardImageLinux() {
44823
45216
  }
44824
45217
  }
44825
45218
  async function readClipboardImageWindows() {
44826
- const tempFile = path3__namespace.join(os__namespace.tmpdir(), `clipboard-${Date.now()}.png`);
45219
+ const tempFile = path2__namespace.join(os2__namespace.tmpdir(), `clipboard-${Date.now()}.png`);
44827
45220
  try {
44828
45221
  const psScript = `
44829
45222
  Add-Type -AssemblyName System.Windows.Forms;
@@ -44836,7 +45229,7 @@ async function readClipboardImageWindows() {
44836
45229
  }
44837
45230
  `;
44838
45231
  await execAsync(`powershell -Command "${psScript}"`);
44839
- if (fs15__namespace.existsSync(tempFile) && fs15__namespace.statSync(tempFile).size > 0) {
45232
+ if (fs16__namespace.existsSync(tempFile) && fs16__namespace.statSync(tempFile).size > 0) {
44840
45233
  return await convertFileToDataUri(tempFile);
44841
45234
  }
44842
45235
  return {
@@ -44849,7 +45242,7 @@ async function readClipboardImageWindows() {
44849
45242
  }
44850
45243
  async function convertFileToDataUri(filePath) {
44851
45244
  try {
44852
- const imageBuffer = fs15__namespace.readFileSync(filePath);
45245
+ const imageBuffer = fs16__namespace.readFileSync(filePath);
44853
45246
  const base64Image = imageBuffer.toString("base64");
44854
45247
  const magic = imageBuffer.slice(0, 4).toString("hex");
44855
45248
  let mimeType = "image/png";
@@ -44876,7 +45269,7 @@ async function convertFileToDataUri(filePath) {
44876
45269
  }
44877
45270
  }
44878
45271
  async function hasClipboardImage() {
44879
- const platform2 = os__namespace.platform();
45272
+ const platform2 = os2__namespace.platform();
44880
45273
  try {
44881
45274
  switch (platform2) {
44882
45275
  case "darwin":
@@ -45094,20 +45487,29 @@ __export(tools_exports, {
45094
45487
  ConnectorTools: () => ConnectorTools,
45095
45488
  DEFAULT_FILESYSTEM_CONFIG: () => DEFAULT_FILESYSTEM_CONFIG,
45096
45489
  DEFAULT_SHELL_CONFIG: () => DEFAULT_SHELL_CONFIG,
45097
- FileMediaOutputHandler: () => FileMediaOutputHandler,
45490
+ FileMediaOutputHandler: () => FileMediaStorage,
45098
45491
  ToolRegistry: () => ToolRegistry,
45099
45492
  bash: () => bash,
45100
45493
  createBashTool: () => createBashTool,
45494
+ createCreatePRTool: () => createCreatePRTool,
45101
45495
  createEditFileTool: () => createEditFileTool,
45102
45496
  createExecuteJavaScriptTool: () => createExecuteJavaScriptTool,
45497
+ createGetPRTool: () => createGetPRTool,
45498
+ createGitHubReadFileTool: () => createGitHubReadFileTool,
45103
45499
  createGlobTool: () => createGlobTool,
45104
45500
  createGrepTool: () => createGrepTool,
45105
45501
  createImageGenerationTool: () => createImageGenerationTool,
45106
45502
  createListDirectoryTool: () => createListDirectoryTool,
45503
+ createPRCommentsTool: () => createPRCommentsTool,
45504
+ createPRFilesTool: () => createPRFilesTool,
45107
45505
  createReadFileTool: () => createReadFileTool,
45506
+ createSearchCodeTool: () => createSearchCodeTool,
45507
+ createSearchFilesTool: () => createSearchFilesTool,
45108
45508
  createSpeechToTextTool: () => createSpeechToTextTool,
45109
45509
  createTextToSpeechTool: () => createTextToSpeechTool,
45110
45510
  createVideoTools: () => createVideoTools,
45511
+ createWebScrapeTool: () => createWebScrapeTool,
45512
+ createWebSearchTool: () => createWebSearchTool,
45111
45513
  createWriteFileTool: () => createWriteFileTool,
45112
45514
  developerTools: () => developerTools,
45113
45515
  editFile: () => editFile,
@@ -45116,6 +45518,7 @@ __export(tools_exports, {
45116
45518
  getAllBuiltInTools: () => getAllBuiltInTools,
45117
45519
  getBackgroundOutput: () => getBackgroundOutput,
45118
45520
  getMediaOutputHandler: () => getMediaOutputHandler,
45521
+ getMediaStorage: () => getMediaStorage,
45119
45522
  getToolByName: () => getToolByName,
45120
45523
  getToolCategories: () => getToolCategories,
45121
45524
  getToolRegistry: () => getToolRegistry,
@@ -45128,15 +45531,15 @@ __export(tools_exports, {
45128
45531
  jsonManipulator: () => jsonManipulator,
45129
45532
  killBackgroundProcess: () => killBackgroundProcess,
45130
45533
  listDirectory: () => listDirectory,
45131
- readFile: () => readFile4,
45534
+ parseRepository: () => parseRepository,
45535
+ readFile: () => readFile5,
45536
+ resolveRepository: () => resolveRepository,
45132
45537
  setMediaOutputHandler: () => setMediaOutputHandler,
45538
+ setMediaStorage: () => setMediaStorage,
45133
45539
  toolRegistry: () => toolRegistry,
45134
45540
  validatePath: () => validatePath,
45135
45541
  webFetch: () => webFetch,
45136
- webFetchJS: () => webFetchJS,
45137
- webScrape: () => webScrape,
45138
- webSearch: () => webSearch,
45139
- writeFile: () => writeFile4
45542
+ writeFile: () => writeFile5
45140
45543
  });
45141
45544
  var DEFAULT_FILESYSTEM_CONFIG = {
45142
45545
  workingDirectory: process.cwd(),
@@ -45195,15 +45598,15 @@ function validatePath(inputPath, config = {}) {
45195
45598
  const blockedDirs = config.blockedDirectories || DEFAULT_FILESYSTEM_CONFIG.blockedDirectories;
45196
45599
  let expandedPath = inputPath;
45197
45600
  if (inputPath.startsWith("~/")) {
45198
- expandedPath = path3.resolve(os.homedir(), inputPath.slice(2));
45601
+ expandedPath = path2.resolve(os2.homedir(), inputPath.slice(2));
45199
45602
  } else if (inputPath === "~") {
45200
- expandedPath = os.homedir();
45603
+ expandedPath = os2.homedir();
45201
45604
  }
45202
45605
  let resolvedPath;
45203
- if (path3.isAbsolute(expandedPath)) {
45204
- resolvedPath = path3.normalize(expandedPath);
45606
+ if (path2.isAbsolute(expandedPath)) {
45607
+ resolvedPath = path2.normalize(expandedPath);
45205
45608
  } else {
45206
- resolvedPath = path3.resolve(workingDir, expandedPath);
45609
+ resolvedPath = path2.resolve(workingDir, expandedPath);
45207
45610
  }
45208
45611
  const pathSegments = resolvedPath.split("/").filter(Boolean);
45209
45612
  for (const blocked of blockedDirs) {
@@ -45216,7 +45619,7 @@ function validatePath(inputPath, config = {}) {
45216
45619
  };
45217
45620
  }
45218
45621
  } else {
45219
- const blockedPath = path3.isAbsolute(blocked) ? blocked : path3.resolve(workingDir, blocked);
45622
+ const blockedPath = path2.isAbsolute(blocked) ? blocked : path2.resolve(workingDir, blocked);
45220
45623
  if (resolvedPath.startsWith(blockedPath + "/") || resolvedPath === blockedPath) {
45221
45624
  return {
45222
45625
  valid: false,
@@ -45229,7 +45632,7 @@ function validatePath(inputPath, config = {}) {
45229
45632
  if (allowedDirs.length > 0) {
45230
45633
  let isAllowed = false;
45231
45634
  for (const allowed of allowedDirs) {
45232
- const allowedPath = path3.isAbsolute(allowed) ? allowed : path3.resolve(workingDir, allowed);
45635
+ const allowedPath = path2.isAbsolute(allowed) ? allowed : path2.resolve(workingDir, allowed);
45233
45636
  if (resolvedPath.startsWith(allowedPath + "/") || resolvedPath === allowedPath) {
45234
45637
  isAllowed = true;
45235
45638
  break;
@@ -45247,9 +45650,9 @@ function validatePath(inputPath, config = {}) {
45247
45650
  }
45248
45651
  function expandTilde(inputPath) {
45249
45652
  if (inputPath.startsWith("~/")) {
45250
- return path3.resolve(os.homedir(), inputPath.slice(2));
45653
+ return path2.resolve(os2.homedir(), inputPath.slice(2));
45251
45654
  } else if (inputPath === "~") {
45252
- return os.homedir();
45655
+ return os2.homedir();
45253
45656
  }
45254
45657
  return inputPath;
45255
45658
  }
@@ -45324,7 +45727,7 @@ EXAMPLES:
45324
45727
  };
45325
45728
  }
45326
45729
  const resolvedPath = validation.resolvedPath;
45327
- if (!fs15.existsSync(resolvedPath)) {
45730
+ if (!fs16.existsSync(resolvedPath)) {
45328
45731
  return {
45329
45732
  success: false,
45330
45733
  error: `File not found: ${file_path}`,
@@ -45332,7 +45735,7 @@ EXAMPLES:
45332
45735
  };
45333
45736
  }
45334
45737
  try {
45335
- const stats = await fs14.stat(resolvedPath);
45738
+ const stats = await fs15.stat(resolvedPath);
45336
45739
  if (!stats.isFile()) {
45337
45740
  return {
45338
45741
  success: false,
@@ -45348,7 +45751,7 @@ EXAMPLES:
45348
45751
  size: stats.size
45349
45752
  };
45350
45753
  }
45351
- const content = await fs14.readFile(resolvedPath, "utf-8");
45754
+ const content = await fs15.readFile(resolvedPath, "utf-8");
45352
45755
  const allLines = content.split("\n");
45353
45756
  const totalLines = allLines.length;
45354
45757
  const startIndex = Math.max(0, offset - 1);
@@ -45389,7 +45792,7 @@ EXAMPLES:
45389
45792
  }
45390
45793
  };
45391
45794
  }
45392
- var readFile4 = createReadFileTool();
45795
+ var readFile5 = createReadFileTool();
45393
45796
  function createWriteFileTool(config = {}) {
45394
45797
  const mergedConfig = { ...DEFAULT_FILESYSTEM_CONFIG, ...config };
45395
45798
  return {
@@ -45453,13 +45856,13 @@ EXAMPLES:
45453
45856
  };
45454
45857
  }
45455
45858
  const resolvedPath = validation.resolvedPath;
45456
- const fileExists = fs15.existsSync(resolvedPath);
45859
+ const fileExists = fs16.existsSync(resolvedPath);
45457
45860
  try {
45458
- const parentDir = path3.dirname(resolvedPath);
45459
- if (!fs15.existsSync(parentDir)) {
45460
- await fs14.mkdir(parentDir, { recursive: true });
45861
+ const parentDir = path2.dirname(resolvedPath);
45862
+ if (!fs16.existsSync(parentDir)) {
45863
+ await fs15.mkdir(parentDir, { recursive: true });
45461
45864
  }
45462
- await fs14.writeFile(resolvedPath, content, "utf-8");
45865
+ await fs15.writeFile(resolvedPath, content, "utf-8");
45463
45866
  return {
45464
45867
  success: true,
45465
45868
  path: file_path,
@@ -45476,7 +45879,7 @@ EXAMPLES:
45476
45879
  }
45477
45880
  };
45478
45881
  }
45479
- var writeFile4 = createWriteFileTool();
45882
+ var writeFile5 = createWriteFileTool();
45480
45883
  function createEditFileTool(config = {}) {
45481
45884
  const mergedConfig = { ...DEFAULT_FILESYSTEM_CONFIG, ...config };
45482
45885
  return {
@@ -45562,7 +45965,7 @@ EXAMPLES:
45562
45965
  };
45563
45966
  }
45564
45967
  const resolvedPath = validation.resolvedPath;
45565
- if (!fs15.existsSync(resolvedPath)) {
45968
+ if (!fs16.existsSync(resolvedPath)) {
45566
45969
  return {
45567
45970
  success: false,
45568
45971
  error: `File not found: ${file_path}`,
@@ -45570,7 +45973,7 @@ EXAMPLES:
45570
45973
  };
45571
45974
  }
45572
45975
  try {
45573
- const content = await fs14.readFile(resolvedPath, "utf-8");
45976
+ const content = await fs15.readFile(resolvedPath, "utf-8");
45574
45977
  let occurrences = 0;
45575
45978
  let searchIndex = 0;
45576
45979
  while (true) {
@@ -45609,7 +46012,7 @@ EXAMPLES:
45609
46012
  } else {
45610
46013
  newContent = content.replace(old_string, new_string);
45611
46014
  }
45612
- await fs14.writeFile(resolvedPath, newContent, "utf-8");
46015
+ await fs15.writeFile(resolvedPath, newContent, "utf-8");
45613
46016
  const diffPreview = generateDiffPreview(old_string, new_string);
45614
46017
  return {
45615
46018
  success: true,
@@ -45665,11 +46068,11 @@ async function findFiles(dir, pattern, baseDir, config, results = [], depth = 0)
45665
46068
  return results;
45666
46069
  }
45667
46070
  try {
45668
- const entries = await fs14.readdir(dir, { withFileTypes: true });
46071
+ const entries = await fs15.readdir(dir, { withFileTypes: true });
45669
46072
  for (const entry of entries) {
45670
46073
  if (results.length >= config.maxResults) break;
45671
- const fullPath = path3.join(dir, entry.name);
45672
- const relativePath = path3.relative(baseDir, fullPath);
46074
+ const fullPath = path2.join(dir, entry.name);
46075
+ const relativePath = path2.relative(baseDir, fullPath);
45673
46076
  if (entry.isDirectory()) {
45674
46077
  const isBlocked = config.blockedDirectories.some(
45675
46078
  (blocked) => entry.name === blocked || relativePath.includes(`/${blocked}/`) || relativePath.startsWith(`${blocked}/`)
@@ -45679,7 +46082,7 @@ async function findFiles(dir, pattern, baseDir, config, results = [], depth = 0)
45679
46082
  } else if (entry.isFile()) {
45680
46083
  if (matchGlobPattern(pattern, relativePath)) {
45681
46084
  try {
45682
- const stats = await fs14.stat(fullPath);
46085
+ const stats = await fs15.stat(fullPath);
45683
46086
  results.push({
45684
46087
  path: relativePath,
45685
46088
  mtime: stats.mtimeMs
@@ -45761,7 +46164,7 @@ WHEN TO USE:
45761
46164
  };
45762
46165
  }
45763
46166
  const resolvedDir = validation.resolvedPath;
45764
- if (!fs15.existsSync(resolvedDir)) {
46167
+ if (!fs16.existsSync(resolvedDir)) {
45765
46168
  return {
45766
46169
  success: false,
45767
46170
  error: `Directory not found: ${searchDir}`
@@ -45816,9 +46219,9 @@ async function findFilesToSearch(dir, baseDir, config, globPattern, fileType, fi
45816
46219
  return files;
45817
46220
  }
45818
46221
  try {
45819
- const entries = await fs14.readdir(dir, { withFileTypes: true });
46222
+ const entries = await fs15.readdir(dir, { withFileTypes: true });
45820
46223
  for (const entry of entries) {
45821
- const fullPath = path3.join(dir, entry.name);
46224
+ const fullPath = path2.join(dir, entry.name);
45822
46225
  if (entry.isDirectory()) {
45823
46226
  const isBlocked = config.blockedDirectories.some(
45824
46227
  (blocked) => entry.name === blocked
@@ -45830,7 +46233,7 @@ async function findFilesToSearch(dir, baseDir, config, globPattern, fileType, fi
45830
46233
  if (fileType) {
45831
46234
  const extensions = FILE_TYPE_MAP[fileType.toLowerCase()];
45832
46235
  if (extensions) {
45833
- const ext = path3.extname(entry.name).toLowerCase();
46236
+ const ext = path2.extname(entry.name).toLowerCase();
45834
46237
  if (!extensions.includes(ext)) continue;
45835
46238
  }
45836
46239
  }
@@ -45849,7 +46252,7 @@ async function findFilesToSearch(dir, baseDir, config, globPattern, fileType, fi
45849
46252
  async function searchFile(filePath, regex, contextBefore, contextAfter) {
45850
46253
  const matches = [];
45851
46254
  try {
45852
- const content = await fs14.readFile(filePath, "utf-8");
46255
+ const content = await fs15.readFile(filePath, "utf-8");
45853
46256
  const lines = content.split("\n");
45854
46257
  for (let i = 0; i < lines.length; i++) {
45855
46258
  const line = lines[i] ?? "";
@@ -45990,7 +46393,7 @@ WHEN TO USE:
45990
46393
  };
45991
46394
  }
45992
46395
  const resolvedPath = validation.resolvedPath;
45993
- if (!fs15.existsSync(resolvedPath)) {
46396
+ if (!fs16.existsSync(resolvedPath)) {
45994
46397
  return {
45995
46398
  success: false,
45996
46399
  error: `Path not found: ${searchPath}`
@@ -46006,7 +46409,7 @@ WHEN TO USE:
46006
46409
  };
46007
46410
  }
46008
46411
  try {
46009
- const stats = await fs14.stat(resolvedPath);
46412
+ const stats = await fs15.stat(resolvedPath);
46010
46413
  let filesToSearch;
46011
46414
  if (stats.isFile()) {
46012
46415
  filesToSearch = [resolvedPath];
@@ -46032,7 +46435,7 @@ WHEN TO USE:
46032
46435
  );
46033
46436
  if (matches.length > 0) {
46034
46437
  filesMatched++;
46035
- const relativePath = path3.relative(resolvedPath, file) || file;
46438
+ const relativePath = path2.relative(resolvedPath, file) || file;
46036
46439
  for (const match of matches) {
46037
46440
  match.file = relativePath;
46038
46441
  }
@@ -46094,11 +46497,11 @@ async function listDir(dir, baseDir, config, recursive, filter, maxDepth = 3, cu
46094
46497
  return entries;
46095
46498
  }
46096
46499
  try {
46097
- const dirEntries = await fs14.readdir(dir, { withFileTypes: true });
46500
+ const dirEntries = await fs15.readdir(dir, { withFileTypes: true });
46098
46501
  for (const entry of dirEntries) {
46099
46502
  if (entries.length >= config.maxResults) break;
46100
- const fullPath = path3.join(dir, entry.name);
46101
- const relativePath = path3.relative(baseDir, fullPath);
46503
+ const fullPath = path2.join(dir, entry.name);
46504
+ const relativePath = path2.relative(baseDir, fullPath);
46102
46505
  if (entry.isDirectory() && config.blockedDirectories.includes(entry.name)) {
46103
46506
  continue;
46104
46507
  }
@@ -46112,7 +46515,7 @@ async function listDir(dir, baseDir, config, recursive, filter, maxDepth = 3, cu
46112
46515
  }
46113
46516
  if (filter === "directories" && !isDir) continue;
46114
46517
  try {
46115
- const stats = await fs14.stat(fullPath);
46518
+ const stats = await fs15.stat(fullPath);
46116
46519
  const dirEntry = {
46117
46520
  name: entry.name,
46118
46521
  path: relativePath,
@@ -46208,14 +46611,14 @@ EXAMPLES:
46208
46611
  };
46209
46612
  }
46210
46613
  const resolvedPath = validation.resolvedPath;
46211
- if (!fs15.existsSync(resolvedPath)) {
46614
+ if (!fs16.existsSync(resolvedPath)) {
46212
46615
  return {
46213
46616
  success: false,
46214
46617
  error: `Directory not found: ${path6}`
46215
46618
  };
46216
46619
  }
46217
46620
  try {
46218
- const stats = await fs14.stat(resolvedPath);
46621
+ const stats = await fs15.stat(resolvedPath);
46219
46622
  if (!stats.isDirectory()) {
46220
46623
  return {
46221
46624
  success: false,
@@ -46403,7 +46806,8 @@ EXAMPLES:
46403
46806
  shell: mergedConfig.shell,
46404
46807
  cwd: mergedConfig.workingDirectory,
46405
46808
  env,
46406
- stdio: ["pipe", "pipe", "pipe"]
46809
+ stdio: ["pipe", "pipe", "pipe"],
46810
+ detached: true
46407
46811
  });
46408
46812
  if (run_in_background && mergedConfig.allowBackground) {
46409
46813
  const bgId = generateBackgroundId();
@@ -46430,14 +46834,27 @@ EXAMPLES:
46430
46834
  let stdout = "";
46431
46835
  let stderr = "";
46432
46836
  let killed = false;
46837
+ const killProcessGroup = (signal) => {
46838
+ try {
46839
+ if (childProcess.pid) {
46840
+ process.kill(-childProcess.pid, signal);
46841
+ }
46842
+ } catch {
46843
+ try {
46844
+ childProcess.kill(signal);
46845
+ } catch {
46846
+ }
46847
+ }
46848
+ };
46849
+ const GRACEFUL_KILL_WAIT_MS = 3e3;
46433
46850
  const timeoutId = setTimeout(() => {
46434
46851
  killed = true;
46435
- childProcess.kill("SIGTERM");
46852
+ killProcessGroup("SIGTERM");
46436
46853
  setTimeout(() => {
46437
46854
  if (!childProcess.killed) {
46438
- childProcess.kill("SIGKILL");
46855
+ killProcessGroup("SIGKILL");
46439
46856
  }
46440
- }, 5e3);
46857
+ }, GRACEFUL_KILL_WAIT_MS);
46441
46858
  }, effectiveTimeout);
46442
46859
  childProcess.stdout.on("data", (data) => {
46443
46860
  stdout += data.toString();
@@ -46451,8 +46868,28 @@ EXAMPLES:
46451
46868
  stderr = stderr.slice(-mergedConfig.maxOutputSize);
46452
46869
  }
46453
46870
  });
46454
- childProcess.on("close", (code, signal) => {
46871
+ let resolved = false;
46872
+ const safeResolve = (result) => {
46873
+ if (resolved) return;
46874
+ resolved = true;
46455
46875
  clearTimeout(timeoutId);
46876
+ clearTimeout(hardTimeoutId);
46877
+ resolve4(result);
46878
+ };
46879
+ const HARD_TIMEOUT_GRACE_MS = 5e3;
46880
+ const hardTimeoutId = setTimeout(() => {
46881
+ if (!resolved) {
46882
+ killProcessGroup("SIGKILL");
46883
+ safeResolve({
46884
+ success: false,
46885
+ stdout,
46886
+ stderr,
46887
+ duration: Date.now() - startTime,
46888
+ error: `Command timed out after ${effectiveTimeout}ms (hard timeout: process group did not exit)`
46889
+ });
46890
+ }
46891
+ }, effectiveTimeout + GRACEFUL_KILL_WAIT_MS + HARD_TIMEOUT_GRACE_MS);
46892
+ childProcess.on("close", (code, signal) => {
46456
46893
  const duration = Date.now() - startTime;
46457
46894
  let truncated = false;
46458
46895
  if (stdout.length > mergedConfig.maxOutputSize) {
@@ -46464,7 +46901,7 @@ EXAMPLES:
46464
46901
  truncated = true;
46465
46902
  }
46466
46903
  if (killed) {
46467
- resolve4({
46904
+ safeResolve({
46468
46905
  success: false,
46469
46906
  stdout,
46470
46907
  stderr,
@@ -46475,7 +46912,7 @@ EXAMPLES:
46475
46912
  error: `Command timed out after ${effectiveTimeout}ms`
46476
46913
  });
46477
46914
  } else {
46478
- resolve4({
46915
+ safeResolve({
46479
46916
  success: code === 0,
46480
46917
  stdout,
46481
46918
  stderr,
@@ -46488,8 +46925,7 @@ EXAMPLES:
46488
46925
  }
46489
46926
  });
46490
46927
  childProcess.on("error", (error) => {
46491
- clearTimeout(timeoutId);
46492
- resolve4({
46928
+ safeResolve({
46493
46929
  success: false,
46494
46930
  error: `Failed to execute command: ${error.message}`,
46495
46931
  duration: Date.now() - startTime
@@ -46825,6 +47261,111 @@ The tool returns a result object with:
46825
47261
  }
46826
47262
  };
46827
47263
 
47264
+ // src/tools/web/createWebSearchTool.ts
47265
+ init_Logger();
47266
+ var searchLogger = exports.logger.child({ component: "webSearch" });
47267
+ function createWebSearchTool(connector) {
47268
+ return {
47269
+ definition: {
47270
+ type: "function",
47271
+ function: {
47272
+ name: "web_search",
47273
+ description: `Search the web and get relevant results with snippets.
47274
+
47275
+ RETURNS:
47276
+ An array of search results, each containing:
47277
+ - title: Page title
47278
+ - url: Direct URL to the page
47279
+ - snippet: Short description/excerpt from the page
47280
+ - position: Search ranking position (1, 2, 3...)
47281
+
47282
+ USE CASES:
47283
+ - Find current information on any topic
47284
+ - Research multiple sources
47285
+ - Discover relevant websites
47286
+ - Find URLs to fetch with web_fetch tool
47287
+
47288
+ WORKFLOW PATTERN:
47289
+ 1. Use web_search to find relevant URLs
47290
+ 2. Use web_fetch to get full content from top results
47291
+ 3. Process and summarize the information
47292
+
47293
+ EXAMPLE:
47294
+ {
47295
+ "query": "latest AI developments 2026",
47296
+ "numResults": 5
47297
+ }`,
47298
+ parameters: {
47299
+ type: "object",
47300
+ properties: {
47301
+ query: {
47302
+ type: "string",
47303
+ description: "The search query string. Be specific for better results."
47304
+ },
47305
+ numResults: {
47306
+ type: "number",
47307
+ description: "Number of results to return (default: 10, max: 100)."
47308
+ },
47309
+ country: {
47310
+ type: "string",
47311
+ description: 'Country/region code for localized results (e.g., "us", "gb", "de")'
47312
+ },
47313
+ language: {
47314
+ type: "string",
47315
+ description: 'Language code for results (e.g., "en", "fr", "de")'
47316
+ }
47317
+ },
47318
+ required: ["query"]
47319
+ }
47320
+ },
47321
+ blocking: true,
47322
+ timeout: 15e3
47323
+ },
47324
+ execute: async (args) => {
47325
+ const numResults = args.numResults || 10;
47326
+ searchLogger.debug({ connectorName: connector.name }, "Executing search with connector");
47327
+ try {
47328
+ const searchProvider = SearchProvider.create({ connector: connector.name });
47329
+ const response = await searchProvider.search(args.query, {
47330
+ numResults,
47331
+ country: args.country,
47332
+ language: args.language
47333
+ });
47334
+ if (response.success) {
47335
+ searchLogger.debug({
47336
+ provider: response.provider,
47337
+ count: response.count
47338
+ }, "Search completed successfully");
47339
+ } else {
47340
+ searchLogger.warn({
47341
+ provider: response.provider,
47342
+ error: response.error
47343
+ }, "Search failed");
47344
+ }
47345
+ return {
47346
+ success: response.success,
47347
+ query: response.query,
47348
+ provider: response.provider,
47349
+ results: response.results,
47350
+ count: response.count,
47351
+ error: response.error
47352
+ };
47353
+ } catch (error) {
47354
+ searchLogger.error({ error: error.message, connectorName: connector.name }, "Search threw exception");
47355
+ return {
47356
+ success: false,
47357
+ query: args.query,
47358
+ provider: connector.name,
47359
+ results: [],
47360
+ count: 0,
47361
+ error: error.message || "Unknown error"
47362
+ };
47363
+ }
47364
+ },
47365
+ describeCall: (args) => `"${args.query}"${args.numResults ? ` (${args.numResults} results)` : ""}`
47366
+ };
47367
+ }
47368
+
46828
47369
  // src/tools/web/contentDetector.ts
46829
47370
  function detectContentQuality(html, text, $) {
46830
47371
  const issues = [];
@@ -46899,7 +47440,7 @@ function detectContentQuality(html, text, $) {
46899
47440
  }
46900
47441
  let suggestion;
46901
47442
  if (requiresJS && score < 50) {
46902
- suggestion = "Content quality is low. This appears to be a JavaScript-rendered site. Use the web_fetch_js tool for better results.";
47443
+ suggestion = "Content quality is low. This appears to be a JavaScript-rendered site. Use a scraping service connector for better results.";
46903
47444
  } else if (score < 30) {
46904
47445
  suggestion = "Content extraction failed or page has errors. Check the URL and try again.";
46905
47446
  }
@@ -47008,7 +47549,7 @@ The tool analyzes the fetched content and returns a quality score (0-100):
47008
47549
  - 50-79: Moderate quality, some content extracted
47009
47550
  - 0-49: Low quality, likely needs JavaScript or has errors
47010
47551
 
47011
- If the quality score is low or requiresJS is true, the tool will suggest using 'web_fetch_js' instead.
47552
+ If the quality score is low or requiresJS is true, consider using a scraping service connector for better results.
47012
47553
 
47013
47554
  RETURNS:
47014
47555
  {
@@ -47172,460 +47713,109 @@ With custom user agent:
47172
47713
  }
47173
47714
  };
47174
47715
 
47175
- // src/tools/web/webFetchJS.ts
47176
- var puppeteerModule = null;
47177
- var browserInstance = null;
47178
- async function loadPuppeteer() {
47179
- if (!puppeteerModule) {
47180
- try {
47181
- puppeteerModule = await import('puppeteer');
47182
- } catch (error) {
47183
- throw new Error("Puppeteer not installed");
47184
- }
47185
- }
47186
- return puppeteerModule;
47187
- }
47188
- async function getBrowser() {
47189
- if (!browserInstance) {
47190
- const puppeteer = await loadPuppeteer();
47191
- browserInstance = await puppeteer.launch({
47192
- headless: true,
47193
- args: ["--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage"]
47194
- });
47195
- process.on("exit", async () => {
47196
- if (browserInstance) {
47197
- await browserInstance.close();
47198
- }
47199
- });
47200
- }
47201
- return browserInstance;
47202
- }
47203
- var webFetchJS = {
47204
- definition: {
47205
- type: "function",
47206
- function: {
47207
- name: "web_fetch_js",
47208
- description: `Fetch and extract content from JavaScript-rendered websites using a headless browser (Puppeteer).
47209
-
47210
- USE THIS TOOL WHEN:
47211
- - The web_fetch tool returned a low quality score (<50)
47212
- - The web_fetch tool suggested using JavaScript rendering
47213
- - You know the website is built with React/Vue/Angular/Next.js
47214
- - Content loads dynamically via JavaScript
47215
- - The page requires interaction (though this tool doesn't support interaction yet)
47216
-
47217
- HOW IT WORKS:
47218
- - Launches a headless Chrome browser
47219
- - Navigates to the URL
47220
- - Waits for JavaScript to execute and content to load
47221
- - Extracts the rendered HTML and text content
47222
- - Optionally captures a screenshot
47223
-
47224
- CAPABILITIES:
47225
- - Executes all JavaScript on the page
47226
- - Waits for network to be idle (all resources loaded)
47227
- - Can wait for specific CSS selectors to appear
47228
- - Handles React, Vue, Angular, Next.js, and other SPAs
47229
- - Returns content after full JavaScript execution
47230
-
47231
- LIMITATIONS:
47232
- - Slower than web_fetch (typically 3-10 seconds vs <1 second)
47233
- - Uses more system resources (runs a full browser)
47234
- - May still fail on sites with aggressive bot detection
47235
- - Requires puppeteer to be installed (npm install puppeteer)
47236
-
47237
- PERFORMANCE:
47238
- - First call: Slower (launches browser ~1-2s)
47239
- - Subsequent calls: Faster (reuses browser instance)
47240
-
47241
- RETURNS:
47242
- {
47243
- success: boolean,
47244
- url: string,
47245
- title: string,
47246
- content: string, // Clean markdown (converted via Readability + Turndown)
47247
- screenshot: string, // Base64 PNG screenshot (if requested)
47248
- loadTime: number, // Time taken in milliseconds
47249
- excerpt: string, // Short summary excerpt (if extracted)
47250
- byline: string, // Author info (if extracted)
47251
- wasTruncated: boolean, // True if content was truncated
47252
- error: string // Error message if failed
47253
- }
47254
-
47255
- EXAMPLES:
47256
- Basic usage:
47257
- {
47258
- url: "https://react-app.com/page"
47259
- }
47260
-
47261
- Wait for specific content:
47262
- {
47263
- url: "https://app.com/dashboard",
47264
- waitForSelector: "#main-content", // Wait for this element
47265
- timeout: 20000
47716
+ // src/tools/web/createWebScrapeTool.ts
47717
+ init_Logger();
47718
+ var scrapeLogger = exports.logger.child({ component: "webScrape" });
47719
+ var DEFAULT_MIN_QUALITY = 50;
47720
+ function stripBase64DataUris(content) {
47721
+ if (!content) return content;
47722
+ let cleaned = content.replace(/!\[[^\]]*\]\(data:[^)]+\)/g, "[image removed]");
47723
+ cleaned = cleaned.replace(/url\(['"]?data:[^)]+['"]?\)/gi, "url([data-uri-removed])");
47724
+ cleaned = cleaned.replace(/data:(?:image|font|application)\/[^;]+;base64,[A-Za-z0-9+/=]{100,}/g, "[base64-data-removed]");
47725
+ return cleaned;
47266
47726
  }
47267
-
47268
- With screenshot:
47269
- {
47270
- url: "https://site.com",
47271
- takeScreenshot: true
47272
- }`,
47273
- parameters: {
47274
- type: "object",
47275
- properties: {
47276
- url: {
47277
- type: "string",
47278
- description: "The URL to fetch. Must start with http:// or https://"
47279
- },
47280
- waitForSelector: {
47281
- type: "string",
47282
- description: 'Optional CSS selector to wait for before extracting content. Example: "#main-content" or ".article-body"'
47283
- },
47284
- timeout: {
47285
- type: "number",
47286
- description: "Max wait time in milliseconds (default: 15000)"
47287
- },
47288
- takeScreenshot: {
47289
- type: "boolean",
47290
- description: "Whether to capture a screenshot of the page (default: false). Screenshot returned as base64 PNG."
47291
- }
47292
- },
47293
- required: ["url"]
47294
- }
47295
- },
47296
- blocking: true,
47297
- timeout: 3e4
47298
- // Allow extra time for browser operations
47299
- },
47300
- execute: async (args) => {
47301
- let page = null;
47727
+ function createWebScrapeTool(connector) {
47728
+ async function tryNative(args, startTime, attemptedMethods) {
47729
+ attemptedMethods.push("native");
47730
+ scrapeLogger.debug({ url: args.url }, "Trying native fetch");
47302
47731
  try {
47303
- const browser = await getBrowser();
47304
- page = await browser.newPage();
47305
- await page.setViewport({ width: 1280, height: 800 });
47306
- await page.setUserAgent(
47307
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
47308
- );
47309
- const startTime = Date.now();
47310
- await page.goto(args.url, {
47311
- waitUntil: "networkidle2",
47312
- // Wait until network is mostly idle
47313
- timeout: args.timeout || 15e3
47732
+ const result = await webFetch.execute({
47733
+ url: args.url,
47734
+ timeout: args.timeout || 1e4
47314
47735
  });
47315
- if (args.waitForSelector) {
47316
- await page.waitForSelector(args.waitForSelector, {
47317
- timeout: args.timeout || 15e3
47318
- });
47319
- }
47320
- const html = await page.content();
47321
- const browserTitle = await page.title();
47322
- const loadTime = Date.now() - startTime;
47323
- let screenshot;
47324
- if (args.takeScreenshot) {
47325
- const buffer = await page.screenshot({
47326
- type: "png",
47327
- fullPage: false
47328
- // Just viewport
47329
- });
47330
- screenshot = buffer.toString("base64");
47331
- }
47332
- await page.close();
47333
- const mdResult = await htmlToMarkdown(html, args.url);
47334
- const title = browserTitle || mdResult.title || "Untitled";
47736
+ const cleanContent = stripBase64DataUris(result.content);
47335
47737
  return {
47336
- success: true,
47738
+ success: result.success,
47337
47739
  url: args.url,
47338
- title,
47339
- content: mdResult.markdown,
47340
- screenshot,
47341
- loadTime,
47342
- excerpt: mdResult.excerpt,
47343
- byline: mdResult.byline,
47344
- wasReadabilityUsed: mdResult.wasReadabilityUsed,
47345
- wasTruncated: mdResult.wasTruncated
47740
+ finalUrl: args.url,
47741
+ method: "native",
47742
+ title: result.title,
47743
+ content: cleanContent,
47744
+ qualityScore: result.qualityScore,
47745
+ durationMs: Date.now() - startTime,
47746
+ attemptedMethods,
47747
+ error: result.error
47346
47748
  };
47347
47749
  } catch (error) {
47348
- if (page) {
47349
- try {
47350
- await page.close();
47351
- } catch {
47352
- }
47353
- }
47354
- if (error.message === "Puppeteer not installed") {
47355
- return {
47356
- success: false,
47357
- url: args.url,
47358
- title: "",
47359
- content: "",
47360
- loadTime: 0,
47361
- error: "Puppeteer is not installed",
47362
- suggestion: "Install Puppeteer with: npm install puppeteer (note: downloads ~50MB Chrome binary)"
47363
- };
47364
- }
47365
47750
  return {
47366
47751
  success: false,
47367
47752
  url: args.url,
47753
+ method: "native",
47368
47754
  title: "",
47369
47755
  content: "",
47370
- loadTime: 0,
47756
+ durationMs: Date.now() - startTime,
47757
+ attemptedMethods,
47371
47758
  error: error.message
47372
47759
  };
47373
47760
  }
47374
47761
  }
47375
- };
47376
-
47377
- // src/tools/web/webSearch.ts
47378
- init_Logger();
47379
-
47380
- // src/tools/web/searchProviders/serper.ts
47381
- async function searchWithSerper(query, numResults, apiKey) {
47382
- const response = await fetch("https://google.serper.dev/search", {
47383
- method: "POST",
47384
- headers: {
47385
- "X-API-KEY": apiKey,
47386
- "Content-Type": "application/json"
47387
- },
47388
- body: JSON.stringify({
47389
- q: query,
47390
- num: numResults
47391
- })
47392
- });
47393
- if (!response.ok) {
47394
- throw new Error(`Serper API error: ${response.status} ${response.statusText}`);
47395
- }
47396
- const data = await response.json();
47397
- if (!data.organic || !Array.isArray(data.organic)) {
47398
- throw new Error("Invalid response from Serper API");
47399
- }
47400
- return data.organic.slice(0, numResults).map((result, index) => ({
47401
- title: result.title || "Untitled",
47402
- url: result.link || "",
47403
- snippet: result.snippet || "",
47404
- position: index + 1
47405
- }));
47406
- }
47407
-
47408
- // src/tools/web/searchProviders/brave.ts
47409
- async function searchWithBrave(query, numResults, apiKey) {
47410
- const url2 = `https://api.search.brave.com/res/v1/web/search?q=${encodeURIComponent(query)}&count=${numResults}`;
47411
- const response = await fetch(url2, {
47412
- headers: {
47413
- "X-Subscription-Token": apiKey,
47414
- Accept: "application/json"
47415
- }
47416
- });
47417
- if (!response.ok) {
47418
- throw new Error(`Brave API error: ${response.status} ${response.statusText}`);
47419
- }
47420
- const data = await response.json();
47421
- if (!data.web?.results || !Array.isArray(data.web.results)) {
47422
- throw new Error("Invalid response from Brave API");
47423
- }
47424
- return data.web.results.slice(0, numResults).map((result, index) => ({
47425
- title: result.title || "Untitled",
47426
- url: result.url || "",
47427
- snippet: result.description || "",
47428
- position: index + 1
47429
- }));
47430
- }
47431
-
47432
- // src/tools/web/searchProviders/tavily.ts
47433
- async function searchWithTavily(query, numResults, apiKey) {
47434
- const response = await fetch("https://api.tavily.com/search", {
47435
- method: "POST",
47436
- headers: {
47437
- "Content-Type": "application/json"
47438
- },
47439
- body: JSON.stringify({
47440
- api_key: apiKey,
47441
- query,
47442
- max_results: numResults,
47443
- search_depth: "basic",
47444
- // 'basic' or 'advanced'
47445
- include_answer: false,
47446
- include_raw_content: false
47447
- })
47448
- });
47449
- if (!response.ok) {
47450
- throw new Error(`Tavily API error: ${response.status} ${response.statusText}`);
47451
- }
47452
- const data = await response.json();
47453
- if (!data.results || !Array.isArray(data.results)) {
47454
- throw new Error("Invalid response from Tavily API");
47455
- }
47456
- return data.results.slice(0, numResults).map((result, index) => ({
47457
- title: result.title || "Untitled",
47458
- url: result.url || "",
47459
- snippet: result.content || "",
47460
- position: index + 1
47461
- }));
47462
- }
47463
-
47464
- // src/tools/web/webSearch.ts
47465
- var searchLogger = exports.logger.child({ component: "webSearch" });
47466
- var SEARCH_SERVICE_TYPES = ["serper", "brave-search", "tavily", "rapidapi-search"];
47467
- var webSearch = {
47468
- definition: {
47469
- type: "function",
47470
- function: {
47471
- name: "web_search",
47472
- description: `Search the web and get relevant results with snippets.
47473
-
47474
- RETURNS:
47475
- An array of search results, each containing:
47476
- - title: Page title
47477
- - url: Direct URL to the page
47478
- - snippet: Short description/excerpt from the page
47479
- - position: Search ranking position (1, 2, 3...)
47480
-
47481
- USE CASES:
47482
- - Find current information on any topic
47483
- - Research multiple sources
47484
- - Discover relevant websites
47485
- - Find URLs to fetch with web_fetch tool
47486
-
47487
- WORKFLOW PATTERN:
47488
- 1. Use web_search to find relevant URLs
47489
- 2. Use web_fetch to get full content from top results
47490
- 3. Process and summarize the information
47491
-
47492
- EXAMPLE:
47493
- {
47494
- "query": "latest AI developments 2026",
47495
- "numResults": 5
47496
- }`,
47497
- parameters: {
47498
- type: "object",
47499
- properties: {
47500
- query: {
47501
- type: "string",
47502
- description: "The search query string. Be specific for better results."
47503
- },
47504
- numResults: {
47505
- type: "number",
47506
- description: "Number of results to return (default: 10, max: 100)."
47507
- },
47508
- country: {
47509
- type: "string",
47510
- description: 'Country/region code for localized results (e.g., "us", "gb", "de")'
47511
- },
47512
- language: {
47513
- type: "string",
47514
- description: 'Language code for results (e.g., "en", "fr", "de")'
47515
- }
47516
- },
47517
- required: ["query"]
47518
- }
47519
- },
47520
- blocking: true,
47521
- timeout: 15e3
47522
- },
47523
- execute: async (args) => {
47524
- const numResults = args.numResults || 10;
47525
- const connector = findConnectorByServiceTypes(SEARCH_SERVICE_TYPES);
47526
- if (connector) {
47527
- return await executeWithConnector(connector.name, args, numResults);
47528
- }
47529
- return await executeWithEnvVar(args, numResults);
47530
- },
47531
- describeCall: (args) => `"${args.query}"${args.numResults ? ` (${args.numResults} results)` : ""}`
47532
- };
47533
- async function executeWithConnector(connectorName, args, numResults) {
47534
- searchLogger.debug({ connectorName }, "Executing search with connector");
47535
- try {
47536
- const searchProvider = SearchProvider.create({ connector: connectorName });
47537
- const response = await searchProvider.search(args.query, {
47538
- numResults,
47539
- country: args.country,
47540
- language: args.language
47541
- });
47542
- if (response.success) {
47543
- searchLogger.debug({
47544
- provider: response.provider,
47545
- count: response.count
47546
- }, "Search completed successfully");
47547
- } else {
47548
- searchLogger.warn({
47549
- provider: response.provider,
47550
- error: response.error
47551
- }, "Search failed");
47552
- }
47553
- return {
47554
- success: response.success,
47555
- query: response.query,
47556
- provider: response.provider,
47557
- results: response.results,
47558
- count: response.count,
47559
- error: response.error
47560
- };
47561
- } catch (error) {
47562
- searchLogger.error({ error: error.message, connectorName }, "Search threw exception");
47563
- return {
47564
- success: false,
47565
- query: args.query,
47566
- provider: connectorName,
47567
- results: [],
47568
- count: 0,
47569
- error: error.message || "Unknown error"
47570
- };
47571
- }
47572
- }
47573
- async function executeWithEnvVar(args, numResults) {
47574
- const providers = [
47575
- { name: "serper", key: process.env.SERPER_API_KEY, fn: searchWithSerper },
47576
- { name: "brave", key: process.env.BRAVE_API_KEY, fn: searchWithBrave },
47577
- { name: "tavily", key: process.env.TAVILY_API_KEY, fn: searchWithTavily }
47578
- ];
47579
- for (const provider of providers) {
47580
- if (provider.key) {
47581
- searchLogger.debug({ provider: provider.name }, "Using environment variable fallback");
47582
- try {
47583
- const results = await provider.fn(args.query, numResults, provider.key);
47584
- return {
47585
- success: true,
47586
- query: args.query,
47587
- provider: provider.name,
47588
- results,
47589
- count: results.length
47590
- };
47591
- } catch (error) {
47592
- searchLogger.warn({ provider: provider.name, error: error.message }, "Provider failed, trying next");
47593
- }
47762
+ async function tryAPI(args, startTime, attemptedMethods) {
47763
+ attemptedMethods.push(`api:${connector.name}`);
47764
+ scrapeLogger.debug({ url: args.url, connectorName: connector.name }, "Trying external API");
47765
+ try {
47766
+ const provider = ScrapeProvider.create({ connector: connector.name });
47767
+ const options = {
47768
+ timeout: args.timeout,
47769
+ waitForSelector: args.waitForSelector,
47770
+ includeHtml: args.includeHtml,
47771
+ includeMarkdown: args.includeMarkdown,
47772
+ includeLinks: args.includeLinks
47773
+ };
47774
+ const result = await provider.scrape(args.url, options);
47775
+ const rawContent = result.result?.content || "";
47776
+ const rawMarkdown = result.result?.markdown;
47777
+ const cleanContent = stripBase64DataUris(rawContent);
47778
+ const cleanMarkdown = rawMarkdown ? stripBase64DataUris(rawMarkdown) : void 0;
47779
+ const isDuplicate = !!cleanMarkdown && cleanContent === cleanMarkdown;
47780
+ return {
47781
+ success: result.success,
47782
+ url: args.url,
47783
+ finalUrl: result.finalUrl,
47784
+ method: result.provider,
47785
+ title: result.result?.title || "",
47786
+ content: cleanContent,
47787
+ html: result.result?.html,
47788
+ markdown: isDuplicate ? void 0 : cleanMarkdown,
47789
+ metadata: result.result?.metadata,
47790
+ links: result.result?.links,
47791
+ qualityScore: result.success ? 90 : 0,
47792
+ durationMs: Date.now() - startTime,
47793
+ attemptedMethods,
47794
+ error: result.error
47795
+ };
47796
+ } catch (error) {
47797
+ return {
47798
+ success: false,
47799
+ url: args.url,
47800
+ method: "api",
47801
+ title: "",
47802
+ content: "",
47803
+ durationMs: Date.now() - startTime,
47804
+ attemptedMethods,
47805
+ error: error.message
47806
+ };
47594
47807
  }
47595
47808
  }
47596
47809
  return {
47597
- success: false,
47598
- query: args.query,
47599
- provider: "none",
47600
- results: [],
47601
- count: 0,
47602
- error: "No search provider configured. Set up a search connector (serper, brave-search, tavily) or set SERPER_API_KEY, BRAVE_API_KEY, or TAVILY_API_KEY environment variable."
47603
- };
47604
- }
47605
-
47606
- // src/tools/web/webScrape.ts
47607
- init_Logger();
47608
- var scrapeLogger = exports.logger.child({ component: "webScrape" });
47609
- function stripBase64DataUris(content) {
47610
- if (!content) return content;
47611
- let cleaned = content.replace(/!\[[^\]]*\]\(data:[^)]+\)/g, "[image removed]");
47612
- cleaned = cleaned.replace(/url\(['"]?data:[^)]+['"]?\)/gi, "url([data-uri-removed])");
47613
- cleaned = cleaned.replace(/data:(?:image|font|application)\/[^;]+;base64,[A-Za-z0-9+/=]{100,}/g, "[base64-data-removed]");
47614
- return cleaned;
47615
- }
47616
- var SCRAPE_SERVICE_TYPES = ["zenrows", "jina-reader", "firecrawl", "scrapingbee"];
47617
- var DEFAULT_MIN_QUALITY = 50;
47618
- var webScrape = {
47619
- definition: {
47620
- type: "function",
47621
- function: {
47622
- name: "web_scrape",
47623
- description: `Scrape any URL with automatic fallback - guaranteed to work on most sites.
47810
+ definition: {
47811
+ type: "function",
47812
+ function: {
47813
+ name: "web_scrape",
47814
+ description: `Scrape any URL with automatic fallback - guaranteed to work on most sites.
47624
47815
 
47625
47816
  Automatically tries multiple methods in sequence:
47626
47817
  1. Native fetch - Fast (~1s), works for blogs/docs/articles
47627
- 2. JS rendering - Handles React/Vue/Angular SPAs
47628
- 3. External API - Handles bot protection, CAPTCHAs (if configured)
47818
+ 2. External API - Handles bot protection, CAPTCHAs, SPAs (if configured)
47629
47819
 
47630
47820
  RETURNS:
47631
47821
  {
@@ -47660,46 +47850,64 @@ For JS-heavy sites:
47660
47850
  "url": "https://spa-app.com",
47661
47851
  "waitForSelector": ".main-content"
47662
47852
  }`,
47663
- parameters: {
47664
- type: "object",
47665
- properties: {
47666
- url: {
47667
- type: "string",
47668
- description: "URL to scrape. Must start with http:// or https://"
47669
- },
47670
- timeout: {
47671
- type: "number",
47672
- description: "Timeout in milliseconds (default: 30000)"
47673
- },
47674
- includeHtml: {
47675
- type: "boolean",
47676
- description: "Include raw HTML in response (default: false)"
47677
- },
47678
- includeMarkdown: {
47679
- type: "boolean",
47680
- description: "Include markdown conversion (default: false)"
47681
- },
47682
- includeLinks: {
47683
- type: "boolean",
47684
- description: "Extract and include links (default: false)"
47853
+ parameters: {
47854
+ type: "object",
47855
+ properties: {
47856
+ url: {
47857
+ type: "string",
47858
+ description: "URL to scrape. Must start with http:// or https://"
47859
+ },
47860
+ timeout: {
47861
+ type: "number",
47862
+ description: "Timeout in milliseconds (default: 30000)"
47863
+ },
47864
+ includeHtml: {
47865
+ type: "boolean",
47866
+ description: "Include raw HTML in response (default: false)"
47867
+ },
47868
+ includeMarkdown: {
47869
+ type: "boolean",
47870
+ description: "Include markdown conversion (default: false)"
47871
+ },
47872
+ includeLinks: {
47873
+ type: "boolean",
47874
+ description: "Extract and include links (default: false)"
47875
+ },
47876
+ waitForSelector: {
47877
+ type: "string",
47878
+ description: "CSS selector to wait for before scraping (for JS-heavy sites)"
47879
+ }
47685
47880
  },
47686
- waitForSelector: {
47687
- type: "string",
47688
- description: "CSS selector to wait for before scraping (for JS-heavy sites)"
47689
- }
47690
- },
47691
- required: ["url"]
47692
- }
47881
+ required: ["url"]
47882
+ }
47883
+ },
47884
+ blocking: true,
47885
+ timeout: 6e4
47693
47886
  },
47694
- blocking: true,
47695
- timeout: 6e4
47696
- },
47697
- execute: async (args) => {
47698
- const startTime = Date.now();
47699
- const attemptedMethods = [];
47700
- try {
47701
- new URL(args.url);
47702
- } catch {
47887
+ execute: async (args) => {
47888
+ const startTime = Date.now();
47889
+ const attemptedMethods = [];
47890
+ try {
47891
+ new URL(args.url);
47892
+ } catch {
47893
+ return {
47894
+ success: false,
47895
+ url: args.url,
47896
+ method: "none",
47897
+ title: "",
47898
+ content: "",
47899
+ durationMs: Date.now() - startTime,
47900
+ attemptedMethods: [],
47901
+ error: "Invalid URL format"
47902
+ };
47903
+ }
47904
+ const native = await tryNative(args, startTime, attemptedMethods);
47905
+ if (native.success && (native.qualityScore ?? 0) >= DEFAULT_MIN_QUALITY) {
47906
+ return native;
47907
+ }
47908
+ const api = await tryAPI(args, startTime, attemptedMethods);
47909
+ if (api.success) return api;
47910
+ if (native.success) return native;
47703
47911
  return {
47704
47912
  success: false,
47705
47913
  url: args.url,
@@ -47707,230 +47915,119 @@ For JS-heavy sites:
47707
47915
  title: "",
47708
47916
  content: "",
47709
47917
  durationMs: Date.now() - startTime,
47710
- attemptedMethods: [],
47711
- error: "Invalid URL format"
47918
+ attemptedMethods,
47919
+ error: "All scraping methods failed. Site may have bot protection."
47712
47920
  };
47713
- }
47714
- const native = await tryNative(args, startTime, attemptedMethods);
47715
- if (native.success && (native.qualityScore ?? 0) >= DEFAULT_MIN_QUALITY) {
47716
- return native;
47717
- }
47718
- const js = await tryJS(args, startTime, attemptedMethods);
47719
- if (js.success && (js.qualityScore ?? 0) >= DEFAULT_MIN_QUALITY) {
47720
- return js;
47721
- }
47722
- const connector = findConnectorByServiceTypes(SCRAPE_SERVICE_TYPES);
47723
- if (connector) {
47724
- const api = await tryAPI(connector.name, args, startTime, attemptedMethods);
47725
- if (api.success) return api;
47726
- }
47727
- if (js.success) return js;
47728
- if (native.success) return native;
47729
- return {
47730
- success: false,
47731
- url: args.url,
47732
- method: "none",
47733
- title: "",
47734
- content: "",
47735
- durationMs: Date.now() - startTime,
47736
- attemptedMethods,
47737
- error: "All scraping methods failed. Site may have bot protection."
47738
- };
47739
- },
47740
- describeCall: (args) => args.url
47741
- };
47742
- async function tryNative(args, startTime, attemptedMethods) {
47743
- attemptedMethods.push("native");
47744
- scrapeLogger.debug({ url: args.url }, "Trying native fetch");
47745
- try {
47746
- const result = await webFetch.execute({
47747
- url: args.url,
47748
- timeout: args.timeout || 1e4
47749
- });
47750
- const cleanContent = stripBase64DataUris(result.content);
47751
- return {
47752
- success: result.success,
47753
- url: args.url,
47754
- finalUrl: args.url,
47755
- method: "native",
47756
- title: result.title,
47757
- content: cleanContent,
47758
- // Note: raw HTML not available with native method (returns markdown instead)
47759
- markdown: args.includeMarkdown ? cleanContent : void 0,
47760
- qualityScore: result.qualityScore,
47761
- durationMs: Date.now() - startTime,
47762
- attemptedMethods,
47763
- error: result.error
47764
- };
47765
- } catch (error) {
47766
- return {
47767
- success: false,
47768
- url: args.url,
47769
- method: "native",
47770
- title: "",
47771
- content: "",
47772
- durationMs: Date.now() - startTime,
47773
- attemptedMethods,
47774
- error: error.message
47775
- };
47776
- }
47921
+ },
47922
+ describeCall: (args) => args.url
47923
+ };
47777
47924
  }
47778
- async function tryJS(args, startTime, attemptedMethods) {
47779
- attemptedMethods.push("js");
47780
- scrapeLogger.debug({ url: args.url }, "Trying JS rendering");
47781
- try {
47782
- const result = await webFetchJS.execute({
47783
- url: args.url,
47784
- timeout: args.timeout || 15e3,
47785
- waitForSelector: args.waitForSelector
47786
- });
47787
- const cleanContent = stripBase64DataUris(result.content);
47788
- return {
47789
- success: result.success,
47790
- url: args.url,
47791
- finalUrl: args.url,
47792
- method: "js",
47793
- title: result.title,
47794
- content: cleanContent,
47795
- // Note: raw HTML not available with JS method (returns markdown instead)
47796
- markdown: args.includeMarkdown ? cleanContent : void 0,
47797
- qualityScore: result.success ? 80 : 0,
47798
- durationMs: Date.now() - startTime,
47799
- attemptedMethods,
47800
- error: result.error
47801
- };
47802
- } catch (error) {
47803
- return {
47804
- success: false,
47805
- url: args.url,
47806
- method: "js",
47807
- title: "",
47808
- content: "",
47809
- durationMs: Date.now() - startTime,
47810
- attemptedMethods,
47811
- error: error.message
47812
- };
47925
+
47926
+ // src/tools/web/register.ts
47927
+ var SEARCH_SERVICE_TYPES = ["serper", "brave-search", "tavily", "rapidapi-search"];
47928
+ var SCRAPE_SERVICE_TYPES = ["zenrows", "jina-reader", "firecrawl", "scrapingbee"];
47929
+ function registerWebTools() {
47930
+ for (const st of SEARCH_SERVICE_TYPES) {
47931
+ ConnectorTools.registerService(st, (connector) => [
47932
+ createWebSearchTool(connector)
47933
+ ]);
47813
47934
  }
47814
- }
47815
- async function tryAPI(connectorName, args, startTime, attemptedMethods) {
47816
- attemptedMethods.push(`api:${connectorName}`);
47817
- scrapeLogger.debug({ url: args.url, connectorName }, "Trying external API");
47818
- try {
47819
- const provider = ScrapeProvider.create({ connector: connectorName });
47820
- const options = {
47821
- timeout: args.timeout,
47822
- waitForSelector: args.waitForSelector,
47823
- includeHtml: args.includeHtml,
47824
- includeMarkdown: args.includeMarkdown,
47825
- includeLinks: args.includeLinks
47826
- };
47827
- const result = await provider.scrape(args.url, options);
47828
- const cleanContent = stripBase64DataUris(result.result?.content || "");
47829
- const cleanMarkdown = result.result?.markdown ? stripBase64DataUris(result.result.markdown) : void 0;
47830
- return {
47831
- success: result.success,
47832
- url: args.url,
47833
- finalUrl: result.finalUrl,
47834
- method: result.provider,
47835
- title: result.result?.title || "",
47836
- content: cleanContent,
47837
- html: result.result?.html,
47838
- // Keep raw HTML as-is (only used if explicitly requested)
47839
- markdown: cleanMarkdown,
47840
- metadata: result.result?.metadata,
47841
- links: result.result?.links,
47842
- qualityScore: result.success ? 90 : 0,
47843
- durationMs: Date.now() - startTime,
47844
- attemptedMethods,
47845
- error: result.error
47846
- };
47847
- } catch (error) {
47848
- return {
47849
- success: false,
47850
- url: args.url,
47851
- method: "api",
47852
- title: "",
47853
- content: "",
47854
- durationMs: Date.now() - startTime,
47855
- attemptedMethods,
47856
- error: error.message
47857
- };
47935
+ for (const st of SCRAPE_SERVICE_TYPES) {
47936
+ ConnectorTools.registerService(st, (connector) => [
47937
+ createWebScrapeTool(connector)
47938
+ ]);
47858
47939
  }
47859
47940
  }
47860
47941
 
47942
+ // src/tools/web/index.ts
47943
+ registerWebTools();
47944
+
47861
47945
  // src/tools/code/executeJavaScript.ts
47862
47946
  init_Connector();
47863
- function generateDescription() {
47864
- const connectors = exports.Connector.listAll();
47865
- const connectorList = connectors.length > 0 ? connectors.map((c) => {
47866
- const authType = c.config.auth?.type || "none";
47867
- return ` \u2022 "${c.name}": ${c.displayName}
47868
- ${c.config.description || "No description"}
47869
- Base URL: ${c.baseURL}
47870
- Auth: ${authType}`;
47871
- }).join("\n\n") : " No connectors registered.";
47872
- return `Execute JavaScript code in a secure sandbox with authenticated API access.
47873
-
47874
- AVAILABLE APIS:
47875
-
47876
- 1. authenticatedFetch(url, options, connectorName, userId?)
47877
- Makes authenticated API calls using the connector's configured auth scheme.
47878
- Auth headers are added automatically - DO NOT set Authorization header.
47947
+ var DEFAULT_TIMEOUT = 1e4;
47948
+ var DEFAULT_MAX_TIMEOUT = 3e4;
47949
+ function formatConnectorEntry(c) {
47950
+ const parts = [];
47951
+ const serviceOrVendor = c.serviceType ?? c.vendor ?? void 0;
47952
+ if (serviceOrVendor) parts.push(`Service: ${serviceOrVendor}`);
47953
+ if (c.config.description) parts.push(c.config.description);
47954
+ if (c.baseURL) parts.push(`URL: ${c.baseURL}`);
47955
+ const details = parts.map((p) => ` ${p}`).join("\n");
47956
+ return ` \u2022 "${c.name}" (${c.displayName})
47957
+ ${details}`;
47958
+ }
47959
+ function generateDescription(context, maxTimeout) {
47960
+ const registry = context?.connectorRegistry ?? exports.Connector.asRegistry();
47961
+ const connectors = registry.listAll();
47962
+ const connectorList = connectors.length > 0 ? connectors.map(formatConnectorEntry).join("\n\n") : " No connectors registered.";
47963
+ const timeoutSec = Math.round(maxTimeout / 1e3);
47964
+ return `Execute JavaScript code in a secure sandbox with authenticated API access to external services.
47965
+
47966
+ Use this tool when you need to:
47967
+ - Call external APIs (GitHub, Slack, Stripe, etc.) using registered connectors
47968
+ - Process, transform, or compute data that requires programmatic logic
47969
+ - Chain multiple API calls or perform complex data manipulation
47970
+ - Do anything that plain text generation cannot accomplish
47971
+
47972
+ SANDBOX API:
47973
+
47974
+ 1. authenticatedFetch(url, options, connectorName)
47975
+ Makes authenticated HTTP requests using the connector's credentials.
47976
+ The current user's identity (userId) is automatically included \u2014 no need to pass it.
47977
+ Auth headers are added automatically \u2014 DO NOT set Authorization header manually.
47879
47978
 
47880
47979
  Parameters:
47881
- \u2022 url: Full URL or relative path (uses connector's baseURL)
47980
+ \u2022 url: Full URL or path relative to the connector's base URL
47882
47981
  - Full: "https://api.github.com/user/repos"
47883
- - Relative: "/user/repos" (appended to connector's baseURL)
47884
- \u2022 options: Standard fetch options { method, body, headers }
47885
- \u2022 connectorName: One of the registered connectors below
47886
- \u2022 userId: (optional) For multi-tenant apps with per-user tokens
47982
+ - Relative: "/user/repos" (resolved against connector's base URL)
47983
+ \u2022 options: Standard fetch options { method, headers, body }
47984
+ - For POST/PUT: set body to JSON.stringify(data) and headers to { 'Content-Type': 'application/json' }
47985
+ \u2022 connectorName: Name of a registered connector (see list below)
47887
47986
 
47888
47987
  Returns: Promise<Response>
47889
- \u2022 response.ok - true if status 200-299
47890
- \u2022 response.status - HTTP status code
47891
- \u2022 response.json() - parse JSON body
47892
- \u2022 response.text() - get text body
47988
+ \u2022 response.ok \u2014 true if status 200-299
47989
+ \u2022 response.status \u2014 HTTP status code
47990
+ \u2022 await response.json() \u2014 parse JSON body
47991
+ \u2022 await response.text() \u2014 get text body
47893
47992
 
47894
- Auth Schemes (handled automatically per connector):
47895
- \u2022 Bearer tokens (GitHub, Slack, Stripe)
47896
- \u2022 Bot tokens (Discord)
47897
- \u2022 Basic auth (Twilio, Zendesk)
47898
- \u2022 Custom headers (Shopify uses X-Shopify-Access-Token)
47993
+ 2. fetch(url, options) \u2014 Standard fetch without authentication
47899
47994
 
47900
- 2. connectors.list() - List available connector names
47901
- 3. connectors.get(name) - Get connector info { displayName, description, baseURL }
47902
- 4. fetch(url, options) - Standard fetch (no auth)
47995
+ 3. connectors.list() \u2014 Array of available connector names
47996
+ 4. connectors.get(name) \u2014 Connector info: { displayName, description, baseURL, serviceType }
47903
47997
 
47904
- INPUT/OUTPUT:
47905
- \u2022 input - data passed to your code via the "input" parameter
47906
- \u2022 output - SET THIS variable to return your result
47998
+ VARIABLES:
47999
+ \u2022 input \u2014 data passed via the "input" parameter (default: {})
48000
+ \u2022 output \u2014 SET THIS to return your result to the caller
47907
48001
 
47908
- UTILITIES: console.log/error/warn, Buffer, JSON, Math, Date, Promise
48002
+ GLOBALS: console.log/error/warn, JSON, Math, Date, Buffer, Promise, Array, Object, String, Number, Boolean, setTimeout, setInterval, URL, URLSearchParams, RegExp, Map, Set, Error, TextEncoder, TextDecoder
47909
48003
 
47910
48004
  REGISTERED CONNECTORS:
47911
48005
  ${connectorList}
47912
48006
 
47913
- EXAMPLE:
47914
- (async () => {
47915
- const response = await authenticatedFetch(
47916
- '/user/repos',
47917
- { method: 'GET' },
47918
- 'github'
47919
- );
48007
+ EXAMPLES:
47920
48008
 
47921
- if (!response.ok) {
47922
- throw new Error(\`API error: \${response.status}\`);
47923
- }
48009
+ // GET request
48010
+ const resp = await authenticatedFetch('/user/repos', { method: 'GET' }, 'github');
48011
+ const repos = await resp.json();
48012
+ output = repos.map(r => r.full_name);
47924
48013
 
47925
- const repos = await response.json();
47926
- console.log(\`Found \${repos.length} repositories\`);
48014
+ // POST request with JSON body
48015
+ const resp = await authenticatedFetch('/chat.postMessage', {
48016
+ method: 'POST',
48017
+ headers: { 'Content-Type': 'application/json' },
48018
+ body: JSON.stringify({ channel: '#general', text: 'Hello!' })
48019
+ }, 'slack');
48020
+ output = await resp.json();
47927
48021
 
47928
- output = repos;
47929
- })();
48022
+ // Data processing (no API needed)
48023
+ const items = input.data;
48024
+ output = items.filter(i => i.score > 0.8).sort((a, b) => b.score - a.score);
47930
48025
 
47931
- SECURITY: 10s timeout, no file system, no require/import.`;
48026
+ LIMITS: ${timeoutSec}s max timeout, no file system access, no require/import.`;
47932
48027
  }
47933
- function createExecuteJavaScriptTool() {
48028
+ function createExecuteJavaScriptTool(options) {
48029
+ const maxTimeout = options?.maxTimeout ?? DEFAULT_MAX_TIMEOUT;
48030
+ const defaultTimeout = options?.defaultTimeout ?? DEFAULT_TIMEOUT;
47934
48031
  return {
47935
48032
  definition: {
47936
48033
  type: "function",
@@ -47943,32 +48040,40 @@ function createExecuteJavaScriptTool() {
47943
48040
  properties: {
47944
48041
  code: {
47945
48042
  type: "string",
47946
- description: 'JavaScript code to execute. MUST set the "output" variable. Wrap in async IIFE for async operations.'
48043
+ description: 'JavaScript code to execute. Set the "output" variable with your result. Code is auto-wrapped in async IIFE \u2014 you can use await directly. For explicit async control, wrap in (async () => { ... })().'
47947
48044
  },
47948
48045
  input: {
47949
- description: 'Optional input data available as "input" variable in your code'
48046
+ description: 'Optional data available as the "input" variable in your code. Can be any JSON value.'
47950
48047
  },
47951
48048
  timeout: {
47952
48049
  type: "number",
47953
- description: "Execution timeout in milliseconds (default: 10000, max: 30000)"
48050
+ description: `Execution timeout in milliseconds. Default: ${defaultTimeout}ms, max: ${maxTimeout}ms. Increase for slow API calls or multiple sequential requests.`
47954
48051
  }
47955
48052
  },
47956
48053
  required: ["code"]
47957
48054
  }
47958
48055
  },
47959
48056
  blocking: true,
47960
- timeout: 35e3
47961
- // Tool timeout (slightly more than max code timeout)
48057
+ timeout: maxTimeout + 5e3
48058
+ // Tool-level timeout slightly above max code timeout
47962
48059
  },
47963
- // Dynamic description - evaluated each time tool definitions are sent to LLM
47964
- // This ensures the connector list is always current
47965
- descriptionFactory: generateDescription,
47966
- execute: async (args) => {
48060
+ // Dynamic description regenerated each time tool definitions are sent to LLM.
48061
+ // Receives ToolContext so connector list is scoped to current userId.
48062
+ descriptionFactory: (context) => generateDescription(context, maxTimeout),
48063
+ execute: async (args, context) => {
47967
48064
  const logs = [];
47968
48065
  const startTime = Date.now();
47969
48066
  try {
47970
- const timeout = Math.min(args.timeout || 1e4, 3e4);
47971
- const result = await executeInVM(args.code, args.input, timeout, logs);
48067
+ const timeout = Math.min(Math.max(args.timeout || defaultTimeout, 0), maxTimeout);
48068
+ const registry = context?.connectorRegistry ?? exports.Connector.asRegistry();
48069
+ const result = await executeInVM(
48070
+ args.code,
48071
+ args.input,
48072
+ timeout,
48073
+ logs,
48074
+ context?.userId,
48075
+ registry
48076
+ );
47972
48077
  return {
47973
48078
  success: true,
47974
48079
  result,
@@ -47988,31 +48093,36 @@ function createExecuteJavaScriptTool() {
47988
48093
  };
47989
48094
  }
47990
48095
  var executeJavaScript = createExecuteJavaScriptTool();
47991
- async function executeInVM(code, input, timeout, logs) {
48096
+ async function executeInVM(code, input, timeout, logs, userId, registry) {
47992
48097
  const sandbox = {
47993
48098
  // Input/output
47994
- input: input || {},
48099
+ input: input ?? {},
47995
48100
  output: null,
47996
- // Console (captured)
48101
+ // Console (captured) — stringify objects for readable logs
47997
48102
  console: {
47998
- log: (...args) => logs.push(args.map((a) => String(a)).join(" ")),
47999
- error: (...args) => logs.push("ERROR: " + args.map((a) => String(a)).join(" ")),
48000
- warn: (...args) => logs.push("WARN: " + args.map((a) => String(a)).join(" "))
48103
+ log: (...args) => logs.push(args.map((a) => typeof a === "object" ? JSON.stringify(a) : String(a)).join(" ")),
48104
+ error: (...args) => logs.push("ERROR: " + args.map((a) => typeof a === "object" ? JSON.stringify(a) : String(a)).join(" ")),
48105
+ warn: (...args) => logs.push("WARN: " + args.map((a) => typeof a === "object" ? JSON.stringify(a) : String(a)).join(" "))
48106
+ },
48107
+ // Authenticated fetch — userId auto-injected from ToolContext.
48108
+ // Only connectors visible in the scoped registry are accessible.
48109
+ authenticatedFetch: (url2, options, connectorName) => {
48110
+ registry.get(connectorName);
48111
+ return authenticatedFetch(url2, options, connectorName, userId);
48001
48112
  },
48002
- // Authenticated fetch
48003
- authenticatedFetch,
48004
- // Standard fetch
48113
+ // Standard fetch (no auth)
48005
48114
  fetch: globalThis.fetch,
48006
- // Connector info
48115
+ // Connector info (userId-scoped)
48007
48116
  connectors: {
48008
- list: () => exports.Connector.list(),
48117
+ list: () => registry.list(),
48009
48118
  get: (name) => {
48010
48119
  try {
48011
- const connector = exports.Connector.get(name);
48120
+ const connector = registry.get(name);
48012
48121
  return {
48013
48122
  displayName: connector.displayName,
48014
48123
  description: connector.config.description || "",
48015
- baseURL: connector.baseURL
48124
+ baseURL: connector.baseURL,
48125
+ serviceType: connector.serviceType
48016
48126
  };
48017
48127
  } catch {
48018
48128
  return null;
@@ -48029,14 +48139,22 @@ async function executeInVM(code, input, timeout, logs) {
48029
48139
  clearTimeout,
48030
48140
  clearInterval,
48031
48141
  Promise,
48032
- // Array/Object
48142
+ // Built-in types
48033
48143
  Array,
48034
48144
  Object,
48035
48145
  String,
48036
48146
  Number,
48037
- Boolean
48147
+ Boolean,
48148
+ RegExp,
48149
+ Map,
48150
+ Set,
48151
+ Error,
48152
+ URL,
48153
+ URLSearchParams,
48154
+ TextEncoder,
48155
+ TextDecoder
48038
48156
  };
48039
- const context = vm__namespace.createContext(sandbox);
48157
+ const vmContext = vm__namespace.createContext(sandbox);
48040
48158
  const wrappedCode = code.trim().startsWith("(async") ? code : `
48041
48159
  (async () => {
48042
48160
  ${code}
@@ -48044,75 +48162,32 @@ async function executeInVM(code, input, timeout, logs) {
48044
48162
  })()
48045
48163
  `;
48046
48164
  const script = new vm__namespace.Script(wrappedCode);
48047
- const resultPromise = script.runInContext(context, {
48165
+ const resultPromise = script.runInContext(vmContext, {
48048
48166
  timeout,
48049
48167
  displayErrors: true
48050
48168
  });
48051
48169
  const result = await resultPromise;
48052
48170
  return result !== void 0 ? result : sandbox.output;
48053
48171
  }
48054
- var MIME_TYPES = {
48055
- png: "image/png",
48056
- jpeg: "image/jpeg",
48057
- jpg: "image/jpeg",
48058
- webp: "image/webp",
48059
- gif: "image/gif",
48060
- mp4: "video/mp4",
48061
- webm: "video/webm",
48062
- mp3: "audio/mpeg",
48063
- wav: "audio/wav",
48064
- opus: "audio/opus",
48065
- ogg: "audio/ogg",
48066
- aac: "audio/aac",
48067
- flac: "audio/flac",
48068
- pcm: "audio/pcm"
48069
- };
48070
- var FileMediaOutputHandler = class {
48071
- outputDir;
48072
- initialized = false;
48073
- constructor(outputDir) {
48074
- this.outputDir = outputDir ?? path3__namespace.join(os__namespace.tmpdir(), "oneringai-media");
48075
- }
48076
- async save(data, metadata) {
48077
- if (!this.initialized) {
48078
- await fs14__namespace.mkdir(this.outputDir, { recursive: true });
48079
- this.initialized = true;
48080
- }
48081
- const filename = metadata.suggestedFilename ?? this.generateFilename(metadata);
48082
- const filePath = path3__namespace.join(this.outputDir, filename);
48083
- await fs14__namespace.writeFile(filePath, data);
48084
- const format = metadata.format.toLowerCase();
48085
- const mimeType = MIME_TYPES[format] ?? `application/octet-stream`;
48086
- return {
48087
- location: filePath,
48088
- mimeType,
48089
- size: data.length
48090
- };
48091
- }
48092
- generateFilename(metadata) {
48093
- const timestamp = Date.now();
48094
- const random2 = crypto2__namespace.randomBytes(4).toString("hex");
48095
- const indexSuffix = metadata.index != null ? `_${metadata.index}` : "";
48096
- return `${metadata.type}_${timestamp}_${random2}${indexSuffix}.${metadata.format}`;
48097
- }
48098
- };
48099
48172
 
48100
48173
  // src/tools/multimedia/config.ts
48101
- var _outputHandler = null;
48102
- function getMediaOutputHandler() {
48103
- if (!_outputHandler) {
48104
- _outputHandler = new FileMediaOutputHandler();
48174
+ var _storage = null;
48175
+ function getMediaStorage() {
48176
+ if (!_storage) {
48177
+ _storage = new FileMediaStorage();
48105
48178
  }
48106
- return _outputHandler;
48179
+ return _storage;
48107
48180
  }
48108
- function setMediaOutputHandler(handler) {
48109
- _outputHandler = handler;
48181
+ function setMediaStorage(storage) {
48182
+ _storage = storage;
48110
48183
  }
48184
+ var getMediaOutputHandler = getMediaStorage;
48185
+ var setMediaOutputHandler = setMediaStorage;
48111
48186
 
48112
48187
  // src/tools/multimedia/imageGeneration.ts
48113
- function createImageGenerationTool(connector, outputHandler) {
48188
+ function createImageGenerationTool(connector, storage, userId) {
48114
48189
  const vendor = connector.vendor;
48115
- const handler = outputHandler ?? getMediaOutputHandler();
48190
+ const handler = storage ?? getMediaStorage();
48116
48191
  const vendorModels = vendor ? getImageModelsByVendor(vendor) : [];
48117
48192
  const modelNames = vendorModels.map((m) => m.name);
48118
48193
  const properties = {
@@ -48185,8 +48260,9 @@ function createImageGenerationTool(connector, outputHandler) {
48185
48260
  }
48186
48261
  }
48187
48262
  },
48188
- execute: async (args) => {
48263
+ execute: async (args, context) => {
48189
48264
  try {
48265
+ const effectiveUserId = userId ?? context?.userId;
48190
48266
  const imageGen = ImageGeneration.create({ connector });
48191
48267
  const response = await imageGen.generate({
48192
48268
  prompt: args.prompt,
@@ -48217,7 +48293,8 @@ function createImageGenerationTool(connector, outputHandler) {
48217
48293
  format,
48218
48294
  model: modelName,
48219
48295
  vendor: vendor || "unknown",
48220
- index: response.data.length > 1 ? i : void 0
48296
+ index: response.data.length > 1 ? i : void 0,
48297
+ userId: effectiveUserId
48221
48298
  });
48222
48299
  images.push({
48223
48300
  location: result.location,
@@ -48244,9 +48321,9 @@ function createImageGenerationTool(connector, outputHandler) {
48244
48321
 
48245
48322
  // src/tools/multimedia/videoGeneration.ts
48246
48323
  var videoGenInstances = /* @__PURE__ */ new Map();
48247
- function createVideoTools(connector, outputHandler) {
48324
+ function createVideoTools(connector, storage, userId) {
48248
48325
  const vendor = connector.vendor;
48249
- const handler = outputHandler ?? getMediaOutputHandler();
48326
+ const handler = storage ?? getMediaStorage();
48250
48327
  const vendorModels = vendor ? getVideoModelsByVendor(vendor) : [];
48251
48328
  const modelNames = vendorModels.map((m) => m.name);
48252
48329
  const generateProperties = {
@@ -48310,7 +48387,7 @@ function createVideoTools(connector, outputHandler) {
48310
48387
  }
48311
48388
  }
48312
48389
  },
48313
- execute: async (args) => {
48390
+ execute: async (args, _context) => {
48314
48391
  try {
48315
48392
  const videoGen = VideoGeneration.create({ connector });
48316
48393
  const response = await videoGen.generate({
@@ -48359,8 +48436,9 @@ function createVideoTools(connector, outputHandler) {
48359
48436
  }
48360
48437
  }
48361
48438
  },
48362
- execute: async (args) => {
48439
+ execute: async (args, context) => {
48363
48440
  try {
48441
+ const effectiveUserId = userId ?? context?.userId;
48364
48442
  let videoGen = videoGenInstances.get(args.jobId);
48365
48443
  if (!videoGen) {
48366
48444
  videoGen = VideoGeneration.create({ connector });
@@ -48386,7 +48464,8 @@ function createVideoTools(connector, outputHandler) {
48386
48464
  type: "video",
48387
48465
  format,
48388
48466
  model: modelName,
48389
- vendor: vendor || "unknown"
48467
+ vendor: vendor || "unknown",
48468
+ userId: effectiveUserId
48390
48469
  });
48391
48470
  videoGenInstances.delete(args.jobId);
48392
48471
  return {
@@ -48434,9 +48513,9 @@ function createVideoTools(connector, outputHandler) {
48434
48513
  }
48435
48514
 
48436
48515
  // src/tools/multimedia/textToSpeech.ts
48437
- function createTextToSpeechTool(connector, outputHandler) {
48516
+ function createTextToSpeechTool(connector, storage, userId) {
48438
48517
  const vendor = connector.vendor;
48439
- const handler = outputHandler ?? getMediaOutputHandler();
48518
+ const handler = storage ?? getMediaStorage();
48440
48519
  const vendorModels = vendor ? getTTSModelsByVendor(vendor) : [];
48441
48520
  const modelNames = vendorModels.map((m) => m.name);
48442
48521
  const properties = {
@@ -48497,8 +48576,9 @@ function createTextToSpeechTool(connector, outputHandler) {
48497
48576
  }
48498
48577
  }
48499
48578
  },
48500
- execute: async (args) => {
48579
+ execute: async (args, context) => {
48501
48580
  try {
48581
+ const effectiveUserId = userId ?? context?.userId;
48502
48582
  const tts = TextToSpeech.create({
48503
48583
  connector,
48504
48584
  model: args.model,
@@ -48512,7 +48592,8 @@ function createTextToSpeechTool(connector, outputHandler) {
48512
48592
  type: "audio",
48513
48593
  format,
48514
48594
  model: args.model || modelNames[0] || "unknown",
48515
- vendor: vendor || "unknown"
48595
+ vendor: vendor || "unknown",
48596
+ userId: effectiveUserId
48516
48597
  });
48517
48598
  return {
48518
48599
  success: true,
@@ -48535,14 +48616,17 @@ function createTextToSpeechTool(connector, outputHandler) {
48535
48616
  }
48536
48617
  };
48537
48618
  }
48538
- function createSpeechToTextTool(connector) {
48619
+
48620
+ // src/tools/multimedia/speechToText.ts
48621
+ function createSpeechToTextTool(connector, storage) {
48539
48622
  const vendor = connector.vendor;
48623
+ const handler = storage ?? getMediaStorage();
48540
48624
  const vendorModels = vendor ? getSTTModelsByVendor(vendor) : [];
48541
48625
  const modelNames = vendorModels.map((m) => m.name);
48542
48626
  const properties = {
48543
- audioFilePath: {
48627
+ audioSource: {
48544
48628
  type: "string",
48545
- description: "Path to the audio file to transcribe"
48629
+ description: "Path or location of the audio file to transcribe (file path, storage location, etc.)"
48546
48630
  }
48547
48631
  };
48548
48632
  if (modelNames.length > 0) {
@@ -48570,13 +48654,19 @@ function createSpeechToTextTool(connector) {
48570
48654
  parameters: {
48571
48655
  type: "object",
48572
48656
  properties,
48573
- required: ["audioFilePath"]
48657
+ required: ["audioSource"]
48574
48658
  }
48575
48659
  }
48576
48660
  },
48577
- execute: async (args) => {
48661
+ execute: async (args, _context) => {
48578
48662
  try {
48579
- const audioBuffer = await fs14__namespace.readFile(args.audioFilePath);
48663
+ const audioBuffer = await handler.read(args.audioSource);
48664
+ if (!audioBuffer) {
48665
+ return {
48666
+ success: false,
48667
+ error: `Audio not found at: ${args.audioSource}`
48668
+ };
48669
+ }
48580
48670
  const stt = SpeechToText.create({
48581
48671
  connector,
48582
48672
  model: args.model,
@@ -48598,7 +48688,7 @@ function createSpeechToTextTool(connector) {
48598
48688
  };
48599
48689
  }
48600
48690
  },
48601
- describeCall: (args) => args.audioFilePath,
48691
+ describeCall: (args) => args.audioSource,
48602
48692
  permission: {
48603
48693
  scope: "session",
48604
48694
  riskLevel: "low",
@@ -48613,21 +48703,22 @@ var VENDOR_CAPABILITIES = {
48613
48703
  [Vendor.Google]: ["image", "video", "tts"],
48614
48704
  [Vendor.Grok]: ["image", "video"]
48615
48705
  };
48616
- function registerMultimediaTools() {
48706
+ function registerMultimediaTools(storage) {
48617
48707
  for (const [vendor, capabilities] of Object.entries(VENDOR_CAPABILITIES)) {
48618
- ConnectorTools.registerService(vendor, (connector, _userId) => {
48708
+ ConnectorTools.registerService(vendor, (connector, userId) => {
48709
+ const handler = getMediaStorage();
48619
48710
  const tools = [];
48620
48711
  if (capabilities.includes("image")) {
48621
- tools.push(createImageGenerationTool(connector));
48712
+ tools.push(createImageGenerationTool(connector, handler, userId));
48622
48713
  }
48623
48714
  if (capabilities.includes("video")) {
48624
- tools.push(...createVideoTools(connector));
48715
+ tools.push(...createVideoTools(connector, handler, userId));
48625
48716
  }
48626
48717
  if (capabilities.includes("tts")) {
48627
- tools.push(createTextToSpeechTool(connector));
48718
+ tools.push(createTextToSpeechTool(connector, handler, userId));
48628
48719
  }
48629
48720
  if (capabilities.includes("stt")) {
48630
- tools.push(createSpeechToTextTool(connector));
48721
+ tools.push(createSpeechToTextTool(connector, handler));
48631
48722
  }
48632
48723
  return tools;
48633
48724
  });
@@ -48637,6 +48728,858 @@ function registerMultimediaTools() {
48637
48728
  // src/tools/multimedia/index.ts
48638
48729
  registerMultimediaTools();
48639
48730
 
48731
+ // src/tools/github/types.ts
48732
+ function parseRepository(input) {
48733
+ if (!input || input.trim().length === 0) {
48734
+ throw new Error("Repository cannot be empty");
48735
+ }
48736
+ const trimmed = input.trim();
48737
+ try {
48738
+ const url2 = new URL(trimmed);
48739
+ if (url2.hostname === "github.com" || url2.hostname === "www.github.com") {
48740
+ const segments = url2.pathname.split("/").filter(Boolean);
48741
+ if (segments.length >= 2) {
48742
+ return { owner: segments[0], repo: segments[1].replace(/\.git$/, "") };
48743
+ }
48744
+ }
48745
+ } catch {
48746
+ }
48747
+ const parts = trimmed.split("/");
48748
+ if (parts.length === 2 && parts[0].length > 0 && parts[1].length > 0) {
48749
+ return { owner: parts[0], repo: parts[1] };
48750
+ }
48751
+ throw new Error(
48752
+ `Invalid repository format: "${input}". Expected "owner/repo" or "https://github.com/owner/repo"`
48753
+ );
48754
+ }
48755
+ function resolveRepository(repository, connector) {
48756
+ const repoStr = repository ?? connector.getOptions().defaultRepository;
48757
+ if (!repoStr) {
48758
+ return {
48759
+ success: false,
48760
+ error: 'No repository specified. Provide a "repository" parameter (e.g., "owner/repo") or configure defaultRepository on the connector.'
48761
+ };
48762
+ }
48763
+ try {
48764
+ return { success: true, repo: parseRepository(repoStr) };
48765
+ } catch (err) {
48766
+ return { success: false, error: err instanceof Error ? err.message : String(err) };
48767
+ }
48768
+ }
48769
+ var GitHubAPIError = class extends Error {
48770
+ constructor(status, statusText, body) {
48771
+ const msg = typeof body === "object" && body !== null && "message" in body ? body.message : statusText;
48772
+ super(`GitHub API error ${status}: ${msg}`);
48773
+ this.status = status;
48774
+ this.statusText = statusText;
48775
+ this.body = body;
48776
+ this.name = "GitHubAPIError";
48777
+ }
48778
+ };
48779
+ async function githubFetch(connector, endpoint, options) {
48780
+ let url2 = endpoint;
48781
+ if (options?.queryParams && Object.keys(options.queryParams).length > 0) {
48782
+ const params = new URLSearchParams();
48783
+ for (const [key, value] of Object.entries(options.queryParams)) {
48784
+ params.append(key, String(value));
48785
+ }
48786
+ url2 += (url2.includes("?") ? "&" : "?") + params.toString();
48787
+ }
48788
+ const headers = {
48789
+ "Accept": options?.accept ?? "application/vnd.github+json",
48790
+ "X-GitHub-Api-Version": "2022-11-28"
48791
+ };
48792
+ if (options?.body) {
48793
+ headers["Content-Type"] = "application/json";
48794
+ }
48795
+ const response = await connector.fetch(
48796
+ url2,
48797
+ {
48798
+ method: options?.method ?? "GET",
48799
+ headers,
48800
+ body: options?.body ? JSON.stringify(options.body) : void 0
48801
+ },
48802
+ options?.userId
48803
+ );
48804
+ const text = await response.text();
48805
+ let data;
48806
+ try {
48807
+ data = JSON.parse(text);
48808
+ } catch {
48809
+ data = text;
48810
+ }
48811
+ if (!response.ok) {
48812
+ throw new GitHubAPIError(response.status, response.statusText, data);
48813
+ }
48814
+ return data;
48815
+ }
48816
+
48817
+ // src/tools/github/searchFiles.ts
48818
+ function matchGlobPattern2(pattern, filePath) {
48819
+ let regexPattern = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, ".").replace(/\{\{GLOBSTAR\}\}/g, ".*");
48820
+ regexPattern = "^" + regexPattern + "$";
48821
+ try {
48822
+ const regex = new RegExp(regexPattern);
48823
+ return regex.test(filePath);
48824
+ } catch {
48825
+ return false;
48826
+ }
48827
+ }
48828
+ function createSearchFilesTool(connector, userId) {
48829
+ return {
48830
+ definition: {
48831
+ type: "function",
48832
+ function: {
48833
+ name: "search_files",
48834
+ description: `Search for files by name/path pattern in a GitHub repository.
48835
+
48836
+ USAGE:
48837
+ - Supports glob patterns like "**/*.ts", "src/**/*.tsx"
48838
+ - Returns matching file paths sorted alphabetically
48839
+ - Uses the repository's file tree for fast matching
48840
+
48841
+ PATTERN SYNTAX:
48842
+ - * matches any characters except /
48843
+ - ** matches any characters including /
48844
+ - ? matches a single character
48845
+
48846
+ EXAMPLES:
48847
+ - Find all TypeScript files: { "pattern": "**/*.ts" }
48848
+ - Find files in src: { "pattern": "src/**/*.{ts,tsx}" }
48849
+ - Find package.json: { "pattern": "**/package.json" }
48850
+ - Search specific branch: { "pattern": "**/*.ts", "ref": "develop" }`,
48851
+ parameters: {
48852
+ type: "object",
48853
+ properties: {
48854
+ repository: {
48855
+ type: "string",
48856
+ description: 'Repository in "owner/repo" format or full GitHub URL. Optional if connector has a default repository.'
48857
+ },
48858
+ pattern: {
48859
+ type: "string",
48860
+ description: 'Glob pattern to match files (e.g., "**/*.ts", "src/**/*.tsx")'
48861
+ },
48862
+ ref: {
48863
+ type: "string",
48864
+ description: "Branch, tag, or commit SHA. Defaults to the repository's default branch."
48865
+ }
48866
+ },
48867
+ required: ["pattern"]
48868
+ }
48869
+ }
48870
+ },
48871
+ describeCall: (args) => {
48872
+ const parts = [args.pattern];
48873
+ if (args.repository) parts.push(`in ${args.repository}`);
48874
+ if (args.ref) parts.push(`@${args.ref}`);
48875
+ return parts.join(" ");
48876
+ },
48877
+ permission: {
48878
+ scope: "session",
48879
+ riskLevel: "low",
48880
+ approvalMessage: `Search files in a GitHub repository via ${connector.displayName}`
48881
+ },
48882
+ execute: async (args, context) => {
48883
+ const effectiveUserId = context?.userId ?? userId;
48884
+ const resolved = resolveRepository(args.repository, connector);
48885
+ if (!resolved.success) {
48886
+ return { success: false, error: resolved.error };
48887
+ }
48888
+ const { owner, repo } = resolved.repo;
48889
+ try {
48890
+ let ref = args.ref;
48891
+ if (!ref) {
48892
+ const repoInfo = await githubFetch(
48893
+ connector,
48894
+ `/repos/${owner}/${repo}`,
48895
+ { userId: effectiveUserId }
48896
+ );
48897
+ ref = repoInfo.default_branch;
48898
+ }
48899
+ const tree = await githubFetch(
48900
+ connector,
48901
+ `/repos/${owner}/${repo}/git/trees/${ref}?recursive=1`,
48902
+ { userId: effectiveUserId }
48903
+ );
48904
+ const matching = tree.tree.filter(
48905
+ (entry) => entry.type === "blob" && matchGlobPattern2(args.pattern, entry.path)
48906
+ ).map((entry) => ({
48907
+ path: entry.path,
48908
+ size: entry.size ?? 0,
48909
+ type: entry.type
48910
+ })).sort((a, b) => a.path.localeCompare(b.path));
48911
+ return {
48912
+ success: true,
48913
+ files: matching,
48914
+ count: matching.length,
48915
+ truncated: tree.truncated
48916
+ };
48917
+ } catch (error) {
48918
+ return {
48919
+ success: false,
48920
+ error: `Failed to search files: ${error instanceof Error ? error.message : String(error)}`
48921
+ };
48922
+ }
48923
+ }
48924
+ };
48925
+ }
48926
+
48927
+ // src/tools/github/searchCode.ts
48928
+ function createSearchCodeTool(connector, userId) {
48929
+ return {
48930
+ definition: {
48931
+ type: "function",
48932
+ function: {
48933
+ name: "search_code",
48934
+ description: `Search for code content across a GitHub repository.
48935
+
48936
+ USAGE:
48937
+ - Search by keyword, function name, class name, or any text
48938
+ - Filter by language, path, or file extension
48939
+ - Returns matching files with text fragments showing context
48940
+
48941
+ RATE LIMITS:
48942
+ - GitHub's code search API is limited to 30 requests per minute
48943
+ - Results may be incomplete for very large repositories
48944
+
48945
+ EXAMPLES:
48946
+ - Find function: { "query": "function handleAuth", "language": "typescript" }
48947
+ - Find imports: { "query": "import React", "extension": "tsx" }
48948
+ - Search in path: { "query": "TODO", "path": "src/utils" }
48949
+ - Limit results: { "query": "console.log", "limit": 10 }`,
48950
+ parameters: {
48951
+ type: "object",
48952
+ properties: {
48953
+ repository: {
48954
+ type: "string",
48955
+ description: 'Repository in "owner/repo" format or full GitHub URL. Optional if connector has a default repository.'
48956
+ },
48957
+ query: {
48958
+ type: "string",
48959
+ description: "Search query \u2014 keyword, function name, or any text to find in code"
48960
+ },
48961
+ language: {
48962
+ type: "string",
48963
+ description: 'Filter by programming language (e.g., "typescript", "python", "go")'
48964
+ },
48965
+ path: {
48966
+ type: "string",
48967
+ description: 'Filter by file path prefix (e.g., "src/", "lib/utils")'
48968
+ },
48969
+ extension: {
48970
+ type: "string",
48971
+ description: 'Filter by file extension without dot (e.g., "ts", "py", "go")'
48972
+ },
48973
+ limit: {
48974
+ type: "number",
48975
+ description: "Maximum number of results (default: 30, max: 100)"
48976
+ }
48977
+ },
48978
+ required: ["query"]
48979
+ }
48980
+ }
48981
+ },
48982
+ describeCall: (args) => {
48983
+ const parts = [`"${args.query}"`];
48984
+ if (args.language) parts.push(`lang:${args.language}`);
48985
+ if (args.repository) parts.push(`in ${args.repository}`);
48986
+ return parts.join(" ");
48987
+ },
48988
+ permission: {
48989
+ scope: "session",
48990
+ riskLevel: "low",
48991
+ approvalMessage: `Search code in a GitHub repository via ${connector.displayName}`
48992
+ },
48993
+ execute: async (args, context) => {
48994
+ const effectiveUserId = context?.userId ?? userId;
48995
+ const resolved = resolveRepository(args.repository, connector);
48996
+ if (!resolved.success) {
48997
+ return { success: false, error: resolved.error };
48998
+ }
48999
+ const { owner, repo } = resolved.repo;
49000
+ try {
49001
+ const qualifiers = [`repo:${owner}/${repo}`];
49002
+ if (args.language) qualifiers.push(`language:${args.language}`);
49003
+ if (args.path) qualifiers.push(`path:${args.path}`);
49004
+ if (args.extension) qualifiers.push(`extension:${args.extension}`);
49005
+ const q = `${args.query} ${qualifiers.join(" ")}`;
49006
+ const perPage = Math.min(args.limit ?? 30, 100);
49007
+ const result = await githubFetch(
49008
+ connector,
49009
+ `/search/code`,
49010
+ {
49011
+ userId: effectiveUserId,
49012
+ // Request text-match fragments
49013
+ accept: "application/vnd.github.text-match+json",
49014
+ queryParams: { q, per_page: perPage }
49015
+ }
49016
+ );
49017
+ const matches = result.items.map((item) => ({
49018
+ file: item.path,
49019
+ fragment: item.text_matches?.[0]?.fragment
49020
+ }));
49021
+ return {
49022
+ success: true,
49023
+ matches,
49024
+ count: result.total_count,
49025
+ truncated: result.incomplete_results || result.total_count > perPage
49026
+ };
49027
+ } catch (error) {
49028
+ return {
49029
+ success: false,
49030
+ error: `Failed to search code: ${error instanceof Error ? error.message : String(error)}`
49031
+ };
49032
+ }
49033
+ }
49034
+ };
49035
+ }
49036
+
49037
+ // src/tools/github/readFile.ts
49038
+ function createGitHubReadFileTool(connector, userId) {
49039
+ return {
49040
+ definition: {
49041
+ type: "function",
49042
+ function: {
49043
+ name: "read_file",
49044
+ description: `Read file content from a GitHub repository.
49045
+
49046
+ USAGE:
49047
+ - Reads a file and returns content with line numbers
49048
+ - Supports line range selection with offset/limit for large files
49049
+ - By default reads up to 2000 lines from the beginning
49050
+
49051
+ EXAMPLES:
49052
+ - Read entire file: { "path": "src/index.ts" }
49053
+ - Read specific branch: { "path": "README.md", "ref": "develop" }
49054
+ - Read lines 100-200: { "path": "src/app.ts", "offset": 100, "limit": 100 }
49055
+ - Specific repo: { "repository": "owner/repo", "path": "package.json" }
49056
+
49057
+ NOTE: Files larger than 1MB are fetched via the Git Blob API. Very large files (>5MB) may be truncated.`,
49058
+ parameters: {
49059
+ type: "object",
49060
+ properties: {
49061
+ repository: {
49062
+ type: "string",
49063
+ description: 'Repository in "owner/repo" format or full GitHub URL. Optional if connector has a default repository.'
49064
+ },
49065
+ path: {
49066
+ type: "string",
49067
+ description: 'File path within the repository (e.g., "src/index.ts")'
49068
+ },
49069
+ ref: {
49070
+ type: "string",
49071
+ description: "Branch, tag, or commit SHA. Defaults to the repository's default branch."
49072
+ },
49073
+ offset: {
49074
+ type: "number",
49075
+ description: "Line number to start reading from (1-indexed). Only provide if the file is too large."
49076
+ },
49077
+ limit: {
49078
+ type: "number",
49079
+ description: "Number of lines to read (default: 2000). Only provide if the file is too large."
49080
+ }
49081
+ },
49082
+ required: ["path"]
49083
+ }
49084
+ }
49085
+ },
49086
+ describeCall: (args) => {
49087
+ const parts = [args.path];
49088
+ if (args.repository) parts.push(`in ${args.repository}`);
49089
+ if (args.ref) parts.push(`@${args.ref}`);
49090
+ if (args.offset && args.limit) parts.push(`[lines ${args.offset}-${args.offset + args.limit}]`);
49091
+ return parts.join(" ");
49092
+ },
49093
+ permission: {
49094
+ scope: "session",
49095
+ riskLevel: "low",
49096
+ approvalMessage: `Read a file from a GitHub repository via ${connector.displayName}`
49097
+ },
49098
+ execute: async (args, context) => {
49099
+ const effectiveUserId = context?.userId ?? userId;
49100
+ const resolved = resolveRepository(args.repository, connector);
49101
+ if (!resolved.success) {
49102
+ return { success: false, error: resolved.error };
49103
+ }
49104
+ const { owner, repo } = resolved.repo;
49105
+ try {
49106
+ let fileContent;
49107
+ let fileSha;
49108
+ let fileSize;
49109
+ const refParam = args.ref ? `?ref=${encodeURIComponent(args.ref)}` : "";
49110
+ const contentResp = await githubFetch(
49111
+ connector,
49112
+ `/repos/${owner}/${repo}/contents/${args.path}${refParam}`,
49113
+ { userId: effectiveUserId }
49114
+ );
49115
+ if (contentResp.type !== "file") {
49116
+ return {
49117
+ success: false,
49118
+ error: `Path is not a file: ${args.path} (type: ${contentResp.type}). Use search_files to explore the repository.`,
49119
+ path: args.path
49120
+ };
49121
+ }
49122
+ fileSha = contentResp.sha;
49123
+ fileSize = contentResp.size;
49124
+ if (contentResp.content && contentResp.encoding === "base64") {
49125
+ fileContent = Buffer.from(contentResp.content, "base64").toString("utf-8");
49126
+ } else if (contentResp.git_url) {
49127
+ const blob = await githubFetch(
49128
+ connector,
49129
+ contentResp.git_url,
49130
+ { userId: effectiveUserId }
49131
+ );
49132
+ fileContent = Buffer.from(blob.content, "base64").toString("utf-8");
49133
+ fileSize = blob.size;
49134
+ } else {
49135
+ return {
49136
+ success: false,
49137
+ error: `Cannot read file content: ${args.path} (no content or git_url in response)`,
49138
+ path: args.path
49139
+ };
49140
+ }
49141
+ const offset = args.offset ?? 1;
49142
+ const limit = args.limit ?? 2e3;
49143
+ const allLines = fileContent.split("\n");
49144
+ const totalLines = allLines.length;
49145
+ const startIndex = Math.max(0, offset - 1);
49146
+ const endIndex = Math.min(totalLines, startIndex + limit);
49147
+ const selectedLines = allLines.slice(startIndex, endIndex);
49148
+ const lineNumberWidth = String(endIndex).length;
49149
+ const formattedLines = selectedLines.map((line, i) => {
49150
+ const lineNum = startIndex + i + 1;
49151
+ const paddedNum = String(lineNum).padStart(lineNumberWidth, " ");
49152
+ const truncatedLine = line.length > 2e3 ? line.substring(0, 2e3) + "..." : line;
49153
+ return `${paddedNum} ${truncatedLine}`;
49154
+ });
49155
+ const truncated = endIndex < totalLines;
49156
+ const result = formattedLines.join("\n");
49157
+ return {
49158
+ success: true,
49159
+ content: result,
49160
+ path: args.path,
49161
+ size: fileSize,
49162
+ lines: totalLines,
49163
+ truncated,
49164
+ sha: fileSha
49165
+ };
49166
+ } catch (error) {
49167
+ return {
49168
+ success: false,
49169
+ error: `Failed to read file: ${error instanceof Error ? error.message : String(error)}`,
49170
+ path: args.path
49171
+ };
49172
+ }
49173
+ }
49174
+ };
49175
+ }
49176
+
49177
+ // src/tools/github/getPR.ts
49178
+ function createGetPRTool(connector, userId) {
49179
+ return {
49180
+ definition: {
49181
+ type: "function",
49182
+ function: {
49183
+ name: "get_pr",
49184
+ description: `Get full details of a pull request from a GitHub repository.
49185
+
49186
+ Returns: title, description, state, author, labels, reviewers, merge status, branches, file stats, and more.
49187
+
49188
+ EXAMPLES:
49189
+ - Get PR: { "pull_number": 123 }
49190
+ - Specific repo: { "repository": "owner/repo", "pull_number": 456 }`,
49191
+ parameters: {
49192
+ type: "object",
49193
+ properties: {
49194
+ repository: {
49195
+ type: "string",
49196
+ description: 'Repository in "owner/repo" format or full GitHub URL. Optional if connector has a default repository.'
49197
+ },
49198
+ pull_number: {
49199
+ type: "number",
49200
+ description: "Pull request number"
49201
+ }
49202
+ },
49203
+ required: ["pull_number"]
49204
+ }
49205
+ }
49206
+ },
49207
+ describeCall: (args) => {
49208
+ const parts = [`#${args.pull_number}`];
49209
+ if (args.repository) parts.push(`in ${args.repository}`);
49210
+ return parts.join(" ");
49211
+ },
49212
+ permission: {
49213
+ scope: "session",
49214
+ riskLevel: "low",
49215
+ approvalMessage: `Get pull request details from GitHub via ${connector.displayName}`
49216
+ },
49217
+ execute: async (args, context) => {
49218
+ const effectiveUserId = context?.userId ?? userId;
49219
+ const resolved = resolveRepository(args.repository, connector);
49220
+ if (!resolved.success) {
49221
+ return { success: false, error: resolved.error };
49222
+ }
49223
+ const { owner, repo } = resolved.repo;
49224
+ try {
49225
+ const pr = await githubFetch(
49226
+ connector,
49227
+ `/repos/${owner}/${repo}/pulls/${args.pull_number}`,
49228
+ { userId: effectiveUserId }
49229
+ );
49230
+ return {
49231
+ success: true,
49232
+ data: {
49233
+ number: pr.number,
49234
+ title: pr.title,
49235
+ body: pr.body,
49236
+ state: pr.state,
49237
+ draft: pr.draft,
49238
+ author: pr.user.login,
49239
+ labels: pr.labels.map((l) => l.name),
49240
+ reviewers: pr.requested_reviewers.map((r) => r.login),
49241
+ mergeable: pr.mergeable,
49242
+ head: pr.head.ref,
49243
+ base: pr.base.ref,
49244
+ url: pr.html_url,
49245
+ created_at: pr.created_at,
49246
+ updated_at: pr.updated_at,
49247
+ additions: pr.additions,
49248
+ deletions: pr.deletions,
49249
+ changed_files: pr.changed_files
49250
+ }
49251
+ };
49252
+ } catch (error) {
49253
+ return {
49254
+ success: false,
49255
+ error: `Failed to get PR: ${error instanceof Error ? error.message : String(error)}`
49256
+ };
49257
+ }
49258
+ }
49259
+ };
49260
+ }
49261
+
49262
+ // src/tools/github/prFiles.ts
49263
+ function createPRFilesTool(connector, userId) {
49264
+ return {
49265
+ definition: {
49266
+ type: "function",
49267
+ function: {
49268
+ name: "pr_files",
49269
+ description: `Get the files changed in a pull request with diffs.
49270
+
49271
+ Returns: filename, status (added/modified/removed/renamed), additions, deletions, and patch (diff) content for each file.
49272
+
49273
+ EXAMPLES:
49274
+ - Get files: { "pull_number": 123 }
49275
+ - Specific repo: { "repository": "owner/repo", "pull_number": 456 }
49276
+
49277
+ NOTE: Very large diffs may be truncated by GitHub. Patch content may be absent for binary files.`,
49278
+ parameters: {
49279
+ type: "object",
49280
+ properties: {
49281
+ repository: {
49282
+ type: "string",
49283
+ description: 'Repository in "owner/repo" format or full GitHub URL. Optional if connector has a default repository.'
49284
+ },
49285
+ pull_number: {
49286
+ type: "number",
49287
+ description: "Pull request number"
49288
+ }
49289
+ },
49290
+ required: ["pull_number"]
49291
+ }
49292
+ }
49293
+ },
49294
+ describeCall: (args) => {
49295
+ const parts = [`files for #${args.pull_number}`];
49296
+ if (args.repository) parts.push(`in ${args.repository}`);
49297
+ return parts.join(" ");
49298
+ },
49299
+ permission: {
49300
+ scope: "session",
49301
+ riskLevel: "low",
49302
+ approvalMessage: `Get PR changed files from GitHub via ${connector.displayName}`
49303
+ },
49304
+ execute: async (args, context) => {
49305
+ const effectiveUserId = context?.userId ?? userId;
49306
+ const resolved = resolveRepository(args.repository, connector);
49307
+ if (!resolved.success) {
49308
+ return { success: false, error: resolved.error };
49309
+ }
49310
+ const { owner, repo } = resolved.repo;
49311
+ try {
49312
+ const files = await githubFetch(
49313
+ connector,
49314
+ `/repos/${owner}/${repo}/pulls/${args.pull_number}/files`,
49315
+ {
49316
+ userId: effectiveUserId,
49317
+ queryParams: { per_page: 100 }
49318
+ }
49319
+ );
49320
+ return {
49321
+ success: true,
49322
+ files: files.map((f) => ({
49323
+ filename: f.filename,
49324
+ status: f.status,
49325
+ additions: f.additions,
49326
+ deletions: f.deletions,
49327
+ changes: f.changes,
49328
+ patch: f.patch
49329
+ })),
49330
+ count: files.length
49331
+ };
49332
+ } catch (error) {
49333
+ return {
49334
+ success: false,
49335
+ error: `Failed to get PR files: ${error instanceof Error ? error.message : String(error)}`
49336
+ };
49337
+ }
49338
+ }
49339
+ };
49340
+ }
49341
+
49342
+ // src/tools/github/prComments.ts
49343
+ function createPRCommentsTool(connector, userId) {
49344
+ return {
49345
+ definition: {
49346
+ type: "function",
49347
+ function: {
49348
+ name: "pr_comments",
49349
+ description: `Get all comments and reviews on a pull request.
49350
+
49351
+ Returns a unified list of:
49352
+ - **review_comment**: Line-level comments on specific code (includes file path and line number)
49353
+ - **review**: Full reviews (approve/request changes/comment)
49354
+ - **comment**: General comments on the PR (issue-level)
49355
+
49356
+ All entries are sorted by creation date (oldest first).
49357
+
49358
+ EXAMPLES:
49359
+ - Get comments: { "pull_number": 123 }
49360
+ - Specific repo: { "repository": "owner/repo", "pull_number": 456 }`,
49361
+ parameters: {
49362
+ type: "object",
49363
+ properties: {
49364
+ repository: {
49365
+ type: "string",
49366
+ description: 'Repository in "owner/repo" format or full GitHub URL. Optional if connector has a default repository.'
49367
+ },
49368
+ pull_number: {
49369
+ type: "number",
49370
+ description: "Pull request number"
49371
+ }
49372
+ },
49373
+ required: ["pull_number"]
49374
+ }
49375
+ }
49376
+ },
49377
+ describeCall: (args) => {
49378
+ const parts = [`comments for #${args.pull_number}`];
49379
+ if (args.repository) parts.push(`in ${args.repository}`);
49380
+ return parts.join(" ");
49381
+ },
49382
+ permission: {
49383
+ scope: "session",
49384
+ riskLevel: "low",
49385
+ approvalMessage: `Get PR comments and reviews from GitHub via ${connector.displayName}`
49386
+ },
49387
+ execute: async (args, context) => {
49388
+ const effectiveUserId = context?.userId ?? userId;
49389
+ const resolved = resolveRepository(args.repository, connector);
49390
+ if (!resolved.success) {
49391
+ return { success: false, error: resolved.error };
49392
+ }
49393
+ const { owner, repo } = resolved.repo;
49394
+ try {
49395
+ const basePath = `/repos/${owner}/${repo}`;
49396
+ const queryOpts = { userId: effectiveUserId, queryParams: { per_page: 100 } };
49397
+ const [reviewComments, reviews, issueComments] = await Promise.all([
49398
+ githubFetch(
49399
+ connector,
49400
+ `${basePath}/pulls/${args.pull_number}/comments`,
49401
+ queryOpts
49402
+ ),
49403
+ githubFetch(
49404
+ connector,
49405
+ `${basePath}/pulls/${args.pull_number}/reviews`,
49406
+ queryOpts
49407
+ ),
49408
+ githubFetch(
49409
+ connector,
49410
+ `${basePath}/issues/${args.pull_number}/comments`,
49411
+ queryOpts
49412
+ )
49413
+ ]);
49414
+ const allComments = [];
49415
+ for (const rc of reviewComments) {
49416
+ allComments.push({
49417
+ id: rc.id,
49418
+ type: "review_comment",
49419
+ author: rc.user.login,
49420
+ body: rc.body,
49421
+ created_at: rc.created_at,
49422
+ path: rc.path,
49423
+ line: rc.line ?? rc.original_line ?? void 0
49424
+ });
49425
+ }
49426
+ for (const r of reviews) {
49427
+ if (!r.body && r.state === "APPROVED") continue;
49428
+ allComments.push({
49429
+ id: r.id,
49430
+ type: "review",
49431
+ author: r.user.login,
49432
+ body: r.body || `[${r.state}]`,
49433
+ created_at: r.submitted_at,
49434
+ state: r.state
49435
+ });
49436
+ }
49437
+ for (const ic of issueComments) {
49438
+ allComments.push({
49439
+ id: ic.id,
49440
+ type: "comment",
49441
+ author: ic.user.login,
49442
+ body: ic.body,
49443
+ created_at: ic.created_at
49444
+ });
49445
+ }
49446
+ allComments.sort(
49447
+ (a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
49448
+ );
49449
+ return {
49450
+ success: true,
49451
+ comments: allComments,
49452
+ count: allComments.length
49453
+ };
49454
+ } catch (error) {
49455
+ return {
49456
+ success: false,
49457
+ error: `Failed to get PR comments: ${error instanceof Error ? error.message : String(error)}`
49458
+ };
49459
+ }
49460
+ }
49461
+ };
49462
+ }
49463
+
49464
+ // src/tools/github/createPR.ts
49465
+ function createCreatePRTool(connector, userId) {
49466
+ return {
49467
+ definition: {
49468
+ type: "function",
49469
+ function: {
49470
+ name: "create_pr",
49471
+ description: `Create a pull request on a GitHub repository.
49472
+
49473
+ USAGE:
49474
+ - Specify source branch (head) and target branch (base)
49475
+ - Optionally create as draft
49476
+
49477
+ EXAMPLES:
49478
+ - Create PR: { "title": "Add feature", "head": "feature-branch", "base": "main" }
49479
+ - Draft PR: { "title": "WIP: Refactor", "head": "refactor", "base": "develop", "draft": true }
49480
+ - With body: { "title": "Fix bug #42", "body": "Fixes the login issue\\n\\n## Changes\\n- Fixed auth flow", "head": "fix/42", "base": "main" }`,
49481
+ parameters: {
49482
+ type: "object",
49483
+ properties: {
49484
+ repository: {
49485
+ type: "string",
49486
+ description: 'Repository in "owner/repo" format or full GitHub URL. Optional if connector has a default repository.'
49487
+ },
49488
+ title: {
49489
+ type: "string",
49490
+ description: "Pull request title"
49491
+ },
49492
+ body: {
49493
+ type: "string",
49494
+ description: "Pull request description/body (Markdown supported)"
49495
+ },
49496
+ head: {
49497
+ type: "string",
49498
+ description: "Source branch name (the branch with your changes)"
49499
+ },
49500
+ base: {
49501
+ type: "string",
49502
+ description: 'Target branch name (the branch you want to merge into, e.g., "main")'
49503
+ },
49504
+ draft: {
49505
+ type: "boolean",
49506
+ description: "Create as a draft pull request (default: false)"
49507
+ }
49508
+ },
49509
+ required: ["title", "head", "base"]
49510
+ }
49511
+ }
49512
+ },
49513
+ describeCall: (args) => {
49514
+ const parts = [args.title];
49515
+ if (args.repository) parts.push(`in ${args.repository}`);
49516
+ return parts.join(" ");
49517
+ },
49518
+ permission: {
49519
+ scope: "session",
49520
+ riskLevel: "medium",
49521
+ approvalMessage: `Create a pull request on GitHub via ${connector.displayName}`
49522
+ },
49523
+ execute: async (args, context) => {
49524
+ const effectiveUserId = context?.userId ?? userId;
49525
+ const resolved = resolveRepository(args.repository, connector);
49526
+ if (!resolved.success) {
49527
+ return { success: false, error: resolved.error };
49528
+ }
49529
+ const { owner, repo } = resolved.repo;
49530
+ try {
49531
+ const pr = await githubFetch(
49532
+ connector,
49533
+ `/repos/${owner}/${repo}/pulls`,
49534
+ {
49535
+ method: "POST",
49536
+ userId: effectiveUserId,
49537
+ body: {
49538
+ title: args.title,
49539
+ body: args.body,
49540
+ head: args.head,
49541
+ base: args.base,
49542
+ draft: args.draft ?? false
49543
+ }
49544
+ }
49545
+ );
49546
+ return {
49547
+ success: true,
49548
+ data: {
49549
+ number: pr.number,
49550
+ url: pr.html_url,
49551
+ state: pr.state,
49552
+ title: pr.title
49553
+ }
49554
+ };
49555
+ } catch (error) {
49556
+ return {
49557
+ success: false,
49558
+ error: `Failed to create PR: ${error instanceof Error ? error.message : String(error)}`
49559
+ };
49560
+ }
49561
+ }
49562
+ };
49563
+ }
49564
+
49565
+ // src/tools/github/register.ts
49566
+ function registerGitHubTools() {
49567
+ ConnectorTools.registerService("github", (connector, userId) => {
49568
+ return [
49569
+ createSearchFilesTool(connector, userId),
49570
+ createSearchCodeTool(connector, userId),
49571
+ createGitHubReadFileTool(connector, userId),
49572
+ createGetPRTool(connector, userId),
49573
+ createPRFilesTool(connector, userId),
49574
+ createPRCommentsTool(connector, userId),
49575
+ createCreatePRTool(connector, userId)
49576
+ ];
49577
+ });
49578
+ }
49579
+
49580
+ // src/tools/github/index.ts
49581
+ registerGitHubTools();
49582
+
48640
49583
  // src/tools/registry.generated.ts
48641
49584
  var toolRegistry = [
48642
49585
  {
@@ -48690,7 +49633,7 @@ var toolRegistry = [
48690
49633
  displayName: "Read File",
48691
49634
  category: "filesystem",
48692
49635
  description: "Read content from a file on the local filesystem.",
48693
- tool: readFile4,
49636
+ tool: readFile5,
48694
49637
  safeByDefault: true
48695
49638
  },
48696
49639
  {
@@ -48699,7 +49642,7 @@ var toolRegistry = [
48699
49642
  displayName: "Write File",
48700
49643
  category: "filesystem",
48701
49644
  description: "Write content to a file on the local filesystem.",
48702
- tool: writeFile4,
49645
+ tool: writeFile5,
48703
49646
  safeByDefault: false
48704
49647
  },
48705
49648
  {
@@ -48728,37 +49671,6 @@ var toolRegistry = [
48728
49671
  description: "Fetch and extract text content from a web page URL.",
48729
49672
  tool: webFetch,
48730
49673
  safeByDefault: true
48731
- },
48732
- {
48733
- name: "web_fetch_js",
48734
- exportName: "webFetchJS",
48735
- displayName: "Web Fetch Js",
48736
- category: "web",
48737
- description: "Fetch and extract content from JavaScript-rendered websites using a headless browser (Puppeteer).",
48738
- tool: webFetchJS,
48739
- safeByDefault: true
48740
- },
48741
- {
48742
- name: "web_scrape",
48743
- exportName: "webScrape",
48744
- displayName: "Web Scrape",
48745
- category: "web",
48746
- description: "Scrape any URL with automatic fallback - guaranteed to work on most sites.",
48747
- tool: webScrape,
48748
- safeByDefault: true,
48749
- requiresConnector: true,
48750
- connectorServiceTypes: ["zenrows"]
48751
- },
48752
- {
48753
- name: "web_search",
48754
- exportName: "webSearch",
48755
- displayName: "Web Search",
48756
- category: "web",
48757
- description: "Search the web and get relevant results with snippets.",
48758
- tool: webSearch,
48759
- safeByDefault: true,
48760
- requiresConnector: true,
48761
- connectorServiceTypes: ["serper", "brave-search", "tavily", "rapidapi-websearch"]
48762
49674
  }
48763
49675
  ];
48764
49676
  function getAllBuiltInTools() {
@@ -48928,8 +49840,8 @@ var ToolRegistry = class {
48928
49840
 
48929
49841
  // src/tools/index.ts
48930
49842
  var developerTools = [
48931
- readFile4,
48932
- writeFile4,
49843
+ readFile5,
49844
+ writeFile5,
48933
49845
  editFile,
48934
49846
  glob,
48935
49847
  grep,
@@ -49153,7 +50065,8 @@ exports.ExternalDependencyHandler = ExternalDependencyHandler;
49153
50065
  exports.FileAgentDefinitionStorage = FileAgentDefinitionStorage;
49154
50066
  exports.FileConnectorStorage = FileConnectorStorage;
49155
50067
  exports.FileContextStorage = FileContextStorage;
49156
- exports.FileMediaOutputHandler = FileMediaOutputHandler;
50068
+ exports.FileMediaOutputHandler = FileMediaStorage;
50069
+ exports.FileMediaStorage = FileMediaStorage;
49157
50070
  exports.FilePersistentInstructionsStorage = FilePersistentInstructionsStorage;
49158
50071
  exports.FileStorage = FileStorage;
49159
50072
  exports.HookManager = HookManager;
@@ -49259,11 +50172,15 @@ exports.createAgentStorage = createAgentStorage;
49259
50172
  exports.createAuthenticatedFetch = createAuthenticatedFetch;
49260
50173
  exports.createBashTool = createBashTool;
49261
50174
  exports.createConnectorFromTemplate = createConnectorFromTemplate;
50175
+ exports.createCreatePRTool = createCreatePRTool;
49262
50176
  exports.createEditFileTool = createEditFileTool;
49263
50177
  exports.createEstimator = createEstimator;
49264
50178
  exports.createExecuteJavaScriptTool = createExecuteJavaScriptTool;
49265
50179
  exports.createFileAgentDefinitionStorage = createFileAgentDefinitionStorage;
49266
50180
  exports.createFileContextStorage = createFileContextStorage;
50181
+ exports.createFileMediaStorage = createFileMediaStorage;
50182
+ exports.createGetPRTool = createGetPRTool;
50183
+ exports.createGitHubReadFileTool = createGitHubReadFileTool;
49267
50184
  exports.createGlobTool = createGlobTool;
49268
50185
  exports.createGrepTool = createGrepTool;
49269
50186
  exports.createImageGenerationTool = createImageGenerationTool;
@@ -49271,9 +50188,13 @@ exports.createImageProvider = createImageProvider;
49271
50188
  exports.createListDirectoryTool = createListDirectoryTool;
49272
50189
  exports.createMessageWithImages = createMessageWithImages;
49273
50190
  exports.createMetricsCollector = createMetricsCollector;
50191
+ exports.createPRCommentsTool = createPRCommentsTool;
50192
+ exports.createPRFilesTool = createPRFilesTool;
49274
50193
  exports.createPlan = createPlan;
49275
50194
  exports.createProvider = createProvider;
49276
50195
  exports.createReadFileTool = createReadFileTool;
50196
+ exports.createSearchCodeTool = createSearchCodeTool;
50197
+ exports.createSearchFilesTool = createSearchFilesTool;
49277
50198
  exports.createSpeechToTextTool = createSpeechToTextTool;
49278
50199
  exports.createTask = createTask;
49279
50200
  exports.createTextMessage = createTextMessage;
@@ -49313,6 +50234,7 @@ exports.getImageModelInfo = getImageModelInfo;
49313
50234
  exports.getImageModelsByVendor = getImageModelsByVendor;
49314
50235
  exports.getImageModelsWithFeature = getImageModelsWithFeature;
49315
50236
  exports.getMediaOutputHandler = getMediaOutputHandler;
50237
+ exports.getMediaStorage = getMediaStorage;
49316
50238
  exports.getModelInfo = getModelInfo;
49317
50239
  exports.getModelsByVendor = getModelsByVendor;
49318
50240
  exports.getNextExecutableTasks = getNextExecutableTasks;
@@ -49335,6 +50257,7 @@ exports.getToolsByCategory = getToolsByCategory;
49335
50257
  exports.getToolsRequiringConnector = getToolsRequiringConnector;
49336
50258
  exports.getVendorAuthTemplate = getVendorAuthTemplate;
49337
50259
  exports.getVendorColor = getVendorColor;
50260
+ exports.getVendorDefaultBaseURL = getVendorDefaultBaseURL;
49338
50261
  exports.getVendorInfo = getVendorInfo;
49339
50262
  exports.getVendorLogo = getVendorLogo;
49340
50263
  exports.getVendorLogoCdnUrl = getVendorLogoCdnUrl;
@@ -49373,15 +50296,18 @@ exports.listVendors = listVendors;
49373
50296
  exports.listVendorsByAuthType = listVendorsByAuthType;
49374
50297
  exports.listVendorsByCategory = listVendorsByCategory;
49375
50298
  exports.listVendorsWithLogos = listVendorsWithLogos;
50299
+ exports.parseRepository = parseRepository;
49376
50300
  exports.readClipboardImage = readClipboardImage;
49377
- exports.readFile = readFile4;
50301
+ exports.readFile = readFile5;
49378
50302
  exports.registerScrapeProvider = registerScrapeProvider;
49379
50303
  exports.resolveConnector = resolveConnector;
49380
50304
  exports.resolveDependencies = resolveDependencies;
50305
+ exports.resolveRepository = resolveRepository;
49381
50306
  exports.retryWithBackoff = retryWithBackoff;
49382
50307
  exports.scopeEquals = scopeEquals;
49383
50308
  exports.scopeMatches = scopeMatches;
49384
50309
  exports.setMediaOutputHandler = setMediaOutputHandler;
50310
+ exports.setMediaStorage = setMediaStorage;
49385
50311
  exports.setMetricsCollector = setMetricsCollector;
49386
50312
  exports.simpleTokenEstimator = simpleTokenEstimator;
49387
50313
  exports.toConnectorOptions = toConnectorOptions;
@@ -49389,6 +50315,6 @@ exports.toolRegistry = toolRegistry;
49389
50315
  exports.tools = tools_exports;
49390
50316
  exports.updateTaskStatus = updateTaskStatus;
49391
50317
  exports.validatePath = validatePath;
49392
- exports.writeFile = writeFile4;
50318
+ exports.writeFile = writeFile5;
49393
50319
  //# sourceMappingURL=index.cjs.map
49394
50320
  //# sourceMappingURL=index.cjs.map