@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/README.md +41 -27
- package/dist/{ImageModel-BkAX5Rr5.d.ts → IProvider-DcYJ3YE-.d.ts} +25 -358
- package/dist/{ImageModel-DtN780fU.d.cts → IProvider-c4QCbPjn.d.cts} +25 -358
- package/dist/ImageModel-BJ2mVPGV.d.ts +337 -0
- package/dist/ImageModel-BWN6VVS6.d.cts +337 -0
- package/dist/Vendor-DYh_bzwo.d.cts +31 -0
- package/dist/Vendor-DYh_bzwo.d.ts +31 -0
- package/dist/capabilities/agents/index.d.cts +3 -2
- package/dist/capabilities/agents/index.d.ts +3 -2
- package/dist/capabilities/images/index.cjs +8 -1
- package/dist/capabilities/images/index.cjs.map +1 -1
- package/dist/capabilities/images/index.d.cts +3 -2
- package/dist/capabilities/images/index.d.ts +3 -2
- package/dist/capabilities/images/index.js +8 -1
- package/dist/capabilities/images/index.js.map +1 -1
- package/dist/{index-BmOYeqU7.d.ts → index-B5UaeEvK.d.ts} +10 -5
- package/dist/{index-DCzFlLoN.d.cts → index-MJ14lkui.d.cts} +10 -5
- package/dist/index.cjs +2020 -1094
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +733 -417
- package/dist/index.d.ts +733 -417
- package/dist/index.js +1898 -986
- package/dist/index.js.map +1 -1
- package/dist/shared/index.cjs +1780 -0
- package/dist/shared/index.cjs.map +1 -0
- package/dist/shared/index.d.cts +266 -0
- package/dist/shared/index.d.ts +266 -0
- package/dist/shared/index.js +1760 -0
- package/dist/shared/index.js.map +1 -0
- package/package.json +6 -4
- package/dist/IProvider-BP49c93d.d.cts +0 -22
- package/dist/IProvider-BP49c93d.d.ts +0 -22
package/dist/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as crypto2 from 'crypto';
|
|
2
2
|
import { randomUUID } from 'crypto';
|
|
3
3
|
import { importPKCS8, SignJWT } from 'jose';
|
|
4
|
-
import * as
|
|
4
|
+
import * as fs16 from 'fs';
|
|
5
5
|
import { promises, existsSync } from 'fs';
|
|
6
6
|
import { EventEmitter } from 'eventemitter3';
|
|
7
|
-
import * as
|
|
7
|
+
import * as path2 from 'path';
|
|
8
8
|
import { join, resolve, dirname, relative, isAbsolute, normalize, extname } from 'path';
|
|
9
|
-
import * as
|
|
9
|
+
import * as os2 from 'os';
|
|
10
10
|
import { homedir } from 'os';
|
|
11
|
-
import
|
|
11
|
+
import OpenAI3 from 'openai';
|
|
12
12
|
import Anthropic from '@anthropic-ai/sdk';
|
|
13
13
|
import { GoogleGenAI } from '@google/genai';
|
|
14
14
|
import 'zod/v3';
|
|
@@ -16,7 +16,7 @@ import * as z4mini from 'zod/v4-mini';
|
|
|
16
16
|
import * as z from 'zod/v4';
|
|
17
17
|
import process2 from 'process';
|
|
18
18
|
import { PassThrough } from 'stream';
|
|
19
|
-
import * as
|
|
19
|
+
import * as fs15 from 'fs/promises';
|
|
20
20
|
import { stat, readFile, mkdir, writeFile, readdir } from 'fs/promises';
|
|
21
21
|
import * as simpleIcons from 'simple-icons';
|
|
22
22
|
import { exec, spawn } from 'child_process';
|
|
@@ -600,7 +600,7 @@ var init_JWTBearer = __esm({
|
|
|
600
600
|
this.privateKey = config.privateKey;
|
|
601
601
|
} else if (config.privateKeyPath) {
|
|
602
602
|
try {
|
|
603
|
-
this.privateKey =
|
|
603
|
+
this.privateKey = fs16.readFileSync(config.privateKeyPath, "utf8");
|
|
604
604
|
} catch (error) {
|
|
605
605
|
throw new Error(`Failed to read private key from ${config.privateKeyPath}: ${error.message}`);
|
|
606
606
|
}
|
|
@@ -1250,11 +1250,11 @@ var init_Logger = __esm({
|
|
|
1250
1250
|
*/
|
|
1251
1251
|
initFileStream(filePath) {
|
|
1252
1252
|
try {
|
|
1253
|
-
const dir =
|
|
1254
|
-
if (!
|
|
1255
|
-
|
|
1253
|
+
const dir = path2.dirname(filePath);
|
|
1254
|
+
if (!fs16.existsSync(dir)) {
|
|
1255
|
+
fs16.mkdirSync(dir, { recursive: true });
|
|
1256
1256
|
}
|
|
1257
|
-
this.fileStream =
|
|
1257
|
+
this.fileStream = fs16.createWriteStream(filePath, {
|
|
1258
1258
|
flags: "a",
|
|
1259
1259
|
// append mode
|
|
1260
1260
|
encoding: "utf8"
|
|
@@ -2003,7 +2003,14 @@ var init_Connector = __esm({
|
|
|
2003
2003
|
}
|
|
2004
2004
|
const startTime = Date.now();
|
|
2005
2005
|
this.requestCount++;
|
|
2006
|
-
|
|
2006
|
+
let url2;
|
|
2007
|
+
if (endpoint.startsWith("http")) {
|
|
2008
|
+
url2 = endpoint;
|
|
2009
|
+
} else {
|
|
2010
|
+
const base = (this.baseURL ?? "").replace(/\/+$/, "");
|
|
2011
|
+
const path6 = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
|
|
2012
|
+
url2 = `${base}${path6}`;
|
|
2013
|
+
}
|
|
2007
2014
|
const timeout = options?.timeout ?? this.config.timeout ?? DEFAULT_CONNECTOR_TIMEOUT;
|
|
2008
2015
|
if (this.config.logging?.enabled) {
|
|
2009
2016
|
this.logRequest(url2, options);
|
|
@@ -14524,12 +14531,12 @@ var require_dist = __commonJS({
|
|
|
14524
14531
|
throw new Error(`Unknown format "${name}"`);
|
|
14525
14532
|
return f;
|
|
14526
14533
|
};
|
|
14527
|
-
function addFormats(ajv, list,
|
|
14534
|
+
function addFormats(ajv, list, fs17, exportName) {
|
|
14528
14535
|
var _a;
|
|
14529
14536
|
var _b;
|
|
14530
14537
|
(_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
14531
14538
|
for (const f of list)
|
|
14532
|
-
ajv.addFormat(f,
|
|
14539
|
+
ajv.addFormat(f, fs17[f]);
|
|
14533
14540
|
}
|
|
14534
14541
|
module.exports = exports$1 = formatsPlugin;
|
|
14535
14542
|
Object.defineProperty(exports$1, "__esModule", { value: true });
|
|
@@ -14542,7 +14549,7 @@ var require_windows = __commonJS({
|
|
|
14542
14549
|
"node_modules/isexe/windows.js"(exports$1, module) {
|
|
14543
14550
|
module.exports = isexe;
|
|
14544
14551
|
isexe.sync = sync;
|
|
14545
|
-
var
|
|
14552
|
+
var fs17 = __require("fs");
|
|
14546
14553
|
function checkPathExt(path6, options) {
|
|
14547
14554
|
var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
|
|
14548
14555
|
if (!pathext) {
|
|
@@ -14560,19 +14567,19 @@ var require_windows = __commonJS({
|
|
|
14560
14567
|
}
|
|
14561
14568
|
return false;
|
|
14562
14569
|
}
|
|
14563
|
-
function checkStat(
|
|
14564
|
-
if (!
|
|
14570
|
+
function checkStat(stat6, path6, options) {
|
|
14571
|
+
if (!stat6.isSymbolicLink() && !stat6.isFile()) {
|
|
14565
14572
|
return false;
|
|
14566
14573
|
}
|
|
14567
14574
|
return checkPathExt(path6, options);
|
|
14568
14575
|
}
|
|
14569
14576
|
function isexe(path6, options, cb) {
|
|
14570
|
-
|
|
14571
|
-
cb(er, er ? false : checkStat(
|
|
14577
|
+
fs17.stat(path6, function(er, stat6) {
|
|
14578
|
+
cb(er, er ? false : checkStat(stat6, path6, options));
|
|
14572
14579
|
});
|
|
14573
14580
|
}
|
|
14574
14581
|
function sync(path6, options) {
|
|
14575
|
-
return checkStat(
|
|
14582
|
+
return checkStat(fs17.statSync(path6), path6, options);
|
|
14576
14583
|
}
|
|
14577
14584
|
}
|
|
14578
14585
|
});
|
|
@@ -14582,22 +14589,22 @@ var require_mode = __commonJS({
|
|
|
14582
14589
|
"node_modules/isexe/mode.js"(exports$1, module) {
|
|
14583
14590
|
module.exports = isexe;
|
|
14584
14591
|
isexe.sync = sync;
|
|
14585
|
-
var
|
|
14592
|
+
var fs17 = __require("fs");
|
|
14586
14593
|
function isexe(path6, options, cb) {
|
|
14587
|
-
|
|
14588
|
-
cb(er, er ? false : checkStat(
|
|
14594
|
+
fs17.stat(path6, function(er, stat6) {
|
|
14595
|
+
cb(er, er ? false : checkStat(stat6, options));
|
|
14589
14596
|
});
|
|
14590
14597
|
}
|
|
14591
14598
|
function sync(path6, options) {
|
|
14592
|
-
return checkStat(
|
|
14599
|
+
return checkStat(fs17.statSync(path6), options);
|
|
14593
14600
|
}
|
|
14594
|
-
function checkStat(
|
|
14595
|
-
return
|
|
14601
|
+
function checkStat(stat6, options) {
|
|
14602
|
+
return stat6.isFile() && checkMode(stat6, options);
|
|
14596
14603
|
}
|
|
14597
|
-
function checkMode(
|
|
14598
|
-
var mod =
|
|
14599
|
-
var uid =
|
|
14600
|
-
var gid =
|
|
14604
|
+
function checkMode(stat6, options) {
|
|
14605
|
+
var mod = stat6.mode;
|
|
14606
|
+
var uid = stat6.uid;
|
|
14607
|
+
var gid = stat6.gid;
|
|
14601
14608
|
var myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid();
|
|
14602
14609
|
var myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid();
|
|
14603
14610
|
var u = parseInt("100", 8);
|
|
@@ -14871,16 +14878,16 @@ var require_shebang_command = __commonJS({
|
|
|
14871
14878
|
// node_modules/cross-spawn/lib/util/readShebang.js
|
|
14872
14879
|
var require_readShebang = __commonJS({
|
|
14873
14880
|
"node_modules/cross-spawn/lib/util/readShebang.js"(exports$1, module) {
|
|
14874
|
-
var
|
|
14881
|
+
var fs17 = __require("fs");
|
|
14875
14882
|
var shebangCommand = require_shebang_command();
|
|
14876
14883
|
function readShebang(command) {
|
|
14877
14884
|
const size = 150;
|
|
14878
14885
|
const buffer = Buffer.alloc(size);
|
|
14879
14886
|
let fd;
|
|
14880
14887
|
try {
|
|
14881
|
-
fd =
|
|
14882
|
-
|
|
14883
|
-
|
|
14888
|
+
fd = fs17.openSync(command, "r");
|
|
14889
|
+
fs17.readSync(fd, buffer, 0, size, 0);
|
|
14890
|
+
fs17.closeSync(fd);
|
|
14884
14891
|
} catch (e) {
|
|
14885
14892
|
}
|
|
14886
14893
|
return shebangCommand(buffer.toString());
|
|
@@ -15989,13 +15996,26 @@ var ToolManager = class extends EventEmitter {
|
|
|
15989
15996
|
pipeline;
|
|
15990
15997
|
/** Optional tool context for execution (set by agent before runs) */
|
|
15991
15998
|
_toolContext;
|
|
15992
|
-
|
|
15999
|
+
/** Hard timeout for tool execution (0 = disabled) */
|
|
16000
|
+
_toolExecutionTimeout;
|
|
16001
|
+
constructor(config) {
|
|
15993
16002
|
super();
|
|
16003
|
+
this._toolExecutionTimeout = config?.toolExecutionTimeout ?? 0;
|
|
15994
16004
|
this.namespaceIndex.set("default", /* @__PURE__ */ new Set());
|
|
15995
16005
|
this.toolLogger = logger.child({ component: "ToolManager" });
|
|
15996
16006
|
this.pipeline = new ToolExecutionPipeline();
|
|
15997
16007
|
this.pipeline.use(new ResultNormalizerPlugin());
|
|
15998
16008
|
}
|
|
16009
|
+
/**
|
|
16010
|
+
* Get or set the hard tool execution timeout in milliseconds.
|
|
16011
|
+
* 0 = disabled (relies on tool's own timeout).
|
|
16012
|
+
*/
|
|
16013
|
+
get toolExecutionTimeout() {
|
|
16014
|
+
return this._toolExecutionTimeout;
|
|
16015
|
+
}
|
|
16016
|
+
set toolExecutionTimeout(value) {
|
|
16017
|
+
this._toolExecutionTimeout = Math.max(0, value);
|
|
16018
|
+
}
|
|
15999
16019
|
/**
|
|
16000
16020
|
* Access the execution pipeline for plugin management.
|
|
16001
16021
|
*
|
|
@@ -16493,7 +16513,7 @@ var ToolManager = class extends EventEmitter {
|
|
|
16493
16513
|
const startTime = Date.now();
|
|
16494
16514
|
metrics.increment("tool.executed", 1, { tool: toolName });
|
|
16495
16515
|
try {
|
|
16496
|
-
const
|
|
16516
|
+
const executionPromise = breaker.execute(async () => {
|
|
16497
16517
|
const toolWithContext = {
|
|
16498
16518
|
...registration.tool,
|
|
16499
16519
|
execute: async (pipelineArgs) => {
|
|
@@ -16502,6 +16522,7 @@ var ToolManager = class extends EventEmitter {
|
|
|
16502
16522
|
};
|
|
16503
16523
|
return await this.pipeline.execute(toolWithContext, args);
|
|
16504
16524
|
});
|
|
16525
|
+
const result = this._toolExecutionTimeout > 0 ? await this.withHardTimeout(executionPromise, toolName, this._toolExecutionTimeout) : await executionPromise;
|
|
16505
16526
|
const duration = Date.now() - startTime;
|
|
16506
16527
|
this.recordExecution(toolName, duration, true);
|
|
16507
16528
|
const resultSummary = this.summarizeResult(result);
|
|
@@ -16564,6 +16585,29 @@ var ToolManager = class extends EventEmitter {
|
|
|
16564
16585
|
return this.list();
|
|
16565
16586
|
}
|
|
16566
16587
|
// ==========================================================================
|
|
16588
|
+
// Hard Timeout
|
|
16589
|
+
// ==========================================================================
|
|
16590
|
+
/**
|
|
16591
|
+
* Wrap a promise with a hard timeout safety net.
|
|
16592
|
+
* If the promise doesn't resolve within the timeout, throws ToolExecutionError.
|
|
16593
|
+
*/
|
|
16594
|
+
async withHardTimeout(promise, toolName, timeoutMs) {
|
|
16595
|
+
let timeoutId;
|
|
16596
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
16597
|
+
timeoutId = setTimeout(() => {
|
|
16598
|
+
reject(new ToolExecutionError(
|
|
16599
|
+
toolName,
|
|
16600
|
+
`Tool execution hard timeout after ${timeoutMs}ms (safety net - tool's own timeout may have failed)`
|
|
16601
|
+
));
|
|
16602
|
+
}, timeoutMs);
|
|
16603
|
+
});
|
|
16604
|
+
try {
|
|
16605
|
+
return await Promise.race([promise, timeoutPromise]);
|
|
16606
|
+
} finally {
|
|
16607
|
+
clearTimeout(timeoutId);
|
|
16608
|
+
}
|
|
16609
|
+
}
|
|
16610
|
+
// ==========================================================================
|
|
16567
16611
|
// Circuit Breaker Management
|
|
16568
16612
|
// ==========================================================================
|
|
16569
16613
|
/**
|
|
@@ -18369,6 +18413,9 @@ var BasePluginNextGen = class {
|
|
|
18369
18413
|
}
|
|
18370
18414
|
};
|
|
18371
18415
|
|
|
18416
|
+
// src/core/context-nextgen/AgentContextNextGen.ts
|
|
18417
|
+
init_Connector();
|
|
18418
|
+
|
|
18372
18419
|
// src/domain/entities/Memory.ts
|
|
18373
18420
|
function isTaskAwareScope(scope) {
|
|
18374
18421
|
return typeof scope === "object" && scope !== null && "type" in scope;
|
|
@@ -19307,13 +19354,18 @@ Values are immediately visible - no retrieval needed.
|
|
|
19307
19354
|
- \`high\`: Keep longer. Important state.
|
|
19308
19355
|
- \`critical\`: Never auto-evicted.
|
|
19309
19356
|
|
|
19357
|
+
**UI Display:** Set \`showInUI: true\` in context_set to display the entry in the user's side panel.
|
|
19358
|
+
Values shown in the UI support the same rich markdown formatting as the chat window
|
|
19359
|
+
(see formatting instructions above). Use this for dashboards, progress displays, and results the user should see.
|
|
19360
|
+
|
|
19310
19361
|
**Tools:** context_set, context_delete, context_list`;
|
|
19311
19362
|
var contextSetDefinition = {
|
|
19312
19363
|
type: "function",
|
|
19313
19364
|
function: {
|
|
19314
19365
|
name: "context_set",
|
|
19315
19366
|
description: `Store or update a key-value pair in live context.
|
|
19316
|
-
Value appears directly in context - no retrieval needed
|
|
19367
|
+
Value appears directly in context - no retrieval needed.
|
|
19368
|
+
Set showInUI to true to also display the entry in the user's side panel.`,
|
|
19317
19369
|
parameters: {
|
|
19318
19370
|
type: "object",
|
|
19319
19371
|
properties: {
|
|
@@ -19324,6 +19376,10 @@ Value appears directly in context - no retrieval needed.`,
|
|
|
19324
19376
|
type: "string",
|
|
19325
19377
|
enum: ["low", "normal", "high", "critical"],
|
|
19326
19378
|
description: 'Eviction priority. Default: "normal"'
|
|
19379
|
+
},
|
|
19380
|
+
showInUI: {
|
|
19381
|
+
type: "boolean",
|
|
19382
|
+
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"
|
|
19327
19383
|
}
|
|
19328
19384
|
},
|
|
19329
19385
|
required: ["key", "description", "value"]
|
|
@@ -19364,6 +19420,7 @@ var InContextMemoryPluginNextGen = class {
|
|
|
19364
19420
|
_destroyed = false;
|
|
19365
19421
|
_tokenCache = null;
|
|
19366
19422
|
_instructionsTokenCache = null;
|
|
19423
|
+
_notifyTimer = null;
|
|
19367
19424
|
constructor(config = {}) {
|
|
19368
19425
|
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
19369
19426
|
}
|
|
@@ -19404,15 +19461,18 @@ var InContextMemoryPluginNextGen = class {
|
|
|
19404
19461
|
return a.updatedAt - b.updatedAt;
|
|
19405
19462
|
});
|
|
19406
19463
|
let freed = 0;
|
|
19464
|
+
let evicted = false;
|
|
19407
19465
|
for (const entry of evictable) {
|
|
19408
19466
|
if (freed >= targetTokensToFree) break;
|
|
19409
19467
|
const entryTokens = this.estimator.estimateTokens(this.formatEntry(entry));
|
|
19410
19468
|
this.entries.delete(entry.key);
|
|
19411
19469
|
freed += entryTokens;
|
|
19470
|
+
evicted = true;
|
|
19412
19471
|
}
|
|
19413
19472
|
this._tokenCache = null;
|
|
19414
19473
|
const content = await this.getContent();
|
|
19415
19474
|
const after = content ? this.estimator.estimateTokens(content) : 0;
|
|
19475
|
+
if (evicted) this.notifyEntriesChanged();
|
|
19416
19476
|
return Math.max(0, before - after);
|
|
19417
19477
|
}
|
|
19418
19478
|
getTools() {
|
|
@@ -19424,6 +19484,7 @@ var InContextMemoryPluginNextGen = class {
|
|
|
19424
19484
|
}
|
|
19425
19485
|
destroy() {
|
|
19426
19486
|
if (this._destroyed) return;
|
|
19487
|
+
if (this._notifyTimer) clearTimeout(this._notifyTimer);
|
|
19427
19488
|
this.entries.clear();
|
|
19428
19489
|
this._destroyed = true;
|
|
19429
19490
|
this._tokenCache = null;
|
|
@@ -19441,6 +19502,7 @@ var InContextMemoryPluginNextGen = class {
|
|
|
19441
19502
|
this.entries.set(entry.key, entry);
|
|
19442
19503
|
}
|
|
19443
19504
|
this._tokenCache = null;
|
|
19505
|
+
this.notifyEntriesChanged();
|
|
19444
19506
|
}
|
|
19445
19507
|
// ============================================================================
|
|
19446
19508
|
// Entry Management
|
|
@@ -19448,19 +19510,21 @@ var InContextMemoryPluginNextGen = class {
|
|
|
19448
19510
|
/**
|
|
19449
19511
|
* Store or update a key-value pair
|
|
19450
19512
|
*/
|
|
19451
|
-
set(key, description, value, priority) {
|
|
19513
|
+
set(key, description, value, priority, showInUI) {
|
|
19452
19514
|
this.assertNotDestroyed();
|
|
19453
19515
|
const entry = {
|
|
19454
19516
|
key,
|
|
19455
19517
|
description,
|
|
19456
19518
|
value,
|
|
19457
19519
|
updatedAt: Date.now(),
|
|
19458
|
-
priority: priority ?? this.config.defaultPriority
|
|
19520
|
+
priority: priority ?? this.config.defaultPriority,
|
|
19521
|
+
showInUI: showInUI ?? false
|
|
19459
19522
|
};
|
|
19460
19523
|
this.entries.set(key, entry);
|
|
19461
19524
|
this.enforceMaxEntries();
|
|
19462
19525
|
this.enforceTokenLimit();
|
|
19463
19526
|
this._tokenCache = null;
|
|
19527
|
+
this.notifyEntriesChanged();
|
|
19464
19528
|
}
|
|
19465
19529
|
/**
|
|
19466
19530
|
* Get a value by key
|
|
@@ -19482,7 +19546,10 @@ var InContextMemoryPluginNextGen = class {
|
|
|
19482
19546
|
delete(key) {
|
|
19483
19547
|
this.assertNotDestroyed();
|
|
19484
19548
|
const deleted = this.entries.delete(key);
|
|
19485
|
-
if (deleted)
|
|
19549
|
+
if (deleted) {
|
|
19550
|
+
this._tokenCache = null;
|
|
19551
|
+
this.notifyEntriesChanged();
|
|
19552
|
+
}
|
|
19486
19553
|
return deleted;
|
|
19487
19554
|
}
|
|
19488
19555
|
/**
|
|
@@ -19494,7 +19561,8 @@ var InContextMemoryPluginNextGen = class {
|
|
|
19494
19561
|
key: e.key,
|
|
19495
19562
|
description: e.description,
|
|
19496
19563
|
priority: e.priority,
|
|
19497
|
-
updatedAt: e.updatedAt
|
|
19564
|
+
updatedAt: e.updatedAt,
|
|
19565
|
+
showInUI: e.showInUI ?? false
|
|
19498
19566
|
}));
|
|
19499
19567
|
}
|
|
19500
19568
|
/**
|
|
@@ -19504,6 +19572,7 @@ var InContextMemoryPluginNextGen = class {
|
|
|
19504
19572
|
this.assertNotDestroyed();
|
|
19505
19573
|
this.entries.clear();
|
|
19506
19574
|
this._tokenCache = null;
|
|
19575
|
+
this.notifyEntriesChanged();
|
|
19507
19576
|
}
|
|
19508
19577
|
// ============================================================================
|
|
19509
19578
|
// Private Helpers
|
|
@@ -19567,6 +19636,20 @@ ${valueStr}
|
|
|
19567
19636
|
return a.updatedAt - b.updatedAt;
|
|
19568
19637
|
});
|
|
19569
19638
|
}
|
|
19639
|
+
/**
|
|
19640
|
+
* Debounced notification when entries change.
|
|
19641
|
+
* Calls config.onEntriesChanged with all current entries.
|
|
19642
|
+
*/
|
|
19643
|
+
notifyEntriesChanged() {
|
|
19644
|
+
if (!this.config.onEntriesChanged) return;
|
|
19645
|
+
if (this._notifyTimer) clearTimeout(this._notifyTimer);
|
|
19646
|
+
this._notifyTimer = setTimeout(() => {
|
|
19647
|
+
this._notifyTimer = null;
|
|
19648
|
+
if (!this._destroyed && this.config.onEntriesChanged) {
|
|
19649
|
+
this.config.onEntriesChanged(Array.from(this.entries.values()));
|
|
19650
|
+
}
|
|
19651
|
+
}, 100);
|
|
19652
|
+
}
|
|
19570
19653
|
assertNotDestroyed() {
|
|
19571
19654
|
if (this._destroyed) {
|
|
19572
19655
|
throw new Error("InContextMemoryPluginNextGen is destroyed");
|
|
@@ -19583,16 +19666,18 @@ ${valueStr}
|
|
|
19583
19666
|
args.key,
|
|
19584
19667
|
args.description,
|
|
19585
19668
|
args.value,
|
|
19586
|
-
args.priority
|
|
19669
|
+
args.priority,
|
|
19670
|
+
args.showInUI
|
|
19587
19671
|
);
|
|
19588
19672
|
return {
|
|
19589
19673
|
success: true,
|
|
19590
19674
|
key: args.key,
|
|
19591
|
-
|
|
19675
|
+
showInUI: args.showInUI ?? false,
|
|
19676
|
+
message: `Stored "${args.key}" in live context${args.showInUI ? " (visible in UI)" : ""}`
|
|
19592
19677
|
};
|
|
19593
19678
|
},
|
|
19594
19679
|
permission: { scope: "always", riskLevel: "low" },
|
|
19595
|
-
describeCall: (args) => `set ${args.key}`
|
|
19680
|
+
describeCall: (args) => `set ${args.key}${args.showInUI ? " [UI]" : ""}`
|
|
19596
19681
|
};
|
|
19597
19682
|
}
|
|
19598
19683
|
createContextDeleteTool() {
|
|
@@ -20904,6 +20989,10 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
|
|
|
20904
20989
|
_sessionId = null;
|
|
20905
20990
|
/** Agent ID */
|
|
20906
20991
|
_agentId;
|
|
20992
|
+
/** User ID for multi-user scenarios */
|
|
20993
|
+
_userId;
|
|
20994
|
+
/** Allowed connector names (when agent is restricted to a subset) */
|
|
20995
|
+
_allowedConnectors;
|
|
20907
20996
|
/** Storage backend */
|
|
20908
20997
|
_storage;
|
|
20909
20998
|
/** Destroyed flag */
|
|
@@ -20940,15 +21029,20 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
|
|
|
20940
21029
|
};
|
|
20941
21030
|
this._systemPrompt = config.systemPrompt;
|
|
20942
21031
|
this._agentId = this._config.agentId;
|
|
21032
|
+
this._userId = config.userId;
|
|
21033
|
+
this._allowedConnectors = config.connectors;
|
|
20943
21034
|
this._storage = config.storage;
|
|
20944
21035
|
this._compactionStrategy = config.compactionStrategy ?? StrategyRegistry.create(this._config.strategy);
|
|
20945
|
-
this._tools = new ToolManager(
|
|
21036
|
+
this._tools = new ToolManager(
|
|
21037
|
+
config.toolExecutionTimeout ? { toolExecutionTimeout: config.toolExecutionTimeout } : void 0
|
|
21038
|
+
);
|
|
20946
21039
|
if (config.tools) {
|
|
20947
21040
|
for (const tool of config.tools) {
|
|
20948
21041
|
this._tools.register(tool);
|
|
20949
21042
|
}
|
|
20950
21043
|
}
|
|
20951
21044
|
this.initializePlugins(config.plugins);
|
|
21045
|
+
this.syncToolContext();
|
|
20952
21046
|
}
|
|
20953
21047
|
/**
|
|
20954
21048
|
* Initialize plugins based on feature flags.
|
|
@@ -20993,6 +21087,62 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
|
|
|
20993
21087
|
);
|
|
20994
21088
|
}
|
|
20995
21089
|
}
|
|
21090
|
+
/**
|
|
21091
|
+
* Sync identity fields and connector registry to ToolContext.
|
|
21092
|
+
* Merges with existing ToolContext to preserve other fields (memory, signal, taskId).
|
|
21093
|
+
*
|
|
21094
|
+
* Connector registry resolution order:
|
|
21095
|
+
* 1. If `connectors` (allowed names) is set → filtered view of global registry
|
|
21096
|
+
* 2. If access policy + userId → scoped view via Connector.scoped()
|
|
21097
|
+
* 3. Otherwise → full global registry
|
|
21098
|
+
*/
|
|
21099
|
+
syncToolContext() {
|
|
21100
|
+
const existing = this._tools.getToolContext();
|
|
21101
|
+
this._tools.setToolContext({
|
|
21102
|
+
...existing,
|
|
21103
|
+
agentId: this._agentId,
|
|
21104
|
+
userId: this._userId,
|
|
21105
|
+
connectorRegistry: this.buildConnectorRegistry()
|
|
21106
|
+
});
|
|
21107
|
+
}
|
|
21108
|
+
/**
|
|
21109
|
+
* Build the connector registry appropriate for this agent's config.
|
|
21110
|
+
*/
|
|
21111
|
+
buildConnectorRegistry() {
|
|
21112
|
+
if (this._allowedConnectors?.length) {
|
|
21113
|
+
const allowedSet = new Set(this._allowedConnectors);
|
|
21114
|
+
const base = this._userId && Connector.getAccessPolicy() ? Connector.scoped({ userId: this._userId }) : Connector.asRegistry();
|
|
21115
|
+
return {
|
|
21116
|
+
get: (name) => {
|
|
21117
|
+
if (!allowedSet.has(name)) {
|
|
21118
|
+
const available = this._allowedConnectors.filter((n) => base.has(n)).join(", ") || "none";
|
|
21119
|
+
throw new Error(`Connector '${name}' not found. Available: ${available}`);
|
|
21120
|
+
}
|
|
21121
|
+
return base.get(name);
|
|
21122
|
+
},
|
|
21123
|
+
has: (name) => allowedSet.has(name) && base.has(name),
|
|
21124
|
+
list: () => base.list().filter((n) => allowedSet.has(n)),
|
|
21125
|
+
listAll: () => base.listAll().filter((c) => allowedSet.has(c.name)),
|
|
21126
|
+
size: () => base.listAll().filter((c) => allowedSet.has(c.name)).length,
|
|
21127
|
+
getDescriptionsForTools: () => {
|
|
21128
|
+
const connectors = base.listAll().filter((c) => allowedSet.has(c.name));
|
|
21129
|
+
if (connectors.length === 0) return "No connectors registered yet.";
|
|
21130
|
+
return connectors.map((c) => ` - "${c.name}": ${c.displayName} - ${c.config.description || "No description"}`).join("\n");
|
|
21131
|
+
},
|
|
21132
|
+
getInfo: () => {
|
|
21133
|
+
const info = {};
|
|
21134
|
+
for (const c of base.listAll().filter((c2) => allowedSet.has(c2.name))) {
|
|
21135
|
+
info[c.name] = { displayName: c.displayName, description: c.config.description || "", baseURL: c.baseURL };
|
|
21136
|
+
}
|
|
21137
|
+
return info;
|
|
21138
|
+
}
|
|
21139
|
+
};
|
|
21140
|
+
}
|
|
21141
|
+
if (this._userId && Connector.getAccessPolicy()) {
|
|
21142
|
+
return Connector.scoped({ userId: this._userId });
|
|
21143
|
+
}
|
|
21144
|
+
return Connector.asRegistry();
|
|
21145
|
+
}
|
|
20996
21146
|
// ============================================================================
|
|
20997
21147
|
// Public Properties
|
|
20998
21148
|
// ============================================================================
|
|
@@ -21008,6 +21158,24 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
|
|
|
21008
21158
|
get agentId() {
|
|
21009
21159
|
return this._agentId;
|
|
21010
21160
|
}
|
|
21161
|
+
/** Get the current user ID */
|
|
21162
|
+
get userId() {
|
|
21163
|
+
return this._userId;
|
|
21164
|
+
}
|
|
21165
|
+
/** Set user ID. Automatically updates ToolContext for all tool executions. */
|
|
21166
|
+
set userId(value) {
|
|
21167
|
+
this._userId = value;
|
|
21168
|
+
this.syncToolContext();
|
|
21169
|
+
}
|
|
21170
|
+
/** Get the allowed connector names (undefined = all visible connectors) */
|
|
21171
|
+
get connectors() {
|
|
21172
|
+
return this._allowedConnectors;
|
|
21173
|
+
}
|
|
21174
|
+
/** Set allowed connector names. Updates ToolContext.connectorRegistry. */
|
|
21175
|
+
set connectors(value) {
|
|
21176
|
+
this._allowedConnectors = value;
|
|
21177
|
+
this.syncToolContext();
|
|
21178
|
+
}
|
|
21011
21179
|
/** Get/set system prompt */
|
|
21012
21180
|
get systemPrompt() {
|
|
21013
21181
|
return this._systemPrompt;
|
|
@@ -21921,6 +22089,7 @@ ${content}`);
|
|
|
21921
22089
|
metadata: {
|
|
21922
22090
|
savedAt: Date.now(),
|
|
21923
22091
|
agentId: this._agentId,
|
|
22092
|
+
userId: this._userId,
|
|
21924
22093
|
model: this._config.model
|
|
21925
22094
|
}
|
|
21926
22095
|
};
|
|
@@ -22678,7 +22847,7 @@ var OpenAITextProvider = class extends BaseTextProvider {
|
|
|
22678
22847
|
streamConverter;
|
|
22679
22848
|
constructor(config) {
|
|
22680
22849
|
super(config);
|
|
22681
|
-
this.client = new
|
|
22850
|
+
this.client = new OpenAI3({
|
|
22682
22851
|
apiKey: this.getApiKey(),
|
|
22683
22852
|
baseURL: this.getBaseURL(),
|
|
22684
22853
|
organization: config.organization,
|
|
@@ -24408,7 +24577,9 @@ var GoogleTextProvider = class extends BaseTextProvider {
|
|
|
24408
24577
|
constructor(config) {
|
|
24409
24578
|
super(config);
|
|
24410
24579
|
this.client = new GoogleGenAI({
|
|
24411
|
-
apiKey: this.getApiKey()
|
|
24580
|
+
apiKey: this.getApiKey(),
|
|
24581
|
+
// Pass custom baseURL for proxy support (e.g. when routing through EW proxy)
|
|
24582
|
+
...config.baseURL ? { httpOptions: { baseUrl: config.baseURL } } : {}
|
|
24412
24583
|
});
|
|
24413
24584
|
this.converter = new GoogleConverter();
|
|
24414
24585
|
this.streamConverter = new GoogleStreamConverter();
|
|
@@ -24705,6 +24876,30 @@ var GenericOpenAIProvider = class extends OpenAITextProvider {
|
|
|
24705
24876
|
};
|
|
24706
24877
|
|
|
24707
24878
|
// src/core/createProvider.ts
|
|
24879
|
+
var VENDOR_DEFAULT_URLS = (() => {
|
|
24880
|
+
const map = /* @__PURE__ */ new Map();
|
|
24881
|
+
try {
|
|
24882
|
+
map.set(Vendor.OpenAI, new OpenAI3({ apiKey: "_" }).baseURL);
|
|
24883
|
+
} catch {
|
|
24884
|
+
}
|
|
24885
|
+
try {
|
|
24886
|
+
map.set(Vendor.Anthropic, new Anthropic({ apiKey: "_" }).baseURL);
|
|
24887
|
+
} catch {
|
|
24888
|
+
}
|
|
24889
|
+
map.set(Vendor.Google, "https://generativelanguage.googleapis.com");
|
|
24890
|
+
map.set(Vendor.GoogleVertex, "https://us-central1-aiplatform.googleapis.com");
|
|
24891
|
+
map.set(Vendor.Groq, "https://api.groq.com/openai/v1");
|
|
24892
|
+
map.set(Vendor.Together, "https://api.together.xyz/v1");
|
|
24893
|
+
map.set(Vendor.Perplexity, "https://api.perplexity.ai");
|
|
24894
|
+
map.set(Vendor.Grok, "https://api.x.ai/v1");
|
|
24895
|
+
map.set(Vendor.DeepSeek, "https://api.deepseek.com/v1");
|
|
24896
|
+
map.set(Vendor.Mistral, "https://api.mistral.ai/v1");
|
|
24897
|
+
map.set(Vendor.Ollama, "http://localhost:11434/v1");
|
|
24898
|
+
return map;
|
|
24899
|
+
})();
|
|
24900
|
+
function getVendorDefaultBaseURL(vendor) {
|
|
24901
|
+
return VENDOR_DEFAULT_URLS.get(vendor);
|
|
24902
|
+
}
|
|
24708
24903
|
function createProvider(connector) {
|
|
24709
24904
|
const injectedProvider = connector.getOptions().provider;
|
|
24710
24905
|
if (injectedProvider && typeof injectedProvider.generate === "function") {
|
|
@@ -24739,39 +24934,15 @@ function createProvider(connector) {
|
|
|
24739
24934
|
});
|
|
24740
24935
|
// OpenAI-compatible providers (use connector.name for unique identification)
|
|
24741
24936
|
case Vendor.Groq:
|
|
24742
|
-
return new GenericOpenAIProvider(connector.name, {
|
|
24743
|
-
...config,
|
|
24744
|
-
baseURL: config.baseURL || "https://api.groq.com/openai/v1"
|
|
24745
|
-
});
|
|
24746
24937
|
case Vendor.Together:
|
|
24747
|
-
return new GenericOpenAIProvider(connector.name, {
|
|
24748
|
-
...config,
|
|
24749
|
-
baseURL: config.baseURL || "https://api.together.xyz/v1"
|
|
24750
|
-
});
|
|
24751
24938
|
case Vendor.Perplexity:
|
|
24752
|
-
return new GenericOpenAIProvider(connector.name, {
|
|
24753
|
-
...config,
|
|
24754
|
-
baseURL: config.baseURL || "https://api.perplexity.ai"
|
|
24755
|
-
});
|
|
24756
24939
|
case Vendor.Grok:
|
|
24757
|
-
return new GenericOpenAIProvider(connector.name, {
|
|
24758
|
-
...config,
|
|
24759
|
-
baseURL: config.baseURL || "https://api.x.ai/v1"
|
|
24760
|
-
});
|
|
24761
24940
|
case Vendor.DeepSeek:
|
|
24762
|
-
return new GenericOpenAIProvider(connector.name, {
|
|
24763
|
-
...config,
|
|
24764
|
-
baseURL: config.baseURL || "https://api.deepseek.com/v1"
|
|
24765
|
-
});
|
|
24766
24941
|
case Vendor.Mistral:
|
|
24767
|
-
return new GenericOpenAIProvider(connector.name, {
|
|
24768
|
-
...config,
|
|
24769
|
-
baseURL: config.baseURL || "https://api.mistral.ai/v1"
|
|
24770
|
-
});
|
|
24771
24942
|
case Vendor.Ollama:
|
|
24772
24943
|
return new GenericOpenAIProvider(connector.name, {
|
|
24773
24944
|
...config,
|
|
24774
|
-
baseURL: config.baseURL ||
|
|
24945
|
+
baseURL: config.baseURL || getVendorDefaultBaseURL(vendor)
|
|
24775
24946
|
});
|
|
24776
24947
|
case Vendor.Custom:
|
|
24777
24948
|
if (!config.baseURL) {
|
|
@@ -24881,9 +25052,14 @@ var BaseAgent = class extends EventEmitter {
|
|
|
24881
25052
|
const contextConfig = {
|
|
24882
25053
|
model: config.model,
|
|
24883
25054
|
agentId: config.name,
|
|
25055
|
+
userId: config.userId,
|
|
25056
|
+
connectors: config.connectors,
|
|
24884
25057
|
// Include storage and sessionId if session config is provided
|
|
24885
25058
|
storage: config.session?.storage,
|
|
25059
|
+
// Thread tool execution timeout to ToolManager
|
|
25060
|
+
toolExecutionTimeout: config.toolExecutionTimeout,
|
|
24886
25061
|
// Subclasses can add systemPrompt via their config
|
|
25062
|
+
// Note: context-level toolExecutionTimeout overrides agent-level if both set
|
|
24887
25063
|
...typeof config.context === "object" && config.context !== null ? config.context : {}
|
|
24888
25064
|
};
|
|
24889
25065
|
return AgentContextNextGen.create(contextConfig);
|
|
@@ -25034,6 +25210,30 @@ var BaseAgent = class extends EventEmitter {
|
|
|
25034
25210
|
get context() {
|
|
25035
25211
|
return this._agentContext;
|
|
25036
25212
|
}
|
|
25213
|
+
/**
|
|
25214
|
+
* Get the current user ID. Delegates to AgentContextNextGen.
|
|
25215
|
+
*/
|
|
25216
|
+
get userId() {
|
|
25217
|
+
return this._agentContext.userId;
|
|
25218
|
+
}
|
|
25219
|
+
/**
|
|
25220
|
+
* Set user ID at runtime. Automatically updates ToolContext for all tool executions.
|
|
25221
|
+
*/
|
|
25222
|
+
set userId(value) {
|
|
25223
|
+
this._agentContext.userId = value;
|
|
25224
|
+
}
|
|
25225
|
+
/**
|
|
25226
|
+
* Get the allowed connector names (undefined = all visible connectors).
|
|
25227
|
+
*/
|
|
25228
|
+
get connectors() {
|
|
25229
|
+
return this._agentContext.connectors;
|
|
25230
|
+
}
|
|
25231
|
+
/**
|
|
25232
|
+
* Restrict this agent to a subset of connectors. Updates ToolContext.connectorRegistry.
|
|
25233
|
+
*/
|
|
25234
|
+
set connectors(value) {
|
|
25235
|
+
this._agentContext.connectors = value;
|
|
25236
|
+
}
|
|
25037
25237
|
/**
|
|
25038
25238
|
* Permission management. Returns ToolPermissionManager for approval control.
|
|
25039
25239
|
*/
|
|
@@ -25085,9 +25285,10 @@ var BaseAgent = class extends EventEmitter {
|
|
|
25085
25285
|
* always sees up-to-date tool descriptions.
|
|
25086
25286
|
*/
|
|
25087
25287
|
getEnabledToolDefinitions() {
|
|
25288
|
+
const toolContext = this._agentContext.tools.getToolContext();
|
|
25088
25289
|
return this._agentContext.tools.getEnabled().map((tool) => {
|
|
25089
25290
|
if (tool.descriptionFactory) {
|
|
25090
|
-
const dynamicDescription = tool.descriptionFactory();
|
|
25291
|
+
const dynamicDescription = tool.descriptionFactory(toolContext);
|
|
25091
25292
|
return {
|
|
25092
25293
|
...tool.definition,
|
|
25093
25294
|
function: {
|
|
@@ -26133,6 +26334,7 @@ var Agent = class _Agent extends BaseAgent {
|
|
|
26133
26334
|
* const agent = Agent.create({
|
|
26134
26335
|
* connector: 'openai', // or Connector instance
|
|
26135
26336
|
* model: 'gpt-4',
|
|
26337
|
+
* userId: 'user-123', // flows to all tool executions automatically
|
|
26136
26338
|
* instructions: 'You are a helpful assistant',
|
|
26137
26339
|
* tools: [myTool]
|
|
26138
26340
|
* });
|
|
@@ -27355,8 +27557,8 @@ var Agent = class _Agent extends BaseAgent {
|
|
|
27355
27557
|
throw new Error("Configuration file not found. Searched: " + this.DEFAULT_PATHS.join(", "));
|
|
27356
27558
|
}
|
|
27357
27559
|
try {
|
|
27358
|
-
const
|
|
27359
|
-
const content =
|
|
27560
|
+
const fs17 = __require("fs");
|
|
27561
|
+
const content = fs17.readFileSync(configPath, "utf-8");
|
|
27360
27562
|
let config = JSON.parse(content);
|
|
27361
27563
|
config = this.interpolateEnvVars(config);
|
|
27362
27564
|
this.validate(config);
|
|
@@ -27385,10 +27587,10 @@ var Agent = class _Agent extends BaseAgent {
|
|
|
27385
27587
|
* Find configuration file synchronously
|
|
27386
27588
|
*/
|
|
27387
27589
|
static findConfigSync() {
|
|
27388
|
-
const
|
|
27590
|
+
const fs17 = __require("fs");
|
|
27389
27591
|
for (const path6 of this.DEFAULT_PATHS) {
|
|
27390
27592
|
try {
|
|
27391
|
-
|
|
27593
|
+
fs17.accessSync(resolve(path6));
|
|
27392
27594
|
return resolve(path6);
|
|
27393
27595
|
} catch {
|
|
27394
27596
|
}
|
|
@@ -33335,7 +33537,7 @@ var OpenAITTSProvider = class extends BaseMediaProvider {
|
|
|
33335
33537
|
client;
|
|
33336
33538
|
constructor(config) {
|
|
33337
33539
|
super({ apiKey: config.auth.apiKey, ...config });
|
|
33338
|
-
this.client = new
|
|
33540
|
+
this.client = new OpenAI3({
|
|
33339
33541
|
apiKey: config.auth.apiKey,
|
|
33340
33542
|
baseURL: config.baseURL,
|
|
33341
33543
|
organization: config.organization,
|
|
@@ -33418,7 +33620,7 @@ var OpenAITTSProvider = class extends BaseMediaProvider {
|
|
|
33418
33620
|
* Handle OpenAI API errors
|
|
33419
33621
|
*/
|
|
33420
33622
|
handleError(error) {
|
|
33421
|
-
if (error instanceof
|
|
33623
|
+
if (error instanceof OpenAI3.APIError) {
|
|
33422
33624
|
const status = error.status;
|
|
33423
33625
|
const message = error.message || "Unknown OpenAI API error";
|
|
33424
33626
|
if (status === 401) {
|
|
@@ -33450,7 +33652,7 @@ var OpenAISTTProvider = class extends BaseMediaProvider {
|
|
|
33450
33652
|
client;
|
|
33451
33653
|
constructor(config) {
|
|
33452
33654
|
super({ apiKey: config.auth.apiKey, ...config });
|
|
33453
|
-
this.client = new
|
|
33655
|
+
this.client = new OpenAI3({
|
|
33454
33656
|
apiKey: config.auth.apiKey,
|
|
33455
33657
|
baseURL: config.baseURL,
|
|
33456
33658
|
organization: config.organization,
|
|
@@ -33552,7 +33754,7 @@ var OpenAISTTProvider = class extends BaseMediaProvider {
|
|
|
33552
33754
|
if (Buffer.isBuffer(audio)) {
|
|
33553
33755
|
return new File([new Uint8Array(audio)], "audio.wav", { type: "audio/wav" });
|
|
33554
33756
|
} else if (typeof audio === "string") {
|
|
33555
|
-
return
|
|
33757
|
+
return fs16.createReadStream(audio);
|
|
33556
33758
|
} else {
|
|
33557
33759
|
throw new Error("Invalid audio input: must be Buffer or file path");
|
|
33558
33760
|
}
|
|
@@ -33611,7 +33813,7 @@ var OpenAISTTProvider = class extends BaseMediaProvider {
|
|
|
33611
33813
|
* Handle OpenAI API errors
|
|
33612
33814
|
*/
|
|
33613
33815
|
handleError(error) {
|
|
33614
|
-
if (error instanceof
|
|
33816
|
+
if (error instanceof OpenAI3.APIError) {
|
|
33615
33817
|
const status = error.status;
|
|
33616
33818
|
const message = error.message || "Unknown OpenAI API error";
|
|
33617
33819
|
if (status === 401) {
|
|
@@ -34105,7 +34307,7 @@ var TextToSpeech = class _TextToSpeech {
|
|
|
34105
34307
|
*/
|
|
34106
34308
|
async toFile(text, filePath, options) {
|
|
34107
34309
|
const response = await this.synthesize(text, options);
|
|
34108
|
-
await
|
|
34310
|
+
await fs15.writeFile(filePath, response.audio);
|
|
34109
34311
|
}
|
|
34110
34312
|
// ======================== Introspection Methods ========================
|
|
34111
34313
|
/**
|
|
@@ -34453,7 +34655,7 @@ var SpeechToText = class _SpeechToText {
|
|
|
34453
34655
|
* @param options - Optional transcription parameters
|
|
34454
34656
|
*/
|
|
34455
34657
|
async transcribeFile(filePath, options) {
|
|
34456
|
-
const audio = await
|
|
34658
|
+
const audio = await fs15.readFile(filePath);
|
|
34457
34659
|
return this.transcribe(audio, options);
|
|
34458
34660
|
}
|
|
34459
34661
|
/**
|
|
@@ -34617,7 +34819,7 @@ var OpenAIImageProvider = class extends BaseMediaProvider {
|
|
|
34617
34819
|
client;
|
|
34618
34820
|
constructor(config) {
|
|
34619
34821
|
super({ apiKey: config.auth.apiKey, ...config });
|
|
34620
|
-
this.client = new
|
|
34822
|
+
this.client = new OpenAI3({
|
|
34621
34823
|
apiKey: config.auth.apiKey,
|
|
34622
34824
|
baseURL: config.baseURL,
|
|
34623
34825
|
organization: config.organization,
|
|
@@ -34779,7 +34981,7 @@ var OpenAIImageProvider = class extends BaseMediaProvider {
|
|
|
34779
34981
|
if (Buffer.isBuffer(image)) {
|
|
34780
34982
|
return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
|
|
34781
34983
|
}
|
|
34782
|
-
return
|
|
34984
|
+
return fs16.createReadStream(image);
|
|
34783
34985
|
}
|
|
34784
34986
|
/**
|
|
34785
34987
|
* Handle OpenAI API errors
|
|
@@ -34926,8 +35128,8 @@ var GoogleImageProvider = class extends BaseMediaProvider {
|
|
|
34926
35128
|
if (Buffer.isBuffer(image)) {
|
|
34927
35129
|
imageBytes = image.toString("base64");
|
|
34928
35130
|
} else {
|
|
34929
|
-
const
|
|
34930
|
-
const buffer =
|
|
35131
|
+
const fs17 = await import('fs');
|
|
35132
|
+
const buffer = fs17.readFileSync(image);
|
|
34931
35133
|
imageBytes = buffer.toString("base64");
|
|
34932
35134
|
}
|
|
34933
35135
|
return {
|
|
@@ -34977,7 +35179,7 @@ var GrokImageProvider = class extends BaseMediaProvider {
|
|
|
34977
35179
|
client;
|
|
34978
35180
|
constructor(config) {
|
|
34979
35181
|
super({ apiKey: config.auth.apiKey, ...config });
|
|
34980
|
-
this.client = new
|
|
35182
|
+
this.client = new OpenAI3({
|
|
34981
35183
|
apiKey: config.auth.apiKey,
|
|
34982
35184
|
baseURL: config.baseURL || GROK_API_BASE_URL,
|
|
34983
35185
|
timeout: config.timeout,
|
|
@@ -35088,7 +35290,7 @@ var GrokImageProvider = class extends BaseMediaProvider {
|
|
|
35088
35290
|
if (Buffer.isBuffer(image)) {
|
|
35089
35291
|
return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
|
|
35090
35292
|
}
|
|
35091
|
-
return
|
|
35293
|
+
return fs16.createReadStream(image);
|
|
35092
35294
|
}
|
|
35093
35295
|
/**
|
|
35094
35296
|
* Handle API errors
|
|
@@ -36290,7 +36492,7 @@ var OpenAISoraProvider = class extends BaseMediaProvider {
|
|
|
36290
36492
|
client;
|
|
36291
36493
|
constructor(config) {
|
|
36292
36494
|
super({ apiKey: config.auth.apiKey, ...config });
|
|
36293
|
-
this.client = new
|
|
36495
|
+
this.client = new OpenAI3({
|
|
36294
36496
|
apiKey: config.auth.apiKey,
|
|
36295
36497
|
baseURL: config.baseURL,
|
|
36296
36498
|
organization: config.organization,
|
|
@@ -36538,8 +36740,8 @@ var OpenAISoraProvider = class extends BaseMediaProvider {
|
|
|
36538
36740
|
return new File([new Uint8Array(image)], "input.png", { type: "image/png" });
|
|
36539
36741
|
}
|
|
36540
36742
|
if (!image.startsWith("http")) {
|
|
36541
|
-
const
|
|
36542
|
-
const data =
|
|
36743
|
+
const fs17 = await import('fs');
|
|
36744
|
+
const data = fs17.readFileSync(image);
|
|
36543
36745
|
return new File([new Uint8Array(data)], "input.png", { type: "image/png" });
|
|
36544
36746
|
}
|
|
36545
36747
|
const response = await fetch(image);
|
|
@@ -36717,7 +36919,7 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
|
|
|
36717
36919
|
if (video.videoBytes) {
|
|
36718
36920
|
buffer = Buffer.from(video.videoBytes, "base64");
|
|
36719
36921
|
} else if (video.uri) {
|
|
36720
|
-
const
|
|
36922
|
+
const fs17 = await import('fs/promises');
|
|
36721
36923
|
const os3 = await import('os');
|
|
36722
36924
|
const path6 = await import('path');
|
|
36723
36925
|
const tempDir = os3.tmpdir();
|
|
@@ -36728,11 +36930,11 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
|
|
|
36728
36930
|
// Pass as GeneratedVideo
|
|
36729
36931
|
downloadPath: tempFile
|
|
36730
36932
|
});
|
|
36731
|
-
buffer = await
|
|
36732
|
-
await
|
|
36933
|
+
buffer = await fs17.readFile(tempFile);
|
|
36934
|
+
await fs17.unlink(tempFile).catch(() => {
|
|
36733
36935
|
});
|
|
36734
36936
|
} catch (downloadError) {
|
|
36735
|
-
await
|
|
36937
|
+
await fs17.unlink(tempFile).catch(() => {
|
|
36736
36938
|
});
|
|
36737
36939
|
throw new ProviderError(
|
|
36738
36940
|
"google",
|
|
@@ -36854,8 +37056,8 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
|
|
|
36854
37056
|
if (image.startsWith("http://") || image.startsWith("https://")) {
|
|
36855
37057
|
return { imageUri: image };
|
|
36856
37058
|
}
|
|
36857
|
-
const
|
|
36858
|
-
const data = await
|
|
37059
|
+
const fs17 = await import('fs/promises');
|
|
37060
|
+
const data = await fs17.readFile(image);
|
|
36859
37061
|
return {
|
|
36860
37062
|
imageBytes: data.toString("base64")
|
|
36861
37063
|
};
|
|
@@ -37162,8 +37364,8 @@ var GrokImagineProvider = class extends BaseMediaProvider {
|
|
|
37162
37364
|
if (image.startsWith("http") || image.startsWith("data:")) {
|
|
37163
37365
|
return image;
|
|
37164
37366
|
}
|
|
37165
|
-
const
|
|
37166
|
-
const data =
|
|
37367
|
+
const fs17 = await import('fs');
|
|
37368
|
+
const data = fs17.readFileSync(image);
|
|
37167
37369
|
const base64 = data.toString("base64");
|
|
37168
37370
|
const ext = image.split(".").pop()?.toLowerCase() || "png";
|
|
37169
37371
|
const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext}`;
|
|
@@ -40900,6 +41102,126 @@ var FileAgentDefinitionStorage = class {
|
|
|
40900
41102
|
function createFileAgentDefinitionStorage(config) {
|
|
40901
41103
|
return new FileAgentDefinitionStorage(config);
|
|
40902
41104
|
}
|
|
41105
|
+
var MIME_TYPES = {
|
|
41106
|
+
png: "image/png",
|
|
41107
|
+
jpeg: "image/jpeg",
|
|
41108
|
+
jpg: "image/jpeg",
|
|
41109
|
+
webp: "image/webp",
|
|
41110
|
+
gif: "image/gif",
|
|
41111
|
+
mp4: "video/mp4",
|
|
41112
|
+
webm: "video/webm",
|
|
41113
|
+
mp3: "audio/mpeg",
|
|
41114
|
+
wav: "audio/wav",
|
|
41115
|
+
opus: "audio/opus",
|
|
41116
|
+
ogg: "audio/ogg",
|
|
41117
|
+
aac: "audio/aac",
|
|
41118
|
+
flac: "audio/flac",
|
|
41119
|
+
pcm: "audio/pcm"
|
|
41120
|
+
};
|
|
41121
|
+
var MEDIA_TYPE_PREFIXES = ["image", "video", "audio"];
|
|
41122
|
+
var FileMediaStorage = class {
|
|
41123
|
+
outputDir;
|
|
41124
|
+
initialized = false;
|
|
41125
|
+
constructor(config) {
|
|
41126
|
+
this.outputDir = config?.outputDir ?? path2.join(os2.tmpdir(), "oneringai-media");
|
|
41127
|
+
}
|
|
41128
|
+
async save(data, metadata) {
|
|
41129
|
+
const dir = metadata.userId ? path2.join(this.outputDir, metadata.userId) : this.outputDir;
|
|
41130
|
+
await fs15.mkdir(dir, { recursive: true });
|
|
41131
|
+
const filename = metadata.suggestedFilename ?? this.generateFilename(metadata);
|
|
41132
|
+
const filePath = path2.join(dir, filename);
|
|
41133
|
+
await fs15.writeFile(filePath, data);
|
|
41134
|
+
const format = metadata.format.toLowerCase();
|
|
41135
|
+
const mimeType = MIME_TYPES[format] ?? "application/octet-stream";
|
|
41136
|
+
return {
|
|
41137
|
+
location: filePath,
|
|
41138
|
+
mimeType,
|
|
41139
|
+
size: data.length
|
|
41140
|
+
};
|
|
41141
|
+
}
|
|
41142
|
+
async read(location) {
|
|
41143
|
+
try {
|
|
41144
|
+
return await fs15.readFile(location);
|
|
41145
|
+
} catch (err) {
|
|
41146
|
+
if (err.code === "ENOENT") {
|
|
41147
|
+
return null;
|
|
41148
|
+
}
|
|
41149
|
+
throw err;
|
|
41150
|
+
}
|
|
41151
|
+
}
|
|
41152
|
+
async delete(location) {
|
|
41153
|
+
try {
|
|
41154
|
+
await fs15.unlink(location);
|
|
41155
|
+
} catch (err) {
|
|
41156
|
+
if (err.code === "ENOENT") {
|
|
41157
|
+
return;
|
|
41158
|
+
}
|
|
41159
|
+
throw err;
|
|
41160
|
+
}
|
|
41161
|
+
}
|
|
41162
|
+
async exists(location) {
|
|
41163
|
+
try {
|
|
41164
|
+
await fs15.access(location);
|
|
41165
|
+
return true;
|
|
41166
|
+
} catch {
|
|
41167
|
+
return false;
|
|
41168
|
+
}
|
|
41169
|
+
}
|
|
41170
|
+
async list(options) {
|
|
41171
|
+
await this.ensureDir();
|
|
41172
|
+
let entries = [];
|
|
41173
|
+
const files = await fs15.readdir(this.outputDir);
|
|
41174
|
+
for (const file of files) {
|
|
41175
|
+
const filePath = path2.join(this.outputDir, file);
|
|
41176
|
+
try {
|
|
41177
|
+
const stat6 = await fs15.stat(filePath);
|
|
41178
|
+
if (!stat6.isFile()) continue;
|
|
41179
|
+
const ext = path2.extname(file).slice(1).toLowerCase();
|
|
41180
|
+
const mimeType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
41181
|
+
let type;
|
|
41182
|
+
for (const prefix of MEDIA_TYPE_PREFIXES) {
|
|
41183
|
+
if (file.startsWith(`${prefix}_`)) {
|
|
41184
|
+
type = prefix;
|
|
41185
|
+
break;
|
|
41186
|
+
}
|
|
41187
|
+
}
|
|
41188
|
+
entries.push({
|
|
41189
|
+
location: filePath,
|
|
41190
|
+
mimeType,
|
|
41191
|
+
size: stat6.size,
|
|
41192
|
+
type,
|
|
41193
|
+
createdAt: stat6.birthtime
|
|
41194
|
+
});
|
|
41195
|
+
} catch {
|
|
41196
|
+
}
|
|
41197
|
+
}
|
|
41198
|
+
if (options?.type) {
|
|
41199
|
+
entries = entries.filter((e) => e.type === options.type);
|
|
41200
|
+
}
|
|
41201
|
+
entries.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
41202
|
+
const offset = options?.offset ?? 0;
|
|
41203
|
+
const limit = options?.limit ?? entries.length;
|
|
41204
|
+
return entries.slice(offset, offset + limit);
|
|
41205
|
+
}
|
|
41206
|
+
getPath() {
|
|
41207
|
+
return this.outputDir;
|
|
41208
|
+
}
|
|
41209
|
+
generateFilename(metadata) {
|
|
41210
|
+
const timestamp = Date.now();
|
|
41211
|
+
const random2 = crypto2.randomBytes(4).toString("hex");
|
|
41212
|
+
const indexSuffix = metadata.index != null ? `_${metadata.index}` : "";
|
|
41213
|
+
return `${metadata.type}_${timestamp}_${random2}${indexSuffix}.${metadata.format}`;
|
|
41214
|
+
}
|
|
41215
|
+
async ensureDir() {
|
|
41216
|
+
if (!this.initialized) {
|
|
41217
|
+
await fs15.mkdir(this.outputDir, { recursive: true });
|
|
41218
|
+
this.initialized = true;
|
|
41219
|
+
}
|
|
41220
|
+
}
|
|
41221
|
+
};
|
|
41222
|
+
function createFileMediaStorage(config) {
|
|
41223
|
+
return new FileMediaStorage(config);
|
|
41224
|
+
}
|
|
40903
41225
|
|
|
40904
41226
|
// src/capabilities/agents/StreamHelpers.ts
|
|
40905
41227
|
var StreamHelpers = class {
|
|
@@ -41590,6 +41912,32 @@ function filterProtectedHeaders(headers) {
|
|
|
41590
41912
|
}
|
|
41591
41913
|
return filtered;
|
|
41592
41914
|
}
|
|
41915
|
+
function normalizeBody(body) {
|
|
41916
|
+
if (typeof body === "string") {
|
|
41917
|
+
try {
|
|
41918
|
+
return JSON.parse(body);
|
|
41919
|
+
} catch {
|
|
41920
|
+
return body;
|
|
41921
|
+
}
|
|
41922
|
+
}
|
|
41923
|
+
return body;
|
|
41924
|
+
}
|
|
41925
|
+
function detectAPIError(data) {
|
|
41926
|
+
if (!data || typeof data !== "object") return null;
|
|
41927
|
+
const obj = data;
|
|
41928
|
+
if (obj.ok === false && typeof obj.error === "string") {
|
|
41929
|
+
return obj.error;
|
|
41930
|
+
}
|
|
41931
|
+
if (obj.success === false) {
|
|
41932
|
+
if (typeof obj.error === "string") return obj.error;
|
|
41933
|
+
if (typeof obj.message === "string") return obj.message;
|
|
41934
|
+
}
|
|
41935
|
+
if (obj.error && typeof obj.error === "object") {
|
|
41936
|
+
const err = obj.error;
|
|
41937
|
+
if (typeof err.message === "string") return err.message;
|
|
41938
|
+
}
|
|
41939
|
+
return null;
|
|
41940
|
+
}
|
|
41593
41941
|
var ConnectorTools = class {
|
|
41594
41942
|
/** Registry of service-specific tool factories */
|
|
41595
41943
|
static factories = /* @__PURE__ */ new Map();
|
|
@@ -41822,7 +42170,7 @@ var ConnectorTools = class {
|
|
|
41822
42170
|
static createGenericAPITool(connector, options) {
|
|
41823
42171
|
const toolName = options?.toolName ?? `${connector.name}_api`;
|
|
41824
42172
|
const userId = options?.userId;
|
|
41825
|
-
const description = options?.description ?? `Make an authenticated API call to ${connector.displayName}.` + (connector.baseURL ? ` Base URL: ${connector.baseURL}
|
|
42173
|
+
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.';
|
|
41826
42174
|
return {
|
|
41827
42175
|
definition: {
|
|
41828
42176
|
type: "function",
|
|
@@ -41839,15 +42187,15 @@ var ConnectorTools = class {
|
|
|
41839
42187
|
},
|
|
41840
42188
|
endpoint: {
|
|
41841
42189
|
type: "string",
|
|
41842
|
-
description:
|
|
42190
|
+
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.'
|
|
41843
42191
|
},
|
|
41844
42192
|
body: {
|
|
41845
42193
|
type: "object",
|
|
41846
|
-
description:
|
|
42194
|
+
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.'
|
|
41847
42195
|
},
|
|
41848
42196
|
queryParams: {
|
|
41849
42197
|
type: "object",
|
|
41850
|
-
description:
|
|
42198
|
+
description: 'URL query parameters (for filtering/pagination on GET requests). Do NOT use for POST/PUT/PATCH data \u2014 use "body" instead.'
|
|
41851
42199
|
},
|
|
41852
42200
|
headers: {
|
|
41853
42201
|
type: "object",
|
|
@@ -41858,7 +42206,8 @@ var ConnectorTools = class {
|
|
|
41858
42206
|
}
|
|
41859
42207
|
}
|
|
41860
42208
|
},
|
|
41861
|
-
execute: async (args) => {
|
|
42209
|
+
execute: async (args, context) => {
|
|
42210
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
41862
42211
|
let url2 = args.endpoint;
|
|
41863
42212
|
if (args.queryParams && Object.keys(args.queryParams).length > 0) {
|
|
41864
42213
|
const params = new URLSearchParams();
|
|
@@ -41871,7 +42220,8 @@ var ConnectorTools = class {
|
|
|
41871
42220
|
let bodyStr;
|
|
41872
42221
|
if (args.body) {
|
|
41873
42222
|
try {
|
|
41874
|
-
|
|
42223
|
+
const normalized = normalizeBody(args.body);
|
|
42224
|
+
bodyStr = safeStringify2(normalized);
|
|
41875
42225
|
} catch (e) {
|
|
41876
42226
|
return {
|
|
41877
42227
|
success: false,
|
|
@@ -41890,7 +42240,7 @@ var ConnectorTools = class {
|
|
|
41890
42240
|
},
|
|
41891
42241
|
body: bodyStr
|
|
41892
42242
|
},
|
|
41893
|
-
|
|
42243
|
+
effectiveUserId
|
|
41894
42244
|
);
|
|
41895
42245
|
const text = await response.text();
|
|
41896
42246
|
let data;
|
|
@@ -41899,11 +42249,12 @@ var ConnectorTools = class {
|
|
|
41899
42249
|
} catch {
|
|
41900
42250
|
data = text;
|
|
41901
42251
|
}
|
|
42252
|
+
const apiError = detectAPIError(data);
|
|
41902
42253
|
return {
|
|
41903
|
-
success: response.ok,
|
|
42254
|
+
success: response.ok && !apiError,
|
|
41904
42255
|
status: response.status,
|
|
41905
|
-
data: response.ok ? data : void 0,
|
|
41906
|
-
error: response.ok ? void 0 : typeof data === "string" ? data : safeStringify2(data)
|
|
42256
|
+
data: response.ok && !apiError ? data : void 0,
|
|
42257
|
+
error: apiError ? apiError : response.ok ? void 0 : typeof data === "string" ? data : safeStringify2(data)
|
|
41907
42258
|
};
|
|
41908
42259
|
} catch (error) {
|
|
41909
42260
|
return {
|
|
@@ -41912,7 +42263,10 @@ var ConnectorTools = class {
|
|
|
41912
42263
|
};
|
|
41913
42264
|
}
|
|
41914
42265
|
},
|
|
41915
|
-
describeCall: (args) =>
|
|
42266
|
+
describeCall: (args) => {
|
|
42267
|
+
const bodyInfo = args.body ? ` body=${JSON.stringify(args.body).slice(0, 100)}` : "";
|
|
42268
|
+
return `${args.method} ${args.endpoint}${bodyInfo}`;
|
|
42269
|
+
},
|
|
41916
42270
|
permission: options?.permission ?? {
|
|
41917
42271
|
scope: "session",
|
|
41918
42272
|
riskLevel: "medium",
|
|
@@ -41947,8 +42301,8 @@ var FileStorage = class {
|
|
|
41947
42301
|
}
|
|
41948
42302
|
async ensureDirectory() {
|
|
41949
42303
|
try {
|
|
41950
|
-
await
|
|
41951
|
-
await
|
|
42304
|
+
await fs15.mkdir(this.directory, { recursive: true });
|
|
42305
|
+
await fs15.chmod(this.directory, 448);
|
|
41952
42306
|
} catch (error) {
|
|
41953
42307
|
}
|
|
41954
42308
|
}
|
|
@@ -41957,20 +42311,20 @@ var FileStorage = class {
|
|
|
41957
42311
|
*/
|
|
41958
42312
|
getFilePath(key) {
|
|
41959
42313
|
const hash = crypto2.createHash("sha256").update(key).digest("hex");
|
|
41960
|
-
return
|
|
42314
|
+
return path2.join(this.directory, `${hash}.token`);
|
|
41961
42315
|
}
|
|
41962
42316
|
async storeToken(key, token) {
|
|
41963
42317
|
await this.ensureDirectory();
|
|
41964
42318
|
const filePath = this.getFilePath(key);
|
|
41965
42319
|
const plaintext = JSON.stringify(token);
|
|
41966
42320
|
const encrypted = encrypt(plaintext, this.encryptionKey);
|
|
41967
|
-
await
|
|
41968
|
-
await
|
|
42321
|
+
await fs15.writeFile(filePath, encrypted, "utf8");
|
|
42322
|
+
await fs15.chmod(filePath, 384);
|
|
41969
42323
|
}
|
|
41970
42324
|
async getToken(key) {
|
|
41971
42325
|
const filePath = this.getFilePath(key);
|
|
41972
42326
|
try {
|
|
41973
|
-
const encrypted = await
|
|
42327
|
+
const encrypted = await fs15.readFile(filePath, "utf8");
|
|
41974
42328
|
const decrypted = decrypt(encrypted, this.encryptionKey);
|
|
41975
42329
|
return JSON.parse(decrypted);
|
|
41976
42330
|
} catch (error) {
|
|
@@ -41979,7 +42333,7 @@ var FileStorage = class {
|
|
|
41979
42333
|
}
|
|
41980
42334
|
console.error("Failed to read/decrypt token file:", error);
|
|
41981
42335
|
try {
|
|
41982
|
-
await
|
|
42336
|
+
await fs15.unlink(filePath);
|
|
41983
42337
|
} catch {
|
|
41984
42338
|
}
|
|
41985
42339
|
return null;
|
|
@@ -41988,7 +42342,7 @@ var FileStorage = class {
|
|
|
41988
42342
|
async deleteToken(key) {
|
|
41989
42343
|
const filePath = this.getFilePath(key);
|
|
41990
42344
|
try {
|
|
41991
|
-
await
|
|
42345
|
+
await fs15.unlink(filePath);
|
|
41992
42346
|
} catch (error) {
|
|
41993
42347
|
if (error.code !== "ENOENT") {
|
|
41994
42348
|
throw error;
|
|
@@ -41998,7 +42352,7 @@ var FileStorage = class {
|
|
|
41998
42352
|
async hasToken(key) {
|
|
41999
42353
|
const filePath = this.getFilePath(key);
|
|
42000
42354
|
try {
|
|
42001
|
-
await
|
|
42355
|
+
await fs15.access(filePath);
|
|
42002
42356
|
return true;
|
|
42003
42357
|
} catch {
|
|
42004
42358
|
return false;
|
|
@@ -42009,7 +42363,7 @@ var FileStorage = class {
|
|
|
42009
42363
|
*/
|
|
42010
42364
|
async listTokens() {
|
|
42011
42365
|
try {
|
|
42012
|
-
const files = await
|
|
42366
|
+
const files = await fs15.readdir(this.directory);
|
|
42013
42367
|
return files.filter((f) => f.endsWith(".token")).map((f) => f.replace(".token", ""));
|
|
42014
42368
|
} catch {
|
|
42015
42369
|
return [];
|
|
@@ -42020,10 +42374,10 @@ var FileStorage = class {
|
|
|
42020
42374
|
*/
|
|
42021
42375
|
async clearAll() {
|
|
42022
42376
|
try {
|
|
42023
|
-
const files = await
|
|
42377
|
+
const files = await fs15.readdir(this.directory);
|
|
42024
42378
|
const tokenFiles = files.filter((f) => f.endsWith(".token"));
|
|
42025
42379
|
await Promise.all(
|
|
42026
|
-
tokenFiles.map((f) =>
|
|
42380
|
+
tokenFiles.map((f) => fs15.unlink(path2.join(this.directory, f)).catch(() => {
|
|
42027
42381
|
}))
|
|
42028
42382
|
);
|
|
42029
42383
|
} catch {
|
|
@@ -42291,22 +42645,26 @@ var ConnectorConfigStore = class {
|
|
|
42291
42645
|
* Encrypt secrets in ConnectorAuth based on auth type
|
|
42292
42646
|
*/
|
|
42293
42647
|
encryptAuthSecrets(auth2) {
|
|
42648
|
+
const encryptedExtra = this.encryptExtra(auth2.extra);
|
|
42294
42649
|
switch (auth2.type) {
|
|
42295
42650
|
case "api_key":
|
|
42296
42651
|
return {
|
|
42297
42652
|
...auth2,
|
|
42298
|
-
apiKey: this.encryptValue(auth2.apiKey)
|
|
42653
|
+
apiKey: this.encryptValue(auth2.apiKey),
|
|
42654
|
+
...encryptedExtra ? { extra: encryptedExtra } : {}
|
|
42299
42655
|
};
|
|
42300
42656
|
case "oauth":
|
|
42301
42657
|
return {
|
|
42302
42658
|
...auth2,
|
|
42303
42659
|
clientSecret: auth2.clientSecret ? this.encryptValue(auth2.clientSecret) : void 0,
|
|
42304
|
-
privateKey: auth2.privateKey ? this.encryptValue(auth2.privateKey) : void 0
|
|
42660
|
+
privateKey: auth2.privateKey ? this.encryptValue(auth2.privateKey) : void 0,
|
|
42661
|
+
...encryptedExtra ? { extra: encryptedExtra } : {}
|
|
42305
42662
|
};
|
|
42306
42663
|
case "jwt":
|
|
42307
42664
|
return {
|
|
42308
42665
|
...auth2,
|
|
42309
|
-
privateKey: this.encryptValue(auth2.privateKey)
|
|
42666
|
+
privateKey: this.encryptValue(auth2.privateKey),
|
|
42667
|
+
...encryptedExtra ? { extra: encryptedExtra } : {}
|
|
42310
42668
|
};
|
|
42311
42669
|
default:
|
|
42312
42670
|
return auth2;
|
|
@@ -42316,27 +42674,53 @@ var ConnectorConfigStore = class {
|
|
|
42316
42674
|
* Decrypt secrets in ConnectorAuth based on auth type
|
|
42317
42675
|
*/
|
|
42318
42676
|
decryptAuthSecrets(auth2) {
|
|
42677
|
+
const decryptedExtra = this.decryptExtra(auth2.extra);
|
|
42319
42678
|
switch (auth2.type) {
|
|
42320
42679
|
case "api_key":
|
|
42321
42680
|
return {
|
|
42322
42681
|
...auth2,
|
|
42323
|
-
apiKey: this.decryptValue(auth2.apiKey)
|
|
42682
|
+
apiKey: this.decryptValue(auth2.apiKey),
|
|
42683
|
+
...decryptedExtra ? { extra: decryptedExtra } : {}
|
|
42324
42684
|
};
|
|
42325
42685
|
case "oauth":
|
|
42326
42686
|
return {
|
|
42327
42687
|
...auth2,
|
|
42328
42688
|
clientSecret: auth2.clientSecret ? this.decryptValue(auth2.clientSecret) : void 0,
|
|
42329
|
-
privateKey: auth2.privateKey ? this.decryptValue(auth2.privateKey) : void 0
|
|
42689
|
+
privateKey: auth2.privateKey ? this.decryptValue(auth2.privateKey) : void 0,
|
|
42690
|
+
...decryptedExtra ? { extra: decryptedExtra } : {}
|
|
42330
42691
|
};
|
|
42331
42692
|
case "jwt":
|
|
42332
42693
|
return {
|
|
42333
42694
|
...auth2,
|
|
42334
|
-
privateKey: this.decryptValue(auth2.privateKey)
|
|
42695
|
+
privateKey: this.decryptValue(auth2.privateKey),
|
|
42696
|
+
...decryptedExtra ? { extra: decryptedExtra } : {}
|
|
42335
42697
|
};
|
|
42336
42698
|
default:
|
|
42337
42699
|
return auth2;
|
|
42338
42700
|
}
|
|
42339
42701
|
}
|
|
42702
|
+
/**
|
|
42703
|
+
* Encrypt all values in an extra Record (vendor-specific credentials)
|
|
42704
|
+
*/
|
|
42705
|
+
encryptExtra(extra) {
|
|
42706
|
+
if (!extra || Object.keys(extra).length === 0) return void 0;
|
|
42707
|
+
const result = {};
|
|
42708
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
42709
|
+
result[key] = this.encryptValue(value);
|
|
42710
|
+
}
|
|
42711
|
+
return result;
|
|
42712
|
+
}
|
|
42713
|
+
/**
|
|
42714
|
+
* Decrypt all values in an extra Record (vendor-specific credentials)
|
|
42715
|
+
*/
|
|
42716
|
+
decryptExtra(extra) {
|
|
42717
|
+
if (!extra || Object.keys(extra).length === 0) return void 0;
|
|
42718
|
+
const result = {};
|
|
42719
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
42720
|
+
result[key] = this.decryptValue(value);
|
|
42721
|
+
}
|
|
42722
|
+
return result;
|
|
42723
|
+
}
|
|
42340
42724
|
/**
|
|
42341
42725
|
* Encrypt a single value if not already encrypted
|
|
42342
42726
|
*/
|
|
@@ -42414,20 +42798,20 @@ var FileConnectorStorage = class {
|
|
|
42414
42798
|
throw new Error("FileConnectorStorage requires a directory path");
|
|
42415
42799
|
}
|
|
42416
42800
|
this.directory = config.directory;
|
|
42417
|
-
this.indexPath =
|
|
42801
|
+
this.indexPath = path2.join(this.directory, "_index.json");
|
|
42418
42802
|
}
|
|
42419
42803
|
async save(name, stored) {
|
|
42420
42804
|
await this.ensureDirectory();
|
|
42421
42805
|
const filePath = this.getFilePath(name);
|
|
42422
42806
|
const json = JSON.stringify(stored, null, 2);
|
|
42423
|
-
await
|
|
42424
|
-
await
|
|
42807
|
+
await fs15.writeFile(filePath, json, "utf8");
|
|
42808
|
+
await fs15.chmod(filePath, 384);
|
|
42425
42809
|
await this.updateIndex(name, "add");
|
|
42426
42810
|
}
|
|
42427
42811
|
async get(name) {
|
|
42428
42812
|
const filePath = this.getFilePath(name);
|
|
42429
42813
|
try {
|
|
42430
|
-
const json = await
|
|
42814
|
+
const json = await fs15.readFile(filePath, "utf8");
|
|
42431
42815
|
return JSON.parse(json);
|
|
42432
42816
|
} catch (error) {
|
|
42433
42817
|
const err = error;
|
|
@@ -42440,7 +42824,7 @@ var FileConnectorStorage = class {
|
|
|
42440
42824
|
async delete(name) {
|
|
42441
42825
|
const filePath = this.getFilePath(name);
|
|
42442
42826
|
try {
|
|
42443
|
-
await
|
|
42827
|
+
await fs15.unlink(filePath);
|
|
42444
42828
|
await this.updateIndex(name, "remove");
|
|
42445
42829
|
return true;
|
|
42446
42830
|
} catch (error) {
|
|
@@ -42454,7 +42838,7 @@ var FileConnectorStorage = class {
|
|
|
42454
42838
|
async has(name) {
|
|
42455
42839
|
const filePath = this.getFilePath(name);
|
|
42456
42840
|
try {
|
|
42457
|
-
await
|
|
42841
|
+
await fs15.access(filePath);
|
|
42458
42842
|
return true;
|
|
42459
42843
|
} catch {
|
|
42460
42844
|
return false;
|
|
@@ -42480,13 +42864,13 @@ var FileConnectorStorage = class {
|
|
|
42480
42864
|
*/
|
|
42481
42865
|
async clear() {
|
|
42482
42866
|
try {
|
|
42483
|
-
const files = await
|
|
42867
|
+
const files = await fs15.readdir(this.directory);
|
|
42484
42868
|
const connectorFiles = files.filter(
|
|
42485
42869
|
(f) => f.endsWith(".connector.json") || f === "_index.json"
|
|
42486
42870
|
);
|
|
42487
42871
|
await Promise.all(
|
|
42488
42872
|
connectorFiles.map(
|
|
42489
|
-
(f) =>
|
|
42873
|
+
(f) => fs15.unlink(path2.join(this.directory, f)).catch(() => {
|
|
42490
42874
|
})
|
|
42491
42875
|
)
|
|
42492
42876
|
);
|
|
@@ -42499,7 +42883,7 @@ var FileConnectorStorage = class {
|
|
|
42499
42883
|
*/
|
|
42500
42884
|
getFilePath(name) {
|
|
42501
42885
|
const hash = this.hashName(name);
|
|
42502
|
-
return
|
|
42886
|
+
return path2.join(this.directory, `${hash}.connector.json`);
|
|
42503
42887
|
}
|
|
42504
42888
|
/**
|
|
42505
42889
|
* Hash connector name to prevent enumeration
|
|
@@ -42513,8 +42897,8 @@ var FileConnectorStorage = class {
|
|
|
42513
42897
|
async ensureDirectory() {
|
|
42514
42898
|
if (this.initialized) return;
|
|
42515
42899
|
try {
|
|
42516
|
-
await
|
|
42517
|
-
await
|
|
42900
|
+
await fs15.mkdir(this.directory, { recursive: true });
|
|
42901
|
+
await fs15.chmod(this.directory, 448);
|
|
42518
42902
|
this.initialized = true;
|
|
42519
42903
|
} catch {
|
|
42520
42904
|
this.initialized = true;
|
|
@@ -42525,7 +42909,7 @@ var FileConnectorStorage = class {
|
|
|
42525
42909
|
*/
|
|
42526
42910
|
async loadIndex() {
|
|
42527
42911
|
try {
|
|
42528
|
-
const json = await
|
|
42912
|
+
const json = await fs15.readFile(this.indexPath, "utf8");
|
|
42529
42913
|
return JSON.parse(json);
|
|
42530
42914
|
} catch {
|
|
42531
42915
|
return { connectors: {} };
|
|
@@ -42543,8 +42927,8 @@ var FileConnectorStorage = class {
|
|
|
42543
42927
|
delete index.connectors[hash];
|
|
42544
42928
|
}
|
|
42545
42929
|
const json = JSON.stringify(index, null, 2);
|
|
42546
|
-
await
|
|
42547
|
-
await
|
|
42930
|
+
await fs15.writeFile(this.indexPath, json, "utf8");
|
|
42931
|
+
await fs15.chmod(this.indexPath, 384);
|
|
42548
42932
|
}
|
|
42549
42933
|
};
|
|
42550
42934
|
|
|
@@ -42589,11 +42973,19 @@ function buildAuthConfig(authTemplate, credentials) {
|
|
|
42589
42973
|
if (!credentials.apiKey) {
|
|
42590
42974
|
throw new Error("API key is required for api_key auth");
|
|
42591
42975
|
}
|
|
42976
|
+
const standardApiKeyFields = /* @__PURE__ */ new Set(["apiKey", "headerName", "headerPrefix"]);
|
|
42977
|
+
const extra = {};
|
|
42978
|
+
for (const field of authTemplate.optionalFields ?? []) {
|
|
42979
|
+
if (!standardApiKeyFields.has(field) && credentials[field]) {
|
|
42980
|
+
extra[field] = credentials[field];
|
|
42981
|
+
}
|
|
42982
|
+
}
|
|
42592
42983
|
return {
|
|
42593
42984
|
type: "api_key",
|
|
42594
42985
|
apiKey: credentials.apiKey,
|
|
42595
42986
|
headerName: defaults.headerName ?? "Authorization",
|
|
42596
|
-
headerPrefix: defaults.headerPrefix ?? "Bearer"
|
|
42987
|
+
headerPrefix: defaults.headerPrefix ?? "Bearer",
|
|
42988
|
+
...Object.keys(extra).length > 0 ? { extra } : {}
|
|
42597
42989
|
};
|
|
42598
42990
|
}
|
|
42599
42991
|
if (!authTemplate.flow) {
|
|
@@ -42863,8 +43255,9 @@ var slackTemplate = {
|
|
|
42863
43255
|
id: "bot-token",
|
|
42864
43256
|
name: "Bot Token",
|
|
42865
43257
|
type: "api_key",
|
|
42866
|
-
description: "Internal workspace bot - get from OAuth & Permissions page of your Slack app",
|
|
43258
|
+
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.",
|
|
42867
43259
|
requiredFields: ["apiKey"],
|
|
43260
|
+
optionalFields: ["appToken", "signingSecret"],
|
|
42868
43261
|
defaults: {
|
|
42869
43262
|
type: "api_key",
|
|
42870
43263
|
headerName: "Authorization",
|
|
@@ -44702,14 +45095,14 @@ function createMessageWithImages(text, imageUrls, role = "user" /* USER */) {
|
|
|
44702
45095
|
var execAsync = promisify(exec);
|
|
44703
45096
|
function cleanupTempFile(filePath) {
|
|
44704
45097
|
try {
|
|
44705
|
-
if (
|
|
44706
|
-
|
|
45098
|
+
if (fs16.existsSync(filePath)) {
|
|
45099
|
+
fs16.unlinkSync(filePath);
|
|
44707
45100
|
}
|
|
44708
45101
|
} catch {
|
|
44709
45102
|
}
|
|
44710
45103
|
}
|
|
44711
45104
|
async function readClipboardImage() {
|
|
44712
|
-
const platform2 =
|
|
45105
|
+
const platform2 = os2.platform();
|
|
44713
45106
|
try {
|
|
44714
45107
|
switch (platform2) {
|
|
44715
45108
|
case "darwin":
|
|
@@ -44732,7 +45125,7 @@ async function readClipboardImage() {
|
|
|
44732
45125
|
}
|
|
44733
45126
|
}
|
|
44734
45127
|
async function readClipboardImageMac() {
|
|
44735
|
-
const tempFile =
|
|
45128
|
+
const tempFile = path2.join(os2.tmpdir(), `clipboard-${Date.now()}.png`);
|
|
44736
45129
|
try {
|
|
44737
45130
|
try {
|
|
44738
45131
|
await execAsync(`pngpaste "${tempFile}"`);
|
|
@@ -44754,7 +45147,7 @@ async function readClipboardImageMac() {
|
|
|
44754
45147
|
end try
|
|
44755
45148
|
`;
|
|
44756
45149
|
const { stdout } = await execAsync(`osascript -e '${script}'`);
|
|
44757
|
-
if (stdout.includes("success") ||
|
|
45150
|
+
if (stdout.includes("success") || fs16.existsSync(tempFile)) {
|
|
44758
45151
|
return await convertFileToDataUri(tempFile);
|
|
44759
45152
|
}
|
|
44760
45153
|
return {
|
|
@@ -44767,18 +45160,18 @@ async function readClipboardImageMac() {
|
|
|
44767
45160
|
}
|
|
44768
45161
|
}
|
|
44769
45162
|
async function readClipboardImageLinux() {
|
|
44770
|
-
const tempFile =
|
|
45163
|
+
const tempFile = path2.join(os2.tmpdir(), `clipboard-${Date.now()}.png`);
|
|
44771
45164
|
try {
|
|
44772
45165
|
try {
|
|
44773
45166
|
await execAsync(`xclip -selection clipboard -t image/png -o > "${tempFile}"`);
|
|
44774
|
-
if (
|
|
45167
|
+
if (fs16.existsSync(tempFile) && fs16.statSync(tempFile).size > 0) {
|
|
44775
45168
|
return await convertFileToDataUri(tempFile);
|
|
44776
45169
|
}
|
|
44777
45170
|
} catch {
|
|
44778
45171
|
}
|
|
44779
45172
|
try {
|
|
44780
45173
|
await execAsync(`wl-paste -t image/png > "${tempFile}"`);
|
|
44781
|
-
if (
|
|
45174
|
+
if (fs16.existsSync(tempFile) && fs16.statSync(tempFile).size > 0) {
|
|
44782
45175
|
return await convertFileToDataUri(tempFile);
|
|
44783
45176
|
}
|
|
44784
45177
|
} catch {
|
|
@@ -44792,7 +45185,7 @@ async function readClipboardImageLinux() {
|
|
|
44792
45185
|
}
|
|
44793
45186
|
}
|
|
44794
45187
|
async function readClipboardImageWindows() {
|
|
44795
|
-
const tempFile =
|
|
45188
|
+
const tempFile = path2.join(os2.tmpdir(), `clipboard-${Date.now()}.png`);
|
|
44796
45189
|
try {
|
|
44797
45190
|
const psScript = `
|
|
44798
45191
|
Add-Type -AssemblyName System.Windows.Forms;
|
|
@@ -44805,7 +45198,7 @@ async function readClipboardImageWindows() {
|
|
|
44805
45198
|
}
|
|
44806
45199
|
`;
|
|
44807
45200
|
await execAsync(`powershell -Command "${psScript}"`);
|
|
44808
|
-
if (
|
|
45201
|
+
if (fs16.existsSync(tempFile) && fs16.statSync(tempFile).size > 0) {
|
|
44809
45202
|
return await convertFileToDataUri(tempFile);
|
|
44810
45203
|
}
|
|
44811
45204
|
return {
|
|
@@ -44818,7 +45211,7 @@ async function readClipboardImageWindows() {
|
|
|
44818
45211
|
}
|
|
44819
45212
|
async function convertFileToDataUri(filePath) {
|
|
44820
45213
|
try {
|
|
44821
|
-
const imageBuffer =
|
|
45214
|
+
const imageBuffer = fs16.readFileSync(filePath);
|
|
44822
45215
|
const base64Image = imageBuffer.toString("base64");
|
|
44823
45216
|
const magic = imageBuffer.slice(0, 4).toString("hex");
|
|
44824
45217
|
let mimeType = "image/png";
|
|
@@ -44845,7 +45238,7 @@ async function convertFileToDataUri(filePath) {
|
|
|
44845
45238
|
}
|
|
44846
45239
|
}
|
|
44847
45240
|
async function hasClipboardImage() {
|
|
44848
|
-
const platform2 =
|
|
45241
|
+
const platform2 = os2.platform();
|
|
44849
45242
|
try {
|
|
44850
45243
|
switch (platform2) {
|
|
44851
45244
|
case "darwin":
|
|
@@ -45063,20 +45456,29 @@ __export(tools_exports, {
|
|
|
45063
45456
|
ConnectorTools: () => ConnectorTools,
|
|
45064
45457
|
DEFAULT_FILESYSTEM_CONFIG: () => DEFAULT_FILESYSTEM_CONFIG,
|
|
45065
45458
|
DEFAULT_SHELL_CONFIG: () => DEFAULT_SHELL_CONFIG,
|
|
45066
|
-
FileMediaOutputHandler: () =>
|
|
45459
|
+
FileMediaOutputHandler: () => FileMediaStorage,
|
|
45067
45460
|
ToolRegistry: () => ToolRegistry,
|
|
45068
45461
|
bash: () => bash,
|
|
45069
45462
|
createBashTool: () => createBashTool,
|
|
45463
|
+
createCreatePRTool: () => createCreatePRTool,
|
|
45070
45464
|
createEditFileTool: () => createEditFileTool,
|
|
45071
45465
|
createExecuteJavaScriptTool: () => createExecuteJavaScriptTool,
|
|
45466
|
+
createGetPRTool: () => createGetPRTool,
|
|
45467
|
+
createGitHubReadFileTool: () => createGitHubReadFileTool,
|
|
45072
45468
|
createGlobTool: () => createGlobTool,
|
|
45073
45469
|
createGrepTool: () => createGrepTool,
|
|
45074
45470
|
createImageGenerationTool: () => createImageGenerationTool,
|
|
45075
45471
|
createListDirectoryTool: () => createListDirectoryTool,
|
|
45472
|
+
createPRCommentsTool: () => createPRCommentsTool,
|
|
45473
|
+
createPRFilesTool: () => createPRFilesTool,
|
|
45076
45474
|
createReadFileTool: () => createReadFileTool,
|
|
45475
|
+
createSearchCodeTool: () => createSearchCodeTool,
|
|
45476
|
+
createSearchFilesTool: () => createSearchFilesTool,
|
|
45077
45477
|
createSpeechToTextTool: () => createSpeechToTextTool,
|
|
45078
45478
|
createTextToSpeechTool: () => createTextToSpeechTool,
|
|
45079
45479
|
createVideoTools: () => createVideoTools,
|
|
45480
|
+
createWebScrapeTool: () => createWebScrapeTool,
|
|
45481
|
+
createWebSearchTool: () => createWebSearchTool,
|
|
45080
45482
|
createWriteFileTool: () => createWriteFileTool,
|
|
45081
45483
|
developerTools: () => developerTools,
|
|
45082
45484
|
editFile: () => editFile,
|
|
@@ -45085,6 +45487,7 @@ __export(tools_exports, {
|
|
|
45085
45487
|
getAllBuiltInTools: () => getAllBuiltInTools,
|
|
45086
45488
|
getBackgroundOutput: () => getBackgroundOutput,
|
|
45087
45489
|
getMediaOutputHandler: () => getMediaOutputHandler,
|
|
45490
|
+
getMediaStorage: () => getMediaStorage,
|
|
45088
45491
|
getToolByName: () => getToolByName,
|
|
45089
45492
|
getToolCategories: () => getToolCategories,
|
|
45090
45493
|
getToolRegistry: () => getToolRegistry,
|
|
@@ -45097,15 +45500,15 @@ __export(tools_exports, {
|
|
|
45097
45500
|
jsonManipulator: () => jsonManipulator,
|
|
45098
45501
|
killBackgroundProcess: () => killBackgroundProcess,
|
|
45099
45502
|
listDirectory: () => listDirectory,
|
|
45100
|
-
|
|
45503
|
+
parseRepository: () => parseRepository,
|
|
45504
|
+
readFile: () => readFile5,
|
|
45505
|
+
resolveRepository: () => resolveRepository,
|
|
45101
45506
|
setMediaOutputHandler: () => setMediaOutputHandler,
|
|
45507
|
+
setMediaStorage: () => setMediaStorage,
|
|
45102
45508
|
toolRegistry: () => toolRegistry,
|
|
45103
45509
|
validatePath: () => validatePath,
|
|
45104
45510
|
webFetch: () => webFetch,
|
|
45105
|
-
|
|
45106
|
-
webScrape: () => webScrape,
|
|
45107
|
-
webSearch: () => webSearch,
|
|
45108
|
-
writeFile: () => writeFile4
|
|
45511
|
+
writeFile: () => writeFile5
|
|
45109
45512
|
});
|
|
45110
45513
|
var DEFAULT_FILESYSTEM_CONFIG = {
|
|
45111
45514
|
workingDirectory: process.cwd(),
|
|
@@ -45358,7 +45761,7 @@ EXAMPLES:
|
|
|
45358
45761
|
}
|
|
45359
45762
|
};
|
|
45360
45763
|
}
|
|
45361
|
-
var
|
|
45764
|
+
var readFile5 = createReadFileTool();
|
|
45362
45765
|
function createWriteFileTool(config = {}) {
|
|
45363
45766
|
const mergedConfig = { ...DEFAULT_FILESYSTEM_CONFIG, ...config };
|
|
45364
45767
|
return {
|
|
@@ -45445,7 +45848,7 @@ EXAMPLES:
|
|
|
45445
45848
|
}
|
|
45446
45849
|
};
|
|
45447
45850
|
}
|
|
45448
|
-
var
|
|
45851
|
+
var writeFile5 = createWriteFileTool();
|
|
45449
45852
|
function createEditFileTool(config = {}) {
|
|
45450
45853
|
const mergedConfig = { ...DEFAULT_FILESYSTEM_CONFIG, ...config };
|
|
45451
45854
|
return {
|
|
@@ -46372,7 +46775,8 @@ EXAMPLES:
|
|
|
46372
46775
|
shell: mergedConfig.shell,
|
|
46373
46776
|
cwd: mergedConfig.workingDirectory,
|
|
46374
46777
|
env,
|
|
46375
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
46778
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
46779
|
+
detached: true
|
|
46376
46780
|
});
|
|
46377
46781
|
if (run_in_background && mergedConfig.allowBackground) {
|
|
46378
46782
|
const bgId = generateBackgroundId();
|
|
@@ -46399,14 +46803,27 @@ EXAMPLES:
|
|
|
46399
46803
|
let stdout = "";
|
|
46400
46804
|
let stderr = "";
|
|
46401
46805
|
let killed = false;
|
|
46806
|
+
const killProcessGroup = (signal) => {
|
|
46807
|
+
try {
|
|
46808
|
+
if (childProcess.pid) {
|
|
46809
|
+
process.kill(-childProcess.pid, signal);
|
|
46810
|
+
}
|
|
46811
|
+
} catch {
|
|
46812
|
+
try {
|
|
46813
|
+
childProcess.kill(signal);
|
|
46814
|
+
} catch {
|
|
46815
|
+
}
|
|
46816
|
+
}
|
|
46817
|
+
};
|
|
46818
|
+
const GRACEFUL_KILL_WAIT_MS = 3e3;
|
|
46402
46819
|
const timeoutId = setTimeout(() => {
|
|
46403
46820
|
killed = true;
|
|
46404
|
-
|
|
46821
|
+
killProcessGroup("SIGTERM");
|
|
46405
46822
|
setTimeout(() => {
|
|
46406
46823
|
if (!childProcess.killed) {
|
|
46407
|
-
|
|
46824
|
+
killProcessGroup("SIGKILL");
|
|
46408
46825
|
}
|
|
46409
|
-
},
|
|
46826
|
+
}, GRACEFUL_KILL_WAIT_MS);
|
|
46410
46827
|
}, effectiveTimeout);
|
|
46411
46828
|
childProcess.stdout.on("data", (data) => {
|
|
46412
46829
|
stdout += data.toString();
|
|
@@ -46420,8 +46837,28 @@ EXAMPLES:
|
|
|
46420
46837
|
stderr = stderr.slice(-mergedConfig.maxOutputSize);
|
|
46421
46838
|
}
|
|
46422
46839
|
});
|
|
46423
|
-
|
|
46840
|
+
let resolved = false;
|
|
46841
|
+
const safeResolve = (result) => {
|
|
46842
|
+
if (resolved) return;
|
|
46843
|
+
resolved = true;
|
|
46424
46844
|
clearTimeout(timeoutId);
|
|
46845
|
+
clearTimeout(hardTimeoutId);
|
|
46846
|
+
resolve4(result);
|
|
46847
|
+
};
|
|
46848
|
+
const HARD_TIMEOUT_GRACE_MS = 5e3;
|
|
46849
|
+
const hardTimeoutId = setTimeout(() => {
|
|
46850
|
+
if (!resolved) {
|
|
46851
|
+
killProcessGroup("SIGKILL");
|
|
46852
|
+
safeResolve({
|
|
46853
|
+
success: false,
|
|
46854
|
+
stdout,
|
|
46855
|
+
stderr,
|
|
46856
|
+
duration: Date.now() - startTime,
|
|
46857
|
+
error: `Command timed out after ${effectiveTimeout}ms (hard timeout: process group did not exit)`
|
|
46858
|
+
});
|
|
46859
|
+
}
|
|
46860
|
+
}, effectiveTimeout + GRACEFUL_KILL_WAIT_MS + HARD_TIMEOUT_GRACE_MS);
|
|
46861
|
+
childProcess.on("close", (code, signal) => {
|
|
46425
46862
|
const duration = Date.now() - startTime;
|
|
46426
46863
|
let truncated = false;
|
|
46427
46864
|
if (stdout.length > mergedConfig.maxOutputSize) {
|
|
@@ -46433,7 +46870,7 @@ EXAMPLES:
|
|
|
46433
46870
|
truncated = true;
|
|
46434
46871
|
}
|
|
46435
46872
|
if (killed) {
|
|
46436
|
-
|
|
46873
|
+
safeResolve({
|
|
46437
46874
|
success: false,
|
|
46438
46875
|
stdout,
|
|
46439
46876
|
stderr,
|
|
@@ -46444,7 +46881,7 @@ EXAMPLES:
|
|
|
46444
46881
|
error: `Command timed out after ${effectiveTimeout}ms`
|
|
46445
46882
|
});
|
|
46446
46883
|
} else {
|
|
46447
|
-
|
|
46884
|
+
safeResolve({
|
|
46448
46885
|
success: code === 0,
|
|
46449
46886
|
stdout,
|
|
46450
46887
|
stderr,
|
|
@@ -46457,8 +46894,7 @@ EXAMPLES:
|
|
|
46457
46894
|
}
|
|
46458
46895
|
});
|
|
46459
46896
|
childProcess.on("error", (error) => {
|
|
46460
|
-
|
|
46461
|
-
resolve4({
|
|
46897
|
+
safeResolve({
|
|
46462
46898
|
success: false,
|
|
46463
46899
|
error: `Failed to execute command: ${error.message}`,
|
|
46464
46900
|
duration: Date.now() - startTime
|
|
@@ -46794,6 +47230,111 @@ The tool returns a result object with:
|
|
|
46794
47230
|
}
|
|
46795
47231
|
};
|
|
46796
47232
|
|
|
47233
|
+
// src/tools/web/createWebSearchTool.ts
|
|
47234
|
+
init_Logger();
|
|
47235
|
+
var searchLogger = logger.child({ component: "webSearch" });
|
|
47236
|
+
function createWebSearchTool(connector) {
|
|
47237
|
+
return {
|
|
47238
|
+
definition: {
|
|
47239
|
+
type: "function",
|
|
47240
|
+
function: {
|
|
47241
|
+
name: "web_search",
|
|
47242
|
+
description: `Search the web and get relevant results with snippets.
|
|
47243
|
+
|
|
47244
|
+
RETURNS:
|
|
47245
|
+
An array of search results, each containing:
|
|
47246
|
+
- title: Page title
|
|
47247
|
+
- url: Direct URL to the page
|
|
47248
|
+
- snippet: Short description/excerpt from the page
|
|
47249
|
+
- position: Search ranking position (1, 2, 3...)
|
|
47250
|
+
|
|
47251
|
+
USE CASES:
|
|
47252
|
+
- Find current information on any topic
|
|
47253
|
+
- Research multiple sources
|
|
47254
|
+
- Discover relevant websites
|
|
47255
|
+
- Find URLs to fetch with web_fetch tool
|
|
47256
|
+
|
|
47257
|
+
WORKFLOW PATTERN:
|
|
47258
|
+
1. Use web_search to find relevant URLs
|
|
47259
|
+
2. Use web_fetch to get full content from top results
|
|
47260
|
+
3. Process and summarize the information
|
|
47261
|
+
|
|
47262
|
+
EXAMPLE:
|
|
47263
|
+
{
|
|
47264
|
+
"query": "latest AI developments 2026",
|
|
47265
|
+
"numResults": 5
|
|
47266
|
+
}`,
|
|
47267
|
+
parameters: {
|
|
47268
|
+
type: "object",
|
|
47269
|
+
properties: {
|
|
47270
|
+
query: {
|
|
47271
|
+
type: "string",
|
|
47272
|
+
description: "The search query string. Be specific for better results."
|
|
47273
|
+
},
|
|
47274
|
+
numResults: {
|
|
47275
|
+
type: "number",
|
|
47276
|
+
description: "Number of results to return (default: 10, max: 100)."
|
|
47277
|
+
},
|
|
47278
|
+
country: {
|
|
47279
|
+
type: "string",
|
|
47280
|
+
description: 'Country/region code for localized results (e.g., "us", "gb", "de")'
|
|
47281
|
+
},
|
|
47282
|
+
language: {
|
|
47283
|
+
type: "string",
|
|
47284
|
+
description: 'Language code for results (e.g., "en", "fr", "de")'
|
|
47285
|
+
}
|
|
47286
|
+
},
|
|
47287
|
+
required: ["query"]
|
|
47288
|
+
}
|
|
47289
|
+
},
|
|
47290
|
+
blocking: true,
|
|
47291
|
+
timeout: 15e3
|
|
47292
|
+
},
|
|
47293
|
+
execute: async (args) => {
|
|
47294
|
+
const numResults = args.numResults || 10;
|
|
47295
|
+
searchLogger.debug({ connectorName: connector.name }, "Executing search with connector");
|
|
47296
|
+
try {
|
|
47297
|
+
const searchProvider = SearchProvider.create({ connector: connector.name });
|
|
47298
|
+
const response = await searchProvider.search(args.query, {
|
|
47299
|
+
numResults,
|
|
47300
|
+
country: args.country,
|
|
47301
|
+
language: args.language
|
|
47302
|
+
});
|
|
47303
|
+
if (response.success) {
|
|
47304
|
+
searchLogger.debug({
|
|
47305
|
+
provider: response.provider,
|
|
47306
|
+
count: response.count
|
|
47307
|
+
}, "Search completed successfully");
|
|
47308
|
+
} else {
|
|
47309
|
+
searchLogger.warn({
|
|
47310
|
+
provider: response.provider,
|
|
47311
|
+
error: response.error
|
|
47312
|
+
}, "Search failed");
|
|
47313
|
+
}
|
|
47314
|
+
return {
|
|
47315
|
+
success: response.success,
|
|
47316
|
+
query: response.query,
|
|
47317
|
+
provider: response.provider,
|
|
47318
|
+
results: response.results,
|
|
47319
|
+
count: response.count,
|
|
47320
|
+
error: response.error
|
|
47321
|
+
};
|
|
47322
|
+
} catch (error) {
|
|
47323
|
+
searchLogger.error({ error: error.message, connectorName: connector.name }, "Search threw exception");
|
|
47324
|
+
return {
|
|
47325
|
+
success: false,
|
|
47326
|
+
query: args.query,
|
|
47327
|
+
provider: connector.name,
|
|
47328
|
+
results: [],
|
|
47329
|
+
count: 0,
|
|
47330
|
+
error: error.message || "Unknown error"
|
|
47331
|
+
};
|
|
47332
|
+
}
|
|
47333
|
+
},
|
|
47334
|
+
describeCall: (args) => `"${args.query}"${args.numResults ? ` (${args.numResults} results)` : ""}`
|
|
47335
|
+
};
|
|
47336
|
+
}
|
|
47337
|
+
|
|
46797
47338
|
// src/tools/web/contentDetector.ts
|
|
46798
47339
|
function detectContentQuality(html, text, $) {
|
|
46799
47340
|
const issues = [];
|
|
@@ -46868,7 +47409,7 @@ function detectContentQuality(html, text, $) {
|
|
|
46868
47409
|
}
|
|
46869
47410
|
let suggestion;
|
|
46870
47411
|
if (requiresJS && score < 50) {
|
|
46871
|
-
suggestion = "Content quality is low. This appears to be a JavaScript-rendered site. Use
|
|
47412
|
+
suggestion = "Content quality is low. This appears to be a JavaScript-rendered site. Use a scraping service connector for better results.";
|
|
46872
47413
|
} else if (score < 30) {
|
|
46873
47414
|
suggestion = "Content extraction failed or page has errors. Check the URL and try again.";
|
|
46874
47415
|
}
|
|
@@ -46977,7 +47518,7 @@ The tool analyzes the fetched content and returns a quality score (0-100):
|
|
|
46977
47518
|
- 50-79: Moderate quality, some content extracted
|
|
46978
47519
|
- 0-49: Low quality, likely needs JavaScript or has errors
|
|
46979
47520
|
|
|
46980
|
-
If the quality score is low or requiresJS is true,
|
|
47521
|
+
If the quality score is low or requiresJS is true, consider using a scraping service connector for better results.
|
|
46981
47522
|
|
|
46982
47523
|
RETURNS:
|
|
46983
47524
|
{
|
|
@@ -47141,460 +47682,109 @@ With custom user agent:
|
|
|
47141
47682
|
}
|
|
47142
47683
|
};
|
|
47143
47684
|
|
|
47144
|
-
// src/tools/web/
|
|
47145
|
-
|
|
47146
|
-
var
|
|
47147
|
-
|
|
47148
|
-
|
|
47149
|
-
|
|
47150
|
-
|
|
47151
|
-
|
|
47152
|
-
|
|
47153
|
-
|
|
47154
|
-
}
|
|
47155
|
-
return puppeteerModule;
|
|
47156
|
-
}
|
|
47157
|
-
async function getBrowser() {
|
|
47158
|
-
if (!browserInstance) {
|
|
47159
|
-
const puppeteer = await loadPuppeteer();
|
|
47160
|
-
browserInstance = await puppeteer.launch({
|
|
47161
|
-
headless: true,
|
|
47162
|
-
args: ["--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage"]
|
|
47163
|
-
});
|
|
47164
|
-
process.on("exit", async () => {
|
|
47165
|
-
if (browserInstance) {
|
|
47166
|
-
await browserInstance.close();
|
|
47167
|
-
}
|
|
47168
|
-
});
|
|
47169
|
-
}
|
|
47170
|
-
return browserInstance;
|
|
47171
|
-
}
|
|
47172
|
-
var webFetchJS = {
|
|
47173
|
-
definition: {
|
|
47174
|
-
type: "function",
|
|
47175
|
-
function: {
|
|
47176
|
-
name: "web_fetch_js",
|
|
47177
|
-
description: `Fetch and extract content from JavaScript-rendered websites using a headless browser (Puppeteer).
|
|
47178
|
-
|
|
47179
|
-
USE THIS TOOL WHEN:
|
|
47180
|
-
- The web_fetch tool returned a low quality score (<50)
|
|
47181
|
-
- The web_fetch tool suggested using JavaScript rendering
|
|
47182
|
-
- You know the website is built with React/Vue/Angular/Next.js
|
|
47183
|
-
- Content loads dynamically via JavaScript
|
|
47184
|
-
- The page requires interaction (though this tool doesn't support interaction yet)
|
|
47185
|
-
|
|
47186
|
-
HOW IT WORKS:
|
|
47187
|
-
- Launches a headless Chrome browser
|
|
47188
|
-
- Navigates to the URL
|
|
47189
|
-
- Waits for JavaScript to execute and content to load
|
|
47190
|
-
- Extracts the rendered HTML and text content
|
|
47191
|
-
- Optionally captures a screenshot
|
|
47192
|
-
|
|
47193
|
-
CAPABILITIES:
|
|
47194
|
-
- Executes all JavaScript on the page
|
|
47195
|
-
- Waits for network to be idle (all resources loaded)
|
|
47196
|
-
- Can wait for specific CSS selectors to appear
|
|
47197
|
-
- Handles React, Vue, Angular, Next.js, and other SPAs
|
|
47198
|
-
- Returns content after full JavaScript execution
|
|
47199
|
-
|
|
47200
|
-
LIMITATIONS:
|
|
47201
|
-
- Slower than web_fetch (typically 3-10 seconds vs <1 second)
|
|
47202
|
-
- Uses more system resources (runs a full browser)
|
|
47203
|
-
- May still fail on sites with aggressive bot detection
|
|
47204
|
-
- Requires puppeteer to be installed (npm install puppeteer)
|
|
47205
|
-
|
|
47206
|
-
PERFORMANCE:
|
|
47207
|
-
- First call: Slower (launches browser ~1-2s)
|
|
47208
|
-
- Subsequent calls: Faster (reuses browser instance)
|
|
47209
|
-
|
|
47210
|
-
RETURNS:
|
|
47211
|
-
{
|
|
47212
|
-
success: boolean,
|
|
47213
|
-
url: string,
|
|
47214
|
-
title: string,
|
|
47215
|
-
content: string, // Clean markdown (converted via Readability + Turndown)
|
|
47216
|
-
screenshot: string, // Base64 PNG screenshot (if requested)
|
|
47217
|
-
loadTime: number, // Time taken in milliseconds
|
|
47218
|
-
excerpt: string, // Short summary excerpt (if extracted)
|
|
47219
|
-
byline: string, // Author info (if extracted)
|
|
47220
|
-
wasTruncated: boolean, // True if content was truncated
|
|
47221
|
-
error: string // Error message if failed
|
|
47222
|
-
}
|
|
47223
|
-
|
|
47224
|
-
EXAMPLES:
|
|
47225
|
-
Basic usage:
|
|
47226
|
-
{
|
|
47227
|
-
url: "https://react-app.com/page"
|
|
47228
|
-
}
|
|
47229
|
-
|
|
47230
|
-
Wait for specific content:
|
|
47231
|
-
{
|
|
47232
|
-
url: "https://app.com/dashboard",
|
|
47233
|
-
waitForSelector: "#main-content", // Wait for this element
|
|
47234
|
-
timeout: 20000
|
|
47685
|
+
// src/tools/web/createWebScrapeTool.ts
|
|
47686
|
+
init_Logger();
|
|
47687
|
+
var scrapeLogger = logger.child({ component: "webScrape" });
|
|
47688
|
+
var DEFAULT_MIN_QUALITY = 50;
|
|
47689
|
+
function stripBase64DataUris(content) {
|
|
47690
|
+
if (!content) return content;
|
|
47691
|
+
let cleaned = content.replace(/!\[[^\]]*\]\(data:[^)]+\)/g, "[image removed]");
|
|
47692
|
+
cleaned = cleaned.replace(/url\(['"]?data:[^)]+['"]?\)/gi, "url([data-uri-removed])");
|
|
47693
|
+
cleaned = cleaned.replace(/data:(?:image|font|application)\/[^;]+;base64,[A-Za-z0-9+/=]{100,}/g, "[base64-data-removed]");
|
|
47694
|
+
return cleaned;
|
|
47235
47695
|
}
|
|
47236
|
-
|
|
47237
|
-
|
|
47238
|
-
|
|
47239
|
-
|
|
47240
|
-
takeScreenshot: true
|
|
47241
|
-
}`,
|
|
47242
|
-
parameters: {
|
|
47243
|
-
type: "object",
|
|
47244
|
-
properties: {
|
|
47245
|
-
url: {
|
|
47246
|
-
type: "string",
|
|
47247
|
-
description: "The URL to fetch. Must start with http:// or https://"
|
|
47248
|
-
},
|
|
47249
|
-
waitForSelector: {
|
|
47250
|
-
type: "string",
|
|
47251
|
-
description: 'Optional CSS selector to wait for before extracting content. Example: "#main-content" or ".article-body"'
|
|
47252
|
-
},
|
|
47253
|
-
timeout: {
|
|
47254
|
-
type: "number",
|
|
47255
|
-
description: "Max wait time in milliseconds (default: 15000)"
|
|
47256
|
-
},
|
|
47257
|
-
takeScreenshot: {
|
|
47258
|
-
type: "boolean",
|
|
47259
|
-
description: "Whether to capture a screenshot of the page (default: false). Screenshot returned as base64 PNG."
|
|
47260
|
-
}
|
|
47261
|
-
},
|
|
47262
|
-
required: ["url"]
|
|
47263
|
-
}
|
|
47264
|
-
},
|
|
47265
|
-
blocking: true,
|
|
47266
|
-
timeout: 3e4
|
|
47267
|
-
// Allow extra time for browser operations
|
|
47268
|
-
},
|
|
47269
|
-
execute: async (args) => {
|
|
47270
|
-
let page = null;
|
|
47696
|
+
function createWebScrapeTool(connector) {
|
|
47697
|
+
async function tryNative(args, startTime, attemptedMethods) {
|
|
47698
|
+
attemptedMethods.push("native");
|
|
47699
|
+
scrapeLogger.debug({ url: args.url }, "Trying native fetch");
|
|
47271
47700
|
try {
|
|
47272
|
-
const
|
|
47273
|
-
|
|
47274
|
-
|
|
47275
|
-
await page.setUserAgent(
|
|
47276
|
-
"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"
|
|
47277
|
-
);
|
|
47278
|
-
const startTime = Date.now();
|
|
47279
|
-
await page.goto(args.url, {
|
|
47280
|
-
waitUntil: "networkidle2",
|
|
47281
|
-
// Wait until network is mostly idle
|
|
47282
|
-
timeout: args.timeout || 15e3
|
|
47701
|
+
const result = await webFetch.execute({
|
|
47702
|
+
url: args.url,
|
|
47703
|
+
timeout: args.timeout || 1e4
|
|
47283
47704
|
});
|
|
47284
|
-
|
|
47285
|
-
await page.waitForSelector(args.waitForSelector, {
|
|
47286
|
-
timeout: args.timeout || 15e3
|
|
47287
|
-
});
|
|
47288
|
-
}
|
|
47289
|
-
const html = await page.content();
|
|
47290
|
-
const browserTitle = await page.title();
|
|
47291
|
-
const loadTime = Date.now() - startTime;
|
|
47292
|
-
let screenshot;
|
|
47293
|
-
if (args.takeScreenshot) {
|
|
47294
|
-
const buffer = await page.screenshot({
|
|
47295
|
-
type: "png",
|
|
47296
|
-
fullPage: false
|
|
47297
|
-
// Just viewport
|
|
47298
|
-
});
|
|
47299
|
-
screenshot = buffer.toString("base64");
|
|
47300
|
-
}
|
|
47301
|
-
await page.close();
|
|
47302
|
-
const mdResult = await htmlToMarkdown(html, args.url);
|
|
47303
|
-
const title = browserTitle || mdResult.title || "Untitled";
|
|
47705
|
+
const cleanContent = stripBase64DataUris(result.content);
|
|
47304
47706
|
return {
|
|
47305
|
-
success:
|
|
47707
|
+
success: result.success,
|
|
47306
47708
|
url: args.url,
|
|
47307
|
-
|
|
47308
|
-
|
|
47309
|
-
|
|
47310
|
-
|
|
47311
|
-
|
|
47312
|
-
|
|
47313
|
-
|
|
47314
|
-
|
|
47709
|
+
finalUrl: args.url,
|
|
47710
|
+
method: "native",
|
|
47711
|
+
title: result.title,
|
|
47712
|
+
content: cleanContent,
|
|
47713
|
+
qualityScore: result.qualityScore,
|
|
47714
|
+
durationMs: Date.now() - startTime,
|
|
47715
|
+
attemptedMethods,
|
|
47716
|
+
error: result.error
|
|
47315
47717
|
};
|
|
47316
47718
|
} catch (error) {
|
|
47317
|
-
if (page) {
|
|
47318
|
-
try {
|
|
47319
|
-
await page.close();
|
|
47320
|
-
} catch {
|
|
47321
|
-
}
|
|
47322
|
-
}
|
|
47323
|
-
if (error.message === "Puppeteer not installed") {
|
|
47324
|
-
return {
|
|
47325
|
-
success: false,
|
|
47326
|
-
url: args.url,
|
|
47327
|
-
title: "",
|
|
47328
|
-
content: "",
|
|
47329
|
-
loadTime: 0,
|
|
47330
|
-
error: "Puppeteer is not installed",
|
|
47331
|
-
suggestion: "Install Puppeteer with: npm install puppeteer (note: downloads ~50MB Chrome binary)"
|
|
47332
|
-
};
|
|
47333
|
-
}
|
|
47334
47719
|
return {
|
|
47335
47720
|
success: false,
|
|
47336
47721
|
url: args.url,
|
|
47722
|
+
method: "native",
|
|
47337
47723
|
title: "",
|
|
47338
47724
|
content: "",
|
|
47339
|
-
|
|
47725
|
+
durationMs: Date.now() - startTime,
|
|
47726
|
+
attemptedMethods,
|
|
47340
47727
|
error: error.message
|
|
47341
47728
|
};
|
|
47342
47729
|
}
|
|
47343
47730
|
}
|
|
47344
|
-
|
|
47345
|
-
|
|
47346
|
-
|
|
47347
|
-
|
|
47348
|
-
|
|
47349
|
-
|
|
47350
|
-
|
|
47351
|
-
|
|
47352
|
-
|
|
47353
|
-
|
|
47354
|
-
|
|
47355
|
-
|
|
47356
|
-
|
|
47357
|
-
|
|
47358
|
-
|
|
47359
|
-
|
|
47360
|
-
|
|
47361
|
-
|
|
47362
|
-
|
|
47363
|
-
|
|
47364
|
-
|
|
47365
|
-
|
|
47366
|
-
|
|
47367
|
-
|
|
47368
|
-
|
|
47369
|
-
|
|
47370
|
-
|
|
47371
|
-
|
|
47372
|
-
|
|
47373
|
-
|
|
47374
|
-
|
|
47375
|
-
|
|
47376
|
-
|
|
47377
|
-
|
|
47378
|
-
|
|
47379
|
-
|
|
47380
|
-
|
|
47381
|
-
|
|
47382
|
-
|
|
47383
|
-
|
|
47384
|
-
|
|
47385
|
-
|
|
47386
|
-
|
|
47387
|
-
|
|
47388
|
-
|
|
47389
|
-
const data = await response.json();
|
|
47390
|
-
if (!data.web?.results || !Array.isArray(data.web.results)) {
|
|
47391
|
-
throw new Error("Invalid response from Brave API");
|
|
47392
|
-
}
|
|
47393
|
-
return data.web.results.slice(0, numResults).map((result, index) => ({
|
|
47394
|
-
title: result.title || "Untitled",
|
|
47395
|
-
url: result.url || "",
|
|
47396
|
-
snippet: result.description || "",
|
|
47397
|
-
position: index + 1
|
|
47398
|
-
}));
|
|
47399
|
-
}
|
|
47400
|
-
|
|
47401
|
-
// src/tools/web/searchProviders/tavily.ts
|
|
47402
|
-
async function searchWithTavily(query, numResults, apiKey) {
|
|
47403
|
-
const response = await fetch("https://api.tavily.com/search", {
|
|
47404
|
-
method: "POST",
|
|
47405
|
-
headers: {
|
|
47406
|
-
"Content-Type": "application/json"
|
|
47407
|
-
},
|
|
47408
|
-
body: JSON.stringify({
|
|
47409
|
-
api_key: apiKey,
|
|
47410
|
-
query,
|
|
47411
|
-
max_results: numResults,
|
|
47412
|
-
search_depth: "basic",
|
|
47413
|
-
// 'basic' or 'advanced'
|
|
47414
|
-
include_answer: false,
|
|
47415
|
-
include_raw_content: false
|
|
47416
|
-
})
|
|
47417
|
-
});
|
|
47418
|
-
if (!response.ok) {
|
|
47419
|
-
throw new Error(`Tavily API error: ${response.status} ${response.statusText}`);
|
|
47420
|
-
}
|
|
47421
|
-
const data = await response.json();
|
|
47422
|
-
if (!data.results || !Array.isArray(data.results)) {
|
|
47423
|
-
throw new Error("Invalid response from Tavily API");
|
|
47424
|
-
}
|
|
47425
|
-
return data.results.slice(0, numResults).map((result, index) => ({
|
|
47426
|
-
title: result.title || "Untitled",
|
|
47427
|
-
url: result.url || "",
|
|
47428
|
-
snippet: result.content || "",
|
|
47429
|
-
position: index + 1
|
|
47430
|
-
}));
|
|
47431
|
-
}
|
|
47432
|
-
|
|
47433
|
-
// src/tools/web/webSearch.ts
|
|
47434
|
-
var searchLogger = logger.child({ component: "webSearch" });
|
|
47435
|
-
var SEARCH_SERVICE_TYPES = ["serper", "brave-search", "tavily", "rapidapi-search"];
|
|
47436
|
-
var webSearch = {
|
|
47437
|
-
definition: {
|
|
47438
|
-
type: "function",
|
|
47439
|
-
function: {
|
|
47440
|
-
name: "web_search",
|
|
47441
|
-
description: `Search the web and get relevant results with snippets.
|
|
47442
|
-
|
|
47443
|
-
RETURNS:
|
|
47444
|
-
An array of search results, each containing:
|
|
47445
|
-
- title: Page title
|
|
47446
|
-
- url: Direct URL to the page
|
|
47447
|
-
- snippet: Short description/excerpt from the page
|
|
47448
|
-
- position: Search ranking position (1, 2, 3...)
|
|
47449
|
-
|
|
47450
|
-
USE CASES:
|
|
47451
|
-
- Find current information on any topic
|
|
47452
|
-
- Research multiple sources
|
|
47453
|
-
- Discover relevant websites
|
|
47454
|
-
- Find URLs to fetch with web_fetch tool
|
|
47455
|
-
|
|
47456
|
-
WORKFLOW PATTERN:
|
|
47457
|
-
1. Use web_search to find relevant URLs
|
|
47458
|
-
2. Use web_fetch to get full content from top results
|
|
47459
|
-
3. Process and summarize the information
|
|
47460
|
-
|
|
47461
|
-
EXAMPLE:
|
|
47462
|
-
{
|
|
47463
|
-
"query": "latest AI developments 2026",
|
|
47464
|
-
"numResults": 5
|
|
47465
|
-
}`,
|
|
47466
|
-
parameters: {
|
|
47467
|
-
type: "object",
|
|
47468
|
-
properties: {
|
|
47469
|
-
query: {
|
|
47470
|
-
type: "string",
|
|
47471
|
-
description: "The search query string. Be specific for better results."
|
|
47472
|
-
},
|
|
47473
|
-
numResults: {
|
|
47474
|
-
type: "number",
|
|
47475
|
-
description: "Number of results to return (default: 10, max: 100)."
|
|
47476
|
-
},
|
|
47477
|
-
country: {
|
|
47478
|
-
type: "string",
|
|
47479
|
-
description: 'Country/region code for localized results (e.g., "us", "gb", "de")'
|
|
47480
|
-
},
|
|
47481
|
-
language: {
|
|
47482
|
-
type: "string",
|
|
47483
|
-
description: 'Language code for results (e.g., "en", "fr", "de")'
|
|
47484
|
-
}
|
|
47485
|
-
},
|
|
47486
|
-
required: ["query"]
|
|
47487
|
-
}
|
|
47488
|
-
},
|
|
47489
|
-
blocking: true,
|
|
47490
|
-
timeout: 15e3
|
|
47491
|
-
},
|
|
47492
|
-
execute: async (args) => {
|
|
47493
|
-
const numResults = args.numResults || 10;
|
|
47494
|
-
const connector = findConnectorByServiceTypes(SEARCH_SERVICE_TYPES);
|
|
47495
|
-
if (connector) {
|
|
47496
|
-
return await executeWithConnector(connector.name, args, numResults);
|
|
47497
|
-
}
|
|
47498
|
-
return await executeWithEnvVar(args, numResults);
|
|
47499
|
-
},
|
|
47500
|
-
describeCall: (args) => `"${args.query}"${args.numResults ? ` (${args.numResults} results)` : ""}`
|
|
47501
|
-
};
|
|
47502
|
-
async function executeWithConnector(connectorName, args, numResults) {
|
|
47503
|
-
searchLogger.debug({ connectorName }, "Executing search with connector");
|
|
47504
|
-
try {
|
|
47505
|
-
const searchProvider = SearchProvider.create({ connector: connectorName });
|
|
47506
|
-
const response = await searchProvider.search(args.query, {
|
|
47507
|
-
numResults,
|
|
47508
|
-
country: args.country,
|
|
47509
|
-
language: args.language
|
|
47510
|
-
});
|
|
47511
|
-
if (response.success) {
|
|
47512
|
-
searchLogger.debug({
|
|
47513
|
-
provider: response.provider,
|
|
47514
|
-
count: response.count
|
|
47515
|
-
}, "Search completed successfully");
|
|
47516
|
-
} else {
|
|
47517
|
-
searchLogger.warn({
|
|
47518
|
-
provider: response.provider,
|
|
47519
|
-
error: response.error
|
|
47520
|
-
}, "Search failed");
|
|
47521
|
-
}
|
|
47522
|
-
return {
|
|
47523
|
-
success: response.success,
|
|
47524
|
-
query: response.query,
|
|
47525
|
-
provider: response.provider,
|
|
47526
|
-
results: response.results,
|
|
47527
|
-
count: response.count,
|
|
47528
|
-
error: response.error
|
|
47529
|
-
};
|
|
47530
|
-
} catch (error) {
|
|
47531
|
-
searchLogger.error({ error: error.message, connectorName }, "Search threw exception");
|
|
47532
|
-
return {
|
|
47533
|
-
success: false,
|
|
47534
|
-
query: args.query,
|
|
47535
|
-
provider: connectorName,
|
|
47536
|
-
results: [],
|
|
47537
|
-
count: 0,
|
|
47538
|
-
error: error.message || "Unknown error"
|
|
47539
|
-
};
|
|
47540
|
-
}
|
|
47541
|
-
}
|
|
47542
|
-
async function executeWithEnvVar(args, numResults) {
|
|
47543
|
-
const providers = [
|
|
47544
|
-
{ name: "serper", key: process.env.SERPER_API_KEY, fn: searchWithSerper },
|
|
47545
|
-
{ name: "brave", key: process.env.BRAVE_API_KEY, fn: searchWithBrave },
|
|
47546
|
-
{ name: "tavily", key: process.env.TAVILY_API_KEY, fn: searchWithTavily }
|
|
47547
|
-
];
|
|
47548
|
-
for (const provider of providers) {
|
|
47549
|
-
if (provider.key) {
|
|
47550
|
-
searchLogger.debug({ provider: provider.name }, "Using environment variable fallback");
|
|
47551
|
-
try {
|
|
47552
|
-
const results = await provider.fn(args.query, numResults, provider.key);
|
|
47553
|
-
return {
|
|
47554
|
-
success: true,
|
|
47555
|
-
query: args.query,
|
|
47556
|
-
provider: provider.name,
|
|
47557
|
-
results,
|
|
47558
|
-
count: results.length
|
|
47559
|
-
};
|
|
47560
|
-
} catch (error) {
|
|
47561
|
-
searchLogger.warn({ provider: provider.name, error: error.message }, "Provider failed, trying next");
|
|
47562
|
-
}
|
|
47731
|
+
async function tryAPI(args, startTime, attemptedMethods) {
|
|
47732
|
+
attemptedMethods.push(`api:${connector.name}`);
|
|
47733
|
+
scrapeLogger.debug({ url: args.url, connectorName: connector.name }, "Trying external API");
|
|
47734
|
+
try {
|
|
47735
|
+
const provider = ScrapeProvider.create({ connector: connector.name });
|
|
47736
|
+
const options = {
|
|
47737
|
+
timeout: args.timeout,
|
|
47738
|
+
waitForSelector: args.waitForSelector,
|
|
47739
|
+
includeHtml: args.includeHtml,
|
|
47740
|
+
includeMarkdown: args.includeMarkdown,
|
|
47741
|
+
includeLinks: args.includeLinks
|
|
47742
|
+
};
|
|
47743
|
+
const result = await provider.scrape(args.url, options);
|
|
47744
|
+
const rawContent = result.result?.content || "";
|
|
47745
|
+
const rawMarkdown = result.result?.markdown;
|
|
47746
|
+
const cleanContent = stripBase64DataUris(rawContent);
|
|
47747
|
+
const cleanMarkdown = rawMarkdown ? stripBase64DataUris(rawMarkdown) : void 0;
|
|
47748
|
+
const isDuplicate = !!cleanMarkdown && cleanContent === cleanMarkdown;
|
|
47749
|
+
return {
|
|
47750
|
+
success: result.success,
|
|
47751
|
+
url: args.url,
|
|
47752
|
+
finalUrl: result.finalUrl,
|
|
47753
|
+
method: result.provider,
|
|
47754
|
+
title: result.result?.title || "",
|
|
47755
|
+
content: cleanContent,
|
|
47756
|
+
html: result.result?.html,
|
|
47757
|
+
markdown: isDuplicate ? void 0 : cleanMarkdown,
|
|
47758
|
+
metadata: result.result?.metadata,
|
|
47759
|
+
links: result.result?.links,
|
|
47760
|
+
qualityScore: result.success ? 90 : 0,
|
|
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: "api",
|
|
47770
|
+
title: "",
|
|
47771
|
+
content: "",
|
|
47772
|
+
durationMs: Date.now() - startTime,
|
|
47773
|
+
attemptedMethods,
|
|
47774
|
+
error: error.message
|
|
47775
|
+
};
|
|
47563
47776
|
}
|
|
47564
47777
|
}
|
|
47565
47778
|
return {
|
|
47566
|
-
|
|
47567
|
-
|
|
47568
|
-
|
|
47569
|
-
|
|
47570
|
-
|
|
47571
|
-
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."
|
|
47572
|
-
};
|
|
47573
|
-
}
|
|
47574
|
-
|
|
47575
|
-
// src/tools/web/webScrape.ts
|
|
47576
|
-
init_Logger();
|
|
47577
|
-
var scrapeLogger = logger.child({ component: "webScrape" });
|
|
47578
|
-
function stripBase64DataUris(content) {
|
|
47579
|
-
if (!content) return content;
|
|
47580
|
-
let cleaned = content.replace(/!\[[^\]]*\]\(data:[^)]+\)/g, "[image removed]");
|
|
47581
|
-
cleaned = cleaned.replace(/url\(['"]?data:[^)]+['"]?\)/gi, "url([data-uri-removed])");
|
|
47582
|
-
cleaned = cleaned.replace(/data:(?:image|font|application)\/[^;]+;base64,[A-Za-z0-9+/=]{100,}/g, "[base64-data-removed]");
|
|
47583
|
-
return cleaned;
|
|
47584
|
-
}
|
|
47585
|
-
var SCRAPE_SERVICE_TYPES = ["zenrows", "jina-reader", "firecrawl", "scrapingbee"];
|
|
47586
|
-
var DEFAULT_MIN_QUALITY = 50;
|
|
47587
|
-
var webScrape = {
|
|
47588
|
-
definition: {
|
|
47589
|
-
type: "function",
|
|
47590
|
-
function: {
|
|
47591
|
-
name: "web_scrape",
|
|
47592
|
-
description: `Scrape any URL with automatic fallback - guaranteed to work on most sites.
|
|
47779
|
+
definition: {
|
|
47780
|
+
type: "function",
|
|
47781
|
+
function: {
|
|
47782
|
+
name: "web_scrape",
|
|
47783
|
+
description: `Scrape any URL with automatic fallback - guaranteed to work on most sites.
|
|
47593
47784
|
|
|
47594
47785
|
Automatically tries multiple methods in sequence:
|
|
47595
47786
|
1. Native fetch - Fast (~1s), works for blogs/docs/articles
|
|
47596
|
-
2.
|
|
47597
|
-
3. External API - Handles bot protection, CAPTCHAs (if configured)
|
|
47787
|
+
2. External API - Handles bot protection, CAPTCHAs, SPAs (if configured)
|
|
47598
47788
|
|
|
47599
47789
|
RETURNS:
|
|
47600
47790
|
{
|
|
@@ -47629,46 +47819,64 @@ For JS-heavy sites:
|
|
|
47629
47819
|
"url": "https://spa-app.com",
|
|
47630
47820
|
"waitForSelector": ".main-content"
|
|
47631
47821
|
}`,
|
|
47632
|
-
|
|
47633
|
-
|
|
47634
|
-
|
|
47635
|
-
|
|
47636
|
-
|
|
47637
|
-
|
|
47638
|
-
|
|
47639
|
-
|
|
47640
|
-
|
|
47641
|
-
|
|
47642
|
-
|
|
47643
|
-
|
|
47644
|
-
|
|
47645
|
-
|
|
47646
|
-
|
|
47647
|
-
|
|
47648
|
-
|
|
47649
|
-
|
|
47650
|
-
|
|
47651
|
-
|
|
47652
|
-
|
|
47653
|
-
|
|
47822
|
+
parameters: {
|
|
47823
|
+
type: "object",
|
|
47824
|
+
properties: {
|
|
47825
|
+
url: {
|
|
47826
|
+
type: "string",
|
|
47827
|
+
description: "URL to scrape. Must start with http:// or https://"
|
|
47828
|
+
},
|
|
47829
|
+
timeout: {
|
|
47830
|
+
type: "number",
|
|
47831
|
+
description: "Timeout in milliseconds (default: 30000)"
|
|
47832
|
+
},
|
|
47833
|
+
includeHtml: {
|
|
47834
|
+
type: "boolean",
|
|
47835
|
+
description: "Include raw HTML in response (default: false)"
|
|
47836
|
+
},
|
|
47837
|
+
includeMarkdown: {
|
|
47838
|
+
type: "boolean",
|
|
47839
|
+
description: "Include markdown conversion (default: false)"
|
|
47840
|
+
},
|
|
47841
|
+
includeLinks: {
|
|
47842
|
+
type: "boolean",
|
|
47843
|
+
description: "Extract and include links (default: false)"
|
|
47844
|
+
},
|
|
47845
|
+
waitForSelector: {
|
|
47846
|
+
type: "string",
|
|
47847
|
+
description: "CSS selector to wait for before scraping (for JS-heavy sites)"
|
|
47848
|
+
}
|
|
47654
47849
|
},
|
|
47655
|
-
|
|
47656
|
-
|
|
47657
|
-
|
|
47658
|
-
|
|
47659
|
-
|
|
47660
|
-
required: ["url"]
|
|
47661
|
-
}
|
|
47850
|
+
required: ["url"]
|
|
47851
|
+
}
|
|
47852
|
+
},
|
|
47853
|
+
blocking: true,
|
|
47854
|
+
timeout: 6e4
|
|
47662
47855
|
},
|
|
47663
|
-
|
|
47664
|
-
|
|
47665
|
-
|
|
47666
|
-
|
|
47667
|
-
|
|
47668
|
-
|
|
47669
|
-
|
|
47670
|
-
|
|
47671
|
-
|
|
47856
|
+
execute: async (args) => {
|
|
47857
|
+
const startTime = Date.now();
|
|
47858
|
+
const attemptedMethods = [];
|
|
47859
|
+
try {
|
|
47860
|
+
new URL(args.url);
|
|
47861
|
+
} catch {
|
|
47862
|
+
return {
|
|
47863
|
+
success: false,
|
|
47864
|
+
url: args.url,
|
|
47865
|
+
method: "none",
|
|
47866
|
+
title: "",
|
|
47867
|
+
content: "",
|
|
47868
|
+
durationMs: Date.now() - startTime,
|
|
47869
|
+
attemptedMethods: [],
|
|
47870
|
+
error: "Invalid URL format"
|
|
47871
|
+
};
|
|
47872
|
+
}
|
|
47873
|
+
const native = await tryNative(args, startTime, attemptedMethods);
|
|
47874
|
+
if (native.success && (native.qualityScore ?? 0) >= DEFAULT_MIN_QUALITY) {
|
|
47875
|
+
return native;
|
|
47876
|
+
}
|
|
47877
|
+
const api = await tryAPI(args, startTime, attemptedMethods);
|
|
47878
|
+
if (api.success) return api;
|
|
47879
|
+
if (native.success) return native;
|
|
47672
47880
|
return {
|
|
47673
47881
|
success: false,
|
|
47674
47882
|
url: args.url,
|
|
@@ -47676,230 +47884,119 @@ For JS-heavy sites:
|
|
|
47676
47884
|
title: "",
|
|
47677
47885
|
content: "",
|
|
47678
47886
|
durationMs: Date.now() - startTime,
|
|
47679
|
-
attemptedMethods
|
|
47680
|
-
error: "
|
|
47887
|
+
attemptedMethods,
|
|
47888
|
+
error: "All scraping methods failed. Site may have bot protection."
|
|
47681
47889
|
};
|
|
47682
|
-
}
|
|
47683
|
-
|
|
47684
|
-
|
|
47685
|
-
return native;
|
|
47686
|
-
}
|
|
47687
|
-
const js = await tryJS(args, startTime, attemptedMethods);
|
|
47688
|
-
if (js.success && (js.qualityScore ?? 0) >= DEFAULT_MIN_QUALITY) {
|
|
47689
|
-
return js;
|
|
47690
|
-
}
|
|
47691
|
-
const connector = findConnectorByServiceTypes(SCRAPE_SERVICE_TYPES);
|
|
47692
|
-
if (connector) {
|
|
47693
|
-
const api = await tryAPI(connector.name, args, startTime, attemptedMethods);
|
|
47694
|
-
if (api.success) return api;
|
|
47695
|
-
}
|
|
47696
|
-
if (js.success) return js;
|
|
47697
|
-
if (native.success) return native;
|
|
47698
|
-
return {
|
|
47699
|
-
success: false,
|
|
47700
|
-
url: args.url,
|
|
47701
|
-
method: "none",
|
|
47702
|
-
title: "",
|
|
47703
|
-
content: "",
|
|
47704
|
-
durationMs: Date.now() - startTime,
|
|
47705
|
-
attemptedMethods,
|
|
47706
|
-
error: "All scraping methods failed. Site may have bot protection."
|
|
47707
|
-
};
|
|
47708
|
-
},
|
|
47709
|
-
describeCall: (args) => args.url
|
|
47710
|
-
};
|
|
47711
|
-
async function tryNative(args, startTime, attemptedMethods) {
|
|
47712
|
-
attemptedMethods.push("native");
|
|
47713
|
-
scrapeLogger.debug({ url: args.url }, "Trying native fetch");
|
|
47714
|
-
try {
|
|
47715
|
-
const result = await webFetch.execute({
|
|
47716
|
-
url: args.url,
|
|
47717
|
-
timeout: args.timeout || 1e4
|
|
47718
|
-
});
|
|
47719
|
-
const cleanContent = stripBase64DataUris(result.content);
|
|
47720
|
-
return {
|
|
47721
|
-
success: result.success,
|
|
47722
|
-
url: args.url,
|
|
47723
|
-
finalUrl: args.url,
|
|
47724
|
-
method: "native",
|
|
47725
|
-
title: result.title,
|
|
47726
|
-
content: cleanContent,
|
|
47727
|
-
// Note: raw HTML not available with native method (returns markdown instead)
|
|
47728
|
-
markdown: args.includeMarkdown ? cleanContent : void 0,
|
|
47729
|
-
qualityScore: result.qualityScore,
|
|
47730
|
-
durationMs: Date.now() - startTime,
|
|
47731
|
-
attemptedMethods,
|
|
47732
|
-
error: result.error
|
|
47733
|
-
};
|
|
47734
|
-
} catch (error) {
|
|
47735
|
-
return {
|
|
47736
|
-
success: false,
|
|
47737
|
-
url: args.url,
|
|
47738
|
-
method: "native",
|
|
47739
|
-
title: "",
|
|
47740
|
-
content: "",
|
|
47741
|
-
durationMs: Date.now() - startTime,
|
|
47742
|
-
attemptedMethods,
|
|
47743
|
-
error: error.message
|
|
47744
|
-
};
|
|
47745
|
-
}
|
|
47890
|
+
},
|
|
47891
|
+
describeCall: (args) => args.url
|
|
47892
|
+
};
|
|
47746
47893
|
}
|
|
47747
|
-
|
|
47748
|
-
|
|
47749
|
-
|
|
47750
|
-
|
|
47751
|
-
|
|
47752
|
-
|
|
47753
|
-
|
|
47754
|
-
|
|
47755
|
-
|
|
47756
|
-
const cleanContent = stripBase64DataUris(result.content);
|
|
47757
|
-
return {
|
|
47758
|
-
success: result.success,
|
|
47759
|
-
url: args.url,
|
|
47760
|
-
finalUrl: args.url,
|
|
47761
|
-
method: "js",
|
|
47762
|
-
title: result.title,
|
|
47763
|
-
content: cleanContent,
|
|
47764
|
-
// Note: raw HTML not available with JS method (returns markdown instead)
|
|
47765
|
-
markdown: args.includeMarkdown ? cleanContent : void 0,
|
|
47766
|
-
qualityScore: result.success ? 80 : 0,
|
|
47767
|
-
durationMs: Date.now() - startTime,
|
|
47768
|
-
attemptedMethods,
|
|
47769
|
-
error: result.error
|
|
47770
|
-
};
|
|
47771
|
-
} catch (error) {
|
|
47772
|
-
return {
|
|
47773
|
-
success: false,
|
|
47774
|
-
url: args.url,
|
|
47775
|
-
method: "js",
|
|
47776
|
-
title: "",
|
|
47777
|
-
content: "",
|
|
47778
|
-
durationMs: Date.now() - startTime,
|
|
47779
|
-
attemptedMethods,
|
|
47780
|
-
error: error.message
|
|
47781
|
-
};
|
|
47894
|
+
|
|
47895
|
+
// src/tools/web/register.ts
|
|
47896
|
+
var SEARCH_SERVICE_TYPES = ["serper", "brave-search", "tavily", "rapidapi-search"];
|
|
47897
|
+
var SCRAPE_SERVICE_TYPES = ["zenrows", "jina-reader", "firecrawl", "scrapingbee"];
|
|
47898
|
+
function registerWebTools() {
|
|
47899
|
+
for (const st of SEARCH_SERVICE_TYPES) {
|
|
47900
|
+
ConnectorTools.registerService(st, (connector) => [
|
|
47901
|
+
createWebSearchTool(connector)
|
|
47902
|
+
]);
|
|
47782
47903
|
}
|
|
47783
|
-
|
|
47784
|
-
|
|
47785
|
-
|
|
47786
|
-
|
|
47787
|
-
try {
|
|
47788
|
-
const provider = ScrapeProvider.create({ connector: connectorName });
|
|
47789
|
-
const options = {
|
|
47790
|
-
timeout: args.timeout,
|
|
47791
|
-
waitForSelector: args.waitForSelector,
|
|
47792
|
-
includeHtml: args.includeHtml,
|
|
47793
|
-
includeMarkdown: args.includeMarkdown,
|
|
47794
|
-
includeLinks: args.includeLinks
|
|
47795
|
-
};
|
|
47796
|
-
const result = await provider.scrape(args.url, options);
|
|
47797
|
-
const cleanContent = stripBase64DataUris(result.result?.content || "");
|
|
47798
|
-
const cleanMarkdown = result.result?.markdown ? stripBase64DataUris(result.result.markdown) : void 0;
|
|
47799
|
-
return {
|
|
47800
|
-
success: result.success,
|
|
47801
|
-
url: args.url,
|
|
47802
|
-
finalUrl: result.finalUrl,
|
|
47803
|
-
method: result.provider,
|
|
47804
|
-
title: result.result?.title || "",
|
|
47805
|
-
content: cleanContent,
|
|
47806
|
-
html: result.result?.html,
|
|
47807
|
-
// Keep raw HTML as-is (only used if explicitly requested)
|
|
47808
|
-
markdown: cleanMarkdown,
|
|
47809
|
-
metadata: result.result?.metadata,
|
|
47810
|
-
links: result.result?.links,
|
|
47811
|
-
qualityScore: result.success ? 90 : 0,
|
|
47812
|
-
durationMs: Date.now() - startTime,
|
|
47813
|
-
attemptedMethods,
|
|
47814
|
-
error: result.error
|
|
47815
|
-
};
|
|
47816
|
-
} catch (error) {
|
|
47817
|
-
return {
|
|
47818
|
-
success: false,
|
|
47819
|
-
url: args.url,
|
|
47820
|
-
method: "api",
|
|
47821
|
-
title: "",
|
|
47822
|
-
content: "",
|
|
47823
|
-
durationMs: Date.now() - startTime,
|
|
47824
|
-
attemptedMethods,
|
|
47825
|
-
error: error.message
|
|
47826
|
-
};
|
|
47904
|
+
for (const st of SCRAPE_SERVICE_TYPES) {
|
|
47905
|
+
ConnectorTools.registerService(st, (connector) => [
|
|
47906
|
+
createWebScrapeTool(connector)
|
|
47907
|
+
]);
|
|
47827
47908
|
}
|
|
47828
47909
|
}
|
|
47829
47910
|
|
|
47911
|
+
// src/tools/web/index.ts
|
|
47912
|
+
registerWebTools();
|
|
47913
|
+
|
|
47830
47914
|
// src/tools/code/executeJavaScript.ts
|
|
47831
47915
|
init_Connector();
|
|
47832
|
-
|
|
47833
|
-
|
|
47834
|
-
|
|
47835
|
-
|
|
47836
|
-
|
|
47837
|
-
|
|
47838
|
-
|
|
47839
|
-
|
|
47840
|
-
}).join("\n
|
|
47841
|
-
return `
|
|
47842
|
-
|
|
47843
|
-
|
|
47844
|
-
|
|
47845
|
-
|
|
47846
|
-
|
|
47847
|
-
|
|
47916
|
+
var DEFAULT_TIMEOUT = 1e4;
|
|
47917
|
+
var DEFAULT_MAX_TIMEOUT = 3e4;
|
|
47918
|
+
function formatConnectorEntry(c) {
|
|
47919
|
+
const parts = [];
|
|
47920
|
+
const serviceOrVendor = c.serviceType ?? c.vendor ?? void 0;
|
|
47921
|
+
if (serviceOrVendor) parts.push(`Service: ${serviceOrVendor}`);
|
|
47922
|
+
if (c.config.description) parts.push(c.config.description);
|
|
47923
|
+
if (c.baseURL) parts.push(`URL: ${c.baseURL}`);
|
|
47924
|
+
const details = parts.map((p) => ` ${p}`).join("\n");
|
|
47925
|
+
return ` \u2022 "${c.name}" (${c.displayName})
|
|
47926
|
+
${details}`;
|
|
47927
|
+
}
|
|
47928
|
+
function generateDescription(context, maxTimeout) {
|
|
47929
|
+
const registry = context?.connectorRegistry ?? Connector.asRegistry();
|
|
47930
|
+
const connectors = registry.listAll();
|
|
47931
|
+
const connectorList = connectors.length > 0 ? connectors.map(formatConnectorEntry).join("\n\n") : " No connectors registered.";
|
|
47932
|
+
const timeoutSec = Math.round(maxTimeout / 1e3);
|
|
47933
|
+
return `Execute JavaScript code in a secure sandbox with authenticated API access to external services.
|
|
47934
|
+
|
|
47935
|
+
Use this tool when you need to:
|
|
47936
|
+
- Call external APIs (GitHub, Slack, Stripe, etc.) using registered connectors
|
|
47937
|
+
- Process, transform, or compute data that requires programmatic logic
|
|
47938
|
+
- Chain multiple API calls or perform complex data manipulation
|
|
47939
|
+
- Do anything that plain text generation cannot accomplish
|
|
47940
|
+
|
|
47941
|
+
SANDBOX API:
|
|
47942
|
+
|
|
47943
|
+
1. authenticatedFetch(url, options, connectorName)
|
|
47944
|
+
Makes authenticated HTTP requests using the connector's credentials.
|
|
47945
|
+
The current user's identity (userId) is automatically included \u2014 no need to pass it.
|
|
47946
|
+
Auth headers are added automatically \u2014 DO NOT set Authorization header manually.
|
|
47848
47947
|
|
|
47849
47948
|
Parameters:
|
|
47850
|
-
\u2022 url: Full URL or relative
|
|
47949
|
+
\u2022 url: Full URL or path relative to the connector's base URL
|
|
47851
47950
|
- Full: "https://api.github.com/user/repos"
|
|
47852
|
-
- Relative: "/user/repos" (
|
|
47853
|
-
\u2022 options: Standard fetch options { method,
|
|
47854
|
-
|
|
47855
|
-
\u2022
|
|
47951
|
+
- Relative: "/user/repos" (resolved against connector's base URL)
|
|
47952
|
+
\u2022 options: Standard fetch options { method, headers, body }
|
|
47953
|
+
- For POST/PUT: set body to JSON.stringify(data) and headers to { 'Content-Type': 'application/json' }
|
|
47954
|
+
\u2022 connectorName: Name of a registered connector (see list below)
|
|
47856
47955
|
|
|
47857
47956
|
Returns: Promise<Response>
|
|
47858
|
-
\u2022 response.ok
|
|
47859
|
-
\u2022 response.status
|
|
47860
|
-
\u2022 response.json()
|
|
47861
|
-
\u2022 response.text()
|
|
47957
|
+
\u2022 response.ok \u2014 true if status 200-299
|
|
47958
|
+
\u2022 response.status \u2014 HTTP status code
|
|
47959
|
+
\u2022 await response.json() \u2014 parse JSON body
|
|
47960
|
+
\u2022 await response.text() \u2014 get text body
|
|
47862
47961
|
|
|
47863
|
-
|
|
47864
|
-
\u2022 Bearer tokens (GitHub, Slack, Stripe)
|
|
47865
|
-
\u2022 Bot tokens (Discord)
|
|
47866
|
-
\u2022 Basic auth (Twilio, Zendesk)
|
|
47867
|
-
\u2022 Custom headers (Shopify uses X-Shopify-Access-Token)
|
|
47962
|
+
2. fetch(url, options) \u2014 Standard fetch without authentication
|
|
47868
47963
|
|
|
47869
|
-
|
|
47870
|
-
|
|
47871
|
-
4. fetch(url, options) - Standard fetch (no auth)
|
|
47964
|
+
3. connectors.list() \u2014 Array of available connector names
|
|
47965
|
+
4. connectors.get(name) \u2014 Connector info: { displayName, description, baseURL, serviceType }
|
|
47872
47966
|
|
|
47873
|
-
|
|
47874
|
-
\u2022 input
|
|
47875
|
-
\u2022 output
|
|
47967
|
+
VARIABLES:
|
|
47968
|
+
\u2022 input \u2014 data passed via the "input" parameter (default: {})
|
|
47969
|
+
\u2022 output \u2014 SET THIS to return your result to the caller
|
|
47876
47970
|
|
|
47877
|
-
|
|
47971
|
+
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
|
|
47878
47972
|
|
|
47879
47973
|
REGISTERED CONNECTORS:
|
|
47880
47974
|
${connectorList}
|
|
47881
47975
|
|
|
47882
|
-
|
|
47883
|
-
(async () => {
|
|
47884
|
-
const response = await authenticatedFetch(
|
|
47885
|
-
'/user/repos',
|
|
47886
|
-
{ method: 'GET' },
|
|
47887
|
-
'github'
|
|
47888
|
-
);
|
|
47976
|
+
EXAMPLES:
|
|
47889
47977
|
|
|
47890
|
-
|
|
47891
|
-
|
|
47892
|
-
|
|
47978
|
+
// GET request
|
|
47979
|
+
const resp = await authenticatedFetch('/user/repos', { method: 'GET' }, 'github');
|
|
47980
|
+
const repos = await resp.json();
|
|
47981
|
+
output = repos.map(r => r.full_name);
|
|
47893
47982
|
|
|
47894
|
-
|
|
47895
|
-
|
|
47983
|
+
// POST request with JSON body
|
|
47984
|
+
const resp = await authenticatedFetch('/chat.postMessage', {
|
|
47985
|
+
method: 'POST',
|
|
47986
|
+
headers: { 'Content-Type': 'application/json' },
|
|
47987
|
+
body: JSON.stringify({ channel: '#general', text: 'Hello!' })
|
|
47988
|
+
}, 'slack');
|
|
47989
|
+
output = await resp.json();
|
|
47896
47990
|
|
|
47897
|
-
|
|
47898
|
-
|
|
47991
|
+
// Data processing (no API needed)
|
|
47992
|
+
const items = input.data;
|
|
47993
|
+
output = items.filter(i => i.score > 0.8).sort((a, b) => b.score - a.score);
|
|
47899
47994
|
|
|
47900
|
-
|
|
47995
|
+
LIMITS: ${timeoutSec}s max timeout, no file system access, no require/import.`;
|
|
47901
47996
|
}
|
|
47902
|
-
function createExecuteJavaScriptTool() {
|
|
47997
|
+
function createExecuteJavaScriptTool(options) {
|
|
47998
|
+
const maxTimeout = options?.maxTimeout ?? DEFAULT_MAX_TIMEOUT;
|
|
47999
|
+
const defaultTimeout = options?.defaultTimeout ?? DEFAULT_TIMEOUT;
|
|
47903
48000
|
return {
|
|
47904
48001
|
definition: {
|
|
47905
48002
|
type: "function",
|
|
@@ -47912,32 +48009,40 @@ function createExecuteJavaScriptTool() {
|
|
|
47912
48009
|
properties: {
|
|
47913
48010
|
code: {
|
|
47914
48011
|
type: "string",
|
|
47915
|
-
description: 'JavaScript code to execute.
|
|
48012
|
+
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 () => { ... })().'
|
|
47916
48013
|
},
|
|
47917
48014
|
input: {
|
|
47918
|
-
description: 'Optional
|
|
48015
|
+
description: 'Optional data available as the "input" variable in your code. Can be any JSON value.'
|
|
47919
48016
|
},
|
|
47920
48017
|
timeout: {
|
|
47921
48018
|
type: "number",
|
|
47922
|
-
description:
|
|
48019
|
+
description: `Execution timeout in milliseconds. Default: ${defaultTimeout}ms, max: ${maxTimeout}ms. Increase for slow API calls or multiple sequential requests.`
|
|
47923
48020
|
}
|
|
47924
48021
|
},
|
|
47925
48022
|
required: ["code"]
|
|
47926
48023
|
}
|
|
47927
48024
|
},
|
|
47928
48025
|
blocking: true,
|
|
47929
|
-
timeout:
|
|
47930
|
-
// Tool timeout
|
|
48026
|
+
timeout: maxTimeout + 5e3
|
|
48027
|
+
// Tool-level timeout slightly above max code timeout
|
|
47931
48028
|
},
|
|
47932
|
-
// Dynamic description
|
|
47933
|
-
//
|
|
47934
|
-
descriptionFactory: generateDescription,
|
|
47935
|
-
execute: async (args) => {
|
|
48029
|
+
// Dynamic description — regenerated each time tool definitions are sent to LLM.
|
|
48030
|
+
// Receives ToolContext so connector list is scoped to current userId.
|
|
48031
|
+
descriptionFactory: (context) => generateDescription(context, maxTimeout),
|
|
48032
|
+
execute: async (args, context) => {
|
|
47936
48033
|
const logs = [];
|
|
47937
48034
|
const startTime = Date.now();
|
|
47938
48035
|
try {
|
|
47939
|
-
const timeout = Math.min(args.timeout ||
|
|
47940
|
-
const
|
|
48036
|
+
const timeout = Math.min(Math.max(args.timeout || defaultTimeout, 0), maxTimeout);
|
|
48037
|
+
const registry = context?.connectorRegistry ?? Connector.asRegistry();
|
|
48038
|
+
const result = await executeInVM(
|
|
48039
|
+
args.code,
|
|
48040
|
+
args.input,
|
|
48041
|
+
timeout,
|
|
48042
|
+
logs,
|
|
48043
|
+
context?.userId,
|
|
48044
|
+
registry
|
|
48045
|
+
);
|
|
47941
48046
|
return {
|
|
47942
48047
|
success: true,
|
|
47943
48048
|
result,
|
|
@@ -47957,31 +48062,36 @@ function createExecuteJavaScriptTool() {
|
|
|
47957
48062
|
};
|
|
47958
48063
|
}
|
|
47959
48064
|
var executeJavaScript = createExecuteJavaScriptTool();
|
|
47960
|
-
async function executeInVM(code, input, timeout, logs) {
|
|
48065
|
+
async function executeInVM(code, input, timeout, logs, userId, registry) {
|
|
47961
48066
|
const sandbox = {
|
|
47962
48067
|
// Input/output
|
|
47963
|
-
input: input
|
|
48068
|
+
input: input ?? {},
|
|
47964
48069
|
output: null,
|
|
47965
|
-
// Console (captured)
|
|
48070
|
+
// Console (captured) — stringify objects for readable logs
|
|
47966
48071
|
console: {
|
|
47967
|
-
log: (...args) => logs.push(args.map((a) => String(a)).join(" ")),
|
|
47968
|
-
error: (...args) => logs.push("ERROR: " + args.map((a) => String(a)).join(" ")),
|
|
47969
|
-
warn: (...args) => logs.push("WARN: " + args.map((a) => String(a)).join(" "))
|
|
48072
|
+
log: (...args) => logs.push(args.map((a) => typeof a === "object" ? JSON.stringify(a) : String(a)).join(" ")),
|
|
48073
|
+
error: (...args) => logs.push("ERROR: " + args.map((a) => typeof a === "object" ? JSON.stringify(a) : String(a)).join(" ")),
|
|
48074
|
+
warn: (...args) => logs.push("WARN: " + args.map((a) => typeof a === "object" ? JSON.stringify(a) : String(a)).join(" "))
|
|
48075
|
+
},
|
|
48076
|
+
// Authenticated fetch — userId auto-injected from ToolContext.
|
|
48077
|
+
// Only connectors visible in the scoped registry are accessible.
|
|
48078
|
+
authenticatedFetch: (url2, options, connectorName) => {
|
|
48079
|
+
registry.get(connectorName);
|
|
48080
|
+
return authenticatedFetch(url2, options, connectorName, userId);
|
|
47970
48081
|
},
|
|
47971
|
-
//
|
|
47972
|
-
authenticatedFetch,
|
|
47973
|
-
// Standard fetch
|
|
48082
|
+
// Standard fetch (no auth)
|
|
47974
48083
|
fetch: globalThis.fetch,
|
|
47975
|
-
// Connector info
|
|
48084
|
+
// Connector info (userId-scoped)
|
|
47976
48085
|
connectors: {
|
|
47977
|
-
list: () =>
|
|
48086
|
+
list: () => registry.list(),
|
|
47978
48087
|
get: (name) => {
|
|
47979
48088
|
try {
|
|
47980
|
-
const connector =
|
|
48089
|
+
const connector = registry.get(name);
|
|
47981
48090
|
return {
|
|
47982
48091
|
displayName: connector.displayName,
|
|
47983
48092
|
description: connector.config.description || "",
|
|
47984
|
-
baseURL: connector.baseURL
|
|
48093
|
+
baseURL: connector.baseURL,
|
|
48094
|
+
serviceType: connector.serviceType
|
|
47985
48095
|
};
|
|
47986
48096
|
} catch {
|
|
47987
48097
|
return null;
|
|
@@ -47998,14 +48108,22 @@ async function executeInVM(code, input, timeout, logs) {
|
|
|
47998
48108
|
clearTimeout,
|
|
47999
48109
|
clearInterval,
|
|
48000
48110
|
Promise,
|
|
48001
|
-
//
|
|
48111
|
+
// Built-in types
|
|
48002
48112
|
Array,
|
|
48003
48113
|
Object,
|
|
48004
48114
|
String,
|
|
48005
48115
|
Number,
|
|
48006
|
-
Boolean
|
|
48116
|
+
Boolean,
|
|
48117
|
+
RegExp,
|
|
48118
|
+
Map,
|
|
48119
|
+
Set,
|
|
48120
|
+
Error,
|
|
48121
|
+
URL,
|
|
48122
|
+
URLSearchParams,
|
|
48123
|
+
TextEncoder,
|
|
48124
|
+
TextDecoder
|
|
48007
48125
|
};
|
|
48008
|
-
const
|
|
48126
|
+
const vmContext = vm.createContext(sandbox);
|
|
48009
48127
|
const wrappedCode = code.trim().startsWith("(async") ? code : `
|
|
48010
48128
|
(async () => {
|
|
48011
48129
|
${code}
|
|
@@ -48013,75 +48131,32 @@ async function executeInVM(code, input, timeout, logs) {
|
|
|
48013
48131
|
})()
|
|
48014
48132
|
`;
|
|
48015
48133
|
const script = new vm.Script(wrappedCode);
|
|
48016
|
-
const resultPromise = script.runInContext(
|
|
48134
|
+
const resultPromise = script.runInContext(vmContext, {
|
|
48017
48135
|
timeout,
|
|
48018
48136
|
displayErrors: true
|
|
48019
48137
|
});
|
|
48020
48138
|
const result = await resultPromise;
|
|
48021
48139
|
return result !== void 0 ? result : sandbox.output;
|
|
48022
48140
|
}
|
|
48023
|
-
var MIME_TYPES = {
|
|
48024
|
-
png: "image/png",
|
|
48025
|
-
jpeg: "image/jpeg",
|
|
48026
|
-
jpg: "image/jpeg",
|
|
48027
|
-
webp: "image/webp",
|
|
48028
|
-
gif: "image/gif",
|
|
48029
|
-
mp4: "video/mp4",
|
|
48030
|
-
webm: "video/webm",
|
|
48031
|
-
mp3: "audio/mpeg",
|
|
48032
|
-
wav: "audio/wav",
|
|
48033
|
-
opus: "audio/opus",
|
|
48034
|
-
ogg: "audio/ogg",
|
|
48035
|
-
aac: "audio/aac",
|
|
48036
|
-
flac: "audio/flac",
|
|
48037
|
-
pcm: "audio/pcm"
|
|
48038
|
-
};
|
|
48039
|
-
var FileMediaOutputHandler = class {
|
|
48040
|
-
outputDir;
|
|
48041
|
-
initialized = false;
|
|
48042
|
-
constructor(outputDir) {
|
|
48043
|
-
this.outputDir = outputDir ?? path3.join(os.tmpdir(), "oneringai-media");
|
|
48044
|
-
}
|
|
48045
|
-
async save(data, metadata) {
|
|
48046
|
-
if (!this.initialized) {
|
|
48047
|
-
await fs14.mkdir(this.outputDir, { recursive: true });
|
|
48048
|
-
this.initialized = true;
|
|
48049
|
-
}
|
|
48050
|
-
const filename = metadata.suggestedFilename ?? this.generateFilename(metadata);
|
|
48051
|
-
const filePath = path3.join(this.outputDir, filename);
|
|
48052
|
-
await fs14.writeFile(filePath, data);
|
|
48053
|
-
const format = metadata.format.toLowerCase();
|
|
48054
|
-
const mimeType = MIME_TYPES[format] ?? `application/octet-stream`;
|
|
48055
|
-
return {
|
|
48056
|
-
location: filePath,
|
|
48057
|
-
mimeType,
|
|
48058
|
-
size: data.length
|
|
48059
|
-
};
|
|
48060
|
-
}
|
|
48061
|
-
generateFilename(metadata) {
|
|
48062
|
-
const timestamp = Date.now();
|
|
48063
|
-
const random2 = crypto2.randomBytes(4).toString("hex");
|
|
48064
|
-
const indexSuffix = metadata.index != null ? `_${metadata.index}` : "";
|
|
48065
|
-
return `${metadata.type}_${timestamp}_${random2}${indexSuffix}.${metadata.format}`;
|
|
48066
|
-
}
|
|
48067
|
-
};
|
|
48068
48141
|
|
|
48069
48142
|
// src/tools/multimedia/config.ts
|
|
48070
|
-
var
|
|
48071
|
-
function
|
|
48072
|
-
if (!
|
|
48073
|
-
|
|
48143
|
+
var _storage = null;
|
|
48144
|
+
function getMediaStorage() {
|
|
48145
|
+
if (!_storage) {
|
|
48146
|
+
_storage = new FileMediaStorage();
|
|
48074
48147
|
}
|
|
48075
|
-
return
|
|
48148
|
+
return _storage;
|
|
48076
48149
|
}
|
|
48077
|
-
function
|
|
48078
|
-
|
|
48150
|
+
function setMediaStorage(storage) {
|
|
48151
|
+
_storage = storage;
|
|
48079
48152
|
}
|
|
48153
|
+
var getMediaOutputHandler = getMediaStorage;
|
|
48154
|
+
var setMediaOutputHandler = setMediaStorage;
|
|
48080
48155
|
|
|
48081
48156
|
// src/tools/multimedia/imageGeneration.ts
|
|
48082
|
-
function createImageGenerationTool(connector,
|
|
48157
|
+
function createImageGenerationTool(connector, storage, userId) {
|
|
48083
48158
|
const vendor = connector.vendor;
|
|
48084
|
-
const handler =
|
|
48159
|
+
const handler = storage ?? getMediaStorage();
|
|
48085
48160
|
const vendorModels = vendor ? getImageModelsByVendor(vendor) : [];
|
|
48086
48161
|
const modelNames = vendorModels.map((m) => m.name);
|
|
48087
48162
|
const properties = {
|
|
@@ -48154,8 +48229,9 @@ function createImageGenerationTool(connector, outputHandler) {
|
|
|
48154
48229
|
}
|
|
48155
48230
|
}
|
|
48156
48231
|
},
|
|
48157
|
-
execute: async (args) => {
|
|
48232
|
+
execute: async (args, context) => {
|
|
48158
48233
|
try {
|
|
48234
|
+
const effectiveUserId = userId ?? context?.userId;
|
|
48159
48235
|
const imageGen = ImageGeneration.create({ connector });
|
|
48160
48236
|
const response = await imageGen.generate({
|
|
48161
48237
|
prompt: args.prompt,
|
|
@@ -48186,7 +48262,8 @@ function createImageGenerationTool(connector, outputHandler) {
|
|
|
48186
48262
|
format,
|
|
48187
48263
|
model: modelName,
|
|
48188
48264
|
vendor: vendor || "unknown",
|
|
48189
|
-
index: response.data.length > 1 ? i : void 0
|
|
48265
|
+
index: response.data.length > 1 ? i : void 0,
|
|
48266
|
+
userId: effectiveUserId
|
|
48190
48267
|
});
|
|
48191
48268
|
images.push({
|
|
48192
48269
|
location: result.location,
|
|
@@ -48213,9 +48290,9 @@ function createImageGenerationTool(connector, outputHandler) {
|
|
|
48213
48290
|
|
|
48214
48291
|
// src/tools/multimedia/videoGeneration.ts
|
|
48215
48292
|
var videoGenInstances = /* @__PURE__ */ new Map();
|
|
48216
|
-
function createVideoTools(connector,
|
|
48293
|
+
function createVideoTools(connector, storage, userId) {
|
|
48217
48294
|
const vendor = connector.vendor;
|
|
48218
|
-
const handler =
|
|
48295
|
+
const handler = storage ?? getMediaStorage();
|
|
48219
48296
|
const vendorModels = vendor ? getVideoModelsByVendor(vendor) : [];
|
|
48220
48297
|
const modelNames = vendorModels.map((m) => m.name);
|
|
48221
48298
|
const generateProperties = {
|
|
@@ -48279,7 +48356,7 @@ function createVideoTools(connector, outputHandler) {
|
|
|
48279
48356
|
}
|
|
48280
48357
|
}
|
|
48281
48358
|
},
|
|
48282
|
-
execute: async (args) => {
|
|
48359
|
+
execute: async (args, _context) => {
|
|
48283
48360
|
try {
|
|
48284
48361
|
const videoGen = VideoGeneration.create({ connector });
|
|
48285
48362
|
const response = await videoGen.generate({
|
|
@@ -48328,8 +48405,9 @@ function createVideoTools(connector, outputHandler) {
|
|
|
48328
48405
|
}
|
|
48329
48406
|
}
|
|
48330
48407
|
},
|
|
48331
|
-
execute: async (args) => {
|
|
48408
|
+
execute: async (args, context) => {
|
|
48332
48409
|
try {
|
|
48410
|
+
const effectiveUserId = userId ?? context?.userId;
|
|
48333
48411
|
let videoGen = videoGenInstances.get(args.jobId);
|
|
48334
48412
|
if (!videoGen) {
|
|
48335
48413
|
videoGen = VideoGeneration.create({ connector });
|
|
@@ -48355,7 +48433,8 @@ function createVideoTools(connector, outputHandler) {
|
|
|
48355
48433
|
type: "video",
|
|
48356
48434
|
format,
|
|
48357
48435
|
model: modelName,
|
|
48358
|
-
vendor: vendor || "unknown"
|
|
48436
|
+
vendor: vendor || "unknown",
|
|
48437
|
+
userId: effectiveUserId
|
|
48359
48438
|
});
|
|
48360
48439
|
videoGenInstances.delete(args.jobId);
|
|
48361
48440
|
return {
|
|
@@ -48403,9 +48482,9 @@ function createVideoTools(connector, outputHandler) {
|
|
|
48403
48482
|
}
|
|
48404
48483
|
|
|
48405
48484
|
// src/tools/multimedia/textToSpeech.ts
|
|
48406
|
-
function createTextToSpeechTool(connector,
|
|
48485
|
+
function createTextToSpeechTool(connector, storage, userId) {
|
|
48407
48486
|
const vendor = connector.vendor;
|
|
48408
|
-
const handler =
|
|
48487
|
+
const handler = storage ?? getMediaStorage();
|
|
48409
48488
|
const vendorModels = vendor ? getTTSModelsByVendor(vendor) : [];
|
|
48410
48489
|
const modelNames = vendorModels.map((m) => m.name);
|
|
48411
48490
|
const properties = {
|
|
@@ -48466,8 +48545,9 @@ function createTextToSpeechTool(connector, outputHandler) {
|
|
|
48466
48545
|
}
|
|
48467
48546
|
}
|
|
48468
48547
|
},
|
|
48469
|
-
execute: async (args) => {
|
|
48548
|
+
execute: async (args, context) => {
|
|
48470
48549
|
try {
|
|
48550
|
+
const effectiveUserId = userId ?? context?.userId;
|
|
48471
48551
|
const tts = TextToSpeech.create({
|
|
48472
48552
|
connector,
|
|
48473
48553
|
model: args.model,
|
|
@@ -48481,7 +48561,8 @@ function createTextToSpeechTool(connector, outputHandler) {
|
|
|
48481
48561
|
type: "audio",
|
|
48482
48562
|
format,
|
|
48483
48563
|
model: args.model || modelNames[0] || "unknown",
|
|
48484
|
-
vendor: vendor || "unknown"
|
|
48564
|
+
vendor: vendor || "unknown",
|
|
48565
|
+
userId: effectiveUserId
|
|
48485
48566
|
});
|
|
48486
48567
|
return {
|
|
48487
48568
|
success: true,
|
|
@@ -48504,14 +48585,17 @@ function createTextToSpeechTool(connector, outputHandler) {
|
|
|
48504
48585
|
}
|
|
48505
48586
|
};
|
|
48506
48587
|
}
|
|
48507
|
-
|
|
48588
|
+
|
|
48589
|
+
// src/tools/multimedia/speechToText.ts
|
|
48590
|
+
function createSpeechToTextTool(connector, storage) {
|
|
48508
48591
|
const vendor = connector.vendor;
|
|
48592
|
+
const handler = storage ?? getMediaStorage();
|
|
48509
48593
|
const vendorModels = vendor ? getSTTModelsByVendor(vendor) : [];
|
|
48510
48594
|
const modelNames = vendorModels.map((m) => m.name);
|
|
48511
48595
|
const properties = {
|
|
48512
|
-
|
|
48596
|
+
audioSource: {
|
|
48513
48597
|
type: "string",
|
|
48514
|
-
description: "Path
|
|
48598
|
+
description: "Path or location of the audio file to transcribe (file path, storage location, etc.)"
|
|
48515
48599
|
}
|
|
48516
48600
|
};
|
|
48517
48601
|
if (modelNames.length > 0) {
|
|
@@ -48539,13 +48623,19 @@ function createSpeechToTextTool(connector) {
|
|
|
48539
48623
|
parameters: {
|
|
48540
48624
|
type: "object",
|
|
48541
48625
|
properties,
|
|
48542
|
-
required: ["
|
|
48626
|
+
required: ["audioSource"]
|
|
48543
48627
|
}
|
|
48544
48628
|
}
|
|
48545
48629
|
},
|
|
48546
|
-
execute: async (args) => {
|
|
48630
|
+
execute: async (args, _context) => {
|
|
48547
48631
|
try {
|
|
48548
|
-
const audioBuffer = await
|
|
48632
|
+
const audioBuffer = await handler.read(args.audioSource);
|
|
48633
|
+
if (!audioBuffer) {
|
|
48634
|
+
return {
|
|
48635
|
+
success: false,
|
|
48636
|
+
error: `Audio not found at: ${args.audioSource}`
|
|
48637
|
+
};
|
|
48638
|
+
}
|
|
48549
48639
|
const stt = SpeechToText.create({
|
|
48550
48640
|
connector,
|
|
48551
48641
|
model: args.model,
|
|
@@ -48567,7 +48657,7 @@ function createSpeechToTextTool(connector) {
|
|
|
48567
48657
|
};
|
|
48568
48658
|
}
|
|
48569
48659
|
},
|
|
48570
|
-
describeCall: (args) => args.
|
|
48660
|
+
describeCall: (args) => args.audioSource,
|
|
48571
48661
|
permission: {
|
|
48572
48662
|
scope: "session",
|
|
48573
48663
|
riskLevel: "low",
|
|
@@ -48582,21 +48672,22 @@ var VENDOR_CAPABILITIES = {
|
|
|
48582
48672
|
[Vendor.Google]: ["image", "video", "tts"],
|
|
48583
48673
|
[Vendor.Grok]: ["image", "video"]
|
|
48584
48674
|
};
|
|
48585
|
-
function registerMultimediaTools() {
|
|
48675
|
+
function registerMultimediaTools(storage) {
|
|
48586
48676
|
for (const [vendor, capabilities] of Object.entries(VENDOR_CAPABILITIES)) {
|
|
48587
|
-
ConnectorTools.registerService(vendor, (connector,
|
|
48677
|
+
ConnectorTools.registerService(vendor, (connector, userId) => {
|
|
48678
|
+
const handler = getMediaStorage();
|
|
48588
48679
|
const tools = [];
|
|
48589
48680
|
if (capabilities.includes("image")) {
|
|
48590
|
-
tools.push(createImageGenerationTool(connector));
|
|
48681
|
+
tools.push(createImageGenerationTool(connector, handler, userId));
|
|
48591
48682
|
}
|
|
48592
48683
|
if (capabilities.includes("video")) {
|
|
48593
|
-
tools.push(...createVideoTools(connector));
|
|
48684
|
+
tools.push(...createVideoTools(connector, handler, userId));
|
|
48594
48685
|
}
|
|
48595
48686
|
if (capabilities.includes("tts")) {
|
|
48596
|
-
tools.push(createTextToSpeechTool(connector));
|
|
48687
|
+
tools.push(createTextToSpeechTool(connector, handler, userId));
|
|
48597
48688
|
}
|
|
48598
48689
|
if (capabilities.includes("stt")) {
|
|
48599
|
-
tools.push(createSpeechToTextTool(connector));
|
|
48690
|
+
tools.push(createSpeechToTextTool(connector, handler));
|
|
48600
48691
|
}
|
|
48601
48692
|
return tools;
|
|
48602
48693
|
});
|
|
@@ -48606,6 +48697,858 @@ function registerMultimediaTools() {
|
|
|
48606
48697
|
// src/tools/multimedia/index.ts
|
|
48607
48698
|
registerMultimediaTools();
|
|
48608
48699
|
|
|
48700
|
+
// src/tools/github/types.ts
|
|
48701
|
+
function parseRepository(input) {
|
|
48702
|
+
if (!input || input.trim().length === 0) {
|
|
48703
|
+
throw new Error("Repository cannot be empty");
|
|
48704
|
+
}
|
|
48705
|
+
const trimmed = input.trim();
|
|
48706
|
+
try {
|
|
48707
|
+
const url2 = new URL(trimmed);
|
|
48708
|
+
if (url2.hostname === "github.com" || url2.hostname === "www.github.com") {
|
|
48709
|
+
const segments = url2.pathname.split("/").filter(Boolean);
|
|
48710
|
+
if (segments.length >= 2) {
|
|
48711
|
+
return { owner: segments[0], repo: segments[1].replace(/\.git$/, "") };
|
|
48712
|
+
}
|
|
48713
|
+
}
|
|
48714
|
+
} catch {
|
|
48715
|
+
}
|
|
48716
|
+
const parts = trimmed.split("/");
|
|
48717
|
+
if (parts.length === 2 && parts[0].length > 0 && parts[1].length > 0) {
|
|
48718
|
+
return { owner: parts[0], repo: parts[1] };
|
|
48719
|
+
}
|
|
48720
|
+
throw new Error(
|
|
48721
|
+
`Invalid repository format: "${input}". Expected "owner/repo" or "https://github.com/owner/repo"`
|
|
48722
|
+
);
|
|
48723
|
+
}
|
|
48724
|
+
function resolveRepository(repository, connector) {
|
|
48725
|
+
const repoStr = repository ?? connector.getOptions().defaultRepository;
|
|
48726
|
+
if (!repoStr) {
|
|
48727
|
+
return {
|
|
48728
|
+
success: false,
|
|
48729
|
+
error: 'No repository specified. Provide a "repository" parameter (e.g., "owner/repo") or configure defaultRepository on the connector.'
|
|
48730
|
+
};
|
|
48731
|
+
}
|
|
48732
|
+
try {
|
|
48733
|
+
return { success: true, repo: parseRepository(repoStr) };
|
|
48734
|
+
} catch (err) {
|
|
48735
|
+
return { success: false, error: err instanceof Error ? err.message : String(err) };
|
|
48736
|
+
}
|
|
48737
|
+
}
|
|
48738
|
+
var GitHubAPIError = class extends Error {
|
|
48739
|
+
constructor(status, statusText, body) {
|
|
48740
|
+
const msg = typeof body === "object" && body !== null && "message" in body ? body.message : statusText;
|
|
48741
|
+
super(`GitHub API error ${status}: ${msg}`);
|
|
48742
|
+
this.status = status;
|
|
48743
|
+
this.statusText = statusText;
|
|
48744
|
+
this.body = body;
|
|
48745
|
+
this.name = "GitHubAPIError";
|
|
48746
|
+
}
|
|
48747
|
+
};
|
|
48748
|
+
async function githubFetch(connector, endpoint, options) {
|
|
48749
|
+
let url2 = endpoint;
|
|
48750
|
+
if (options?.queryParams && Object.keys(options.queryParams).length > 0) {
|
|
48751
|
+
const params = new URLSearchParams();
|
|
48752
|
+
for (const [key, value] of Object.entries(options.queryParams)) {
|
|
48753
|
+
params.append(key, String(value));
|
|
48754
|
+
}
|
|
48755
|
+
url2 += (url2.includes("?") ? "&" : "?") + params.toString();
|
|
48756
|
+
}
|
|
48757
|
+
const headers = {
|
|
48758
|
+
"Accept": options?.accept ?? "application/vnd.github+json",
|
|
48759
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
48760
|
+
};
|
|
48761
|
+
if (options?.body) {
|
|
48762
|
+
headers["Content-Type"] = "application/json";
|
|
48763
|
+
}
|
|
48764
|
+
const response = await connector.fetch(
|
|
48765
|
+
url2,
|
|
48766
|
+
{
|
|
48767
|
+
method: options?.method ?? "GET",
|
|
48768
|
+
headers,
|
|
48769
|
+
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
48770
|
+
},
|
|
48771
|
+
options?.userId
|
|
48772
|
+
);
|
|
48773
|
+
const text = await response.text();
|
|
48774
|
+
let data;
|
|
48775
|
+
try {
|
|
48776
|
+
data = JSON.parse(text);
|
|
48777
|
+
} catch {
|
|
48778
|
+
data = text;
|
|
48779
|
+
}
|
|
48780
|
+
if (!response.ok) {
|
|
48781
|
+
throw new GitHubAPIError(response.status, response.statusText, data);
|
|
48782
|
+
}
|
|
48783
|
+
return data;
|
|
48784
|
+
}
|
|
48785
|
+
|
|
48786
|
+
// src/tools/github/searchFiles.ts
|
|
48787
|
+
function matchGlobPattern2(pattern, filePath) {
|
|
48788
|
+
let regexPattern = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, ".").replace(/\{\{GLOBSTAR\}\}/g, ".*");
|
|
48789
|
+
regexPattern = "^" + regexPattern + "$";
|
|
48790
|
+
try {
|
|
48791
|
+
const regex = new RegExp(regexPattern);
|
|
48792
|
+
return regex.test(filePath);
|
|
48793
|
+
} catch {
|
|
48794
|
+
return false;
|
|
48795
|
+
}
|
|
48796
|
+
}
|
|
48797
|
+
function createSearchFilesTool(connector, userId) {
|
|
48798
|
+
return {
|
|
48799
|
+
definition: {
|
|
48800
|
+
type: "function",
|
|
48801
|
+
function: {
|
|
48802
|
+
name: "search_files",
|
|
48803
|
+
description: `Search for files by name/path pattern in a GitHub repository.
|
|
48804
|
+
|
|
48805
|
+
USAGE:
|
|
48806
|
+
- Supports glob patterns like "**/*.ts", "src/**/*.tsx"
|
|
48807
|
+
- Returns matching file paths sorted alphabetically
|
|
48808
|
+
- Uses the repository's file tree for fast matching
|
|
48809
|
+
|
|
48810
|
+
PATTERN SYNTAX:
|
|
48811
|
+
- * matches any characters except /
|
|
48812
|
+
- ** matches any characters including /
|
|
48813
|
+
- ? matches a single character
|
|
48814
|
+
|
|
48815
|
+
EXAMPLES:
|
|
48816
|
+
- Find all TypeScript files: { "pattern": "**/*.ts" }
|
|
48817
|
+
- Find files in src: { "pattern": "src/**/*.{ts,tsx}" }
|
|
48818
|
+
- Find package.json: { "pattern": "**/package.json" }
|
|
48819
|
+
- Search specific branch: { "pattern": "**/*.ts", "ref": "develop" }`,
|
|
48820
|
+
parameters: {
|
|
48821
|
+
type: "object",
|
|
48822
|
+
properties: {
|
|
48823
|
+
repository: {
|
|
48824
|
+
type: "string",
|
|
48825
|
+
description: 'Repository in "owner/repo" format or full GitHub URL. Optional if connector has a default repository.'
|
|
48826
|
+
},
|
|
48827
|
+
pattern: {
|
|
48828
|
+
type: "string",
|
|
48829
|
+
description: 'Glob pattern to match files (e.g., "**/*.ts", "src/**/*.tsx")'
|
|
48830
|
+
},
|
|
48831
|
+
ref: {
|
|
48832
|
+
type: "string",
|
|
48833
|
+
description: "Branch, tag, or commit SHA. Defaults to the repository's default branch."
|
|
48834
|
+
}
|
|
48835
|
+
},
|
|
48836
|
+
required: ["pattern"]
|
|
48837
|
+
}
|
|
48838
|
+
}
|
|
48839
|
+
},
|
|
48840
|
+
describeCall: (args) => {
|
|
48841
|
+
const parts = [args.pattern];
|
|
48842
|
+
if (args.repository) parts.push(`in ${args.repository}`);
|
|
48843
|
+
if (args.ref) parts.push(`@${args.ref}`);
|
|
48844
|
+
return parts.join(" ");
|
|
48845
|
+
},
|
|
48846
|
+
permission: {
|
|
48847
|
+
scope: "session",
|
|
48848
|
+
riskLevel: "low",
|
|
48849
|
+
approvalMessage: `Search files in a GitHub repository via ${connector.displayName}`
|
|
48850
|
+
},
|
|
48851
|
+
execute: async (args, context) => {
|
|
48852
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
48853
|
+
const resolved = resolveRepository(args.repository, connector);
|
|
48854
|
+
if (!resolved.success) {
|
|
48855
|
+
return { success: false, error: resolved.error };
|
|
48856
|
+
}
|
|
48857
|
+
const { owner, repo } = resolved.repo;
|
|
48858
|
+
try {
|
|
48859
|
+
let ref = args.ref;
|
|
48860
|
+
if (!ref) {
|
|
48861
|
+
const repoInfo = await githubFetch(
|
|
48862
|
+
connector,
|
|
48863
|
+
`/repos/${owner}/${repo}`,
|
|
48864
|
+
{ userId: effectiveUserId }
|
|
48865
|
+
);
|
|
48866
|
+
ref = repoInfo.default_branch;
|
|
48867
|
+
}
|
|
48868
|
+
const tree = await githubFetch(
|
|
48869
|
+
connector,
|
|
48870
|
+
`/repos/${owner}/${repo}/git/trees/${ref}?recursive=1`,
|
|
48871
|
+
{ userId: effectiveUserId }
|
|
48872
|
+
);
|
|
48873
|
+
const matching = tree.tree.filter(
|
|
48874
|
+
(entry) => entry.type === "blob" && matchGlobPattern2(args.pattern, entry.path)
|
|
48875
|
+
).map((entry) => ({
|
|
48876
|
+
path: entry.path,
|
|
48877
|
+
size: entry.size ?? 0,
|
|
48878
|
+
type: entry.type
|
|
48879
|
+
})).sort((a, b) => a.path.localeCompare(b.path));
|
|
48880
|
+
return {
|
|
48881
|
+
success: true,
|
|
48882
|
+
files: matching,
|
|
48883
|
+
count: matching.length,
|
|
48884
|
+
truncated: tree.truncated
|
|
48885
|
+
};
|
|
48886
|
+
} catch (error) {
|
|
48887
|
+
return {
|
|
48888
|
+
success: false,
|
|
48889
|
+
error: `Failed to search files: ${error instanceof Error ? error.message : String(error)}`
|
|
48890
|
+
};
|
|
48891
|
+
}
|
|
48892
|
+
}
|
|
48893
|
+
};
|
|
48894
|
+
}
|
|
48895
|
+
|
|
48896
|
+
// src/tools/github/searchCode.ts
|
|
48897
|
+
function createSearchCodeTool(connector, userId) {
|
|
48898
|
+
return {
|
|
48899
|
+
definition: {
|
|
48900
|
+
type: "function",
|
|
48901
|
+
function: {
|
|
48902
|
+
name: "search_code",
|
|
48903
|
+
description: `Search for code content across a GitHub repository.
|
|
48904
|
+
|
|
48905
|
+
USAGE:
|
|
48906
|
+
- Search by keyword, function name, class name, or any text
|
|
48907
|
+
- Filter by language, path, or file extension
|
|
48908
|
+
- Returns matching files with text fragments showing context
|
|
48909
|
+
|
|
48910
|
+
RATE LIMITS:
|
|
48911
|
+
- GitHub's code search API is limited to 30 requests per minute
|
|
48912
|
+
- Results may be incomplete for very large repositories
|
|
48913
|
+
|
|
48914
|
+
EXAMPLES:
|
|
48915
|
+
- Find function: { "query": "function handleAuth", "language": "typescript" }
|
|
48916
|
+
- Find imports: { "query": "import React", "extension": "tsx" }
|
|
48917
|
+
- Search in path: { "query": "TODO", "path": "src/utils" }
|
|
48918
|
+
- Limit results: { "query": "console.log", "limit": 10 }`,
|
|
48919
|
+
parameters: {
|
|
48920
|
+
type: "object",
|
|
48921
|
+
properties: {
|
|
48922
|
+
repository: {
|
|
48923
|
+
type: "string",
|
|
48924
|
+
description: 'Repository in "owner/repo" format or full GitHub URL. Optional if connector has a default repository.'
|
|
48925
|
+
},
|
|
48926
|
+
query: {
|
|
48927
|
+
type: "string",
|
|
48928
|
+
description: "Search query \u2014 keyword, function name, or any text to find in code"
|
|
48929
|
+
},
|
|
48930
|
+
language: {
|
|
48931
|
+
type: "string",
|
|
48932
|
+
description: 'Filter by programming language (e.g., "typescript", "python", "go")'
|
|
48933
|
+
},
|
|
48934
|
+
path: {
|
|
48935
|
+
type: "string",
|
|
48936
|
+
description: 'Filter by file path prefix (e.g., "src/", "lib/utils")'
|
|
48937
|
+
},
|
|
48938
|
+
extension: {
|
|
48939
|
+
type: "string",
|
|
48940
|
+
description: 'Filter by file extension without dot (e.g., "ts", "py", "go")'
|
|
48941
|
+
},
|
|
48942
|
+
limit: {
|
|
48943
|
+
type: "number",
|
|
48944
|
+
description: "Maximum number of results (default: 30, max: 100)"
|
|
48945
|
+
}
|
|
48946
|
+
},
|
|
48947
|
+
required: ["query"]
|
|
48948
|
+
}
|
|
48949
|
+
}
|
|
48950
|
+
},
|
|
48951
|
+
describeCall: (args) => {
|
|
48952
|
+
const parts = [`"${args.query}"`];
|
|
48953
|
+
if (args.language) parts.push(`lang:${args.language}`);
|
|
48954
|
+
if (args.repository) parts.push(`in ${args.repository}`);
|
|
48955
|
+
return parts.join(" ");
|
|
48956
|
+
},
|
|
48957
|
+
permission: {
|
|
48958
|
+
scope: "session",
|
|
48959
|
+
riskLevel: "low",
|
|
48960
|
+
approvalMessage: `Search code in a GitHub repository via ${connector.displayName}`
|
|
48961
|
+
},
|
|
48962
|
+
execute: async (args, context) => {
|
|
48963
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
48964
|
+
const resolved = resolveRepository(args.repository, connector);
|
|
48965
|
+
if (!resolved.success) {
|
|
48966
|
+
return { success: false, error: resolved.error };
|
|
48967
|
+
}
|
|
48968
|
+
const { owner, repo } = resolved.repo;
|
|
48969
|
+
try {
|
|
48970
|
+
const qualifiers = [`repo:${owner}/${repo}`];
|
|
48971
|
+
if (args.language) qualifiers.push(`language:${args.language}`);
|
|
48972
|
+
if (args.path) qualifiers.push(`path:${args.path}`);
|
|
48973
|
+
if (args.extension) qualifiers.push(`extension:${args.extension}`);
|
|
48974
|
+
const q = `${args.query} ${qualifiers.join(" ")}`;
|
|
48975
|
+
const perPage = Math.min(args.limit ?? 30, 100);
|
|
48976
|
+
const result = await githubFetch(
|
|
48977
|
+
connector,
|
|
48978
|
+
`/search/code`,
|
|
48979
|
+
{
|
|
48980
|
+
userId: effectiveUserId,
|
|
48981
|
+
// Request text-match fragments
|
|
48982
|
+
accept: "application/vnd.github.text-match+json",
|
|
48983
|
+
queryParams: { q, per_page: perPage }
|
|
48984
|
+
}
|
|
48985
|
+
);
|
|
48986
|
+
const matches = result.items.map((item) => ({
|
|
48987
|
+
file: item.path,
|
|
48988
|
+
fragment: item.text_matches?.[0]?.fragment
|
|
48989
|
+
}));
|
|
48990
|
+
return {
|
|
48991
|
+
success: true,
|
|
48992
|
+
matches,
|
|
48993
|
+
count: result.total_count,
|
|
48994
|
+
truncated: result.incomplete_results || result.total_count > perPage
|
|
48995
|
+
};
|
|
48996
|
+
} catch (error) {
|
|
48997
|
+
return {
|
|
48998
|
+
success: false,
|
|
48999
|
+
error: `Failed to search code: ${error instanceof Error ? error.message : String(error)}`
|
|
49000
|
+
};
|
|
49001
|
+
}
|
|
49002
|
+
}
|
|
49003
|
+
};
|
|
49004
|
+
}
|
|
49005
|
+
|
|
49006
|
+
// src/tools/github/readFile.ts
|
|
49007
|
+
function createGitHubReadFileTool(connector, userId) {
|
|
49008
|
+
return {
|
|
49009
|
+
definition: {
|
|
49010
|
+
type: "function",
|
|
49011
|
+
function: {
|
|
49012
|
+
name: "read_file",
|
|
49013
|
+
description: `Read file content from a GitHub repository.
|
|
49014
|
+
|
|
49015
|
+
USAGE:
|
|
49016
|
+
- Reads a file and returns content with line numbers
|
|
49017
|
+
- Supports line range selection with offset/limit for large files
|
|
49018
|
+
- By default reads up to 2000 lines from the beginning
|
|
49019
|
+
|
|
49020
|
+
EXAMPLES:
|
|
49021
|
+
- Read entire file: { "path": "src/index.ts" }
|
|
49022
|
+
- Read specific branch: { "path": "README.md", "ref": "develop" }
|
|
49023
|
+
- Read lines 100-200: { "path": "src/app.ts", "offset": 100, "limit": 100 }
|
|
49024
|
+
- Specific repo: { "repository": "owner/repo", "path": "package.json" }
|
|
49025
|
+
|
|
49026
|
+
NOTE: Files larger than 1MB are fetched via the Git Blob API. Very large files (>5MB) may be truncated.`,
|
|
49027
|
+
parameters: {
|
|
49028
|
+
type: "object",
|
|
49029
|
+
properties: {
|
|
49030
|
+
repository: {
|
|
49031
|
+
type: "string",
|
|
49032
|
+
description: 'Repository in "owner/repo" format or full GitHub URL. Optional if connector has a default repository.'
|
|
49033
|
+
},
|
|
49034
|
+
path: {
|
|
49035
|
+
type: "string",
|
|
49036
|
+
description: 'File path within the repository (e.g., "src/index.ts")'
|
|
49037
|
+
},
|
|
49038
|
+
ref: {
|
|
49039
|
+
type: "string",
|
|
49040
|
+
description: "Branch, tag, or commit SHA. Defaults to the repository's default branch."
|
|
49041
|
+
},
|
|
49042
|
+
offset: {
|
|
49043
|
+
type: "number",
|
|
49044
|
+
description: "Line number to start reading from (1-indexed). Only provide if the file is too large."
|
|
49045
|
+
},
|
|
49046
|
+
limit: {
|
|
49047
|
+
type: "number",
|
|
49048
|
+
description: "Number of lines to read (default: 2000). Only provide if the file is too large."
|
|
49049
|
+
}
|
|
49050
|
+
},
|
|
49051
|
+
required: ["path"]
|
|
49052
|
+
}
|
|
49053
|
+
}
|
|
49054
|
+
},
|
|
49055
|
+
describeCall: (args) => {
|
|
49056
|
+
const parts = [args.path];
|
|
49057
|
+
if (args.repository) parts.push(`in ${args.repository}`);
|
|
49058
|
+
if (args.ref) parts.push(`@${args.ref}`);
|
|
49059
|
+
if (args.offset && args.limit) parts.push(`[lines ${args.offset}-${args.offset + args.limit}]`);
|
|
49060
|
+
return parts.join(" ");
|
|
49061
|
+
},
|
|
49062
|
+
permission: {
|
|
49063
|
+
scope: "session",
|
|
49064
|
+
riskLevel: "low",
|
|
49065
|
+
approvalMessage: `Read a file from a GitHub repository via ${connector.displayName}`
|
|
49066
|
+
},
|
|
49067
|
+
execute: async (args, context) => {
|
|
49068
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
49069
|
+
const resolved = resolveRepository(args.repository, connector);
|
|
49070
|
+
if (!resolved.success) {
|
|
49071
|
+
return { success: false, error: resolved.error };
|
|
49072
|
+
}
|
|
49073
|
+
const { owner, repo } = resolved.repo;
|
|
49074
|
+
try {
|
|
49075
|
+
let fileContent;
|
|
49076
|
+
let fileSha;
|
|
49077
|
+
let fileSize;
|
|
49078
|
+
const refParam = args.ref ? `?ref=${encodeURIComponent(args.ref)}` : "";
|
|
49079
|
+
const contentResp = await githubFetch(
|
|
49080
|
+
connector,
|
|
49081
|
+
`/repos/${owner}/${repo}/contents/${args.path}${refParam}`,
|
|
49082
|
+
{ userId: effectiveUserId }
|
|
49083
|
+
);
|
|
49084
|
+
if (contentResp.type !== "file") {
|
|
49085
|
+
return {
|
|
49086
|
+
success: false,
|
|
49087
|
+
error: `Path is not a file: ${args.path} (type: ${contentResp.type}). Use search_files to explore the repository.`,
|
|
49088
|
+
path: args.path
|
|
49089
|
+
};
|
|
49090
|
+
}
|
|
49091
|
+
fileSha = contentResp.sha;
|
|
49092
|
+
fileSize = contentResp.size;
|
|
49093
|
+
if (contentResp.content && contentResp.encoding === "base64") {
|
|
49094
|
+
fileContent = Buffer.from(contentResp.content, "base64").toString("utf-8");
|
|
49095
|
+
} else if (contentResp.git_url) {
|
|
49096
|
+
const blob = await githubFetch(
|
|
49097
|
+
connector,
|
|
49098
|
+
contentResp.git_url,
|
|
49099
|
+
{ userId: effectiveUserId }
|
|
49100
|
+
);
|
|
49101
|
+
fileContent = Buffer.from(blob.content, "base64").toString("utf-8");
|
|
49102
|
+
fileSize = blob.size;
|
|
49103
|
+
} else {
|
|
49104
|
+
return {
|
|
49105
|
+
success: false,
|
|
49106
|
+
error: `Cannot read file content: ${args.path} (no content or git_url in response)`,
|
|
49107
|
+
path: args.path
|
|
49108
|
+
};
|
|
49109
|
+
}
|
|
49110
|
+
const offset = args.offset ?? 1;
|
|
49111
|
+
const limit = args.limit ?? 2e3;
|
|
49112
|
+
const allLines = fileContent.split("\n");
|
|
49113
|
+
const totalLines = allLines.length;
|
|
49114
|
+
const startIndex = Math.max(0, offset - 1);
|
|
49115
|
+
const endIndex = Math.min(totalLines, startIndex + limit);
|
|
49116
|
+
const selectedLines = allLines.slice(startIndex, endIndex);
|
|
49117
|
+
const lineNumberWidth = String(endIndex).length;
|
|
49118
|
+
const formattedLines = selectedLines.map((line, i) => {
|
|
49119
|
+
const lineNum = startIndex + i + 1;
|
|
49120
|
+
const paddedNum = String(lineNum).padStart(lineNumberWidth, " ");
|
|
49121
|
+
const truncatedLine = line.length > 2e3 ? line.substring(0, 2e3) + "..." : line;
|
|
49122
|
+
return `${paddedNum} ${truncatedLine}`;
|
|
49123
|
+
});
|
|
49124
|
+
const truncated = endIndex < totalLines;
|
|
49125
|
+
const result = formattedLines.join("\n");
|
|
49126
|
+
return {
|
|
49127
|
+
success: true,
|
|
49128
|
+
content: result,
|
|
49129
|
+
path: args.path,
|
|
49130
|
+
size: fileSize,
|
|
49131
|
+
lines: totalLines,
|
|
49132
|
+
truncated,
|
|
49133
|
+
sha: fileSha
|
|
49134
|
+
};
|
|
49135
|
+
} catch (error) {
|
|
49136
|
+
return {
|
|
49137
|
+
success: false,
|
|
49138
|
+
error: `Failed to read file: ${error instanceof Error ? error.message : String(error)}`,
|
|
49139
|
+
path: args.path
|
|
49140
|
+
};
|
|
49141
|
+
}
|
|
49142
|
+
}
|
|
49143
|
+
};
|
|
49144
|
+
}
|
|
49145
|
+
|
|
49146
|
+
// src/tools/github/getPR.ts
|
|
49147
|
+
function createGetPRTool(connector, userId) {
|
|
49148
|
+
return {
|
|
49149
|
+
definition: {
|
|
49150
|
+
type: "function",
|
|
49151
|
+
function: {
|
|
49152
|
+
name: "get_pr",
|
|
49153
|
+
description: `Get full details of a pull request from a GitHub repository.
|
|
49154
|
+
|
|
49155
|
+
Returns: title, description, state, author, labels, reviewers, merge status, branches, file stats, and more.
|
|
49156
|
+
|
|
49157
|
+
EXAMPLES:
|
|
49158
|
+
- Get PR: { "pull_number": 123 }
|
|
49159
|
+
- Specific repo: { "repository": "owner/repo", "pull_number": 456 }`,
|
|
49160
|
+
parameters: {
|
|
49161
|
+
type: "object",
|
|
49162
|
+
properties: {
|
|
49163
|
+
repository: {
|
|
49164
|
+
type: "string",
|
|
49165
|
+
description: 'Repository in "owner/repo" format or full GitHub URL. Optional if connector has a default repository.'
|
|
49166
|
+
},
|
|
49167
|
+
pull_number: {
|
|
49168
|
+
type: "number",
|
|
49169
|
+
description: "Pull request number"
|
|
49170
|
+
}
|
|
49171
|
+
},
|
|
49172
|
+
required: ["pull_number"]
|
|
49173
|
+
}
|
|
49174
|
+
}
|
|
49175
|
+
},
|
|
49176
|
+
describeCall: (args) => {
|
|
49177
|
+
const parts = [`#${args.pull_number}`];
|
|
49178
|
+
if (args.repository) parts.push(`in ${args.repository}`);
|
|
49179
|
+
return parts.join(" ");
|
|
49180
|
+
},
|
|
49181
|
+
permission: {
|
|
49182
|
+
scope: "session",
|
|
49183
|
+
riskLevel: "low",
|
|
49184
|
+
approvalMessage: `Get pull request details from GitHub via ${connector.displayName}`
|
|
49185
|
+
},
|
|
49186
|
+
execute: async (args, context) => {
|
|
49187
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
49188
|
+
const resolved = resolveRepository(args.repository, connector);
|
|
49189
|
+
if (!resolved.success) {
|
|
49190
|
+
return { success: false, error: resolved.error };
|
|
49191
|
+
}
|
|
49192
|
+
const { owner, repo } = resolved.repo;
|
|
49193
|
+
try {
|
|
49194
|
+
const pr = await githubFetch(
|
|
49195
|
+
connector,
|
|
49196
|
+
`/repos/${owner}/${repo}/pulls/${args.pull_number}`,
|
|
49197
|
+
{ userId: effectiveUserId }
|
|
49198
|
+
);
|
|
49199
|
+
return {
|
|
49200
|
+
success: true,
|
|
49201
|
+
data: {
|
|
49202
|
+
number: pr.number,
|
|
49203
|
+
title: pr.title,
|
|
49204
|
+
body: pr.body,
|
|
49205
|
+
state: pr.state,
|
|
49206
|
+
draft: pr.draft,
|
|
49207
|
+
author: pr.user.login,
|
|
49208
|
+
labels: pr.labels.map((l) => l.name),
|
|
49209
|
+
reviewers: pr.requested_reviewers.map((r) => r.login),
|
|
49210
|
+
mergeable: pr.mergeable,
|
|
49211
|
+
head: pr.head.ref,
|
|
49212
|
+
base: pr.base.ref,
|
|
49213
|
+
url: pr.html_url,
|
|
49214
|
+
created_at: pr.created_at,
|
|
49215
|
+
updated_at: pr.updated_at,
|
|
49216
|
+
additions: pr.additions,
|
|
49217
|
+
deletions: pr.deletions,
|
|
49218
|
+
changed_files: pr.changed_files
|
|
49219
|
+
}
|
|
49220
|
+
};
|
|
49221
|
+
} catch (error) {
|
|
49222
|
+
return {
|
|
49223
|
+
success: false,
|
|
49224
|
+
error: `Failed to get PR: ${error instanceof Error ? error.message : String(error)}`
|
|
49225
|
+
};
|
|
49226
|
+
}
|
|
49227
|
+
}
|
|
49228
|
+
};
|
|
49229
|
+
}
|
|
49230
|
+
|
|
49231
|
+
// src/tools/github/prFiles.ts
|
|
49232
|
+
function createPRFilesTool(connector, userId) {
|
|
49233
|
+
return {
|
|
49234
|
+
definition: {
|
|
49235
|
+
type: "function",
|
|
49236
|
+
function: {
|
|
49237
|
+
name: "pr_files",
|
|
49238
|
+
description: `Get the files changed in a pull request with diffs.
|
|
49239
|
+
|
|
49240
|
+
Returns: filename, status (added/modified/removed/renamed), additions, deletions, and patch (diff) content for each file.
|
|
49241
|
+
|
|
49242
|
+
EXAMPLES:
|
|
49243
|
+
- Get files: { "pull_number": 123 }
|
|
49244
|
+
- Specific repo: { "repository": "owner/repo", "pull_number": 456 }
|
|
49245
|
+
|
|
49246
|
+
NOTE: Very large diffs may be truncated by GitHub. Patch content may be absent for binary files.`,
|
|
49247
|
+
parameters: {
|
|
49248
|
+
type: "object",
|
|
49249
|
+
properties: {
|
|
49250
|
+
repository: {
|
|
49251
|
+
type: "string",
|
|
49252
|
+
description: 'Repository in "owner/repo" format or full GitHub URL. Optional if connector has a default repository.'
|
|
49253
|
+
},
|
|
49254
|
+
pull_number: {
|
|
49255
|
+
type: "number",
|
|
49256
|
+
description: "Pull request number"
|
|
49257
|
+
}
|
|
49258
|
+
},
|
|
49259
|
+
required: ["pull_number"]
|
|
49260
|
+
}
|
|
49261
|
+
}
|
|
49262
|
+
},
|
|
49263
|
+
describeCall: (args) => {
|
|
49264
|
+
const parts = [`files for #${args.pull_number}`];
|
|
49265
|
+
if (args.repository) parts.push(`in ${args.repository}`);
|
|
49266
|
+
return parts.join(" ");
|
|
49267
|
+
},
|
|
49268
|
+
permission: {
|
|
49269
|
+
scope: "session",
|
|
49270
|
+
riskLevel: "low",
|
|
49271
|
+
approvalMessage: `Get PR changed files from GitHub via ${connector.displayName}`
|
|
49272
|
+
},
|
|
49273
|
+
execute: async (args, context) => {
|
|
49274
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
49275
|
+
const resolved = resolveRepository(args.repository, connector);
|
|
49276
|
+
if (!resolved.success) {
|
|
49277
|
+
return { success: false, error: resolved.error };
|
|
49278
|
+
}
|
|
49279
|
+
const { owner, repo } = resolved.repo;
|
|
49280
|
+
try {
|
|
49281
|
+
const files = await githubFetch(
|
|
49282
|
+
connector,
|
|
49283
|
+
`/repos/${owner}/${repo}/pulls/${args.pull_number}/files`,
|
|
49284
|
+
{
|
|
49285
|
+
userId: effectiveUserId,
|
|
49286
|
+
queryParams: { per_page: 100 }
|
|
49287
|
+
}
|
|
49288
|
+
);
|
|
49289
|
+
return {
|
|
49290
|
+
success: true,
|
|
49291
|
+
files: files.map((f) => ({
|
|
49292
|
+
filename: f.filename,
|
|
49293
|
+
status: f.status,
|
|
49294
|
+
additions: f.additions,
|
|
49295
|
+
deletions: f.deletions,
|
|
49296
|
+
changes: f.changes,
|
|
49297
|
+
patch: f.patch
|
|
49298
|
+
})),
|
|
49299
|
+
count: files.length
|
|
49300
|
+
};
|
|
49301
|
+
} catch (error) {
|
|
49302
|
+
return {
|
|
49303
|
+
success: false,
|
|
49304
|
+
error: `Failed to get PR files: ${error instanceof Error ? error.message : String(error)}`
|
|
49305
|
+
};
|
|
49306
|
+
}
|
|
49307
|
+
}
|
|
49308
|
+
};
|
|
49309
|
+
}
|
|
49310
|
+
|
|
49311
|
+
// src/tools/github/prComments.ts
|
|
49312
|
+
function createPRCommentsTool(connector, userId) {
|
|
49313
|
+
return {
|
|
49314
|
+
definition: {
|
|
49315
|
+
type: "function",
|
|
49316
|
+
function: {
|
|
49317
|
+
name: "pr_comments",
|
|
49318
|
+
description: `Get all comments and reviews on a pull request.
|
|
49319
|
+
|
|
49320
|
+
Returns a unified list of:
|
|
49321
|
+
- **review_comment**: Line-level comments on specific code (includes file path and line number)
|
|
49322
|
+
- **review**: Full reviews (approve/request changes/comment)
|
|
49323
|
+
- **comment**: General comments on the PR (issue-level)
|
|
49324
|
+
|
|
49325
|
+
All entries are sorted by creation date (oldest first).
|
|
49326
|
+
|
|
49327
|
+
EXAMPLES:
|
|
49328
|
+
- Get comments: { "pull_number": 123 }
|
|
49329
|
+
- Specific repo: { "repository": "owner/repo", "pull_number": 456 }`,
|
|
49330
|
+
parameters: {
|
|
49331
|
+
type: "object",
|
|
49332
|
+
properties: {
|
|
49333
|
+
repository: {
|
|
49334
|
+
type: "string",
|
|
49335
|
+
description: 'Repository in "owner/repo" format or full GitHub URL. Optional if connector has a default repository.'
|
|
49336
|
+
},
|
|
49337
|
+
pull_number: {
|
|
49338
|
+
type: "number",
|
|
49339
|
+
description: "Pull request number"
|
|
49340
|
+
}
|
|
49341
|
+
},
|
|
49342
|
+
required: ["pull_number"]
|
|
49343
|
+
}
|
|
49344
|
+
}
|
|
49345
|
+
},
|
|
49346
|
+
describeCall: (args) => {
|
|
49347
|
+
const parts = [`comments for #${args.pull_number}`];
|
|
49348
|
+
if (args.repository) parts.push(`in ${args.repository}`);
|
|
49349
|
+
return parts.join(" ");
|
|
49350
|
+
},
|
|
49351
|
+
permission: {
|
|
49352
|
+
scope: "session",
|
|
49353
|
+
riskLevel: "low",
|
|
49354
|
+
approvalMessage: `Get PR comments and reviews from GitHub via ${connector.displayName}`
|
|
49355
|
+
},
|
|
49356
|
+
execute: async (args, context) => {
|
|
49357
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
49358
|
+
const resolved = resolveRepository(args.repository, connector);
|
|
49359
|
+
if (!resolved.success) {
|
|
49360
|
+
return { success: false, error: resolved.error };
|
|
49361
|
+
}
|
|
49362
|
+
const { owner, repo } = resolved.repo;
|
|
49363
|
+
try {
|
|
49364
|
+
const basePath = `/repos/${owner}/${repo}`;
|
|
49365
|
+
const queryOpts = { userId: effectiveUserId, queryParams: { per_page: 100 } };
|
|
49366
|
+
const [reviewComments, reviews, issueComments] = await Promise.all([
|
|
49367
|
+
githubFetch(
|
|
49368
|
+
connector,
|
|
49369
|
+
`${basePath}/pulls/${args.pull_number}/comments`,
|
|
49370
|
+
queryOpts
|
|
49371
|
+
),
|
|
49372
|
+
githubFetch(
|
|
49373
|
+
connector,
|
|
49374
|
+
`${basePath}/pulls/${args.pull_number}/reviews`,
|
|
49375
|
+
queryOpts
|
|
49376
|
+
),
|
|
49377
|
+
githubFetch(
|
|
49378
|
+
connector,
|
|
49379
|
+
`${basePath}/issues/${args.pull_number}/comments`,
|
|
49380
|
+
queryOpts
|
|
49381
|
+
)
|
|
49382
|
+
]);
|
|
49383
|
+
const allComments = [];
|
|
49384
|
+
for (const rc of reviewComments) {
|
|
49385
|
+
allComments.push({
|
|
49386
|
+
id: rc.id,
|
|
49387
|
+
type: "review_comment",
|
|
49388
|
+
author: rc.user.login,
|
|
49389
|
+
body: rc.body,
|
|
49390
|
+
created_at: rc.created_at,
|
|
49391
|
+
path: rc.path,
|
|
49392
|
+
line: rc.line ?? rc.original_line ?? void 0
|
|
49393
|
+
});
|
|
49394
|
+
}
|
|
49395
|
+
for (const r of reviews) {
|
|
49396
|
+
if (!r.body && r.state === "APPROVED") continue;
|
|
49397
|
+
allComments.push({
|
|
49398
|
+
id: r.id,
|
|
49399
|
+
type: "review",
|
|
49400
|
+
author: r.user.login,
|
|
49401
|
+
body: r.body || `[${r.state}]`,
|
|
49402
|
+
created_at: r.submitted_at,
|
|
49403
|
+
state: r.state
|
|
49404
|
+
});
|
|
49405
|
+
}
|
|
49406
|
+
for (const ic of issueComments) {
|
|
49407
|
+
allComments.push({
|
|
49408
|
+
id: ic.id,
|
|
49409
|
+
type: "comment",
|
|
49410
|
+
author: ic.user.login,
|
|
49411
|
+
body: ic.body,
|
|
49412
|
+
created_at: ic.created_at
|
|
49413
|
+
});
|
|
49414
|
+
}
|
|
49415
|
+
allComments.sort(
|
|
49416
|
+
(a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
|
|
49417
|
+
);
|
|
49418
|
+
return {
|
|
49419
|
+
success: true,
|
|
49420
|
+
comments: allComments,
|
|
49421
|
+
count: allComments.length
|
|
49422
|
+
};
|
|
49423
|
+
} catch (error) {
|
|
49424
|
+
return {
|
|
49425
|
+
success: false,
|
|
49426
|
+
error: `Failed to get PR comments: ${error instanceof Error ? error.message : String(error)}`
|
|
49427
|
+
};
|
|
49428
|
+
}
|
|
49429
|
+
}
|
|
49430
|
+
};
|
|
49431
|
+
}
|
|
49432
|
+
|
|
49433
|
+
// src/tools/github/createPR.ts
|
|
49434
|
+
function createCreatePRTool(connector, userId) {
|
|
49435
|
+
return {
|
|
49436
|
+
definition: {
|
|
49437
|
+
type: "function",
|
|
49438
|
+
function: {
|
|
49439
|
+
name: "create_pr",
|
|
49440
|
+
description: `Create a pull request on a GitHub repository.
|
|
49441
|
+
|
|
49442
|
+
USAGE:
|
|
49443
|
+
- Specify source branch (head) and target branch (base)
|
|
49444
|
+
- Optionally create as draft
|
|
49445
|
+
|
|
49446
|
+
EXAMPLES:
|
|
49447
|
+
- Create PR: { "title": "Add feature", "head": "feature-branch", "base": "main" }
|
|
49448
|
+
- Draft PR: { "title": "WIP: Refactor", "head": "refactor", "base": "develop", "draft": true }
|
|
49449
|
+
- With body: { "title": "Fix bug #42", "body": "Fixes the login issue\\n\\n## Changes\\n- Fixed auth flow", "head": "fix/42", "base": "main" }`,
|
|
49450
|
+
parameters: {
|
|
49451
|
+
type: "object",
|
|
49452
|
+
properties: {
|
|
49453
|
+
repository: {
|
|
49454
|
+
type: "string",
|
|
49455
|
+
description: 'Repository in "owner/repo" format or full GitHub URL. Optional if connector has a default repository.'
|
|
49456
|
+
},
|
|
49457
|
+
title: {
|
|
49458
|
+
type: "string",
|
|
49459
|
+
description: "Pull request title"
|
|
49460
|
+
},
|
|
49461
|
+
body: {
|
|
49462
|
+
type: "string",
|
|
49463
|
+
description: "Pull request description/body (Markdown supported)"
|
|
49464
|
+
},
|
|
49465
|
+
head: {
|
|
49466
|
+
type: "string",
|
|
49467
|
+
description: "Source branch name (the branch with your changes)"
|
|
49468
|
+
},
|
|
49469
|
+
base: {
|
|
49470
|
+
type: "string",
|
|
49471
|
+
description: 'Target branch name (the branch you want to merge into, e.g., "main")'
|
|
49472
|
+
},
|
|
49473
|
+
draft: {
|
|
49474
|
+
type: "boolean",
|
|
49475
|
+
description: "Create as a draft pull request (default: false)"
|
|
49476
|
+
}
|
|
49477
|
+
},
|
|
49478
|
+
required: ["title", "head", "base"]
|
|
49479
|
+
}
|
|
49480
|
+
}
|
|
49481
|
+
},
|
|
49482
|
+
describeCall: (args) => {
|
|
49483
|
+
const parts = [args.title];
|
|
49484
|
+
if (args.repository) parts.push(`in ${args.repository}`);
|
|
49485
|
+
return parts.join(" ");
|
|
49486
|
+
},
|
|
49487
|
+
permission: {
|
|
49488
|
+
scope: "session",
|
|
49489
|
+
riskLevel: "medium",
|
|
49490
|
+
approvalMessage: `Create a pull request on GitHub via ${connector.displayName}`
|
|
49491
|
+
},
|
|
49492
|
+
execute: async (args, context) => {
|
|
49493
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
49494
|
+
const resolved = resolveRepository(args.repository, connector);
|
|
49495
|
+
if (!resolved.success) {
|
|
49496
|
+
return { success: false, error: resolved.error };
|
|
49497
|
+
}
|
|
49498
|
+
const { owner, repo } = resolved.repo;
|
|
49499
|
+
try {
|
|
49500
|
+
const pr = await githubFetch(
|
|
49501
|
+
connector,
|
|
49502
|
+
`/repos/${owner}/${repo}/pulls`,
|
|
49503
|
+
{
|
|
49504
|
+
method: "POST",
|
|
49505
|
+
userId: effectiveUserId,
|
|
49506
|
+
body: {
|
|
49507
|
+
title: args.title,
|
|
49508
|
+
body: args.body,
|
|
49509
|
+
head: args.head,
|
|
49510
|
+
base: args.base,
|
|
49511
|
+
draft: args.draft ?? false
|
|
49512
|
+
}
|
|
49513
|
+
}
|
|
49514
|
+
);
|
|
49515
|
+
return {
|
|
49516
|
+
success: true,
|
|
49517
|
+
data: {
|
|
49518
|
+
number: pr.number,
|
|
49519
|
+
url: pr.html_url,
|
|
49520
|
+
state: pr.state,
|
|
49521
|
+
title: pr.title
|
|
49522
|
+
}
|
|
49523
|
+
};
|
|
49524
|
+
} catch (error) {
|
|
49525
|
+
return {
|
|
49526
|
+
success: false,
|
|
49527
|
+
error: `Failed to create PR: ${error instanceof Error ? error.message : String(error)}`
|
|
49528
|
+
};
|
|
49529
|
+
}
|
|
49530
|
+
}
|
|
49531
|
+
};
|
|
49532
|
+
}
|
|
49533
|
+
|
|
49534
|
+
// src/tools/github/register.ts
|
|
49535
|
+
function registerGitHubTools() {
|
|
49536
|
+
ConnectorTools.registerService("github", (connector, userId) => {
|
|
49537
|
+
return [
|
|
49538
|
+
createSearchFilesTool(connector, userId),
|
|
49539
|
+
createSearchCodeTool(connector, userId),
|
|
49540
|
+
createGitHubReadFileTool(connector, userId),
|
|
49541
|
+
createGetPRTool(connector, userId),
|
|
49542
|
+
createPRFilesTool(connector, userId),
|
|
49543
|
+
createPRCommentsTool(connector, userId),
|
|
49544
|
+
createCreatePRTool(connector, userId)
|
|
49545
|
+
];
|
|
49546
|
+
});
|
|
49547
|
+
}
|
|
49548
|
+
|
|
49549
|
+
// src/tools/github/index.ts
|
|
49550
|
+
registerGitHubTools();
|
|
49551
|
+
|
|
48609
49552
|
// src/tools/registry.generated.ts
|
|
48610
49553
|
var toolRegistry = [
|
|
48611
49554
|
{
|
|
@@ -48659,7 +49602,7 @@ var toolRegistry = [
|
|
|
48659
49602
|
displayName: "Read File",
|
|
48660
49603
|
category: "filesystem",
|
|
48661
49604
|
description: "Read content from a file on the local filesystem.",
|
|
48662
|
-
tool:
|
|
49605
|
+
tool: readFile5,
|
|
48663
49606
|
safeByDefault: true
|
|
48664
49607
|
},
|
|
48665
49608
|
{
|
|
@@ -48668,7 +49611,7 @@ var toolRegistry = [
|
|
|
48668
49611
|
displayName: "Write File",
|
|
48669
49612
|
category: "filesystem",
|
|
48670
49613
|
description: "Write content to a file on the local filesystem.",
|
|
48671
|
-
tool:
|
|
49614
|
+
tool: writeFile5,
|
|
48672
49615
|
safeByDefault: false
|
|
48673
49616
|
},
|
|
48674
49617
|
{
|
|
@@ -48697,37 +49640,6 @@ var toolRegistry = [
|
|
|
48697
49640
|
description: "Fetch and extract text content from a web page URL.",
|
|
48698
49641
|
tool: webFetch,
|
|
48699
49642
|
safeByDefault: true
|
|
48700
|
-
},
|
|
48701
|
-
{
|
|
48702
|
-
name: "web_fetch_js",
|
|
48703
|
-
exportName: "webFetchJS",
|
|
48704
|
-
displayName: "Web Fetch Js",
|
|
48705
|
-
category: "web",
|
|
48706
|
-
description: "Fetch and extract content from JavaScript-rendered websites using a headless browser (Puppeteer).",
|
|
48707
|
-
tool: webFetchJS,
|
|
48708
|
-
safeByDefault: true
|
|
48709
|
-
},
|
|
48710
|
-
{
|
|
48711
|
-
name: "web_scrape",
|
|
48712
|
-
exportName: "webScrape",
|
|
48713
|
-
displayName: "Web Scrape",
|
|
48714
|
-
category: "web",
|
|
48715
|
-
description: "Scrape any URL with automatic fallback - guaranteed to work on most sites.",
|
|
48716
|
-
tool: webScrape,
|
|
48717
|
-
safeByDefault: true,
|
|
48718
|
-
requiresConnector: true,
|
|
48719
|
-
connectorServiceTypes: ["zenrows"]
|
|
48720
|
-
},
|
|
48721
|
-
{
|
|
48722
|
-
name: "web_search",
|
|
48723
|
-
exportName: "webSearch",
|
|
48724
|
-
displayName: "Web Search",
|
|
48725
|
-
category: "web",
|
|
48726
|
-
description: "Search the web and get relevant results with snippets.",
|
|
48727
|
-
tool: webSearch,
|
|
48728
|
-
safeByDefault: true,
|
|
48729
|
-
requiresConnector: true,
|
|
48730
|
-
connectorServiceTypes: ["serper", "brave-search", "tavily", "rapidapi-websearch"]
|
|
48731
49643
|
}
|
|
48732
49644
|
];
|
|
48733
49645
|
function getAllBuiltInTools() {
|
|
@@ -48897,8 +49809,8 @@ var ToolRegistry = class {
|
|
|
48897
49809
|
|
|
48898
49810
|
// src/tools/index.ts
|
|
48899
49811
|
var developerTools = [
|
|
48900
|
-
|
|
48901
|
-
|
|
49812
|
+
readFile5,
|
|
49813
|
+
writeFile5,
|
|
48902
49814
|
editFile,
|
|
48903
49815
|
glob,
|
|
48904
49816
|
grep,
|
|
@@ -49085,6 +49997,6 @@ REMEMBER: Keep it conversational, ask one question at a time, and only output th
|
|
|
49085
49997
|
}
|
|
49086
49998
|
};
|
|
49087
49999
|
|
|
49088
|
-
export { AGENT_DEFINITION_FORMAT_VERSION, AIError, APPROVAL_STATE_VERSION, Agent, AgentContextNextGen, ApproximateTokenEstimator, BaseMediaProvider, BasePluginNextGen, BaseProvider, BaseTextProvider, BraveProvider, CONNECTOR_CONFIG_VERSION, CONTEXT_SESSION_FORMAT_VERSION, CheckpointManager, CircuitBreaker, CircuitOpenError, Connector, ConnectorConfigStore, ConnectorTools, ConsoleMetrics, ContentType, ContextOverflowError, DEFAULT_ALLOWLIST, DEFAULT_BACKOFF_CONFIG, DEFAULT_BASE_DELAY_MS, DEFAULT_CHECKPOINT_STRATEGY, DEFAULT_CIRCUIT_BREAKER_CONFIG, DEFAULT_CONFIG2 as DEFAULT_CONFIG, DEFAULT_CONNECTOR_TIMEOUT, DEFAULT_CONTEXT_CONFIG, DEFAULT_FEATURES, DEFAULT_FILESYSTEM_CONFIG, DEFAULT_HISTORY_MANAGER_CONFIG, DEFAULT_MAX_DELAY_MS, DEFAULT_MAX_RETRIES, DEFAULT_MEMORY_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_RATE_LIMITER_CONFIG, DEFAULT_RETRYABLE_STATUSES, DEFAULT_SHELL_CONFIG, DefaultCompactionStrategy, DependencyCycleError, ErrorHandler, ExecutionContext, ExternalDependencyHandler, FileAgentDefinitionStorage, FileConnectorStorage, FileContextStorage, FileMediaOutputHandler, FilePersistentInstructionsStorage, FileStorage, FrameworkLogger, HookManager, IMAGE_MODELS, IMAGE_MODEL_REGISTRY, ImageGeneration, InContextMemoryPluginNextGen, InMemoryAgentStateStorage, InMemoryHistoryStorage, InMemoryMetrics, InMemoryPlanStorage, InMemoryStorage, InvalidConfigError, InvalidToolArgumentsError, LLM_MODELS, LoggingPlugin, MCPClient, MCPConnectionError, MCPError, MCPProtocolError, MCPRegistry, MCPResourceError, MCPTimeoutError, MCPToolError, MEMORY_PRIORITY_VALUES, MODEL_REGISTRY, MemoryConnectorStorage, MemoryEvictionCompactor, MemoryStorage, MessageBuilder, MessageRole, ModelNotSupportedError, NoOpMetrics, OAuthManager, ParallelTasksError, PersistentInstructionsPluginNextGen, PlanningAgent, ProviderAuthError, ProviderConfigAgent, ProviderContextLengthError, ProviderError, ProviderErrorMapper, ProviderNotFoundError, ProviderRateLimitError, RapidAPIProvider, RateLimitError, SERVICE_DEFINITIONS, SERVICE_INFO, SERVICE_URL_PATTERNS, SIMPLE_ICONS_CDN, STT_MODELS, STT_MODEL_REGISTRY, ScopedConnectorRegistry, ScrapeProvider, SearchProvider, SerperProvider, Services, SpeechToText, StrategyRegistry, StreamEventType, StreamHelpers, StreamState, SummarizeCompactor, TERMINAL_TASK_STATUSES, TTS_MODELS, TTS_MODEL_REGISTRY, TaskTimeoutError, TaskValidationError, TavilyProvider, TextToSpeech, TokenBucketRateLimiter, ToolCallState, ToolExecutionError, ToolExecutionPipeline, ToolManager, ToolNotFoundError, ToolPermissionManager, ToolRegistry, ToolTimeoutError, TruncateCompactor, VENDORS, VENDOR_ICON_MAP, VIDEO_MODELS, VIDEO_MODEL_REGISTRY, Vendor, VideoGeneration, WorkingMemory, WorkingMemoryPluginNextGen, addJitter, allVendorTemplates, assertNotDestroyed, authenticatedFetch, backoffSequence, backoffWait, bash, buildAuthConfig, buildEndpointWithQuery, buildQueryString, calculateBackoff, calculateCost, calculateEntrySize, calculateImageCost, calculateSTTCost, calculateTTSCost, calculateVideoCost, canTaskExecute, createAgentStorage, createAuthenticatedFetch, createBashTool, createConnectorFromTemplate, createEditFileTool, createEstimator, createExecuteJavaScriptTool, createFileAgentDefinitionStorage, createFileContextStorage, createGlobTool, createGrepTool, createImageGenerationTool, createImageProvider, createListDirectoryTool, createMessageWithImages, createMetricsCollector, createPlan, createProvider, createReadFileTool, createSpeechToTextTool, createTask, createTextMessage, createTextToSpeechTool, createVideoProvider, createVideoTools, createWriteFileTool, defaultDescribeCall, detectDependencyCycle, detectServiceFromURL, developerTools, editFile, evaluateCondition, extractJSON, extractJSONField, extractNumber, findConnectorByServiceTypes, forPlan, forTasks, generateEncryptionKey, generateSimplePlan, generateWebAPITool, getActiveImageModels, getActiveModels, getActiveSTTModels, getActiveTTSModels, getActiveVideoModels, getAllBuiltInTools, getAllServiceIds, getAllVendorLogos, getAllVendorTemplates, getBackgroundOutput, getConnectorTools, getCredentialsSetupURL, getDocsURL, getImageModelInfo, getImageModelsByVendor, getImageModelsWithFeature, getMediaOutputHandler, getModelInfo, getModelsByVendor, getNextExecutableTasks, getRegisteredScrapeProviders, getSTTModelInfo, getSTTModelsByVendor, getSTTModelsWithFeature, getServiceDefinition, getServiceInfo, getServicesByCategory, getTTSModelInfo, getTTSModelsByVendor, getTTSModelsWithFeature, getTaskDependencies, getToolByName, getToolCallDescription, getToolCategories, getToolRegistry, getToolsByCategory, getToolsRequiringConnector, getVendorAuthTemplate, getVendorColor, getVendorInfo, getVendorLogo, getVendorLogoCdnUrl, getVendorLogoSvg, getVendorTemplate, getVideoModelInfo, getVideoModelsByVendor, getVideoModelsWithAudio, getVideoModelsWithFeature, glob, globalErrorHandler, grep, hasClipboardImage, hasVendorLogo, isBlockedCommand, isErrorEvent, isExcludedExtension, isKnownService, isOutputTextDelta, isResponseComplete, isSimpleScope, isStreamEvent, isTaskAwareScope, isTaskBlocked, isTerminalMemoryStatus, isTerminalStatus, isToolCallArgumentsDelta, isToolCallArgumentsDone, isToolCallStart, isVendor, killBackgroundProcess, listConnectorsByServiceTypes, listDirectory, listVendorIds, listVendors, listVendorsByAuthType, listVendorsByCategory, listVendorsWithLogos, logger, metrics, readClipboardImage,
|
|
50000
|
+
export { AGENT_DEFINITION_FORMAT_VERSION, AIError, APPROVAL_STATE_VERSION, Agent, AgentContextNextGen, ApproximateTokenEstimator, BaseMediaProvider, BasePluginNextGen, BaseProvider, BaseTextProvider, BraveProvider, CONNECTOR_CONFIG_VERSION, CONTEXT_SESSION_FORMAT_VERSION, CheckpointManager, CircuitBreaker, CircuitOpenError, Connector, ConnectorConfigStore, ConnectorTools, ConsoleMetrics, ContentType, ContextOverflowError, DEFAULT_ALLOWLIST, DEFAULT_BACKOFF_CONFIG, DEFAULT_BASE_DELAY_MS, DEFAULT_CHECKPOINT_STRATEGY, DEFAULT_CIRCUIT_BREAKER_CONFIG, DEFAULT_CONFIG2 as DEFAULT_CONFIG, DEFAULT_CONNECTOR_TIMEOUT, DEFAULT_CONTEXT_CONFIG, DEFAULT_FEATURES, DEFAULT_FILESYSTEM_CONFIG, DEFAULT_HISTORY_MANAGER_CONFIG, DEFAULT_MAX_DELAY_MS, DEFAULT_MAX_RETRIES, DEFAULT_MEMORY_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_RATE_LIMITER_CONFIG, DEFAULT_RETRYABLE_STATUSES, DEFAULT_SHELL_CONFIG, DefaultCompactionStrategy, DependencyCycleError, ErrorHandler, ExecutionContext, ExternalDependencyHandler, FileAgentDefinitionStorage, FileConnectorStorage, FileContextStorage, FileMediaStorage as FileMediaOutputHandler, FileMediaStorage, FilePersistentInstructionsStorage, FileStorage, FrameworkLogger, HookManager, IMAGE_MODELS, IMAGE_MODEL_REGISTRY, ImageGeneration, InContextMemoryPluginNextGen, InMemoryAgentStateStorage, InMemoryHistoryStorage, InMemoryMetrics, InMemoryPlanStorage, InMemoryStorage, InvalidConfigError, InvalidToolArgumentsError, LLM_MODELS, LoggingPlugin, MCPClient, MCPConnectionError, MCPError, MCPProtocolError, MCPRegistry, MCPResourceError, MCPTimeoutError, MCPToolError, MEMORY_PRIORITY_VALUES, MODEL_REGISTRY, MemoryConnectorStorage, MemoryEvictionCompactor, MemoryStorage, MessageBuilder, MessageRole, ModelNotSupportedError, NoOpMetrics, OAuthManager, ParallelTasksError, PersistentInstructionsPluginNextGen, PlanningAgent, ProviderAuthError, ProviderConfigAgent, ProviderContextLengthError, ProviderError, ProviderErrorMapper, ProviderNotFoundError, ProviderRateLimitError, RapidAPIProvider, RateLimitError, SERVICE_DEFINITIONS, SERVICE_INFO, SERVICE_URL_PATTERNS, SIMPLE_ICONS_CDN, STT_MODELS, STT_MODEL_REGISTRY, ScopedConnectorRegistry, ScrapeProvider, SearchProvider, SerperProvider, Services, SpeechToText, StrategyRegistry, StreamEventType, StreamHelpers, StreamState, SummarizeCompactor, TERMINAL_TASK_STATUSES, TTS_MODELS, TTS_MODEL_REGISTRY, TaskTimeoutError, TaskValidationError, TavilyProvider, TextToSpeech, TokenBucketRateLimiter, ToolCallState, ToolExecutionError, ToolExecutionPipeline, ToolManager, ToolNotFoundError, ToolPermissionManager, ToolRegistry, ToolTimeoutError, TruncateCompactor, VENDORS, VENDOR_ICON_MAP, VIDEO_MODELS, VIDEO_MODEL_REGISTRY, Vendor, VideoGeneration, WorkingMemory, WorkingMemoryPluginNextGen, addJitter, allVendorTemplates, assertNotDestroyed, authenticatedFetch, backoffSequence, backoffWait, bash, buildAuthConfig, buildEndpointWithQuery, buildQueryString, calculateBackoff, calculateCost, calculateEntrySize, calculateImageCost, calculateSTTCost, calculateTTSCost, calculateVideoCost, canTaskExecute, createAgentStorage, createAuthenticatedFetch, createBashTool, createConnectorFromTemplate, createCreatePRTool, createEditFileTool, createEstimator, createExecuteJavaScriptTool, createFileAgentDefinitionStorage, createFileContextStorage, createFileMediaStorage, createGetPRTool, createGitHubReadFileTool, createGlobTool, createGrepTool, createImageGenerationTool, createImageProvider, createListDirectoryTool, createMessageWithImages, createMetricsCollector, createPRCommentsTool, createPRFilesTool, createPlan, createProvider, createReadFileTool, createSearchCodeTool, createSearchFilesTool, createSpeechToTextTool, createTask, createTextMessage, createTextToSpeechTool, createVideoProvider, createVideoTools, createWriteFileTool, defaultDescribeCall, detectDependencyCycle, detectServiceFromURL, developerTools, editFile, evaluateCondition, extractJSON, extractJSONField, extractNumber, findConnectorByServiceTypes, forPlan, forTasks, generateEncryptionKey, generateSimplePlan, generateWebAPITool, getActiveImageModels, getActiveModels, getActiveSTTModels, getActiveTTSModels, getActiveVideoModels, getAllBuiltInTools, getAllServiceIds, getAllVendorLogos, getAllVendorTemplates, getBackgroundOutput, getConnectorTools, getCredentialsSetupURL, getDocsURL, getImageModelInfo, getImageModelsByVendor, getImageModelsWithFeature, getMediaOutputHandler, getMediaStorage, getModelInfo, getModelsByVendor, getNextExecutableTasks, getRegisteredScrapeProviders, getSTTModelInfo, getSTTModelsByVendor, getSTTModelsWithFeature, getServiceDefinition, getServiceInfo, getServicesByCategory, getTTSModelInfo, getTTSModelsByVendor, getTTSModelsWithFeature, getTaskDependencies, getToolByName, getToolCallDescription, getToolCategories, getToolRegistry, getToolsByCategory, getToolsRequiringConnector, getVendorAuthTemplate, getVendorColor, getVendorDefaultBaseURL, getVendorInfo, getVendorLogo, getVendorLogoCdnUrl, getVendorLogoSvg, getVendorTemplate, getVideoModelInfo, getVideoModelsByVendor, getVideoModelsWithAudio, getVideoModelsWithFeature, glob, globalErrorHandler, grep, hasClipboardImage, hasVendorLogo, isBlockedCommand, isErrorEvent, isExcludedExtension, isKnownService, isOutputTextDelta, isResponseComplete, isSimpleScope, isStreamEvent, isTaskAwareScope, isTaskBlocked, isTerminalMemoryStatus, isTerminalStatus, isToolCallArgumentsDelta, isToolCallArgumentsDone, isToolCallStart, isVendor, killBackgroundProcess, listConnectorsByServiceTypes, listDirectory, listVendorIds, listVendors, listVendorsByAuthType, listVendorsByCategory, listVendorsWithLogos, logger, metrics, parseRepository, readClipboardImage, readFile5 as readFile, registerScrapeProvider, resolveConnector, resolveDependencies, resolveRepository, retryWithBackoff, scopeEquals, scopeMatches, setMediaOutputHandler, setMediaStorage, setMetricsCollector, simpleTokenEstimator, toConnectorOptions, toolRegistry, tools_exports as tools, updateTaskStatus, validatePath, writeFile5 as writeFile };
|
|
49089
50001
|
//# sourceMappingURL=index.js.map
|
|
49090
50002
|
//# sourceMappingURL=index.js.map
|