@everworker/oneringai 0.3.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +115 -3
- package/dist/capabilities/agents/index.cjs +14 -2
- package/dist/capabilities/agents/index.cjs.map +1 -1
- package/dist/capabilities/agents/index.d.cts +1 -1
- package/dist/capabilities/agents/index.d.ts +1 -1
- package/dist/capabilities/agents/index.js +14 -2
- package/dist/capabilities/agents/index.js.map +1 -1
- package/dist/capabilities/images/index.cjs.map +1 -1
- package/dist/capabilities/images/index.js.map +1 -1
- package/dist/{index-WlQwiNF8.d.cts → index-CR5PHkck.d.cts} +6 -1
- package/dist/{index-BeZcWDiq.d.ts → index-Cb7N9QIj.d.ts} +6 -1
- package/dist/index.cjs +2282 -568
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +919 -340
- package/dist/index.d.ts +919 -340
- package/dist/index.js +2188 -493
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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 fs19 from 'fs';
|
|
5
5
|
import { promises, existsSync } from 'fs';
|
|
6
6
|
import { EventEmitter } from 'eventemitter3';
|
|
7
7
|
import * as path2 from 'path';
|
|
@@ -19,7 +19,7 @@ import * as z from 'zod/v4';
|
|
|
19
19
|
import spawn$1 from 'cross-spawn';
|
|
20
20
|
import process2 from 'process';
|
|
21
21
|
import { PassThrough } from 'stream';
|
|
22
|
-
import * as
|
|
22
|
+
import * as fs18 from 'fs/promises';
|
|
23
23
|
import { stat, readFile, mkdir, writeFile, readdir } from 'fs/promises';
|
|
24
24
|
import * as simpleIcons from 'simple-icons';
|
|
25
25
|
import { exec, spawn } from 'child_process';
|
|
@@ -641,7 +641,7 @@ var init_JWTBearer = __esm({
|
|
|
641
641
|
this.privateKey = config.privateKey;
|
|
642
642
|
} else if (config.privateKeyPath) {
|
|
643
643
|
try {
|
|
644
|
-
this.privateKey =
|
|
644
|
+
this.privateKey = fs19.readFileSync(config.privateKeyPath, "utf8");
|
|
645
645
|
} catch (error) {
|
|
646
646
|
throw new Error(`Failed to read private key from ${config.privateKeyPath}: ${error.message}`);
|
|
647
647
|
}
|
|
@@ -1400,10 +1400,10 @@ var init_Logger = __esm({
|
|
|
1400
1400
|
initFileStream(filePath) {
|
|
1401
1401
|
try {
|
|
1402
1402
|
const dir = path2.dirname(filePath);
|
|
1403
|
-
if (!
|
|
1404
|
-
|
|
1403
|
+
if (!fs19.existsSync(dir)) {
|
|
1404
|
+
fs19.mkdirSync(dir, { recursive: true });
|
|
1405
1405
|
}
|
|
1406
|
-
this.fileStream =
|
|
1406
|
+
this.fileStream = fs19.createWriteStream(filePath, {
|
|
1407
1407
|
flags: "a",
|
|
1408
1408
|
// append mode
|
|
1409
1409
|
encoding: "utf8"
|
|
@@ -9133,12 +9133,12 @@ var require_dist = __commonJS({
|
|
|
9133
9133
|
throw new Error(`Unknown format "${name}"`);
|
|
9134
9134
|
return f;
|
|
9135
9135
|
};
|
|
9136
|
-
function addFormats(ajv, list,
|
|
9136
|
+
function addFormats(ajv, list, fs20, exportName) {
|
|
9137
9137
|
var _a;
|
|
9138
9138
|
var _b;
|
|
9139
9139
|
(_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
9140
9140
|
for (const f of list)
|
|
9141
|
-
ajv.addFormat(f,
|
|
9141
|
+
ajv.addFormat(f, fs20[f]);
|
|
9142
9142
|
}
|
|
9143
9143
|
module.exports = exports$1 = formatsPlugin;
|
|
9144
9144
|
Object.defineProperty(exports$1, "__esModule", { value: true });
|
|
@@ -14473,7 +14473,7 @@ var PRIORITY_VALUES = {
|
|
|
14473
14473
|
};
|
|
14474
14474
|
var DEFAULT_CONFIG = {
|
|
14475
14475
|
maxEntries: 20,
|
|
14476
|
-
maxTotalTokens:
|
|
14476
|
+
maxTotalTokens: 4e4,
|
|
14477
14477
|
defaultPriority: "normal",
|
|
14478
14478
|
showTimestamps: false
|
|
14479
14479
|
};
|
|
@@ -16658,7 +16658,7 @@ var StrategyRegistry = class {
|
|
|
16658
16658
|
// src/core/context-nextgen/types.ts
|
|
16659
16659
|
var DEFAULT_FEATURES = {
|
|
16660
16660
|
workingMemory: true,
|
|
16661
|
-
inContextMemory:
|
|
16661
|
+
inContextMemory: true,
|
|
16662
16662
|
persistentInstructions: false,
|
|
16663
16663
|
userInfo: false
|
|
16664
16664
|
};
|
|
@@ -17338,6 +17338,8 @@ ${content}`);
|
|
|
17338
17338
|
breakdown.pluginContents[plugin.name] = plugin.getTokenSize();
|
|
17339
17339
|
}
|
|
17340
17340
|
}
|
|
17341
|
+
const now = /* @__PURE__ */ new Date();
|
|
17342
|
+
parts.push(`CURRENT DATE AND TIME: ${now.toLocaleString("en-US", { dateStyle: "full", timeStyle: "long", timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone })}`);
|
|
17341
17343
|
const systemText = parts.join("\n\n---\n\n");
|
|
17342
17344
|
const systemTokens = this._estimator.estimateTokens(systemText);
|
|
17343
17345
|
const systemMessage = {
|
|
@@ -20796,6 +20798,7 @@ var BaseAgent = class extends EventEmitter {
|
|
|
20796
20798
|
_agentContext;
|
|
20797
20799
|
// SINGLE SOURCE OF TRUTH for tools and sessions
|
|
20798
20800
|
_permissionManager;
|
|
20801
|
+
_ownsContext = true;
|
|
20799
20802
|
_isDestroyed = false;
|
|
20800
20803
|
_cleanupCallbacks = [];
|
|
20801
20804
|
_logger;
|
|
@@ -20848,8 +20851,10 @@ var BaseAgent = class extends EventEmitter {
|
|
|
20848
20851
|
*/
|
|
20849
20852
|
initializeAgentContext(config) {
|
|
20850
20853
|
if (config.context instanceof AgentContextNextGen) {
|
|
20854
|
+
this._ownsContext = false;
|
|
20851
20855
|
return config.context;
|
|
20852
20856
|
}
|
|
20857
|
+
this._ownsContext = true;
|
|
20853
20858
|
const contextConfig = {
|
|
20854
20859
|
model: config.model,
|
|
20855
20860
|
agentId: config.name,
|
|
@@ -21361,7 +21366,9 @@ var BaseAgent = class extends EventEmitter {
|
|
|
21361
21366
|
clearInterval(this._autoSaveInterval);
|
|
21362
21367
|
this._autoSaveInterval = null;
|
|
21363
21368
|
}
|
|
21364
|
-
this.
|
|
21369
|
+
if (this._ownsContext) {
|
|
21370
|
+
this._agentContext.destroy();
|
|
21371
|
+
}
|
|
21365
21372
|
this._permissionManager.removeAllListeners();
|
|
21366
21373
|
this.removeAllListeners();
|
|
21367
21374
|
}
|
|
@@ -21702,6 +21709,18 @@ var HookManager = class {
|
|
|
21702
21709
|
}
|
|
21703
21710
|
existing.push(hook);
|
|
21704
21711
|
}
|
|
21712
|
+
/**
|
|
21713
|
+
* Unregister a specific hook function by reference.
|
|
21714
|
+
* Returns true if the hook was found and removed.
|
|
21715
|
+
*/
|
|
21716
|
+
unregister(name, hook) {
|
|
21717
|
+
const hooks = this.hooks.get(name);
|
|
21718
|
+
if (!hooks) return false;
|
|
21719
|
+
const index = hooks.indexOf(hook);
|
|
21720
|
+
if (index === -1) return false;
|
|
21721
|
+
hooks.splice(index, 1);
|
|
21722
|
+
return true;
|
|
21723
|
+
}
|
|
21705
21724
|
/**
|
|
21706
21725
|
* Execute hooks for a given name
|
|
21707
21726
|
*/
|
|
@@ -21724,7 +21743,7 @@ var HookManager = class {
|
|
|
21724
21743
|
const hook = hooks[i];
|
|
21725
21744
|
const hookKey = this.getHookKey(hook, i);
|
|
21726
21745
|
const hookResult = await this.executeHookSafely(hook, context, hookKey);
|
|
21727
|
-
if (hookResult
|
|
21746
|
+
if (hookResult == null) {
|
|
21728
21747
|
continue;
|
|
21729
21748
|
}
|
|
21730
21749
|
result = { ...result, ...hookResult };
|
|
@@ -21744,7 +21763,7 @@ var HookManager = class {
|
|
|
21744
21763
|
return this.executeHookSafely(hook, context, hookKey);
|
|
21745
21764
|
})
|
|
21746
21765
|
);
|
|
21747
|
-
const validResults = results.filter((r) => r
|
|
21766
|
+
const validResults = results.filter((r) => r != null);
|
|
21748
21767
|
return validResults.reduce(
|
|
21749
21768
|
(acc, hookResult) => ({ ...acc, ...hookResult }),
|
|
21750
21769
|
defaultResult
|
|
@@ -22420,7 +22439,6 @@ var Agent = class _Agent extends BaseAgent {
|
|
|
22420
22439
|
_cleanupExecution(streamState) {
|
|
22421
22440
|
streamState?.clear();
|
|
22422
22441
|
this.executionContext?.cleanup();
|
|
22423
|
-
this.hookManager.clear();
|
|
22424
22442
|
}
|
|
22425
22443
|
/**
|
|
22426
22444
|
* Emit iteration complete event (helper for run loop)
|
|
@@ -23305,6 +23323,27 @@ var Agent = class _Agent extends BaseAgent {
|
|
|
23305
23323
|
isCancelled() {
|
|
23306
23324
|
return this._cancelled;
|
|
23307
23325
|
}
|
|
23326
|
+
/**
|
|
23327
|
+
* Clear conversation history, resetting the context for a fresh interaction.
|
|
23328
|
+
* Plugins (working memory, in-context memory, etc.) are NOT affected.
|
|
23329
|
+
*/
|
|
23330
|
+
clearConversation(reason) {
|
|
23331
|
+
this._agentContext.clearConversation(reason);
|
|
23332
|
+
this._logger.info({ reason }, "Conversation cleared");
|
|
23333
|
+
}
|
|
23334
|
+
// ===== Hook Management =====
|
|
23335
|
+
/**
|
|
23336
|
+
* Register a hook on the agent. Can be called after creation.
|
|
23337
|
+
*/
|
|
23338
|
+
registerHook(name, hook) {
|
|
23339
|
+
this.hookManager.register(name, hook);
|
|
23340
|
+
}
|
|
23341
|
+
/**
|
|
23342
|
+
* Unregister a previously registered hook by reference.
|
|
23343
|
+
*/
|
|
23344
|
+
unregisterHook(name, hook) {
|
|
23345
|
+
return this.hookManager.unregister(name, hook);
|
|
23346
|
+
}
|
|
23308
23347
|
// ===== Cleanup =====
|
|
23309
23348
|
destroy() {
|
|
23310
23349
|
if (this._isDestroyed) {
|
|
@@ -23334,6 +23373,1006 @@ var Agent = class _Agent extends BaseAgent {
|
|
|
23334
23373
|
}
|
|
23335
23374
|
};
|
|
23336
23375
|
|
|
23376
|
+
// src/domain/entities/Task.ts
|
|
23377
|
+
var TERMINAL_TASK_STATUSES = ["completed", "failed", "skipped", "cancelled"];
|
|
23378
|
+
function isTerminalStatus(status) {
|
|
23379
|
+
return TERMINAL_TASK_STATUSES.includes(status);
|
|
23380
|
+
}
|
|
23381
|
+
function createTask(input) {
|
|
23382
|
+
const now = Date.now();
|
|
23383
|
+
const id = input.id ?? `task-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
23384
|
+
return {
|
|
23385
|
+
id,
|
|
23386
|
+
name: input.name,
|
|
23387
|
+
description: input.description,
|
|
23388
|
+
status: "pending",
|
|
23389
|
+
dependsOn: input.dependsOn ?? [],
|
|
23390
|
+
externalDependency: input.externalDependency,
|
|
23391
|
+
condition: input.condition,
|
|
23392
|
+
execution: input.execution,
|
|
23393
|
+
suggestedTools: input.suggestedTools,
|
|
23394
|
+
validation: input.validation,
|
|
23395
|
+
expectedOutput: input.expectedOutput,
|
|
23396
|
+
attempts: 0,
|
|
23397
|
+
maxAttempts: input.maxAttempts ?? 3,
|
|
23398
|
+
createdAt: now,
|
|
23399
|
+
lastUpdatedAt: now,
|
|
23400
|
+
metadata: input.metadata
|
|
23401
|
+
};
|
|
23402
|
+
}
|
|
23403
|
+
function createPlan(input) {
|
|
23404
|
+
const now = Date.now();
|
|
23405
|
+
const id = `plan-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
23406
|
+
const tasks = input.tasks.map((taskInput) => createTask(taskInput));
|
|
23407
|
+
const nameToId = /* @__PURE__ */ new Map();
|
|
23408
|
+
for (const task of tasks) {
|
|
23409
|
+
nameToId.set(task.name, task.id);
|
|
23410
|
+
}
|
|
23411
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
23412
|
+
const taskInput = input.tasks[i];
|
|
23413
|
+
const task = tasks[i];
|
|
23414
|
+
if (taskInput.dependsOn && taskInput.dependsOn.length > 0) {
|
|
23415
|
+
task.dependsOn = taskInput.dependsOn.map((dep) => {
|
|
23416
|
+
if (dep.startsWith("task-")) {
|
|
23417
|
+
return dep;
|
|
23418
|
+
}
|
|
23419
|
+
const resolvedId = nameToId.get(dep);
|
|
23420
|
+
if (!resolvedId) {
|
|
23421
|
+
throw new Error(`Task dependency "${dep}" not found in plan`);
|
|
23422
|
+
}
|
|
23423
|
+
return resolvedId;
|
|
23424
|
+
});
|
|
23425
|
+
}
|
|
23426
|
+
}
|
|
23427
|
+
if (!input.skipCycleCheck) {
|
|
23428
|
+
const cycle = detectDependencyCycle(tasks);
|
|
23429
|
+
if (cycle) {
|
|
23430
|
+
const cycleNames = cycle.map((taskId) => {
|
|
23431
|
+
const task = tasks.find((t) => t.id === taskId);
|
|
23432
|
+
return task ? task.name : taskId;
|
|
23433
|
+
});
|
|
23434
|
+
throw new DependencyCycleError(cycleNames, id);
|
|
23435
|
+
}
|
|
23436
|
+
}
|
|
23437
|
+
return {
|
|
23438
|
+
id,
|
|
23439
|
+
goal: input.goal,
|
|
23440
|
+
context: input.context,
|
|
23441
|
+
tasks,
|
|
23442
|
+
concurrency: input.concurrency,
|
|
23443
|
+
allowDynamicTasks: input.allowDynamicTasks ?? true,
|
|
23444
|
+
status: "pending",
|
|
23445
|
+
createdAt: now,
|
|
23446
|
+
lastUpdatedAt: now,
|
|
23447
|
+
metadata: input.metadata
|
|
23448
|
+
};
|
|
23449
|
+
}
|
|
23450
|
+
function canTaskExecute(task, allTasks) {
|
|
23451
|
+
if (task.status !== "pending") {
|
|
23452
|
+
return false;
|
|
23453
|
+
}
|
|
23454
|
+
if (task.dependsOn.length > 0) {
|
|
23455
|
+
for (const depId of task.dependsOn) {
|
|
23456
|
+
const depTask = allTasks.find((t) => t.id === depId);
|
|
23457
|
+
if (!depTask || depTask.status !== "completed") {
|
|
23458
|
+
return false;
|
|
23459
|
+
}
|
|
23460
|
+
}
|
|
23461
|
+
}
|
|
23462
|
+
return true;
|
|
23463
|
+
}
|
|
23464
|
+
function getNextExecutableTasks(plan) {
|
|
23465
|
+
const executable = plan.tasks.filter((task) => canTaskExecute(task, plan.tasks));
|
|
23466
|
+
if (executable.length === 0) {
|
|
23467
|
+
return [];
|
|
23468
|
+
}
|
|
23469
|
+
if (!plan.concurrency) {
|
|
23470
|
+
return [executable[0]];
|
|
23471
|
+
}
|
|
23472
|
+
const runningCount = plan.tasks.filter((t) => t.status === "in_progress").length;
|
|
23473
|
+
const availableSlots = plan.concurrency.maxParallelTasks - runningCount;
|
|
23474
|
+
if (availableSlots <= 0) {
|
|
23475
|
+
return [];
|
|
23476
|
+
}
|
|
23477
|
+
const parallelTasks = executable.filter((task) => task.execution?.parallel === true);
|
|
23478
|
+
if (parallelTasks.length === 0) {
|
|
23479
|
+
return [executable[0]];
|
|
23480
|
+
}
|
|
23481
|
+
let sortedTasks = [...parallelTasks];
|
|
23482
|
+
if (plan.concurrency.strategy === "priority") {
|
|
23483
|
+
sortedTasks.sort((a, b) => (b.execution?.priority ?? 0) - (a.execution?.priority ?? 0));
|
|
23484
|
+
}
|
|
23485
|
+
return sortedTasks.slice(0, availableSlots);
|
|
23486
|
+
}
|
|
23487
|
+
async function evaluateCondition(condition, memory) {
|
|
23488
|
+
const value = await memory.get(condition.memoryKey);
|
|
23489
|
+
switch (condition.operator) {
|
|
23490
|
+
case "exists":
|
|
23491
|
+
return value !== void 0;
|
|
23492
|
+
case "not_exists":
|
|
23493
|
+
return value === void 0;
|
|
23494
|
+
case "equals":
|
|
23495
|
+
return value === condition.value;
|
|
23496
|
+
case "contains":
|
|
23497
|
+
if (Array.isArray(value)) {
|
|
23498
|
+
return value.includes(condition.value);
|
|
23499
|
+
}
|
|
23500
|
+
if (typeof value === "string" && typeof condition.value === "string") {
|
|
23501
|
+
return value.includes(condition.value);
|
|
23502
|
+
}
|
|
23503
|
+
return false;
|
|
23504
|
+
case "truthy":
|
|
23505
|
+
return !!value;
|
|
23506
|
+
case "greater_than":
|
|
23507
|
+
if (typeof value === "number" && typeof condition.value === "number") {
|
|
23508
|
+
return value > condition.value;
|
|
23509
|
+
}
|
|
23510
|
+
return false;
|
|
23511
|
+
case "less_than":
|
|
23512
|
+
if (typeof value === "number" && typeof condition.value === "number") {
|
|
23513
|
+
return value < condition.value;
|
|
23514
|
+
}
|
|
23515
|
+
return false;
|
|
23516
|
+
default:
|
|
23517
|
+
return false;
|
|
23518
|
+
}
|
|
23519
|
+
}
|
|
23520
|
+
function updateTaskStatus(task, status) {
|
|
23521
|
+
const now = Date.now();
|
|
23522
|
+
const updated = {
|
|
23523
|
+
...task,
|
|
23524
|
+
status,
|
|
23525
|
+
lastUpdatedAt: now
|
|
23526
|
+
};
|
|
23527
|
+
if (status === "in_progress") {
|
|
23528
|
+
if (!updated.startedAt) {
|
|
23529
|
+
updated.startedAt = now;
|
|
23530
|
+
}
|
|
23531
|
+
updated.attempts += 1;
|
|
23532
|
+
}
|
|
23533
|
+
if ((status === "completed" || status === "failed") && !updated.completedAt) {
|
|
23534
|
+
updated.completedAt = now;
|
|
23535
|
+
}
|
|
23536
|
+
return updated;
|
|
23537
|
+
}
|
|
23538
|
+
function isTaskBlocked(task, allTasks) {
|
|
23539
|
+
if (task.dependsOn.length === 0) {
|
|
23540
|
+
return false;
|
|
23541
|
+
}
|
|
23542
|
+
for (const depId of task.dependsOn) {
|
|
23543
|
+
const depTask = allTasks.find((t) => t.id === depId);
|
|
23544
|
+
if (!depTask) {
|
|
23545
|
+
return true;
|
|
23546
|
+
}
|
|
23547
|
+
if (depTask.status !== "completed") {
|
|
23548
|
+
return true;
|
|
23549
|
+
}
|
|
23550
|
+
}
|
|
23551
|
+
return false;
|
|
23552
|
+
}
|
|
23553
|
+
function getTaskDependencies(task, allTasks) {
|
|
23554
|
+
if (task.dependsOn.length === 0) {
|
|
23555
|
+
return [];
|
|
23556
|
+
}
|
|
23557
|
+
return task.dependsOn.map((depId) => allTasks.find((t) => t.id === depId)).filter((t) => t !== void 0);
|
|
23558
|
+
}
|
|
23559
|
+
function resolveDependencies(taskInputs, tasks) {
|
|
23560
|
+
const nameToId = /* @__PURE__ */ new Map();
|
|
23561
|
+
for (const task of tasks) {
|
|
23562
|
+
nameToId.set(task.name, task.id);
|
|
23563
|
+
}
|
|
23564
|
+
for (const input of taskInputs) {
|
|
23565
|
+
if (input.dependsOn && input.dependsOn.length > 0) {
|
|
23566
|
+
input.dependsOn = input.dependsOn.map((dep) => {
|
|
23567
|
+
if (dep.startsWith("task-")) {
|
|
23568
|
+
return dep;
|
|
23569
|
+
}
|
|
23570
|
+
const resolvedId = nameToId.get(dep);
|
|
23571
|
+
if (!resolvedId) {
|
|
23572
|
+
throw new Error(`Task dependency "${dep}" not found`);
|
|
23573
|
+
}
|
|
23574
|
+
return resolvedId;
|
|
23575
|
+
});
|
|
23576
|
+
}
|
|
23577
|
+
}
|
|
23578
|
+
}
|
|
23579
|
+
function detectDependencyCycle(tasks) {
|
|
23580
|
+
const visited = /* @__PURE__ */ new Set();
|
|
23581
|
+
const recStack = /* @__PURE__ */ new Set();
|
|
23582
|
+
const taskMap = new Map(tasks.map((t) => [t.id, t]));
|
|
23583
|
+
function dfs(taskId, path6) {
|
|
23584
|
+
if (recStack.has(taskId)) {
|
|
23585
|
+
const cycleStart = path6.indexOf(taskId);
|
|
23586
|
+
return [...path6.slice(cycleStart), taskId];
|
|
23587
|
+
}
|
|
23588
|
+
if (visited.has(taskId)) {
|
|
23589
|
+
return null;
|
|
23590
|
+
}
|
|
23591
|
+
visited.add(taskId);
|
|
23592
|
+
recStack.add(taskId);
|
|
23593
|
+
const task = taskMap.get(taskId);
|
|
23594
|
+
if (task) {
|
|
23595
|
+
for (const depId of task.dependsOn) {
|
|
23596
|
+
const cycle = dfs(depId, [...path6, taskId]);
|
|
23597
|
+
if (cycle) {
|
|
23598
|
+
return cycle;
|
|
23599
|
+
}
|
|
23600
|
+
}
|
|
23601
|
+
}
|
|
23602
|
+
recStack.delete(taskId);
|
|
23603
|
+
return null;
|
|
23604
|
+
}
|
|
23605
|
+
for (const task of tasks) {
|
|
23606
|
+
if (!visited.has(task.id)) {
|
|
23607
|
+
const cycle = dfs(task.id, []);
|
|
23608
|
+
if (cycle) {
|
|
23609
|
+
return cycle;
|
|
23610
|
+
}
|
|
23611
|
+
}
|
|
23612
|
+
}
|
|
23613
|
+
return null;
|
|
23614
|
+
}
|
|
23615
|
+
|
|
23616
|
+
// src/domain/entities/Routine.ts
|
|
23617
|
+
function createRoutineDefinition(input) {
|
|
23618
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
23619
|
+
const id = input.id ?? `routine-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
23620
|
+
const taskNames = new Set(input.tasks.map((t) => t.name));
|
|
23621
|
+
const taskIds = new Set(input.tasks.filter((t) => t.id).map((t) => t.id));
|
|
23622
|
+
for (const task of input.tasks) {
|
|
23623
|
+
if (task.dependsOn) {
|
|
23624
|
+
for (const dep of task.dependsOn) {
|
|
23625
|
+
if (!taskNames.has(dep) && !taskIds.has(dep)) {
|
|
23626
|
+
throw new Error(
|
|
23627
|
+
`Routine "${input.name}": task "${task.name}" depends on unknown task "${dep}"`
|
|
23628
|
+
);
|
|
23629
|
+
}
|
|
23630
|
+
}
|
|
23631
|
+
}
|
|
23632
|
+
}
|
|
23633
|
+
createPlan({
|
|
23634
|
+
goal: input.name,
|
|
23635
|
+
tasks: input.tasks
|
|
23636
|
+
});
|
|
23637
|
+
return {
|
|
23638
|
+
id,
|
|
23639
|
+
name: input.name,
|
|
23640
|
+
description: input.description,
|
|
23641
|
+
version: input.version,
|
|
23642
|
+
tasks: input.tasks,
|
|
23643
|
+
requiredTools: input.requiredTools,
|
|
23644
|
+
requiredPlugins: input.requiredPlugins,
|
|
23645
|
+
instructions: input.instructions,
|
|
23646
|
+
concurrency: input.concurrency,
|
|
23647
|
+
allowDynamicTasks: input.allowDynamicTasks ?? false,
|
|
23648
|
+
tags: input.tags,
|
|
23649
|
+
author: input.author,
|
|
23650
|
+
createdAt: now,
|
|
23651
|
+
updatedAt: now,
|
|
23652
|
+
metadata: input.metadata
|
|
23653
|
+
};
|
|
23654
|
+
}
|
|
23655
|
+
function createRoutineExecution(definition) {
|
|
23656
|
+
const now = Date.now();
|
|
23657
|
+
const executionId = `rexec-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
23658
|
+
const plan = createPlan({
|
|
23659
|
+
goal: definition.name,
|
|
23660
|
+
context: definition.description,
|
|
23661
|
+
tasks: definition.tasks,
|
|
23662
|
+
concurrency: definition.concurrency,
|
|
23663
|
+
allowDynamicTasks: definition.allowDynamicTasks
|
|
23664
|
+
});
|
|
23665
|
+
return {
|
|
23666
|
+
id: executionId,
|
|
23667
|
+
routineId: definition.id,
|
|
23668
|
+
plan,
|
|
23669
|
+
status: "pending",
|
|
23670
|
+
progress: 0,
|
|
23671
|
+
lastUpdatedAt: now
|
|
23672
|
+
};
|
|
23673
|
+
}
|
|
23674
|
+
function getRoutineProgress(execution) {
|
|
23675
|
+
const { tasks } = execution.plan;
|
|
23676
|
+
if (tasks.length === 0) return 100;
|
|
23677
|
+
const completed = tasks.filter((t) => isTerminalStatus(t.status)).length;
|
|
23678
|
+
return Math.round(completed / tasks.length * 100);
|
|
23679
|
+
}
|
|
23680
|
+
|
|
23681
|
+
// src/utils/jsonExtractor.ts
|
|
23682
|
+
function extractJSON(text) {
|
|
23683
|
+
if (!text || typeof text !== "string") {
|
|
23684
|
+
return {
|
|
23685
|
+
success: false,
|
|
23686
|
+
error: "Input is empty or not a string"
|
|
23687
|
+
};
|
|
23688
|
+
}
|
|
23689
|
+
const trimmedText = text.trim();
|
|
23690
|
+
const codeBlockResult = extractFromCodeBlock(trimmedText);
|
|
23691
|
+
if (codeBlockResult.success) {
|
|
23692
|
+
return codeBlockResult;
|
|
23693
|
+
}
|
|
23694
|
+
const inlineResult = extractInlineJSON(trimmedText);
|
|
23695
|
+
if (inlineResult.success) {
|
|
23696
|
+
return inlineResult;
|
|
23697
|
+
}
|
|
23698
|
+
try {
|
|
23699
|
+
const data = JSON.parse(trimmedText);
|
|
23700
|
+
return {
|
|
23701
|
+
success: true,
|
|
23702
|
+
data,
|
|
23703
|
+
rawJson: trimmedText,
|
|
23704
|
+
method: "raw"
|
|
23705
|
+
};
|
|
23706
|
+
} catch (e) {
|
|
23707
|
+
return {
|
|
23708
|
+
success: false,
|
|
23709
|
+
error: `Could not extract JSON from text: ${e instanceof Error ? e.message : String(e)}`
|
|
23710
|
+
};
|
|
23711
|
+
}
|
|
23712
|
+
}
|
|
23713
|
+
function extractFromCodeBlock(text) {
|
|
23714
|
+
const codeBlockRegex = /```(?:json)?\s*([\s\S]*?)```/g;
|
|
23715
|
+
let match;
|
|
23716
|
+
while ((match = codeBlockRegex.exec(text)) !== null) {
|
|
23717
|
+
const content = match[1];
|
|
23718
|
+
if (content) {
|
|
23719
|
+
const trimmed = content.trim();
|
|
23720
|
+
try {
|
|
23721
|
+
const data = JSON.parse(trimmed);
|
|
23722
|
+
return {
|
|
23723
|
+
success: true,
|
|
23724
|
+
data,
|
|
23725
|
+
rawJson: trimmed,
|
|
23726
|
+
method: "code_block"
|
|
23727
|
+
};
|
|
23728
|
+
} catch {
|
|
23729
|
+
continue;
|
|
23730
|
+
}
|
|
23731
|
+
}
|
|
23732
|
+
}
|
|
23733
|
+
return { success: false };
|
|
23734
|
+
}
|
|
23735
|
+
function extractInlineJSON(text) {
|
|
23736
|
+
const objectMatch = findJSONObject(text);
|
|
23737
|
+
if (objectMatch) {
|
|
23738
|
+
try {
|
|
23739
|
+
const data = JSON.parse(objectMatch);
|
|
23740
|
+
return {
|
|
23741
|
+
success: true,
|
|
23742
|
+
data,
|
|
23743
|
+
rawJson: objectMatch,
|
|
23744
|
+
method: "inline"
|
|
23745
|
+
};
|
|
23746
|
+
} catch {
|
|
23747
|
+
}
|
|
23748
|
+
}
|
|
23749
|
+
const arrayMatch = findJSONArray(text);
|
|
23750
|
+
if (arrayMatch) {
|
|
23751
|
+
try {
|
|
23752
|
+
const data = JSON.parse(arrayMatch);
|
|
23753
|
+
return {
|
|
23754
|
+
success: true,
|
|
23755
|
+
data,
|
|
23756
|
+
rawJson: arrayMatch,
|
|
23757
|
+
method: "inline"
|
|
23758
|
+
};
|
|
23759
|
+
} catch {
|
|
23760
|
+
}
|
|
23761
|
+
}
|
|
23762
|
+
return { success: false };
|
|
23763
|
+
}
|
|
23764
|
+
function findJSONObject(text) {
|
|
23765
|
+
const startIndex = text.indexOf("{");
|
|
23766
|
+
if (startIndex === -1) return null;
|
|
23767
|
+
let depth = 0;
|
|
23768
|
+
let inString = false;
|
|
23769
|
+
let escaped = false;
|
|
23770
|
+
for (let i = startIndex; i < text.length; i++) {
|
|
23771
|
+
const char = text[i];
|
|
23772
|
+
if (escaped) {
|
|
23773
|
+
escaped = false;
|
|
23774
|
+
continue;
|
|
23775
|
+
}
|
|
23776
|
+
if (char === "\\" && inString) {
|
|
23777
|
+
escaped = true;
|
|
23778
|
+
continue;
|
|
23779
|
+
}
|
|
23780
|
+
if (char === '"') {
|
|
23781
|
+
inString = !inString;
|
|
23782
|
+
continue;
|
|
23783
|
+
}
|
|
23784
|
+
if (inString) continue;
|
|
23785
|
+
if (char === "{") {
|
|
23786
|
+
depth++;
|
|
23787
|
+
} else if (char === "}") {
|
|
23788
|
+
depth--;
|
|
23789
|
+
if (depth === 0) {
|
|
23790
|
+
return text.slice(startIndex, i + 1);
|
|
23791
|
+
}
|
|
23792
|
+
}
|
|
23793
|
+
}
|
|
23794
|
+
return null;
|
|
23795
|
+
}
|
|
23796
|
+
function findJSONArray(text) {
|
|
23797
|
+
const startIndex = text.indexOf("[");
|
|
23798
|
+
if (startIndex === -1) return null;
|
|
23799
|
+
let depth = 0;
|
|
23800
|
+
let inString = false;
|
|
23801
|
+
let escaped = false;
|
|
23802
|
+
for (let i = startIndex; i < text.length; i++) {
|
|
23803
|
+
const char = text[i];
|
|
23804
|
+
if (escaped) {
|
|
23805
|
+
escaped = false;
|
|
23806
|
+
continue;
|
|
23807
|
+
}
|
|
23808
|
+
if (char === "\\" && inString) {
|
|
23809
|
+
escaped = true;
|
|
23810
|
+
continue;
|
|
23811
|
+
}
|
|
23812
|
+
if (char === '"') {
|
|
23813
|
+
inString = !inString;
|
|
23814
|
+
continue;
|
|
23815
|
+
}
|
|
23816
|
+
if (inString) continue;
|
|
23817
|
+
if (char === "[") {
|
|
23818
|
+
depth++;
|
|
23819
|
+
} else if (char === "]") {
|
|
23820
|
+
depth--;
|
|
23821
|
+
if (depth === 0) {
|
|
23822
|
+
return text.slice(startIndex, i + 1);
|
|
23823
|
+
}
|
|
23824
|
+
}
|
|
23825
|
+
}
|
|
23826
|
+
return null;
|
|
23827
|
+
}
|
|
23828
|
+
function extractJSONField(text, field, defaultValue) {
|
|
23829
|
+
const result = extractJSON(text);
|
|
23830
|
+
if (result.success && result.data && field in result.data) {
|
|
23831
|
+
return result.data[field];
|
|
23832
|
+
}
|
|
23833
|
+
return defaultValue;
|
|
23834
|
+
}
|
|
23835
|
+
function extractNumber(text, patterns = [
|
|
23836
|
+
/(\d{1,3})%?\s*(?:complete|score|percent)/i,
|
|
23837
|
+
/(?:score|completion|rating)[:\s]+(\d{1,3})/i,
|
|
23838
|
+
/(\d{1,3})\s*(?:out of|\/)\s*100/i
|
|
23839
|
+
], defaultValue = 0) {
|
|
23840
|
+
const jsonResult = extractJSON(text);
|
|
23841
|
+
if (jsonResult.success && jsonResult.data) {
|
|
23842
|
+
const scoreFields = ["score", "completionScore", "completion_score", "rating", "percent", "value"];
|
|
23843
|
+
for (const field of scoreFields) {
|
|
23844
|
+
if (field in jsonResult.data && typeof jsonResult.data[field] === "number") {
|
|
23845
|
+
return jsonResult.data[field];
|
|
23846
|
+
}
|
|
23847
|
+
}
|
|
23848
|
+
}
|
|
23849
|
+
for (const pattern of patterns) {
|
|
23850
|
+
const match = text.match(pattern);
|
|
23851
|
+
if (match && match[1]) {
|
|
23852
|
+
const num = parseInt(match[1], 10);
|
|
23853
|
+
if (!isNaN(num)) {
|
|
23854
|
+
return num;
|
|
23855
|
+
}
|
|
23856
|
+
}
|
|
23857
|
+
}
|
|
23858
|
+
return defaultValue;
|
|
23859
|
+
}
|
|
23860
|
+
|
|
23861
|
+
// src/core/routineRunner.ts
|
|
23862
|
+
init_Logger();
|
|
23863
|
+
function defaultSystemPrompt(definition) {
|
|
23864
|
+
const parts = [];
|
|
23865
|
+
if (definition.instructions) {
|
|
23866
|
+
parts.push(definition.instructions);
|
|
23867
|
+
}
|
|
23868
|
+
parts.push(
|
|
23869
|
+
`You are executing a routine called "${definition.name}".`,
|
|
23870
|
+
"",
|
|
23871
|
+
"Between tasks, your conversation history is cleared but your memory persists.",
|
|
23872
|
+
"Use these strategies to pass information between tasks:",
|
|
23873
|
+
"- Use context_set for small key results that subsequent tasks need immediately (visible in context, no retrieval needed).",
|
|
23874
|
+
'- Use memory_store with tier="findings" for larger data that may be needed later.',
|
|
23875
|
+
"- Use memory_retrieve to access data stored by previous tasks.",
|
|
23876
|
+
"",
|
|
23877
|
+
"IMPORTANT: When you have completed the current task, you MUST stop immediately.",
|
|
23878
|
+
"Do NOT repeat work you have already done. Do NOT re-fetch data you already have.",
|
|
23879
|
+
"Store key results in memory once, then produce a final text response (no more tool calls) to signal completion."
|
|
23880
|
+
);
|
|
23881
|
+
return parts.join("\n");
|
|
23882
|
+
}
|
|
23883
|
+
function defaultTaskPrompt(task) {
|
|
23884
|
+
const parts = [];
|
|
23885
|
+
parts.push(`## Current Task: ${task.name}`, "");
|
|
23886
|
+
parts.push(task.description, "");
|
|
23887
|
+
if (task.expectedOutput) {
|
|
23888
|
+
parts.push(`**Expected output:** ${task.expectedOutput}`, "");
|
|
23889
|
+
}
|
|
23890
|
+
if (task.suggestedTools && task.suggestedTools.length > 0) {
|
|
23891
|
+
parts.push(`**Suggested tools:** ${task.suggestedTools.join(", ")}`, "");
|
|
23892
|
+
}
|
|
23893
|
+
const criteria = task.validation?.completionCriteria;
|
|
23894
|
+
if (criteria && criteria.length > 0) {
|
|
23895
|
+
parts.push("### Completion Criteria");
|
|
23896
|
+
parts.push("When you are done, ensure the following are met:");
|
|
23897
|
+
for (const c of criteria) {
|
|
23898
|
+
parts.push(`- ${c}`);
|
|
23899
|
+
}
|
|
23900
|
+
parts.push("");
|
|
23901
|
+
}
|
|
23902
|
+
if (task.dependsOn.length > 0) {
|
|
23903
|
+
parts.push("Note: Results from prerequisite tasks are available in your live context.");
|
|
23904
|
+
parts.push("Small results appear directly; larger results are in working memory \u2014 use memory_retrieve to access them.");
|
|
23905
|
+
parts.push("Review the plan overview and dependency results before starting.");
|
|
23906
|
+
parts.push("");
|
|
23907
|
+
}
|
|
23908
|
+
parts.push("After completing the work, store key results in memory once, then respond with a text summary (no more tool calls).");
|
|
23909
|
+
return parts.join("\n");
|
|
23910
|
+
}
|
|
23911
|
+
function defaultValidationPrompt(task, context) {
|
|
23912
|
+
const criteria = task.validation?.completionCriteria ?? [];
|
|
23913
|
+
const criteriaList = criteria.length > 0 ? criteria.map((c, i) => `${i + 1}. ${c}`).join("\n") : "The task was completed as described.";
|
|
23914
|
+
const parts = [
|
|
23915
|
+
`Evaluate if the task "${task.name}" was completed successfully.`,
|
|
23916
|
+
"",
|
|
23917
|
+
`Task description: ${task.description}`,
|
|
23918
|
+
"",
|
|
23919
|
+
"Completion criteria:",
|
|
23920
|
+
criteriaList,
|
|
23921
|
+
"",
|
|
23922
|
+
"--- EVIDENCE ---",
|
|
23923
|
+
"",
|
|
23924
|
+
"Agent response (final text output):",
|
|
23925
|
+
context.responseText || "(no text output)",
|
|
23926
|
+
"",
|
|
23927
|
+
"Tool calls made during this task:",
|
|
23928
|
+
context.toolCallLog
|
|
23929
|
+
];
|
|
23930
|
+
if (context.inContextMemory) {
|
|
23931
|
+
parts.push("", "In-context memory (current state):", context.inContextMemory);
|
|
23932
|
+
}
|
|
23933
|
+
if (context.workingMemoryIndex) {
|
|
23934
|
+
parts.push("", "Working memory index (stored data):", context.workingMemoryIndex);
|
|
23935
|
+
}
|
|
23936
|
+
parts.push(
|
|
23937
|
+
"",
|
|
23938
|
+
"--- END EVIDENCE ---",
|
|
23939
|
+
"",
|
|
23940
|
+
"Use the evidence above to verify each criterion. Check tool call results, not just the agent's claims.",
|
|
23941
|
+
"",
|
|
23942
|
+
"Return a JSON object with the following structure:",
|
|
23943
|
+
"```json",
|
|
23944
|
+
'{ "isComplete": boolean, "completionScore": number (0-100), "explanation": "..." }',
|
|
23945
|
+
"```",
|
|
23946
|
+
"",
|
|
23947
|
+
"Be strict: only mark isComplete=true if all criteria are clearly met based on the evidence."
|
|
23948
|
+
);
|
|
23949
|
+
return parts.join("\n");
|
|
23950
|
+
}
|
|
23951
|
+
function formatToolCallLog(conversation) {
|
|
23952
|
+
const calls = [];
|
|
23953
|
+
for (const item of conversation) {
|
|
23954
|
+
if (!("content" in item) || !Array.isArray(item.content)) continue;
|
|
23955
|
+
const msg = item;
|
|
23956
|
+
for (const c of msg.content) {
|
|
23957
|
+
if (c.type === "tool_use" /* TOOL_USE */) {
|
|
23958
|
+
let argsStr;
|
|
23959
|
+
try {
|
|
23960
|
+
const parsed = JSON.parse(c.arguments);
|
|
23961
|
+
argsStr = JSON.stringify(parsed, null, 2);
|
|
23962
|
+
if (argsStr.length > 500) argsStr = argsStr.slice(0, 500) + "... (truncated)";
|
|
23963
|
+
} catch {
|
|
23964
|
+
argsStr = c.arguments;
|
|
23965
|
+
}
|
|
23966
|
+
calls.push(`CALL: ${c.name}(${argsStr})`);
|
|
23967
|
+
} else if (c.type === "tool_result" /* TOOL_RESULT */) {
|
|
23968
|
+
let resultStr = typeof c.content === "string" ? c.content : JSON.stringify(c.content);
|
|
23969
|
+
if (resultStr.length > 500) resultStr = resultStr.slice(0, 500) + "... (truncated)";
|
|
23970
|
+
const prefix = c.error ? "ERROR" : "RESULT";
|
|
23971
|
+
calls.push(` ${prefix}: ${resultStr}`);
|
|
23972
|
+
}
|
|
23973
|
+
}
|
|
23974
|
+
}
|
|
23975
|
+
return calls.length > 0 ? calls.join("\n") : "(no tool calls)";
|
|
23976
|
+
}
|
|
23977
|
+
async function collectValidationContext(agent, responseText) {
|
|
23978
|
+
const icmPlugin = agent.context.getPlugin("in_context_memory");
|
|
23979
|
+
const inContextMemory = icmPlugin ? await icmPlugin.getContent() : null;
|
|
23980
|
+
const wmPlugin = agent.context.memory;
|
|
23981
|
+
const workingMemoryIndex = wmPlugin ? await wmPlugin.getContent() : null;
|
|
23982
|
+
const conversation = agent.context.getConversation();
|
|
23983
|
+
const toolCallLog = formatToolCallLog(conversation);
|
|
23984
|
+
return {
|
|
23985
|
+
responseText,
|
|
23986
|
+
inContextMemory,
|
|
23987
|
+
workingMemoryIndex,
|
|
23988
|
+
toolCallLog
|
|
23989
|
+
};
|
|
23990
|
+
}
|
|
23991
|
+
function estimateTokens(text) {
|
|
23992
|
+
return Math.ceil(text.length / 4);
|
|
23993
|
+
}
|
|
23994
|
+
function buildPlanOverview(execution, definition, currentTaskId) {
|
|
23995
|
+
const parts = [];
|
|
23996
|
+
const progress = execution.progress ?? 0;
|
|
23997
|
+
parts.push(`Routine: ${definition.name}`);
|
|
23998
|
+
if (definition.description) {
|
|
23999
|
+
parts.push(`Goal: ${definition.description}`);
|
|
24000
|
+
}
|
|
24001
|
+
parts.push(`Progress: ${Math.round(progress * 100)}%`);
|
|
24002
|
+
parts.push("");
|
|
24003
|
+
parts.push("Tasks:");
|
|
24004
|
+
for (const task of execution.plan.tasks) {
|
|
24005
|
+
let statusIcon;
|
|
24006
|
+
switch (task.status) {
|
|
24007
|
+
case "completed":
|
|
24008
|
+
statusIcon = "[x]";
|
|
24009
|
+
break;
|
|
24010
|
+
case "in_progress":
|
|
24011
|
+
statusIcon = "[>]";
|
|
24012
|
+
break;
|
|
24013
|
+
case "failed":
|
|
24014
|
+
statusIcon = "[!]";
|
|
24015
|
+
break;
|
|
24016
|
+
case "skipped":
|
|
24017
|
+
statusIcon = "[-]";
|
|
24018
|
+
break;
|
|
24019
|
+
default:
|
|
24020
|
+
statusIcon = "[ ]";
|
|
24021
|
+
}
|
|
24022
|
+
let line = `${statusIcon} ${task.name}`;
|
|
24023
|
+
if (task.dependsOn.length > 0) {
|
|
24024
|
+
const depNames = task.dependsOn.map((depId) => execution.plan.tasks.find((t) => t.id === depId)?.name ?? depId).join(", ");
|
|
24025
|
+
line += ` (after: ${depNames})`;
|
|
24026
|
+
}
|
|
24027
|
+
if (task.id === currentTaskId) {
|
|
24028
|
+
line += " \u2190 CURRENT";
|
|
24029
|
+
}
|
|
24030
|
+
parts.push(line);
|
|
24031
|
+
}
|
|
24032
|
+
return parts.join("\n");
|
|
24033
|
+
}
|
|
24034
|
+
async function injectRoutineContext(agent, execution, definition, currentTask) {
|
|
24035
|
+
const icmPlugin = agent.context.getPlugin("in_context_memory");
|
|
24036
|
+
const wmPlugin = agent.context.memory;
|
|
24037
|
+
if (!icmPlugin && !wmPlugin) {
|
|
24038
|
+
logger.warn("injectRoutineContext: No ICM or WM plugin available \u2014 skipping context injection");
|
|
24039
|
+
return;
|
|
24040
|
+
}
|
|
24041
|
+
const planOverview = buildPlanOverview(execution, definition, currentTask.id);
|
|
24042
|
+
if (icmPlugin) {
|
|
24043
|
+
icmPlugin.set("__routine_plan", "Routine plan overview with task statuses", planOverview, "high");
|
|
24044
|
+
}
|
|
24045
|
+
if (icmPlugin) {
|
|
24046
|
+
for (const entry of icmPlugin.list()) {
|
|
24047
|
+
if (entry.key.startsWith("__dep_result_") || entry.key === "__routine_deps") {
|
|
24048
|
+
icmPlugin.delete(entry.key);
|
|
24049
|
+
}
|
|
24050
|
+
}
|
|
24051
|
+
}
|
|
24052
|
+
if (wmPlugin) {
|
|
24053
|
+
const { entries: wmEntries } = await wmPlugin.query();
|
|
24054
|
+
for (const entry of wmEntries) {
|
|
24055
|
+
if (entry.key.startsWith("__dep_result_") || entry.key.startsWith("findings/__dep_result_")) {
|
|
24056
|
+
await wmPlugin.delete(entry.key);
|
|
24057
|
+
}
|
|
24058
|
+
}
|
|
24059
|
+
}
|
|
24060
|
+
if (currentTask.dependsOn.length === 0) return;
|
|
24061
|
+
const inContextDeps = [];
|
|
24062
|
+
const workingMemoryDeps = [];
|
|
24063
|
+
for (const depId of currentTask.dependsOn) {
|
|
24064
|
+
const depTask = execution.plan.tasks.find((t) => t.id === depId);
|
|
24065
|
+
if (!depTask?.result?.output) continue;
|
|
24066
|
+
const output = typeof depTask.result.output === "string" ? depTask.result.output : JSON.stringify(depTask.result.output);
|
|
24067
|
+
const tokens = estimateTokens(output);
|
|
24068
|
+
const depKey = `__dep_result_${depId}`;
|
|
24069
|
+
const depLabel = `Result from task "${depTask.name}"`;
|
|
24070
|
+
if (tokens < 5e3 && icmPlugin) {
|
|
24071
|
+
icmPlugin.set(depKey, depLabel, output, "high");
|
|
24072
|
+
inContextDeps.push(depTask.name);
|
|
24073
|
+
} else if (wmPlugin) {
|
|
24074
|
+
await wmPlugin.store(depKey, depLabel, output, { tier: "findings" });
|
|
24075
|
+
workingMemoryDeps.push(depTask.name);
|
|
24076
|
+
} else if (icmPlugin) {
|
|
24077
|
+
const truncated = output.slice(0, 2e4) + "\n... (truncated, full result not available)";
|
|
24078
|
+
icmPlugin.set(depKey, depLabel, truncated, "high");
|
|
24079
|
+
inContextDeps.push(depTask.name + " (truncated)");
|
|
24080
|
+
}
|
|
24081
|
+
}
|
|
24082
|
+
if (icmPlugin && (inContextDeps.length > 0 || workingMemoryDeps.length > 0)) {
|
|
24083
|
+
const summaryParts = ["Dependency results available:"];
|
|
24084
|
+
if (inContextDeps.length > 0) {
|
|
24085
|
+
summaryParts.push(`In context (visible now): ${inContextDeps.join(", ")}`);
|
|
24086
|
+
}
|
|
24087
|
+
if (workingMemoryDeps.length > 0) {
|
|
24088
|
+
summaryParts.push(`In working memory (use memory_retrieve): ${workingMemoryDeps.join(", ")}`);
|
|
24089
|
+
}
|
|
24090
|
+
icmPlugin.set("__routine_deps", "Dependency results location guide", summaryParts.join("\n"), "high");
|
|
24091
|
+
}
|
|
24092
|
+
}
|
|
24093
|
+
async function cleanupRoutineContext(agent) {
|
|
24094
|
+
const icmPlugin = agent.context.getPlugin("in_context_memory");
|
|
24095
|
+
const wmPlugin = agent.context.memory;
|
|
24096
|
+
if (icmPlugin) {
|
|
24097
|
+
for (const entry of icmPlugin.list()) {
|
|
24098
|
+
if (entry.key.startsWith("__routine_") || entry.key.startsWith("__dep_result_")) {
|
|
24099
|
+
icmPlugin.delete(entry.key);
|
|
24100
|
+
}
|
|
24101
|
+
}
|
|
24102
|
+
}
|
|
24103
|
+
if (wmPlugin) {
|
|
24104
|
+
const { entries: wmEntries } = await wmPlugin.query();
|
|
24105
|
+
for (const entry of wmEntries) {
|
|
24106
|
+
if (entry.key.startsWith("__dep_result_") || entry.key.startsWith("findings/__dep_result_")) {
|
|
24107
|
+
await wmPlugin.delete(entry.key);
|
|
24108
|
+
}
|
|
24109
|
+
}
|
|
24110
|
+
}
|
|
24111
|
+
}
|
|
24112
|
+
async function validateTaskCompletion(agent, task, responseText, validationPromptBuilder) {
|
|
24113
|
+
const hasExplicitValidation = task.validation?.skipReflection === false && task.validation?.completionCriteria && task.validation.completionCriteria.length > 0;
|
|
24114
|
+
if (!hasExplicitValidation) {
|
|
24115
|
+
return {
|
|
24116
|
+
isComplete: true,
|
|
24117
|
+
completionScore: 100,
|
|
24118
|
+
explanation: "Auto-passed (LLM validation not enabled)",
|
|
24119
|
+
requiresUserApproval: false
|
|
24120
|
+
};
|
|
24121
|
+
}
|
|
24122
|
+
const validationContext = await collectValidationContext(agent, responseText);
|
|
24123
|
+
const prompt = validationPromptBuilder(task, validationContext);
|
|
24124
|
+
const response = await agent.runDirect(prompt, {
|
|
24125
|
+
instructions: "You are a task completion evaluator. Return only JSON.",
|
|
24126
|
+
temperature: 0.1
|
|
24127
|
+
});
|
|
24128
|
+
const text = response.output_text ?? "";
|
|
24129
|
+
const extracted = extractJSON(text);
|
|
24130
|
+
if (!extracted.success || !extracted.data) {
|
|
24131
|
+
return {
|
|
24132
|
+
isComplete: false,
|
|
24133
|
+
completionScore: 0,
|
|
24134
|
+
explanation: `Failed to parse validation response: ${extracted.error ?? "unknown error"}`,
|
|
24135
|
+
requiresUserApproval: false
|
|
24136
|
+
};
|
|
24137
|
+
}
|
|
24138
|
+
const { isComplete, completionScore, explanation } = extracted.data;
|
|
24139
|
+
const minScore = task.validation?.minCompletionScore ?? 80;
|
|
24140
|
+
return {
|
|
24141
|
+
isComplete: isComplete && completionScore >= minScore,
|
|
24142
|
+
completionScore,
|
|
24143
|
+
explanation,
|
|
24144
|
+
requiresUserApproval: false
|
|
24145
|
+
};
|
|
24146
|
+
}
|
|
24147
|
+
async function executeRoutine(options) {
|
|
24148
|
+
const {
|
|
24149
|
+
definition,
|
|
24150
|
+
agent: existingAgent,
|
|
24151
|
+
connector,
|
|
24152
|
+
model,
|
|
24153
|
+
tools: extraTools,
|
|
24154
|
+
onTaskStarted,
|
|
24155
|
+
onTaskComplete,
|
|
24156
|
+
onTaskFailed,
|
|
24157
|
+
onTaskValidation,
|
|
24158
|
+
hooks,
|
|
24159
|
+
prompts
|
|
24160
|
+
} = options;
|
|
24161
|
+
if (!existingAgent && (!connector || !model)) {
|
|
24162
|
+
throw new Error("executeRoutine requires either `agent` or both `connector` and `model`");
|
|
24163
|
+
}
|
|
24164
|
+
const ownsAgent = !existingAgent;
|
|
24165
|
+
const log = logger.child({ routine: definition.name });
|
|
24166
|
+
const execution = createRoutineExecution(definition);
|
|
24167
|
+
execution.status = "running";
|
|
24168
|
+
execution.startedAt = Date.now();
|
|
24169
|
+
execution.lastUpdatedAt = Date.now();
|
|
24170
|
+
const buildSystemPrompt = prompts?.system ?? defaultSystemPrompt;
|
|
24171
|
+
const buildTaskPrompt = prompts?.task ?? defaultTaskPrompt;
|
|
24172
|
+
const buildValidationPrompt = prompts?.validation ?? defaultValidationPrompt;
|
|
24173
|
+
let agent;
|
|
24174
|
+
const registeredHooks = [];
|
|
24175
|
+
if (existingAgent) {
|
|
24176
|
+
agent = existingAgent;
|
|
24177
|
+
if (hooks) {
|
|
24178
|
+
const hookNames = [
|
|
24179
|
+
"before:execution",
|
|
24180
|
+
"after:execution",
|
|
24181
|
+
"before:llm",
|
|
24182
|
+
"after:llm",
|
|
24183
|
+
"before:tool",
|
|
24184
|
+
"after:tool",
|
|
24185
|
+
"approve:tool",
|
|
24186
|
+
"pause:check"
|
|
24187
|
+
];
|
|
24188
|
+
for (const name of hookNames) {
|
|
24189
|
+
const hook = hooks[name];
|
|
24190
|
+
if (hook) {
|
|
24191
|
+
agent.registerHook(name, hook);
|
|
24192
|
+
registeredHooks.push({ name, hook });
|
|
24193
|
+
}
|
|
24194
|
+
}
|
|
24195
|
+
}
|
|
24196
|
+
} else {
|
|
24197
|
+
const allTools = [...extraTools ?? []];
|
|
24198
|
+
if (definition.requiredTools && definition.requiredTools.length > 0) {
|
|
24199
|
+
const availableToolNames = new Set(allTools.map((t) => t.definition.function.name));
|
|
24200
|
+
const missing = definition.requiredTools.filter((name) => !availableToolNames.has(name));
|
|
24201
|
+
if (missing.length > 0) {
|
|
24202
|
+
execution.status = "failed";
|
|
24203
|
+
execution.error = `Missing required tools: ${missing.join(", ")}`;
|
|
24204
|
+
execution.completedAt = Date.now();
|
|
24205
|
+
execution.lastUpdatedAt = Date.now();
|
|
24206
|
+
return execution;
|
|
24207
|
+
}
|
|
24208
|
+
}
|
|
24209
|
+
agent = Agent.create({
|
|
24210
|
+
connector,
|
|
24211
|
+
model,
|
|
24212
|
+
tools: allTools,
|
|
24213
|
+
instructions: buildSystemPrompt(definition),
|
|
24214
|
+
hooks,
|
|
24215
|
+
context: {
|
|
24216
|
+
model,
|
|
24217
|
+
features: {
|
|
24218
|
+
workingMemory: true,
|
|
24219
|
+
inContextMemory: true
|
|
24220
|
+
}
|
|
24221
|
+
}
|
|
24222
|
+
});
|
|
24223
|
+
}
|
|
24224
|
+
if (definition.requiredPlugins && definition.requiredPlugins.length > 0) {
|
|
24225
|
+
const missing = definition.requiredPlugins.filter(
|
|
24226
|
+
(name) => !agent.context.hasPlugin(name)
|
|
24227
|
+
);
|
|
24228
|
+
if (missing.length > 0) {
|
|
24229
|
+
if (ownsAgent) agent.destroy();
|
|
24230
|
+
execution.status = "failed";
|
|
24231
|
+
execution.error = `Missing required plugins: ${missing.join(", ")}`;
|
|
24232
|
+
execution.completedAt = Date.now();
|
|
24233
|
+
execution.lastUpdatedAt = Date.now();
|
|
24234
|
+
return execution;
|
|
24235
|
+
}
|
|
24236
|
+
}
|
|
24237
|
+
const failureMode = definition.concurrency?.failureMode ?? "fail-fast";
|
|
24238
|
+
try {
|
|
24239
|
+
let nextTasks = getNextExecutableTasks(execution.plan);
|
|
24240
|
+
while (nextTasks.length > 0) {
|
|
24241
|
+
const task = nextTasks[0];
|
|
24242
|
+
const taskIndex = execution.plan.tasks.findIndex((t) => t.id === task.id);
|
|
24243
|
+
log.info({ taskName: task.name, taskId: task.id }, "Starting task");
|
|
24244
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(task, "in_progress");
|
|
24245
|
+
execution.lastUpdatedAt = Date.now();
|
|
24246
|
+
onTaskStarted?.(execution.plan.tasks[taskIndex], execution);
|
|
24247
|
+
let taskCompleted = false;
|
|
24248
|
+
const maxTaskIterations = task.execution?.maxIterations ?? 15;
|
|
24249
|
+
const iterationLimiter = async (ctx) => {
|
|
24250
|
+
if (ctx.iteration >= maxTaskIterations) {
|
|
24251
|
+
agent.cancel(`Task "${task.name}" exceeded max iterations (${maxTaskIterations})`);
|
|
24252
|
+
}
|
|
24253
|
+
return { shouldPause: false };
|
|
24254
|
+
};
|
|
24255
|
+
agent.registerHook("pause:check", iterationLimiter);
|
|
24256
|
+
const getTask = () => execution.plan.tasks[taskIndex];
|
|
24257
|
+
await injectRoutineContext(agent, execution, definition, getTask());
|
|
24258
|
+
while (!taskCompleted) {
|
|
24259
|
+
try {
|
|
24260
|
+
const taskPrompt = buildTaskPrompt(getTask());
|
|
24261
|
+
const response = await agent.run(taskPrompt);
|
|
24262
|
+
const responseText = response.output_text ?? "";
|
|
24263
|
+
const validationResult = await validateTaskCompletion(
|
|
24264
|
+
agent,
|
|
24265
|
+
getTask(),
|
|
24266
|
+
responseText,
|
|
24267
|
+
buildValidationPrompt
|
|
24268
|
+
);
|
|
24269
|
+
onTaskValidation?.(getTask(), validationResult, execution);
|
|
24270
|
+
if (validationResult.isComplete) {
|
|
24271
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "completed");
|
|
24272
|
+
execution.plan.tasks[taskIndex].result = {
|
|
24273
|
+
success: true,
|
|
24274
|
+
output: responseText,
|
|
24275
|
+
validationScore: validationResult.completionScore,
|
|
24276
|
+
validationExplanation: validationResult.explanation
|
|
24277
|
+
};
|
|
24278
|
+
taskCompleted = true;
|
|
24279
|
+
log.info(
|
|
24280
|
+
{ taskName: getTask().name, score: validationResult.completionScore },
|
|
24281
|
+
"Task completed"
|
|
24282
|
+
);
|
|
24283
|
+
execution.progress = getRoutineProgress(execution);
|
|
24284
|
+
execution.lastUpdatedAt = Date.now();
|
|
24285
|
+
onTaskComplete?.(execution.plan.tasks[taskIndex], execution);
|
|
24286
|
+
} else {
|
|
24287
|
+
log.warn(
|
|
24288
|
+
{
|
|
24289
|
+
taskName: getTask().name,
|
|
24290
|
+
score: validationResult.completionScore,
|
|
24291
|
+
attempt: getTask().attempts,
|
|
24292
|
+
maxAttempts: getTask().maxAttempts
|
|
24293
|
+
},
|
|
24294
|
+
"Task validation failed"
|
|
24295
|
+
);
|
|
24296
|
+
if (getTask().attempts >= getTask().maxAttempts) {
|
|
24297
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
|
|
24298
|
+
execution.plan.tasks[taskIndex].result = {
|
|
24299
|
+
success: false,
|
|
24300
|
+
error: validationResult.explanation,
|
|
24301
|
+
validationScore: validationResult.completionScore,
|
|
24302
|
+
validationExplanation: validationResult.explanation
|
|
24303
|
+
};
|
|
24304
|
+
break;
|
|
24305
|
+
}
|
|
24306
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
|
|
24307
|
+
}
|
|
24308
|
+
} catch (error) {
|
|
24309
|
+
const errorMessage = error.message;
|
|
24310
|
+
log.error({ taskName: getTask().name, error: errorMessage }, "Task execution error");
|
|
24311
|
+
if (getTask().attempts >= getTask().maxAttempts) {
|
|
24312
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
|
|
24313
|
+
execution.plan.tasks[taskIndex].result = {
|
|
24314
|
+
success: false,
|
|
24315
|
+
error: errorMessage
|
|
24316
|
+
};
|
|
24317
|
+
break;
|
|
24318
|
+
}
|
|
24319
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
|
|
24320
|
+
}
|
|
24321
|
+
}
|
|
24322
|
+
if (!taskCompleted) {
|
|
24323
|
+
execution.progress = getRoutineProgress(execution);
|
|
24324
|
+
execution.lastUpdatedAt = Date.now();
|
|
24325
|
+
onTaskFailed?.(execution.plan.tasks[taskIndex], execution);
|
|
24326
|
+
if (failureMode === "fail-fast") {
|
|
24327
|
+
execution.status = "failed";
|
|
24328
|
+
execution.error = `Task "${getTask().name}" failed after ${getTask().attempts} attempt(s)`;
|
|
24329
|
+
execution.completedAt = Date.now();
|
|
24330
|
+
execution.lastUpdatedAt = Date.now();
|
|
24331
|
+
break;
|
|
24332
|
+
}
|
|
24333
|
+
}
|
|
24334
|
+
agent.unregisterHook("pause:check", iterationLimiter);
|
|
24335
|
+
agent.clearConversation("task-boundary");
|
|
24336
|
+
nextTasks = getNextExecutableTasks(execution.plan);
|
|
24337
|
+
}
|
|
24338
|
+
if (execution.status === "running") {
|
|
24339
|
+
const allTerminal = execution.plan.tasks.every((t) => isTerminalStatus(t.status));
|
|
24340
|
+
const allCompleted = execution.plan.tasks.every((t) => t.status === "completed");
|
|
24341
|
+
if (allCompleted) {
|
|
24342
|
+
execution.status = "completed";
|
|
24343
|
+
} else if (allTerminal) {
|
|
24344
|
+
execution.status = "failed";
|
|
24345
|
+
execution.error = "Not all tasks completed successfully";
|
|
24346
|
+
} else {
|
|
24347
|
+
execution.status = "failed";
|
|
24348
|
+
execution.error = "Execution stalled: remaining tasks are blocked by incomplete dependencies";
|
|
24349
|
+
}
|
|
24350
|
+
execution.completedAt = Date.now();
|
|
24351
|
+
execution.lastUpdatedAt = Date.now();
|
|
24352
|
+
execution.progress = getRoutineProgress(execution);
|
|
24353
|
+
}
|
|
24354
|
+
log.info(
|
|
24355
|
+
{ status: execution.status, progress: execution.progress },
|
|
24356
|
+
"Routine execution finished"
|
|
24357
|
+
);
|
|
24358
|
+
return execution;
|
|
24359
|
+
} finally {
|
|
24360
|
+
try {
|
|
24361
|
+
await cleanupRoutineContext(agent);
|
|
24362
|
+
} catch {
|
|
24363
|
+
}
|
|
24364
|
+
for (const { name, hook } of registeredHooks) {
|
|
24365
|
+
try {
|
|
24366
|
+
agent.unregisterHook(name, hook);
|
|
24367
|
+
} catch {
|
|
24368
|
+
}
|
|
24369
|
+
}
|
|
24370
|
+
if (ownsAgent) {
|
|
24371
|
+
agent.destroy();
|
|
24372
|
+
}
|
|
24373
|
+
}
|
|
24374
|
+
}
|
|
24375
|
+
|
|
23337
24376
|
// src/core/index.ts
|
|
23338
24377
|
init_constants();
|
|
23339
24378
|
(class {
|
|
@@ -23371,8 +24410,8 @@ init_constants();
|
|
|
23371
24410
|
throw new Error("Configuration file not found. Searched: " + this.DEFAULT_PATHS.join(", "));
|
|
23372
24411
|
}
|
|
23373
24412
|
try {
|
|
23374
|
-
const
|
|
23375
|
-
const content =
|
|
24413
|
+
const fs20 = __require("fs");
|
|
24414
|
+
const content = fs20.readFileSync(configPath, "utf-8");
|
|
23376
24415
|
let config = JSON.parse(content);
|
|
23377
24416
|
config = this.interpolateEnvVars(config);
|
|
23378
24417
|
this.validate(config);
|
|
@@ -23401,10 +24440,10 @@ init_constants();
|
|
|
23401
24440
|
* Find configuration file synchronously
|
|
23402
24441
|
*/
|
|
23403
24442
|
static findConfigSync() {
|
|
23404
|
-
const
|
|
24443
|
+
const fs20 = __require("fs");
|
|
23405
24444
|
for (const path6 of this.DEFAULT_PATHS) {
|
|
23406
24445
|
try {
|
|
23407
|
-
|
|
24446
|
+
fs20.accessSync(resolve(path6));
|
|
23408
24447
|
return resolve(path6);
|
|
23409
24448
|
} catch {
|
|
23410
24449
|
}
|
|
@@ -29583,7 +30622,7 @@ var OpenAISTTProvider = class extends BaseMediaProvider {
|
|
|
29583
30622
|
if (Buffer.isBuffer(audio)) {
|
|
29584
30623
|
return new File([new Uint8Array(audio)], "audio.wav", { type: "audio/wav" });
|
|
29585
30624
|
} else if (typeof audio === "string") {
|
|
29586
|
-
return
|
|
30625
|
+
return fs19.createReadStream(audio);
|
|
29587
30626
|
} else {
|
|
29588
30627
|
throw new Error("Invalid audio input: must be Buffer or file path");
|
|
29589
30628
|
}
|
|
@@ -30136,7 +31175,7 @@ var TextToSpeech = class _TextToSpeech {
|
|
|
30136
31175
|
*/
|
|
30137
31176
|
async toFile(text, filePath, options) {
|
|
30138
31177
|
const response = await this.synthesize(text, options);
|
|
30139
|
-
await
|
|
31178
|
+
await fs18.writeFile(filePath, response.audio);
|
|
30140
31179
|
}
|
|
30141
31180
|
// ======================== Introspection Methods ========================
|
|
30142
31181
|
/**
|
|
@@ -30484,7 +31523,7 @@ var SpeechToText = class _SpeechToText {
|
|
|
30484
31523
|
* @param options - Optional transcription parameters
|
|
30485
31524
|
*/
|
|
30486
31525
|
async transcribeFile(filePath, options) {
|
|
30487
|
-
const audio = await
|
|
31526
|
+
const audio = await fs18.readFile(filePath);
|
|
30488
31527
|
return this.transcribe(audio, options);
|
|
30489
31528
|
}
|
|
30490
31529
|
/**
|
|
@@ -30810,7 +31849,7 @@ var OpenAIImageProvider = class extends BaseMediaProvider {
|
|
|
30810
31849
|
if (Buffer.isBuffer(image)) {
|
|
30811
31850
|
return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
|
|
30812
31851
|
}
|
|
30813
|
-
return
|
|
31852
|
+
return fs19.createReadStream(image);
|
|
30814
31853
|
}
|
|
30815
31854
|
/**
|
|
30816
31855
|
* Handle OpenAI API errors
|
|
@@ -30957,8 +31996,8 @@ var GoogleImageProvider = class extends BaseMediaProvider {
|
|
|
30957
31996
|
if (Buffer.isBuffer(image)) {
|
|
30958
31997
|
imageBytes = image.toString("base64");
|
|
30959
31998
|
} else {
|
|
30960
|
-
const
|
|
30961
|
-
const buffer =
|
|
31999
|
+
const fs20 = await import('fs');
|
|
32000
|
+
const buffer = fs20.readFileSync(image);
|
|
30962
32001
|
imageBytes = buffer.toString("base64");
|
|
30963
32002
|
}
|
|
30964
32003
|
return {
|
|
@@ -31119,7 +32158,7 @@ var GrokImageProvider = class extends BaseMediaProvider {
|
|
|
31119
32158
|
if (Buffer.isBuffer(image)) {
|
|
31120
32159
|
return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
|
|
31121
32160
|
}
|
|
31122
|
-
return
|
|
32161
|
+
return fs19.createReadStream(image);
|
|
31123
32162
|
}
|
|
31124
32163
|
/**
|
|
31125
32164
|
* Handle API errors
|
|
@@ -32569,8 +33608,8 @@ var OpenAISoraProvider = class extends BaseMediaProvider {
|
|
|
32569
33608
|
return new File([new Uint8Array(image)], "input.png", { type: "image/png" });
|
|
32570
33609
|
}
|
|
32571
33610
|
if (!image.startsWith("http")) {
|
|
32572
|
-
const
|
|
32573
|
-
const data =
|
|
33611
|
+
const fs20 = await import('fs');
|
|
33612
|
+
const data = fs20.readFileSync(image);
|
|
32574
33613
|
return new File([new Uint8Array(data)], "input.png", { type: "image/png" });
|
|
32575
33614
|
}
|
|
32576
33615
|
const response = await fetch(image);
|
|
@@ -32748,7 +33787,7 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
|
|
|
32748
33787
|
if (video.videoBytes) {
|
|
32749
33788
|
buffer = Buffer.from(video.videoBytes, "base64");
|
|
32750
33789
|
} else if (video.uri) {
|
|
32751
|
-
const
|
|
33790
|
+
const fs20 = await import('fs/promises');
|
|
32752
33791
|
const os3 = await import('os');
|
|
32753
33792
|
const path6 = await import('path');
|
|
32754
33793
|
const tempDir = os3.tmpdir();
|
|
@@ -32759,11 +33798,11 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
|
|
|
32759
33798
|
// Pass as GeneratedVideo
|
|
32760
33799
|
downloadPath: tempFile
|
|
32761
33800
|
});
|
|
32762
|
-
buffer = await
|
|
32763
|
-
await
|
|
33801
|
+
buffer = await fs20.readFile(tempFile);
|
|
33802
|
+
await fs20.unlink(tempFile).catch(() => {
|
|
32764
33803
|
});
|
|
32765
33804
|
} catch (downloadError) {
|
|
32766
|
-
await
|
|
33805
|
+
await fs20.unlink(tempFile).catch(() => {
|
|
32767
33806
|
});
|
|
32768
33807
|
throw new ProviderError(
|
|
32769
33808
|
"google",
|
|
@@ -32885,8 +33924,8 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
|
|
|
32885
33924
|
if (image.startsWith("http://") || image.startsWith("https://")) {
|
|
32886
33925
|
return { imageUri: image };
|
|
32887
33926
|
}
|
|
32888
|
-
const
|
|
32889
|
-
const data = await
|
|
33927
|
+
const fs20 = await import('fs/promises');
|
|
33928
|
+
const data = await fs20.readFile(image);
|
|
32890
33929
|
return {
|
|
32891
33930
|
imageBytes: data.toString("base64")
|
|
32892
33931
|
};
|
|
@@ -33193,8 +34232,8 @@ var GrokImagineProvider = class extends BaseMediaProvider {
|
|
|
33193
34232
|
if (image.startsWith("http") || image.startsWith("data:")) {
|
|
33194
34233
|
return image;
|
|
33195
34234
|
}
|
|
33196
|
-
const
|
|
33197
|
-
const data =
|
|
34235
|
+
const fs20 = await import('fs');
|
|
34236
|
+
const data = fs20.readFileSync(image);
|
|
33198
34237
|
const base64 = data.toString("base64");
|
|
33199
34238
|
const ext = image.split(".").pop()?.toLowerCase() || "png";
|
|
33200
34239
|
const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext}`;
|
|
@@ -35863,245 +36902,6 @@ var CheckpointManager = class {
|
|
|
35863
36902
|
}
|
|
35864
36903
|
};
|
|
35865
36904
|
|
|
35866
|
-
// src/domain/entities/Task.ts
|
|
35867
|
-
var TERMINAL_TASK_STATUSES = ["completed", "failed", "skipped", "cancelled"];
|
|
35868
|
-
function isTerminalStatus(status) {
|
|
35869
|
-
return TERMINAL_TASK_STATUSES.includes(status);
|
|
35870
|
-
}
|
|
35871
|
-
function createTask(input) {
|
|
35872
|
-
const now = Date.now();
|
|
35873
|
-
const id = input.id ?? `task-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
35874
|
-
return {
|
|
35875
|
-
id,
|
|
35876
|
-
name: input.name,
|
|
35877
|
-
description: input.description,
|
|
35878
|
-
status: "pending",
|
|
35879
|
-
dependsOn: input.dependsOn ?? [],
|
|
35880
|
-
externalDependency: input.externalDependency,
|
|
35881
|
-
condition: input.condition,
|
|
35882
|
-
execution: input.execution,
|
|
35883
|
-
validation: input.validation,
|
|
35884
|
-
expectedOutput: input.expectedOutput,
|
|
35885
|
-
attempts: 0,
|
|
35886
|
-
maxAttempts: input.maxAttempts ?? 3,
|
|
35887
|
-
createdAt: now,
|
|
35888
|
-
lastUpdatedAt: now,
|
|
35889
|
-
metadata: input.metadata
|
|
35890
|
-
};
|
|
35891
|
-
}
|
|
35892
|
-
function createPlan(input) {
|
|
35893
|
-
const now = Date.now();
|
|
35894
|
-
const id = `plan-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
35895
|
-
const tasks = input.tasks.map((taskInput) => createTask(taskInput));
|
|
35896
|
-
const nameToId = /* @__PURE__ */ new Map();
|
|
35897
|
-
for (const task of tasks) {
|
|
35898
|
-
nameToId.set(task.name, task.id);
|
|
35899
|
-
}
|
|
35900
|
-
for (let i = 0; i < tasks.length; i++) {
|
|
35901
|
-
const taskInput = input.tasks[i];
|
|
35902
|
-
const task = tasks[i];
|
|
35903
|
-
if (taskInput.dependsOn && taskInput.dependsOn.length > 0) {
|
|
35904
|
-
task.dependsOn = taskInput.dependsOn.map((dep) => {
|
|
35905
|
-
if (dep.startsWith("task-")) {
|
|
35906
|
-
return dep;
|
|
35907
|
-
}
|
|
35908
|
-
const resolvedId = nameToId.get(dep);
|
|
35909
|
-
if (!resolvedId) {
|
|
35910
|
-
throw new Error(`Task dependency "${dep}" not found in plan`);
|
|
35911
|
-
}
|
|
35912
|
-
return resolvedId;
|
|
35913
|
-
});
|
|
35914
|
-
}
|
|
35915
|
-
}
|
|
35916
|
-
if (!input.skipCycleCheck) {
|
|
35917
|
-
const cycle = detectDependencyCycle(tasks);
|
|
35918
|
-
if (cycle) {
|
|
35919
|
-
const cycleNames = cycle.map((taskId) => {
|
|
35920
|
-
const task = tasks.find((t) => t.id === taskId);
|
|
35921
|
-
return task ? task.name : taskId;
|
|
35922
|
-
});
|
|
35923
|
-
throw new DependencyCycleError(cycleNames, id);
|
|
35924
|
-
}
|
|
35925
|
-
}
|
|
35926
|
-
return {
|
|
35927
|
-
id,
|
|
35928
|
-
goal: input.goal,
|
|
35929
|
-
context: input.context,
|
|
35930
|
-
tasks,
|
|
35931
|
-
concurrency: input.concurrency,
|
|
35932
|
-
allowDynamicTasks: input.allowDynamicTasks ?? true,
|
|
35933
|
-
status: "pending",
|
|
35934
|
-
createdAt: now,
|
|
35935
|
-
lastUpdatedAt: now,
|
|
35936
|
-
metadata: input.metadata
|
|
35937
|
-
};
|
|
35938
|
-
}
|
|
35939
|
-
function canTaskExecute(task, allTasks) {
|
|
35940
|
-
if (task.status !== "pending") {
|
|
35941
|
-
return false;
|
|
35942
|
-
}
|
|
35943
|
-
if (task.dependsOn.length > 0) {
|
|
35944
|
-
for (const depId of task.dependsOn) {
|
|
35945
|
-
const depTask = allTasks.find((t) => t.id === depId);
|
|
35946
|
-
if (!depTask || depTask.status !== "completed") {
|
|
35947
|
-
return false;
|
|
35948
|
-
}
|
|
35949
|
-
}
|
|
35950
|
-
}
|
|
35951
|
-
return true;
|
|
35952
|
-
}
|
|
35953
|
-
function getNextExecutableTasks(plan) {
|
|
35954
|
-
const executable = plan.tasks.filter((task) => canTaskExecute(task, plan.tasks));
|
|
35955
|
-
if (executable.length === 0) {
|
|
35956
|
-
return [];
|
|
35957
|
-
}
|
|
35958
|
-
if (!plan.concurrency) {
|
|
35959
|
-
return [executable[0]];
|
|
35960
|
-
}
|
|
35961
|
-
const runningCount = plan.tasks.filter((t) => t.status === "in_progress").length;
|
|
35962
|
-
const availableSlots = plan.concurrency.maxParallelTasks - runningCount;
|
|
35963
|
-
if (availableSlots <= 0) {
|
|
35964
|
-
return [];
|
|
35965
|
-
}
|
|
35966
|
-
const parallelTasks = executable.filter((task) => task.execution?.parallel === true);
|
|
35967
|
-
if (parallelTasks.length === 0) {
|
|
35968
|
-
return [executable[0]];
|
|
35969
|
-
}
|
|
35970
|
-
let sortedTasks = [...parallelTasks];
|
|
35971
|
-
if (plan.concurrency.strategy === "priority") {
|
|
35972
|
-
sortedTasks.sort((a, b) => (b.execution?.priority ?? 0) - (a.execution?.priority ?? 0));
|
|
35973
|
-
}
|
|
35974
|
-
return sortedTasks.slice(0, availableSlots);
|
|
35975
|
-
}
|
|
35976
|
-
async function evaluateCondition(condition, memory) {
|
|
35977
|
-
const value = await memory.get(condition.memoryKey);
|
|
35978
|
-
switch (condition.operator) {
|
|
35979
|
-
case "exists":
|
|
35980
|
-
return value !== void 0;
|
|
35981
|
-
case "not_exists":
|
|
35982
|
-
return value === void 0;
|
|
35983
|
-
case "equals":
|
|
35984
|
-
return value === condition.value;
|
|
35985
|
-
case "contains":
|
|
35986
|
-
if (Array.isArray(value)) {
|
|
35987
|
-
return value.includes(condition.value);
|
|
35988
|
-
}
|
|
35989
|
-
if (typeof value === "string" && typeof condition.value === "string") {
|
|
35990
|
-
return value.includes(condition.value);
|
|
35991
|
-
}
|
|
35992
|
-
return false;
|
|
35993
|
-
case "truthy":
|
|
35994
|
-
return !!value;
|
|
35995
|
-
case "greater_than":
|
|
35996
|
-
if (typeof value === "number" && typeof condition.value === "number") {
|
|
35997
|
-
return value > condition.value;
|
|
35998
|
-
}
|
|
35999
|
-
return false;
|
|
36000
|
-
case "less_than":
|
|
36001
|
-
if (typeof value === "number" && typeof condition.value === "number") {
|
|
36002
|
-
return value < condition.value;
|
|
36003
|
-
}
|
|
36004
|
-
return false;
|
|
36005
|
-
default:
|
|
36006
|
-
return false;
|
|
36007
|
-
}
|
|
36008
|
-
}
|
|
36009
|
-
function updateTaskStatus(task, status) {
|
|
36010
|
-
const now = Date.now();
|
|
36011
|
-
const updated = {
|
|
36012
|
-
...task,
|
|
36013
|
-
status,
|
|
36014
|
-
lastUpdatedAt: now
|
|
36015
|
-
};
|
|
36016
|
-
if (status === "in_progress") {
|
|
36017
|
-
if (!updated.startedAt) {
|
|
36018
|
-
updated.startedAt = now;
|
|
36019
|
-
}
|
|
36020
|
-
updated.attempts += 1;
|
|
36021
|
-
}
|
|
36022
|
-
if ((status === "completed" || status === "failed") && !updated.completedAt) {
|
|
36023
|
-
updated.completedAt = now;
|
|
36024
|
-
}
|
|
36025
|
-
return updated;
|
|
36026
|
-
}
|
|
36027
|
-
function isTaskBlocked(task, allTasks) {
|
|
36028
|
-
if (task.dependsOn.length === 0) {
|
|
36029
|
-
return false;
|
|
36030
|
-
}
|
|
36031
|
-
for (const depId of task.dependsOn) {
|
|
36032
|
-
const depTask = allTasks.find((t) => t.id === depId);
|
|
36033
|
-
if (!depTask) {
|
|
36034
|
-
return true;
|
|
36035
|
-
}
|
|
36036
|
-
if (depTask.status !== "completed") {
|
|
36037
|
-
return true;
|
|
36038
|
-
}
|
|
36039
|
-
}
|
|
36040
|
-
return false;
|
|
36041
|
-
}
|
|
36042
|
-
function getTaskDependencies(task, allTasks) {
|
|
36043
|
-
if (task.dependsOn.length === 0) {
|
|
36044
|
-
return [];
|
|
36045
|
-
}
|
|
36046
|
-
return task.dependsOn.map((depId) => allTasks.find((t) => t.id === depId)).filter((t) => t !== void 0);
|
|
36047
|
-
}
|
|
36048
|
-
function resolveDependencies(taskInputs, tasks) {
|
|
36049
|
-
const nameToId = /* @__PURE__ */ new Map();
|
|
36050
|
-
for (const task of tasks) {
|
|
36051
|
-
nameToId.set(task.name, task.id);
|
|
36052
|
-
}
|
|
36053
|
-
for (const input of taskInputs) {
|
|
36054
|
-
if (input.dependsOn && input.dependsOn.length > 0) {
|
|
36055
|
-
input.dependsOn = input.dependsOn.map((dep) => {
|
|
36056
|
-
if (dep.startsWith("task-")) {
|
|
36057
|
-
return dep;
|
|
36058
|
-
}
|
|
36059
|
-
const resolvedId = nameToId.get(dep);
|
|
36060
|
-
if (!resolvedId) {
|
|
36061
|
-
throw new Error(`Task dependency "${dep}" not found`);
|
|
36062
|
-
}
|
|
36063
|
-
return resolvedId;
|
|
36064
|
-
});
|
|
36065
|
-
}
|
|
36066
|
-
}
|
|
36067
|
-
}
|
|
36068
|
-
function detectDependencyCycle(tasks) {
|
|
36069
|
-
const visited = /* @__PURE__ */ new Set();
|
|
36070
|
-
const recStack = /* @__PURE__ */ new Set();
|
|
36071
|
-
const taskMap = new Map(tasks.map((t) => [t.id, t]));
|
|
36072
|
-
function dfs(taskId, path6) {
|
|
36073
|
-
if (recStack.has(taskId)) {
|
|
36074
|
-
const cycleStart = path6.indexOf(taskId);
|
|
36075
|
-
return [...path6.slice(cycleStart), taskId];
|
|
36076
|
-
}
|
|
36077
|
-
if (visited.has(taskId)) {
|
|
36078
|
-
return null;
|
|
36079
|
-
}
|
|
36080
|
-
visited.add(taskId);
|
|
36081
|
-
recStack.add(taskId);
|
|
36082
|
-
const task = taskMap.get(taskId);
|
|
36083
|
-
if (task) {
|
|
36084
|
-
for (const depId of task.dependsOn) {
|
|
36085
|
-
const cycle = dfs(depId, [...path6, taskId]);
|
|
36086
|
-
if (cycle) {
|
|
36087
|
-
return cycle;
|
|
36088
|
-
}
|
|
36089
|
-
}
|
|
36090
|
-
}
|
|
36091
|
-
recStack.delete(taskId);
|
|
36092
|
-
return null;
|
|
36093
|
-
}
|
|
36094
|
-
for (const task of tasks) {
|
|
36095
|
-
if (!visited.has(task.id)) {
|
|
36096
|
-
const cycle = dfs(task.id, []);
|
|
36097
|
-
if (cycle) {
|
|
36098
|
-
return cycle;
|
|
36099
|
-
}
|
|
36100
|
-
}
|
|
36101
|
-
}
|
|
36102
|
-
return null;
|
|
36103
|
-
}
|
|
36104
|
-
|
|
36105
36905
|
// src/capabilities/taskAgent/PlanningAgent.ts
|
|
36106
36906
|
var PLANNING_SYSTEM_PROMPT = `You are an AI planning agent. Your job is to analyze goals and break them down into structured, executable task plans.
|
|
36107
36907
|
|
|
@@ -37466,10 +38266,10 @@ var FileMediaStorage = class {
|
|
|
37466
38266
|
}
|
|
37467
38267
|
async save(data, metadata) {
|
|
37468
38268
|
const dir = metadata.userId ? path2.join(this.outputDir, metadata.userId) : this.outputDir;
|
|
37469
|
-
await
|
|
38269
|
+
await fs18.mkdir(dir, { recursive: true });
|
|
37470
38270
|
const filename = metadata.suggestedFilename ?? this.generateFilename(metadata);
|
|
37471
38271
|
const filePath = path2.join(dir, filename);
|
|
37472
|
-
await
|
|
38272
|
+
await fs18.writeFile(filePath, data);
|
|
37473
38273
|
const format = metadata.format.toLowerCase();
|
|
37474
38274
|
const mimeType = MIME_TYPES2[format] ?? "application/octet-stream";
|
|
37475
38275
|
return {
|
|
@@ -37480,7 +38280,7 @@ var FileMediaStorage = class {
|
|
|
37480
38280
|
}
|
|
37481
38281
|
async read(location) {
|
|
37482
38282
|
try {
|
|
37483
|
-
return await
|
|
38283
|
+
return await fs18.readFile(location);
|
|
37484
38284
|
} catch (err) {
|
|
37485
38285
|
if (err.code === "ENOENT") {
|
|
37486
38286
|
return null;
|
|
@@ -37490,7 +38290,7 @@ var FileMediaStorage = class {
|
|
|
37490
38290
|
}
|
|
37491
38291
|
async delete(location) {
|
|
37492
38292
|
try {
|
|
37493
|
-
await
|
|
38293
|
+
await fs18.unlink(location);
|
|
37494
38294
|
} catch (err) {
|
|
37495
38295
|
if (err.code === "ENOENT") {
|
|
37496
38296
|
return;
|
|
@@ -37500,7 +38300,7 @@ var FileMediaStorage = class {
|
|
|
37500
38300
|
}
|
|
37501
38301
|
async exists(location) {
|
|
37502
38302
|
try {
|
|
37503
|
-
await
|
|
38303
|
+
await fs18.access(location);
|
|
37504
38304
|
return true;
|
|
37505
38305
|
} catch {
|
|
37506
38306
|
return false;
|
|
@@ -37509,11 +38309,11 @@ var FileMediaStorage = class {
|
|
|
37509
38309
|
async list(options) {
|
|
37510
38310
|
await this.ensureDir();
|
|
37511
38311
|
let entries = [];
|
|
37512
|
-
const files = await
|
|
38312
|
+
const files = await fs18.readdir(this.outputDir);
|
|
37513
38313
|
for (const file of files) {
|
|
37514
38314
|
const filePath = path2.join(this.outputDir, file);
|
|
37515
38315
|
try {
|
|
37516
|
-
const stat6 = await
|
|
38316
|
+
const stat6 = await fs18.stat(filePath);
|
|
37517
38317
|
if (!stat6.isFile()) continue;
|
|
37518
38318
|
const ext = path2.extname(file).slice(1).toLowerCase();
|
|
37519
38319
|
const mimeType = MIME_TYPES2[ext] ?? "application/octet-stream";
|
|
@@ -37553,7 +38353,7 @@ var FileMediaStorage = class {
|
|
|
37553
38353
|
}
|
|
37554
38354
|
async ensureDir() {
|
|
37555
38355
|
if (!this.initialized) {
|
|
37556
|
-
await
|
|
38356
|
+
await fs18.mkdir(this.outputDir, { recursive: true });
|
|
37557
38357
|
this.initialized = true;
|
|
37558
38358
|
}
|
|
37559
38359
|
}
|
|
@@ -37803,6 +38603,234 @@ var FileCustomToolStorage = class {
|
|
|
37803
38603
|
function createFileCustomToolStorage(config) {
|
|
37804
38604
|
return new FileCustomToolStorage(config);
|
|
37805
38605
|
}
|
|
38606
|
+
var STORAGE_VERSION = 1;
|
|
38607
|
+
var DEFAULT_USER_ID3 = "default";
|
|
38608
|
+
function getDefaultBaseDirectory6() {
|
|
38609
|
+
const platform2 = process.platform;
|
|
38610
|
+
if (platform2 === "win32") {
|
|
38611
|
+
const appData = process.env.APPDATA || process.env.LOCALAPPDATA;
|
|
38612
|
+
if (appData) {
|
|
38613
|
+
return join(appData, "oneringai", "users");
|
|
38614
|
+
}
|
|
38615
|
+
}
|
|
38616
|
+
return join(homedir(), ".oneringai", "users");
|
|
38617
|
+
}
|
|
38618
|
+
function sanitizeUserId3(userId) {
|
|
38619
|
+
if (!userId) {
|
|
38620
|
+
return DEFAULT_USER_ID3;
|
|
38621
|
+
}
|
|
38622
|
+
return userId.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase() || DEFAULT_USER_ID3;
|
|
38623
|
+
}
|
|
38624
|
+
function sanitizeId2(id) {
|
|
38625
|
+
return id.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase() || "default";
|
|
38626
|
+
}
|
|
38627
|
+
var FileRoutineDefinitionStorage = class {
|
|
38628
|
+
baseDirectory;
|
|
38629
|
+
prettyPrint;
|
|
38630
|
+
constructor(config = {}) {
|
|
38631
|
+
this.baseDirectory = config.baseDirectory ?? getDefaultBaseDirectory6();
|
|
38632
|
+
this.prettyPrint = config.prettyPrint ?? true;
|
|
38633
|
+
}
|
|
38634
|
+
getUserDirectory(userId) {
|
|
38635
|
+
const sanitizedId = sanitizeUserId3(userId);
|
|
38636
|
+
return join(this.baseDirectory, sanitizedId, "routines");
|
|
38637
|
+
}
|
|
38638
|
+
getIndexPath(userId) {
|
|
38639
|
+
return join(this.getUserDirectory(userId), "_index.json");
|
|
38640
|
+
}
|
|
38641
|
+
getRoutinePath(userId, sanitizedId) {
|
|
38642
|
+
return join(this.getUserDirectory(userId), `${sanitizedId}.json`);
|
|
38643
|
+
}
|
|
38644
|
+
async save(userId, definition) {
|
|
38645
|
+
const directory = this.getUserDirectory(userId);
|
|
38646
|
+
const sanitized = sanitizeId2(definition.id);
|
|
38647
|
+
const filePath = this.getRoutinePath(userId, sanitized);
|
|
38648
|
+
await this.ensureDirectory(directory);
|
|
38649
|
+
const stored = { version: STORAGE_VERSION, definition };
|
|
38650
|
+
const data = this.prettyPrint ? JSON.stringify(stored, null, 2) : JSON.stringify(stored);
|
|
38651
|
+
const tempPath = `${filePath}.tmp`;
|
|
38652
|
+
try {
|
|
38653
|
+
await promises.writeFile(tempPath, data, "utf-8");
|
|
38654
|
+
await promises.rename(tempPath, filePath);
|
|
38655
|
+
} catch (error) {
|
|
38656
|
+
try {
|
|
38657
|
+
await promises.unlink(tempPath);
|
|
38658
|
+
} catch {
|
|
38659
|
+
}
|
|
38660
|
+
throw error;
|
|
38661
|
+
}
|
|
38662
|
+
await this.updateIndex(userId, definition);
|
|
38663
|
+
}
|
|
38664
|
+
async load(userId, id) {
|
|
38665
|
+
const sanitized = sanitizeId2(id);
|
|
38666
|
+
const filePath = this.getRoutinePath(userId, sanitized);
|
|
38667
|
+
try {
|
|
38668
|
+
const data = await promises.readFile(filePath, "utf-8");
|
|
38669
|
+
const stored = JSON.parse(data);
|
|
38670
|
+
return stored.definition;
|
|
38671
|
+
} catch (error) {
|
|
38672
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
38673
|
+
return null;
|
|
38674
|
+
}
|
|
38675
|
+
if (error instanceof SyntaxError) {
|
|
38676
|
+
return null;
|
|
38677
|
+
}
|
|
38678
|
+
throw error;
|
|
38679
|
+
}
|
|
38680
|
+
}
|
|
38681
|
+
async delete(userId, id) {
|
|
38682
|
+
const sanitized = sanitizeId2(id);
|
|
38683
|
+
const filePath = this.getRoutinePath(userId, sanitized);
|
|
38684
|
+
try {
|
|
38685
|
+
await promises.unlink(filePath);
|
|
38686
|
+
} catch (error) {
|
|
38687
|
+
if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
|
|
38688
|
+
throw error;
|
|
38689
|
+
}
|
|
38690
|
+
}
|
|
38691
|
+
await this.removeFromIndex(userId, id);
|
|
38692
|
+
}
|
|
38693
|
+
async exists(userId, id) {
|
|
38694
|
+
const sanitized = sanitizeId2(id);
|
|
38695
|
+
const filePath = this.getRoutinePath(userId, sanitized);
|
|
38696
|
+
try {
|
|
38697
|
+
await promises.access(filePath);
|
|
38698
|
+
return true;
|
|
38699
|
+
} catch {
|
|
38700
|
+
return false;
|
|
38701
|
+
}
|
|
38702
|
+
}
|
|
38703
|
+
async list(userId, options) {
|
|
38704
|
+
const index = await this.loadIndex(userId);
|
|
38705
|
+
let entries = [...index.routines];
|
|
38706
|
+
if (options?.tags && options.tags.length > 0) {
|
|
38707
|
+
entries = entries.filter((e) => {
|
|
38708
|
+
const entryTags = e.tags ?? [];
|
|
38709
|
+
return options.tags.some((t) => entryTags.includes(t));
|
|
38710
|
+
});
|
|
38711
|
+
}
|
|
38712
|
+
if (options?.search) {
|
|
38713
|
+
const searchLower = options.search.toLowerCase();
|
|
38714
|
+
entries = entries.filter(
|
|
38715
|
+
(e) => e.name.toLowerCase().includes(searchLower) || e.description.toLowerCase().includes(searchLower)
|
|
38716
|
+
);
|
|
38717
|
+
}
|
|
38718
|
+
entries.sort(
|
|
38719
|
+
(a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
|
|
38720
|
+
);
|
|
38721
|
+
if (options?.offset) {
|
|
38722
|
+
entries = entries.slice(options.offset);
|
|
38723
|
+
}
|
|
38724
|
+
if (options?.limit) {
|
|
38725
|
+
entries = entries.slice(0, options.limit);
|
|
38726
|
+
}
|
|
38727
|
+
const results = [];
|
|
38728
|
+
for (const entry of entries) {
|
|
38729
|
+
const def = await this.load(userId, entry.id);
|
|
38730
|
+
if (def) {
|
|
38731
|
+
results.push(def);
|
|
38732
|
+
}
|
|
38733
|
+
}
|
|
38734
|
+
return results;
|
|
38735
|
+
}
|
|
38736
|
+
getPath(userId) {
|
|
38737
|
+
return this.getUserDirectory(userId);
|
|
38738
|
+
}
|
|
38739
|
+
// ==========================================================================
|
|
38740
|
+
// Private Helpers
|
|
38741
|
+
// ==========================================================================
|
|
38742
|
+
async ensureDirectory(dir) {
|
|
38743
|
+
try {
|
|
38744
|
+
await promises.mkdir(dir, { recursive: true });
|
|
38745
|
+
} catch (error) {
|
|
38746
|
+
if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
|
|
38747
|
+
throw error;
|
|
38748
|
+
}
|
|
38749
|
+
}
|
|
38750
|
+
}
|
|
38751
|
+
async loadIndex(userId) {
|
|
38752
|
+
const indexPath = this.getIndexPath(userId);
|
|
38753
|
+
try {
|
|
38754
|
+
const data = await promises.readFile(indexPath, "utf-8");
|
|
38755
|
+
return JSON.parse(data);
|
|
38756
|
+
} catch (error) {
|
|
38757
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
38758
|
+
return await this.rebuildIndex(userId);
|
|
38759
|
+
}
|
|
38760
|
+
throw error;
|
|
38761
|
+
}
|
|
38762
|
+
}
|
|
38763
|
+
async saveIndex(userId, index) {
|
|
38764
|
+
const directory = this.getUserDirectory(userId);
|
|
38765
|
+
const indexPath = this.getIndexPath(userId);
|
|
38766
|
+
await this.ensureDirectory(directory);
|
|
38767
|
+
index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
38768
|
+
const data = this.prettyPrint ? JSON.stringify(index, null, 2) : JSON.stringify(index);
|
|
38769
|
+
await promises.writeFile(indexPath, data, "utf-8");
|
|
38770
|
+
}
|
|
38771
|
+
async updateIndex(userId, definition) {
|
|
38772
|
+
const index = await this.loadIndex(userId);
|
|
38773
|
+
const entry = this.definitionToIndexEntry(definition);
|
|
38774
|
+
const existingIdx = index.routines.findIndex((e) => e.id === definition.id);
|
|
38775
|
+
if (existingIdx >= 0) {
|
|
38776
|
+
index.routines[existingIdx] = entry;
|
|
38777
|
+
} else {
|
|
38778
|
+
index.routines.push(entry);
|
|
38779
|
+
}
|
|
38780
|
+
await this.saveIndex(userId, index);
|
|
38781
|
+
}
|
|
38782
|
+
async removeFromIndex(userId, id) {
|
|
38783
|
+
const index = await this.loadIndex(userId);
|
|
38784
|
+
index.routines = index.routines.filter((e) => e.id !== id);
|
|
38785
|
+
await this.saveIndex(userId, index);
|
|
38786
|
+
}
|
|
38787
|
+
definitionToIndexEntry(definition) {
|
|
38788
|
+
return {
|
|
38789
|
+
id: definition.id,
|
|
38790
|
+
name: definition.name,
|
|
38791
|
+
description: definition.description,
|
|
38792
|
+
tags: definition.tags,
|
|
38793
|
+
author: definition.author,
|
|
38794
|
+
updatedAt: definition.updatedAt
|
|
38795
|
+
};
|
|
38796
|
+
}
|
|
38797
|
+
/**
|
|
38798
|
+
* Rebuild index by scanning directory for .json files (excluding _index.json).
|
|
38799
|
+
* Returns empty index if directory doesn't exist.
|
|
38800
|
+
*/
|
|
38801
|
+
async rebuildIndex(userId) {
|
|
38802
|
+
const directory = this.getUserDirectory(userId);
|
|
38803
|
+
const index = {
|
|
38804
|
+
version: 1,
|
|
38805
|
+
routines: [],
|
|
38806
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
38807
|
+
};
|
|
38808
|
+
let files;
|
|
38809
|
+
try {
|
|
38810
|
+
files = await promises.readdir(directory);
|
|
38811
|
+
} catch {
|
|
38812
|
+
return index;
|
|
38813
|
+
}
|
|
38814
|
+
for (const file of files) {
|
|
38815
|
+
if (!file.endsWith(".json") || file === "_index.json") continue;
|
|
38816
|
+
try {
|
|
38817
|
+
const data = await promises.readFile(join(directory, file), "utf-8");
|
|
38818
|
+
const stored = JSON.parse(data);
|
|
38819
|
+
if (stored.definition) {
|
|
38820
|
+
index.routines.push(this.definitionToIndexEntry(stored.definition));
|
|
38821
|
+
}
|
|
38822
|
+
} catch {
|
|
38823
|
+
}
|
|
38824
|
+
}
|
|
38825
|
+
if (index.routines.length > 0) {
|
|
38826
|
+
await this.saveIndex(userId, index);
|
|
38827
|
+
}
|
|
38828
|
+
return index;
|
|
38829
|
+
}
|
|
38830
|
+
};
|
|
38831
|
+
function createFileRoutineDefinitionStorage(config) {
|
|
38832
|
+
return new FileRoutineDefinitionStorage(config);
|
|
38833
|
+
}
|
|
37806
38834
|
|
|
37807
38835
|
// src/domain/entities/CustomToolDefinition.ts
|
|
37808
38836
|
var CUSTOM_TOOL_DEFINITION_VERSION = 1;
|
|
@@ -38903,8 +39931,8 @@ var FileStorage = class {
|
|
|
38903
39931
|
}
|
|
38904
39932
|
async ensureDirectory() {
|
|
38905
39933
|
try {
|
|
38906
|
-
await
|
|
38907
|
-
await
|
|
39934
|
+
await fs18.mkdir(this.directory, { recursive: true });
|
|
39935
|
+
await fs18.chmod(this.directory, 448);
|
|
38908
39936
|
} catch (error) {
|
|
38909
39937
|
}
|
|
38910
39938
|
}
|
|
@@ -38920,13 +39948,13 @@ var FileStorage = class {
|
|
|
38920
39948
|
const filePath = this.getFilePath(key);
|
|
38921
39949
|
const plaintext = JSON.stringify(token);
|
|
38922
39950
|
const encrypted = encrypt(plaintext, this.encryptionKey);
|
|
38923
|
-
await
|
|
38924
|
-
await
|
|
39951
|
+
await fs18.writeFile(filePath, encrypted, "utf8");
|
|
39952
|
+
await fs18.chmod(filePath, 384);
|
|
38925
39953
|
}
|
|
38926
39954
|
async getToken(key) {
|
|
38927
39955
|
const filePath = this.getFilePath(key);
|
|
38928
39956
|
try {
|
|
38929
|
-
const encrypted = await
|
|
39957
|
+
const encrypted = await fs18.readFile(filePath, "utf8");
|
|
38930
39958
|
const decrypted = decrypt(encrypted, this.encryptionKey);
|
|
38931
39959
|
return JSON.parse(decrypted);
|
|
38932
39960
|
} catch (error) {
|
|
@@ -38935,7 +39963,7 @@ var FileStorage = class {
|
|
|
38935
39963
|
}
|
|
38936
39964
|
console.error("Failed to read/decrypt token file:", error);
|
|
38937
39965
|
try {
|
|
38938
|
-
await
|
|
39966
|
+
await fs18.unlink(filePath);
|
|
38939
39967
|
} catch {
|
|
38940
39968
|
}
|
|
38941
39969
|
return null;
|
|
@@ -38944,7 +39972,7 @@ var FileStorage = class {
|
|
|
38944
39972
|
async deleteToken(key) {
|
|
38945
39973
|
const filePath = this.getFilePath(key);
|
|
38946
39974
|
try {
|
|
38947
|
-
await
|
|
39975
|
+
await fs18.unlink(filePath);
|
|
38948
39976
|
} catch (error) {
|
|
38949
39977
|
if (error.code !== "ENOENT") {
|
|
38950
39978
|
throw error;
|
|
@@ -38954,7 +39982,7 @@ var FileStorage = class {
|
|
|
38954
39982
|
async hasToken(key) {
|
|
38955
39983
|
const filePath = this.getFilePath(key);
|
|
38956
39984
|
try {
|
|
38957
|
-
await
|
|
39985
|
+
await fs18.access(filePath);
|
|
38958
39986
|
return true;
|
|
38959
39987
|
} catch {
|
|
38960
39988
|
return false;
|
|
@@ -38965,7 +39993,7 @@ var FileStorage = class {
|
|
|
38965
39993
|
*/
|
|
38966
39994
|
async listTokens() {
|
|
38967
39995
|
try {
|
|
38968
|
-
const files = await
|
|
39996
|
+
const files = await fs18.readdir(this.directory);
|
|
38969
39997
|
return files.filter((f) => f.endsWith(".token")).map((f) => f.replace(".token", ""));
|
|
38970
39998
|
} catch {
|
|
38971
39999
|
return [];
|
|
@@ -38976,10 +40004,10 @@ var FileStorage = class {
|
|
|
38976
40004
|
*/
|
|
38977
40005
|
async clearAll() {
|
|
38978
40006
|
try {
|
|
38979
|
-
const files = await
|
|
40007
|
+
const files = await fs18.readdir(this.directory);
|
|
38980
40008
|
const tokenFiles = files.filter((f) => f.endsWith(".token"));
|
|
38981
40009
|
await Promise.all(
|
|
38982
|
-
tokenFiles.map((f) =>
|
|
40010
|
+
tokenFiles.map((f) => fs18.unlink(path2.join(this.directory, f)).catch(() => {
|
|
38983
40011
|
}))
|
|
38984
40012
|
);
|
|
38985
40013
|
} catch {
|
|
@@ -39427,14 +40455,14 @@ var FileConnectorStorage = class {
|
|
|
39427
40455
|
await this.ensureDirectory();
|
|
39428
40456
|
const filePath = this.getFilePath(name);
|
|
39429
40457
|
const json = JSON.stringify(stored, null, 2);
|
|
39430
|
-
await
|
|
39431
|
-
await
|
|
40458
|
+
await fs18.writeFile(filePath, json, "utf8");
|
|
40459
|
+
await fs18.chmod(filePath, 384);
|
|
39432
40460
|
await this.updateIndex(name, "add");
|
|
39433
40461
|
}
|
|
39434
40462
|
async get(name) {
|
|
39435
40463
|
const filePath = this.getFilePath(name);
|
|
39436
40464
|
try {
|
|
39437
|
-
const json = await
|
|
40465
|
+
const json = await fs18.readFile(filePath, "utf8");
|
|
39438
40466
|
return JSON.parse(json);
|
|
39439
40467
|
} catch (error) {
|
|
39440
40468
|
const err = error;
|
|
@@ -39447,7 +40475,7 @@ var FileConnectorStorage = class {
|
|
|
39447
40475
|
async delete(name) {
|
|
39448
40476
|
const filePath = this.getFilePath(name);
|
|
39449
40477
|
try {
|
|
39450
|
-
await
|
|
40478
|
+
await fs18.unlink(filePath);
|
|
39451
40479
|
await this.updateIndex(name, "remove");
|
|
39452
40480
|
return true;
|
|
39453
40481
|
} catch (error) {
|
|
@@ -39461,7 +40489,7 @@ var FileConnectorStorage = class {
|
|
|
39461
40489
|
async has(name) {
|
|
39462
40490
|
const filePath = this.getFilePath(name);
|
|
39463
40491
|
try {
|
|
39464
|
-
await
|
|
40492
|
+
await fs18.access(filePath);
|
|
39465
40493
|
return true;
|
|
39466
40494
|
} catch {
|
|
39467
40495
|
return false;
|
|
@@ -39487,13 +40515,13 @@ var FileConnectorStorage = class {
|
|
|
39487
40515
|
*/
|
|
39488
40516
|
async clear() {
|
|
39489
40517
|
try {
|
|
39490
|
-
const files = await
|
|
40518
|
+
const files = await fs18.readdir(this.directory);
|
|
39491
40519
|
const connectorFiles = files.filter(
|
|
39492
40520
|
(f) => f.endsWith(".connector.json") || f === "_index.json"
|
|
39493
40521
|
);
|
|
39494
40522
|
await Promise.all(
|
|
39495
40523
|
connectorFiles.map(
|
|
39496
|
-
(f) =>
|
|
40524
|
+
(f) => fs18.unlink(path2.join(this.directory, f)).catch(() => {
|
|
39497
40525
|
})
|
|
39498
40526
|
)
|
|
39499
40527
|
);
|
|
@@ -39520,8 +40548,8 @@ var FileConnectorStorage = class {
|
|
|
39520
40548
|
async ensureDirectory() {
|
|
39521
40549
|
if (this.initialized) return;
|
|
39522
40550
|
try {
|
|
39523
|
-
await
|
|
39524
|
-
await
|
|
40551
|
+
await fs18.mkdir(this.directory, { recursive: true });
|
|
40552
|
+
await fs18.chmod(this.directory, 448);
|
|
39525
40553
|
this.initialized = true;
|
|
39526
40554
|
} catch {
|
|
39527
40555
|
this.initialized = true;
|
|
@@ -39532,7 +40560,7 @@ var FileConnectorStorage = class {
|
|
|
39532
40560
|
*/
|
|
39533
40561
|
async loadIndex() {
|
|
39534
40562
|
try {
|
|
39535
|
-
const json = await
|
|
40563
|
+
const json = await fs18.readFile(this.indexPath, "utf8");
|
|
39536
40564
|
return JSON.parse(json);
|
|
39537
40565
|
} catch {
|
|
39538
40566
|
return { connectors: {} };
|
|
@@ -39550,8 +40578,8 @@ var FileConnectorStorage = class {
|
|
|
39550
40578
|
delete index.connectors[hash];
|
|
39551
40579
|
}
|
|
39552
40580
|
const json = JSON.stringify(index, null, 2);
|
|
39553
|
-
await
|
|
39554
|
-
await
|
|
40581
|
+
await fs18.writeFile(this.indexPath, json, "utf8");
|
|
40582
|
+
await fs18.chmod(this.indexPath, 384);
|
|
39555
40583
|
}
|
|
39556
40584
|
};
|
|
39557
40585
|
|
|
@@ -42006,8 +43034,8 @@ function createMessageWithImages(text, imageUrls, role = "user" /* USER */) {
|
|
|
42006
43034
|
var execAsync = promisify(exec);
|
|
42007
43035
|
function cleanupTempFile(filePath) {
|
|
42008
43036
|
try {
|
|
42009
|
-
if (
|
|
42010
|
-
|
|
43037
|
+
if (fs19.existsSync(filePath)) {
|
|
43038
|
+
fs19.unlinkSync(filePath);
|
|
42011
43039
|
}
|
|
42012
43040
|
} catch {
|
|
42013
43041
|
}
|
|
@@ -42058,7 +43086,7 @@ async function readClipboardImageMac() {
|
|
|
42058
43086
|
end try
|
|
42059
43087
|
`;
|
|
42060
43088
|
const { stdout } = await execAsync(`osascript -e '${script}'`);
|
|
42061
|
-
if (stdout.includes("success") ||
|
|
43089
|
+
if (stdout.includes("success") || fs19.existsSync(tempFile)) {
|
|
42062
43090
|
return await convertFileToDataUri(tempFile);
|
|
42063
43091
|
}
|
|
42064
43092
|
return {
|
|
@@ -42075,14 +43103,14 @@ async function readClipboardImageLinux() {
|
|
|
42075
43103
|
try {
|
|
42076
43104
|
try {
|
|
42077
43105
|
await execAsync(`xclip -selection clipboard -t image/png -o > "${tempFile}"`);
|
|
42078
|
-
if (
|
|
43106
|
+
if (fs19.existsSync(tempFile) && fs19.statSync(tempFile).size > 0) {
|
|
42079
43107
|
return await convertFileToDataUri(tempFile);
|
|
42080
43108
|
}
|
|
42081
43109
|
} catch {
|
|
42082
43110
|
}
|
|
42083
43111
|
try {
|
|
42084
43112
|
await execAsync(`wl-paste -t image/png > "${tempFile}"`);
|
|
42085
|
-
if (
|
|
43113
|
+
if (fs19.existsSync(tempFile) && fs19.statSync(tempFile).size > 0) {
|
|
42086
43114
|
return await convertFileToDataUri(tempFile);
|
|
42087
43115
|
}
|
|
42088
43116
|
} catch {
|
|
@@ -42109,7 +43137,7 @@ async function readClipboardImageWindows() {
|
|
|
42109
43137
|
}
|
|
42110
43138
|
`;
|
|
42111
43139
|
await execAsync(`powershell -Command "${psScript}"`);
|
|
42112
|
-
if (
|
|
43140
|
+
if (fs19.existsSync(tempFile) && fs19.statSync(tempFile).size > 0) {
|
|
42113
43141
|
return await convertFileToDataUri(tempFile);
|
|
42114
43142
|
}
|
|
42115
43143
|
return {
|
|
@@ -42122,7 +43150,7 @@ async function readClipboardImageWindows() {
|
|
|
42122
43150
|
}
|
|
42123
43151
|
async function convertFileToDataUri(filePath) {
|
|
42124
43152
|
try {
|
|
42125
|
-
const imageBuffer =
|
|
43153
|
+
const imageBuffer = fs19.readFileSync(filePath);
|
|
42126
43154
|
const base64Image = imageBuffer.toString("base64");
|
|
42127
43155
|
const magic = imageBuffer.slice(0, 4).toString("hex");
|
|
42128
43156
|
let mimeType = "image/png";
|
|
@@ -42181,186 +43209,6 @@ async function hasClipboardImage() {
|
|
|
42181
43209
|
}
|
|
42182
43210
|
}
|
|
42183
43211
|
|
|
42184
|
-
// src/utils/jsonExtractor.ts
|
|
42185
|
-
function extractJSON(text) {
|
|
42186
|
-
if (!text || typeof text !== "string") {
|
|
42187
|
-
return {
|
|
42188
|
-
success: false,
|
|
42189
|
-
error: "Input is empty or not a string"
|
|
42190
|
-
};
|
|
42191
|
-
}
|
|
42192
|
-
const trimmedText = text.trim();
|
|
42193
|
-
const codeBlockResult = extractFromCodeBlock(trimmedText);
|
|
42194
|
-
if (codeBlockResult.success) {
|
|
42195
|
-
return codeBlockResult;
|
|
42196
|
-
}
|
|
42197
|
-
const inlineResult = extractInlineJSON(trimmedText);
|
|
42198
|
-
if (inlineResult.success) {
|
|
42199
|
-
return inlineResult;
|
|
42200
|
-
}
|
|
42201
|
-
try {
|
|
42202
|
-
const data = JSON.parse(trimmedText);
|
|
42203
|
-
return {
|
|
42204
|
-
success: true,
|
|
42205
|
-
data,
|
|
42206
|
-
rawJson: trimmedText,
|
|
42207
|
-
method: "raw"
|
|
42208
|
-
};
|
|
42209
|
-
} catch (e) {
|
|
42210
|
-
return {
|
|
42211
|
-
success: false,
|
|
42212
|
-
error: `Could not extract JSON from text: ${e instanceof Error ? e.message : String(e)}`
|
|
42213
|
-
};
|
|
42214
|
-
}
|
|
42215
|
-
}
|
|
42216
|
-
function extractFromCodeBlock(text) {
|
|
42217
|
-
const codeBlockRegex = /```(?:json)?\s*([\s\S]*?)```/g;
|
|
42218
|
-
let match;
|
|
42219
|
-
while ((match = codeBlockRegex.exec(text)) !== null) {
|
|
42220
|
-
const content = match[1];
|
|
42221
|
-
if (content) {
|
|
42222
|
-
const trimmed = content.trim();
|
|
42223
|
-
try {
|
|
42224
|
-
const data = JSON.parse(trimmed);
|
|
42225
|
-
return {
|
|
42226
|
-
success: true,
|
|
42227
|
-
data,
|
|
42228
|
-
rawJson: trimmed,
|
|
42229
|
-
method: "code_block"
|
|
42230
|
-
};
|
|
42231
|
-
} catch {
|
|
42232
|
-
continue;
|
|
42233
|
-
}
|
|
42234
|
-
}
|
|
42235
|
-
}
|
|
42236
|
-
return { success: false };
|
|
42237
|
-
}
|
|
42238
|
-
function extractInlineJSON(text) {
|
|
42239
|
-
const objectMatch = findJSONObject(text);
|
|
42240
|
-
if (objectMatch) {
|
|
42241
|
-
try {
|
|
42242
|
-
const data = JSON.parse(objectMatch);
|
|
42243
|
-
return {
|
|
42244
|
-
success: true,
|
|
42245
|
-
data,
|
|
42246
|
-
rawJson: objectMatch,
|
|
42247
|
-
method: "inline"
|
|
42248
|
-
};
|
|
42249
|
-
} catch {
|
|
42250
|
-
}
|
|
42251
|
-
}
|
|
42252
|
-
const arrayMatch = findJSONArray(text);
|
|
42253
|
-
if (arrayMatch) {
|
|
42254
|
-
try {
|
|
42255
|
-
const data = JSON.parse(arrayMatch);
|
|
42256
|
-
return {
|
|
42257
|
-
success: true,
|
|
42258
|
-
data,
|
|
42259
|
-
rawJson: arrayMatch,
|
|
42260
|
-
method: "inline"
|
|
42261
|
-
};
|
|
42262
|
-
} catch {
|
|
42263
|
-
}
|
|
42264
|
-
}
|
|
42265
|
-
return { success: false };
|
|
42266
|
-
}
|
|
42267
|
-
function findJSONObject(text) {
|
|
42268
|
-
const startIndex = text.indexOf("{");
|
|
42269
|
-
if (startIndex === -1) return null;
|
|
42270
|
-
let depth = 0;
|
|
42271
|
-
let inString = false;
|
|
42272
|
-
let escaped = false;
|
|
42273
|
-
for (let i = startIndex; i < text.length; i++) {
|
|
42274
|
-
const char = text[i];
|
|
42275
|
-
if (escaped) {
|
|
42276
|
-
escaped = false;
|
|
42277
|
-
continue;
|
|
42278
|
-
}
|
|
42279
|
-
if (char === "\\" && inString) {
|
|
42280
|
-
escaped = true;
|
|
42281
|
-
continue;
|
|
42282
|
-
}
|
|
42283
|
-
if (char === '"') {
|
|
42284
|
-
inString = !inString;
|
|
42285
|
-
continue;
|
|
42286
|
-
}
|
|
42287
|
-
if (inString) continue;
|
|
42288
|
-
if (char === "{") {
|
|
42289
|
-
depth++;
|
|
42290
|
-
} else if (char === "}") {
|
|
42291
|
-
depth--;
|
|
42292
|
-
if (depth === 0) {
|
|
42293
|
-
return text.slice(startIndex, i + 1);
|
|
42294
|
-
}
|
|
42295
|
-
}
|
|
42296
|
-
}
|
|
42297
|
-
return null;
|
|
42298
|
-
}
|
|
42299
|
-
function findJSONArray(text) {
|
|
42300
|
-
const startIndex = text.indexOf("[");
|
|
42301
|
-
if (startIndex === -1) return null;
|
|
42302
|
-
let depth = 0;
|
|
42303
|
-
let inString = false;
|
|
42304
|
-
let escaped = false;
|
|
42305
|
-
for (let i = startIndex; i < text.length; i++) {
|
|
42306
|
-
const char = text[i];
|
|
42307
|
-
if (escaped) {
|
|
42308
|
-
escaped = false;
|
|
42309
|
-
continue;
|
|
42310
|
-
}
|
|
42311
|
-
if (char === "\\" && inString) {
|
|
42312
|
-
escaped = true;
|
|
42313
|
-
continue;
|
|
42314
|
-
}
|
|
42315
|
-
if (char === '"') {
|
|
42316
|
-
inString = !inString;
|
|
42317
|
-
continue;
|
|
42318
|
-
}
|
|
42319
|
-
if (inString) continue;
|
|
42320
|
-
if (char === "[") {
|
|
42321
|
-
depth++;
|
|
42322
|
-
} else if (char === "]") {
|
|
42323
|
-
depth--;
|
|
42324
|
-
if (depth === 0) {
|
|
42325
|
-
return text.slice(startIndex, i + 1);
|
|
42326
|
-
}
|
|
42327
|
-
}
|
|
42328
|
-
}
|
|
42329
|
-
return null;
|
|
42330
|
-
}
|
|
42331
|
-
function extractJSONField(text, field, defaultValue) {
|
|
42332
|
-
const result = extractJSON(text);
|
|
42333
|
-
if (result.success && result.data && field in result.data) {
|
|
42334
|
-
return result.data[field];
|
|
42335
|
-
}
|
|
42336
|
-
return defaultValue;
|
|
42337
|
-
}
|
|
42338
|
-
function extractNumber(text, patterns = [
|
|
42339
|
-
/(\d{1,3})%?\s*(?:complete|score|percent)/i,
|
|
42340
|
-
/(?:score|completion|rating)[:\s]+(\d{1,3})/i,
|
|
42341
|
-
/(\d{1,3})\s*(?:out of|\/)\s*100/i
|
|
42342
|
-
], defaultValue = 0) {
|
|
42343
|
-
const jsonResult = extractJSON(text);
|
|
42344
|
-
if (jsonResult.success && jsonResult.data) {
|
|
42345
|
-
const scoreFields = ["score", "completionScore", "completion_score", "rating", "percent", "value"];
|
|
42346
|
-
for (const field of scoreFields) {
|
|
42347
|
-
if (field in jsonResult.data && typeof jsonResult.data[field] === "number") {
|
|
42348
|
-
return jsonResult.data[field];
|
|
42349
|
-
}
|
|
42350
|
-
}
|
|
42351
|
-
}
|
|
42352
|
-
for (const pattern of patterns) {
|
|
42353
|
-
const match = text.match(pattern);
|
|
42354
|
-
if (match && match[1]) {
|
|
42355
|
-
const num = parseInt(match[1], 10);
|
|
42356
|
-
if (!isNaN(num)) {
|
|
42357
|
-
return num;
|
|
42358
|
-
}
|
|
42359
|
-
}
|
|
42360
|
-
}
|
|
42361
|
-
return defaultValue;
|
|
42362
|
-
}
|
|
42363
|
-
|
|
42364
43212
|
// src/tools/index.ts
|
|
42365
43213
|
var tools_exports = {};
|
|
42366
43214
|
__export(tools_exports, {
|
|
@@ -42396,19 +43244,25 @@ __export(tools_exports, {
|
|
|
42396
43244
|
createDesktopScreenshotTool: () => createDesktopScreenshotTool,
|
|
42397
43245
|
createDesktopWindowFocusTool: () => createDesktopWindowFocusTool,
|
|
42398
43246
|
createDesktopWindowListTool: () => createDesktopWindowListTool,
|
|
43247
|
+
createDraftEmailTool: () => createDraftEmailTool,
|
|
42399
43248
|
createEditFileTool: () => createEditFileTool,
|
|
43249
|
+
createEditMeetingTool: () => createEditMeetingTool,
|
|
42400
43250
|
createExecuteJavaScriptTool: () => createExecuteJavaScriptTool,
|
|
43251
|
+
createFindMeetingSlotsTool: () => createFindMeetingSlotsTool,
|
|
43252
|
+
createGetMeetingTranscriptTool: () => createGetMeetingTranscriptTool,
|
|
42401
43253
|
createGetPRTool: () => createGetPRTool,
|
|
42402
43254
|
createGitHubReadFileTool: () => createGitHubReadFileTool,
|
|
42403
43255
|
createGlobTool: () => createGlobTool,
|
|
42404
43256
|
createGrepTool: () => createGrepTool,
|
|
42405
43257
|
createImageGenerationTool: () => createImageGenerationTool,
|
|
42406
43258
|
createListDirectoryTool: () => createListDirectoryTool,
|
|
43259
|
+
createMeetingTool: () => createMeetingTool,
|
|
42407
43260
|
createPRCommentsTool: () => createPRCommentsTool,
|
|
42408
43261
|
createPRFilesTool: () => createPRFilesTool,
|
|
42409
43262
|
createReadFileTool: () => createReadFileTool,
|
|
42410
43263
|
createSearchCodeTool: () => createSearchCodeTool,
|
|
42411
43264
|
createSearchFilesTool: () => createSearchFilesTool,
|
|
43265
|
+
createSendEmailTool: () => createSendEmailTool,
|
|
42412
43266
|
createSpeechToTextTool: () => createSpeechToTextTool,
|
|
42413
43267
|
createTextToSpeechTool: () => createTextToSpeechTool,
|
|
42414
43268
|
createVideoTools: () => createVideoTools,
|
|
@@ -42438,6 +43292,8 @@ __export(tools_exports, {
|
|
|
42438
43292
|
executeInVM: () => executeInVM,
|
|
42439
43293
|
executeJavaScript: () => executeJavaScript,
|
|
42440
43294
|
expandTilde: () => expandTilde,
|
|
43295
|
+
formatAttendees: () => formatAttendees,
|
|
43296
|
+
formatRecipients: () => formatRecipients,
|
|
42441
43297
|
getAllBuiltInTools: () => getAllBuiltInTools,
|
|
42442
43298
|
getBackgroundOutput: () => getBackgroundOutput,
|
|
42443
43299
|
getDesktopDriver: () => getDesktopDriver,
|
|
@@ -42448,19 +43304,24 @@ __export(tools_exports, {
|
|
|
42448
43304
|
getToolRegistry: () => getToolRegistry,
|
|
42449
43305
|
getToolsByCategory: () => getToolsByCategory,
|
|
42450
43306
|
getToolsRequiringConnector: () => getToolsRequiringConnector,
|
|
43307
|
+
getUserPathPrefix: () => getUserPathPrefix,
|
|
42451
43308
|
glob: () => glob,
|
|
42452
43309
|
grep: () => grep,
|
|
42453
43310
|
hydrateCustomTool: () => hydrateCustomTool,
|
|
42454
43311
|
isBlockedCommand: () => isBlockedCommand,
|
|
42455
43312
|
isExcludedExtension: () => isExcludedExtension,
|
|
43313
|
+
isTeamsMeetingUrl: () => isTeamsMeetingUrl,
|
|
42456
43314
|
jsonManipulator: () => jsonManipulator,
|
|
42457
43315
|
killBackgroundProcess: () => killBackgroundProcess,
|
|
42458
43316
|
listDirectory: () => listDirectory,
|
|
42459
43317
|
mergeTextPieces: () => mergeTextPieces,
|
|
43318
|
+
microsoftFetch: () => microsoftFetch,
|
|
43319
|
+
normalizeEmails: () => normalizeEmails,
|
|
42460
43320
|
parseKeyCombo: () => parseKeyCombo,
|
|
42461
43321
|
parseRepository: () => parseRepository,
|
|
42462
43322
|
readFile: () => readFile5,
|
|
42463
43323
|
resetDefaultDriver: () => resetDefaultDriver,
|
|
43324
|
+
resolveMeetingId: () => resolveMeetingId,
|
|
42464
43325
|
resolveRepository: () => resolveRepository,
|
|
42465
43326
|
setMediaOutputHandler: () => setMediaOutputHandler,
|
|
42466
43327
|
setMediaStorage: () => setMediaStorage,
|
|
@@ -46542,6 +47403,840 @@ function registerGitHubTools() {
|
|
|
46542
47403
|
// src/tools/github/index.ts
|
|
46543
47404
|
registerGitHubTools();
|
|
46544
47405
|
|
|
47406
|
+
// src/tools/microsoft/types.ts
|
|
47407
|
+
function getUserPathPrefix(connector, targetUser) {
|
|
47408
|
+
const auth2 = connector.config.auth;
|
|
47409
|
+
if (auth2.type === "oauth" && auth2.flow === "client_credentials") {
|
|
47410
|
+
if (!targetUser) {
|
|
47411
|
+
throw new Error(
|
|
47412
|
+
'targetUser is required when using client_credentials (application) flow. Provide a user ID or UPN (e.g., "user@domain.com").'
|
|
47413
|
+
);
|
|
47414
|
+
}
|
|
47415
|
+
return `/users/${targetUser}`;
|
|
47416
|
+
}
|
|
47417
|
+
return "/me";
|
|
47418
|
+
}
|
|
47419
|
+
var MicrosoftAPIError = class extends Error {
|
|
47420
|
+
constructor(status, statusText, body) {
|
|
47421
|
+
const msg = typeof body === "object" && body !== null && "error" in body ? body.error?.message ?? statusText : statusText;
|
|
47422
|
+
super(`Microsoft Graph API error ${status}: ${msg}`);
|
|
47423
|
+
this.status = status;
|
|
47424
|
+
this.statusText = statusText;
|
|
47425
|
+
this.body = body;
|
|
47426
|
+
this.name = "MicrosoftAPIError";
|
|
47427
|
+
}
|
|
47428
|
+
};
|
|
47429
|
+
async function microsoftFetch(connector, endpoint, options) {
|
|
47430
|
+
let url2 = endpoint;
|
|
47431
|
+
if (options?.queryParams && Object.keys(options.queryParams).length > 0) {
|
|
47432
|
+
const params = new URLSearchParams();
|
|
47433
|
+
for (const [key, value] of Object.entries(options.queryParams)) {
|
|
47434
|
+
params.append(key, String(value));
|
|
47435
|
+
}
|
|
47436
|
+
url2 += (url2.includes("?") ? "&" : "?") + params.toString();
|
|
47437
|
+
}
|
|
47438
|
+
const headers = {
|
|
47439
|
+
"Accept": options?.accept ?? "application/json"
|
|
47440
|
+
};
|
|
47441
|
+
if (options?.body) {
|
|
47442
|
+
headers["Content-Type"] = "application/json";
|
|
47443
|
+
}
|
|
47444
|
+
const response = await connector.fetch(
|
|
47445
|
+
url2,
|
|
47446
|
+
{
|
|
47447
|
+
method: options?.method ?? "GET",
|
|
47448
|
+
headers,
|
|
47449
|
+
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
47450
|
+
},
|
|
47451
|
+
options?.userId
|
|
47452
|
+
);
|
|
47453
|
+
const text = await response.text();
|
|
47454
|
+
if (!response.ok) {
|
|
47455
|
+
let data;
|
|
47456
|
+
try {
|
|
47457
|
+
data = JSON.parse(text);
|
|
47458
|
+
} catch {
|
|
47459
|
+
data = text;
|
|
47460
|
+
}
|
|
47461
|
+
throw new MicrosoftAPIError(response.status, response.statusText, data);
|
|
47462
|
+
}
|
|
47463
|
+
if (!text || text.trim().length === 0) {
|
|
47464
|
+
return void 0;
|
|
47465
|
+
}
|
|
47466
|
+
try {
|
|
47467
|
+
return JSON.parse(text);
|
|
47468
|
+
} catch {
|
|
47469
|
+
return text;
|
|
47470
|
+
}
|
|
47471
|
+
}
|
|
47472
|
+
function normalizeEmails(input) {
|
|
47473
|
+
return input.map((item) => {
|
|
47474
|
+
if (typeof item === "string") return item;
|
|
47475
|
+
if (typeof item === "object" && item !== null) {
|
|
47476
|
+
const obj = item;
|
|
47477
|
+
if (obj.emailAddress && typeof obj.emailAddress === "object") {
|
|
47478
|
+
const ea = obj.emailAddress;
|
|
47479
|
+
if (typeof ea.address === "string") return ea.address;
|
|
47480
|
+
}
|
|
47481
|
+
if (typeof obj.address === "string") return obj.address;
|
|
47482
|
+
if (typeof obj.email === "string") return obj.email;
|
|
47483
|
+
}
|
|
47484
|
+
return String(item);
|
|
47485
|
+
});
|
|
47486
|
+
}
|
|
47487
|
+
function formatRecipients(emails) {
|
|
47488
|
+
return normalizeEmails(emails).map((address) => ({ emailAddress: { address } }));
|
|
47489
|
+
}
|
|
47490
|
+
function formatAttendees(emails) {
|
|
47491
|
+
return normalizeEmails(emails).map((address) => ({
|
|
47492
|
+
emailAddress: { address },
|
|
47493
|
+
type: "required"
|
|
47494
|
+
}));
|
|
47495
|
+
}
|
|
47496
|
+
function isTeamsMeetingUrl(input) {
|
|
47497
|
+
try {
|
|
47498
|
+
const url2 = new URL(input.trim());
|
|
47499
|
+
return (url2.hostname === "teams.microsoft.com" || url2.hostname === "teams.live.com") && url2.pathname.includes("meetup-join");
|
|
47500
|
+
} catch {
|
|
47501
|
+
return false;
|
|
47502
|
+
}
|
|
47503
|
+
}
|
|
47504
|
+
async function resolveMeetingId(connector, input, prefix, effectiveUserId) {
|
|
47505
|
+
if (!input || input.trim().length === 0) {
|
|
47506
|
+
throw new Error("Meeting ID cannot be empty");
|
|
47507
|
+
}
|
|
47508
|
+
const trimmed = input.trim();
|
|
47509
|
+
if (!isTeamsMeetingUrl(trimmed)) {
|
|
47510
|
+
return { meetingId: trimmed };
|
|
47511
|
+
}
|
|
47512
|
+
const meetings = await microsoftFetch(
|
|
47513
|
+
connector,
|
|
47514
|
+
`${prefix}/onlineMeetings`,
|
|
47515
|
+
{
|
|
47516
|
+
userId: effectiveUserId,
|
|
47517
|
+
queryParams: { "$filter": `JoinWebUrl eq '${trimmed}'` }
|
|
47518
|
+
}
|
|
47519
|
+
);
|
|
47520
|
+
if (!meetings.value || meetings.value.length === 0) {
|
|
47521
|
+
throw new Error(
|
|
47522
|
+
`Could not find an online meeting matching the provided Teams URL. Make sure the URL is correct and you have access to this meeting.`
|
|
47523
|
+
);
|
|
47524
|
+
}
|
|
47525
|
+
return {
|
|
47526
|
+
meetingId: meetings.value[0].id,
|
|
47527
|
+
subject: meetings.value[0].subject
|
|
47528
|
+
};
|
|
47529
|
+
}
|
|
47530
|
+
|
|
47531
|
+
// src/tools/microsoft/createDraftEmail.ts
|
|
47532
|
+
function createDraftEmailTool(connector, userId) {
|
|
47533
|
+
return {
|
|
47534
|
+
definition: {
|
|
47535
|
+
type: "function",
|
|
47536
|
+
function: {
|
|
47537
|
+
name: "create_draft_email",
|
|
47538
|
+
description: `Create a draft email or draft reply in the user's Outlook mailbox via Microsoft Graph. The draft is saved but NOT sent \u2014 use send_email to send immediately instead.
|
|
47539
|
+
|
|
47540
|
+
PARAMETER FORMATS:
|
|
47541
|
+
- to/cc: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects.
|
|
47542
|
+
- subject: plain string. Example: "Project update" or "Re: Project update" for replies.
|
|
47543
|
+
- body: HTML string. Example: "<p>Hi Alice,</p><p>Here is the update.</p>". Use <p>, <br>, <b>, <ul> tags for formatting.
|
|
47544
|
+
- replyToMessageId: Graph message ID string (starts with "AAMk..."). Only set when replying to an existing email.
|
|
47545
|
+
|
|
47546
|
+
EXAMPLES:
|
|
47547
|
+
- New draft: { "to": ["alice@contoso.com"], "subject": "Project update", "body": "<p>Hi Alice,</p><p>Here is the update.</p>" }
|
|
47548
|
+
- Reply draft: { "to": ["alice@contoso.com"], "subject": "Re: Project update", "body": "<p>Thanks!</p>", "replyToMessageId": "AAMkADI1..." }
|
|
47549
|
+
- With CC: { "to": ["alice@contoso.com"], "subject": "Notes", "body": "<p>See attached.</p>", "cc": ["bob@contoso.com"] }`,
|
|
47550
|
+
parameters: {
|
|
47551
|
+
type: "object",
|
|
47552
|
+
properties: {
|
|
47553
|
+
to: {
|
|
47554
|
+
type: "array",
|
|
47555
|
+
items: { type: "string" },
|
|
47556
|
+
description: 'Recipient email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]'
|
|
47557
|
+
},
|
|
47558
|
+
subject: {
|
|
47559
|
+
type: "string",
|
|
47560
|
+
description: 'Email subject as plain string. Example: "Project update" or "Re: Original subject" for replies.'
|
|
47561
|
+
},
|
|
47562
|
+
body: {
|
|
47563
|
+
type: "string",
|
|
47564
|
+
description: 'Email body as an HTML string. Example: "<p>Hello!</p><p>See you tomorrow.</p>"'
|
|
47565
|
+
},
|
|
47566
|
+
cc: {
|
|
47567
|
+
type: "array",
|
|
47568
|
+
items: { type: "string" },
|
|
47569
|
+
description: 'CC email addresses as plain strings. Example: ["bob@contoso.com"]. Optional.'
|
|
47570
|
+
},
|
|
47571
|
+
replyToMessageId: {
|
|
47572
|
+
type: "string",
|
|
47573
|
+
description: 'Graph message ID of the email to reply to. Example: "AAMkADI1M2I3YzgtODg...". When set, creates a threaded reply draft.'
|
|
47574
|
+
},
|
|
47575
|
+
targetUser: {
|
|
47576
|
+
type: "string",
|
|
47577
|
+
description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
|
|
47578
|
+
}
|
|
47579
|
+
},
|
|
47580
|
+
required: ["to", "subject", "body"]
|
|
47581
|
+
}
|
|
47582
|
+
}
|
|
47583
|
+
},
|
|
47584
|
+
describeCall: (args) => {
|
|
47585
|
+
const action = args.replyToMessageId ? "Reply draft" : "Draft";
|
|
47586
|
+
return `${action} to ${args.to.join(", ")}: ${args.subject}`;
|
|
47587
|
+
},
|
|
47588
|
+
permission: {
|
|
47589
|
+
scope: "session",
|
|
47590
|
+
riskLevel: "medium",
|
|
47591
|
+
approvalMessage: `Create a draft email via ${connector.displayName}`
|
|
47592
|
+
},
|
|
47593
|
+
execute: async (args, context) => {
|
|
47594
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
47595
|
+
try {
|
|
47596
|
+
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
47597
|
+
if (args.replyToMessageId) {
|
|
47598
|
+
const replyDraft = await microsoftFetch(
|
|
47599
|
+
connector,
|
|
47600
|
+
`${prefix}/messages/${args.replyToMessageId}/createReply`,
|
|
47601
|
+
{ method: "POST", userId: effectiveUserId, body: {} }
|
|
47602
|
+
);
|
|
47603
|
+
const updated = await microsoftFetch(
|
|
47604
|
+
connector,
|
|
47605
|
+
`${prefix}/messages/${replyDraft.id}`,
|
|
47606
|
+
{
|
|
47607
|
+
method: "PATCH",
|
|
47608
|
+
userId: effectiveUserId,
|
|
47609
|
+
body: {
|
|
47610
|
+
subject: args.subject,
|
|
47611
|
+
body: { contentType: "HTML", content: args.body },
|
|
47612
|
+
toRecipients: formatRecipients(args.to),
|
|
47613
|
+
...args.cc && { ccRecipients: formatRecipients(args.cc) }
|
|
47614
|
+
}
|
|
47615
|
+
}
|
|
47616
|
+
);
|
|
47617
|
+
return {
|
|
47618
|
+
success: true,
|
|
47619
|
+
draftId: updated.id,
|
|
47620
|
+
webLink: updated.webLink
|
|
47621
|
+
};
|
|
47622
|
+
}
|
|
47623
|
+
const draft = await microsoftFetch(
|
|
47624
|
+
connector,
|
|
47625
|
+
`${prefix}/messages`,
|
|
47626
|
+
{
|
|
47627
|
+
method: "POST",
|
|
47628
|
+
userId: effectiveUserId,
|
|
47629
|
+
body: {
|
|
47630
|
+
isDraft: true,
|
|
47631
|
+
subject: args.subject,
|
|
47632
|
+
body: { contentType: "HTML", content: args.body },
|
|
47633
|
+
toRecipients: formatRecipients(args.to),
|
|
47634
|
+
...args.cc && { ccRecipients: formatRecipients(args.cc) }
|
|
47635
|
+
}
|
|
47636
|
+
}
|
|
47637
|
+
);
|
|
47638
|
+
return {
|
|
47639
|
+
success: true,
|
|
47640
|
+
draftId: draft.id,
|
|
47641
|
+
webLink: draft.webLink
|
|
47642
|
+
};
|
|
47643
|
+
} catch (error) {
|
|
47644
|
+
return {
|
|
47645
|
+
success: false,
|
|
47646
|
+
error: `Failed to create draft email: ${error instanceof Error ? error.message : String(error)}`
|
|
47647
|
+
};
|
|
47648
|
+
}
|
|
47649
|
+
}
|
|
47650
|
+
};
|
|
47651
|
+
}
|
|
47652
|
+
|
|
47653
|
+
// src/tools/microsoft/sendEmail.ts
|
|
47654
|
+
function createSendEmailTool(connector, userId) {
|
|
47655
|
+
return {
|
|
47656
|
+
definition: {
|
|
47657
|
+
type: "function",
|
|
47658
|
+
function: {
|
|
47659
|
+
name: "send_email",
|
|
47660
|
+
description: `Send an email immediately or reply to an existing message via Microsoft Graph (Outlook). The email is sent right away \u2014 use create_draft_email to save a draft instead.
|
|
47661
|
+
|
|
47662
|
+
PARAMETER FORMATS:
|
|
47663
|
+
- to/cc: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects.
|
|
47664
|
+
- subject: plain string. Example: "Meeting tomorrow" or "Re: Meeting tomorrow" for replies.
|
|
47665
|
+
- body: HTML string. Example: "<p>Hi Alice,</p><p>Can we meet at 2pm?</p>". Use <p>, <br>, <b>, <ul> tags.
|
|
47666
|
+
- replyToMessageId: Graph message ID string (starts with "AAMk..."). Only set when replying to an existing email.
|
|
47667
|
+
|
|
47668
|
+
EXAMPLES:
|
|
47669
|
+
- Send email: { "to": ["alice@contoso.com"], "subject": "Meeting tomorrow", "body": "<p>Can we meet at 2pm?</p>" }
|
|
47670
|
+
- Reply: { "to": ["alice@contoso.com"], "subject": "Re: Meeting", "body": "<p>Confirmed!</p>", "replyToMessageId": "AAMkADI1..." }
|
|
47671
|
+
- With CC: { "to": ["alice@contoso.com"], "subject": "Update", "body": "<p>FYI</p>", "cc": ["bob@contoso.com"] }`,
|
|
47672
|
+
parameters: {
|
|
47673
|
+
type: "object",
|
|
47674
|
+
properties: {
|
|
47675
|
+
to: {
|
|
47676
|
+
type: "array",
|
|
47677
|
+
items: { type: "string" },
|
|
47678
|
+
description: 'Recipient email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]'
|
|
47679
|
+
},
|
|
47680
|
+
subject: {
|
|
47681
|
+
type: "string",
|
|
47682
|
+
description: 'Email subject as plain string. Example: "Meeting tomorrow" or "Re: Original subject" for replies.'
|
|
47683
|
+
},
|
|
47684
|
+
body: {
|
|
47685
|
+
type: "string",
|
|
47686
|
+
description: 'Email body as an HTML string. Example: "<p>Hi!</p><p>Can we meet at 2pm?</p>"'
|
|
47687
|
+
},
|
|
47688
|
+
cc: {
|
|
47689
|
+
type: "array",
|
|
47690
|
+
items: { type: "string" },
|
|
47691
|
+
description: 'CC email addresses as plain strings. Example: ["bob@contoso.com"]. Optional.'
|
|
47692
|
+
},
|
|
47693
|
+
replyToMessageId: {
|
|
47694
|
+
type: "string",
|
|
47695
|
+
description: 'Graph message ID of the email to reply to. Example: "AAMkADI1M2I3YzgtODg...". When set, sends a threaded reply.'
|
|
47696
|
+
},
|
|
47697
|
+
targetUser: {
|
|
47698
|
+
type: "string",
|
|
47699
|
+
description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
|
|
47700
|
+
}
|
|
47701
|
+
},
|
|
47702
|
+
required: ["to", "subject", "body"]
|
|
47703
|
+
}
|
|
47704
|
+
}
|
|
47705
|
+
},
|
|
47706
|
+
describeCall: (args) => {
|
|
47707
|
+
const action = args.replyToMessageId ? "Reply" : "Send";
|
|
47708
|
+
return `${action} to ${args.to.join(", ")}: ${args.subject}`;
|
|
47709
|
+
},
|
|
47710
|
+
permission: {
|
|
47711
|
+
scope: "session",
|
|
47712
|
+
riskLevel: "medium",
|
|
47713
|
+
approvalMessage: `Send an email via ${connector.displayName}`
|
|
47714
|
+
},
|
|
47715
|
+
execute: async (args, context) => {
|
|
47716
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
47717
|
+
try {
|
|
47718
|
+
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
47719
|
+
if (args.replyToMessageId) {
|
|
47720
|
+
await microsoftFetch(
|
|
47721
|
+
connector,
|
|
47722
|
+
`${prefix}/messages/${args.replyToMessageId}/reply`,
|
|
47723
|
+
{
|
|
47724
|
+
method: "POST",
|
|
47725
|
+
userId: effectiveUserId,
|
|
47726
|
+
body: {
|
|
47727
|
+
message: {
|
|
47728
|
+
toRecipients: formatRecipients(args.to),
|
|
47729
|
+
...args.cc && { ccRecipients: formatRecipients(args.cc) }
|
|
47730
|
+
},
|
|
47731
|
+
comment: args.body
|
|
47732
|
+
}
|
|
47733
|
+
}
|
|
47734
|
+
);
|
|
47735
|
+
} else {
|
|
47736
|
+
await microsoftFetch(
|
|
47737
|
+
connector,
|
|
47738
|
+
`${prefix}/sendMail`,
|
|
47739
|
+
{
|
|
47740
|
+
method: "POST",
|
|
47741
|
+
userId: effectiveUserId,
|
|
47742
|
+
body: {
|
|
47743
|
+
message: {
|
|
47744
|
+
subject: args.subject,
|
|
47745
|
+
body: { contentType: "HTML", content: args.body },
|
|
47746
|
+
toRecipients: formatRecipients(args.to),
|
|
47747
|
+
...args.cc && { ccRecipients: formatRecipients(args.cc) }
|
|
47748
|
+
},
|
|
47749
|
+
saveToSentItems: true
|
|
47750
|
+
}
|
|
47751
|
+
}
|
|
47752
|
+
);
|
|
47753
|
+
}
|
|
47754
|
+
return { success: true };
|
|
47755
|
+
} catch (error) {
|
|
47756
|
+
return {
|
|
47757
|
+
success: false,
|
|
47758
|
+
error: `Failed to send email: ${error instanceof Error ? error.message : String(error)}`
|
|
47759
|
+
};
|
|
47760
|
+
}
|
|
47761
|
+
}
|
|
47762
|
+
};
|
|
47763
|
+
}
|
|
47764
|
+
|
|
47765
|
+
// src/tools/microsoft/createMeeting.ts
|
|
47766
|
+
function createMeetingTool(connector, userId) {
|
|
47767
|
+
return {
|
|
47768
|
+
definition: {
|
|
47769
|
+
type: "function",
|
|
47770
|
+
function: {
|
|
47771
|
+
name: "create_meeting",
|
|
47772
|
+
description: `Create a calendar event on the user's Outlook calendar via Microsoft Graph, optionally with a Teams online meeting link.
|
|
47773
|
+
|
|
47774
|
+
PARAMETER FORMATS:
|
|
47775
|
+
- subject: plain string. Example: "Sprint Review"
|
|
47776
|
+
- startDateTime/endDateTime: ISO 8601 string WITHOUT timezone suffix (timezone is a separate param). Example: "2025-01-15T09:00:00"
|
|
47777
|
+
- attendees: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects.
|
|
47778
|
+
- body: HTML string for the invitation body. Example: "<p>Agenda: discuss Q1 goals</p>". Optional.
|
|
47779
|
+
- timeZone: IANA timezone string. Example: "America/New_York", "Europe/Zurich". Default: "UTC".
|
|
47780
|
+
- isOnlineMeeting: boolean. Set true to auto-generate a Teams meeting link.
|
|
47781
|
+
- location: plain string. Example: "Conference Room A". Optional.
|
|
47782
|
+
|
|
47783
|
+
EXAMPLES:
|
|
47784
|
+
- Simple: { "subject": "Standup", "startDateTime": "2025-01-15T09:00:00", "endDateTime": "2025-01-15T09:30:00", "attendees": ["alice@contoso.com"], "timeZone": "America/New_York" }
|
|
47785
|
+
- Teams: { "subject": "Sprint Review", "startDateTime": "2025-01-15T14:00:00", "endDateTime": "2025-01-15T15:00:00", "attendees": ["alice@contoso.com", "bob@contoso.com"], "isOnlineMeeting": true }`,
|
|
47786
|
+
parameters: {
|
|
47787
|
+
type: "object",
|
|
47788
|
+
properties: {
|
|
47789
|
+
subject: {
|
|
47790
|
+
type: "string",
|
|
47791
|
+
description: 'Meeting title as plain string. Example: "Sprint Review"'
|
|
47792
|
+
},
|
|
47793
|
+
startDateTime: {
|
|
47794
|
+
type: "string",
|
|
47795
|
+
description: 'Start date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T09:00:00"'
|
|
47796
|
+
},
|
|
47797
|
+
endDateTime: {
|
|
47798
|
+
type: "string",
|
|
47799
|
+
description: 'End date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T09:30:00"'
|
|
47800
|
+
},
|
|
47801
|
+
attendees: {
|
|
47802
|
+
type: "array",
|
|
47803
|
+
items: { type: "string" },
|
|
47804
|
+
description: 'Attendee email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]'
|
|
47805
|
+
},
|
|
47806
|
+
body: {
|
|
47807
|
+
type: "string",
|
|
47808
|
+
description: 'Meeting description as HTML string. Example: "<p>Agenda: discuss Q1 goals</p>". Optional.'
|
|
47809
|
+
},
|
|
47810
|
+
isOnlineMeeting: {
|
|
47811
|
+
type: "boolean",
|
|
47812
|
+
description: "Set to true to generate a Teams online meeting link. Default: false."
|
|
47813
|
+
},
|
|
47814
|
+
location: {
|
|
47815
|
+
type: "string",
|
|
47816
|
+
description: 'Physical location as plain string. Example: "Conference Room A". Optional.'
|
|
47817
|
+
},
|
|
47818
|
+
timeZone: {
|
|
47819
|
+
type: "string",
|
|
47820
|
+
description: 'IANA timezone string for start/end times. Example: "America/New_York", "Europe/Zurich". Default: "UTC".'
|
|
47821
|
+
},
|
|
47822
|
+
targetUser: {
|
|
47823
|
+
type: "string",
|
|
47824
|
+
description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
|
|
47825
|
+
}
|
|
47826
|
+
},
|
|
47827
|
+
required: ["subject", "startDateTime", "endDateTime", "attendees"]
|
|
47828
|
+
}
|
|
47829
|
+
}
|
|
47830
|
+
},
|
|
47831
|
+
describeCall: (args) => {
|
|
47832
|
+
return `Create meeting: ${args.subject} (${args.attendees.length} attendees)`;
|
|
47833
|
+
},
|
|
47834
|
+
permission: {
|
|
47835
|
+
scope: "session",
|
|
47836
|
+
riskLevel: "medium",
|
|
47837
|
+
approvalMessage: `Create a calendar event via ${connector.displayName}`
|
|
47838
|
+
},
|
|
47839
|
+
execute: async (args, context) => {
|
|
47840
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
47841
|
+
try {
|
|
47842
|
+
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
47843
|
+
const tz = args.timeZone ?? "UTC";
|
|
47844
|
+
const eventBody = {
|
|
47845
|
+
subject: args.subject,
|
|
47846
|
+
start: { dateTime: args.startDateTime, timeZone: tz },
|
|
47847
|
+
end: { dateTime: args.endDateTime, timeZone: tz },
|
|
47848
|
+
attendees: formatAttendees(args.attendees)
|
|
47849
|
+
};
|
|
47850
|
+
if (args.body) {
|
|
47851
|
+
eventBody.body = { contentType: "HTML", content: args.body };
|
|
47852
|
+
}
|
|
47853
|
+
if (args.isOnlineMeeting) {
|
|
47854
|
+
eventBody.isOnlineMeeting = true;
|
|
47855
|
+
eventBody.onlineMeetingProvider = "teamsForBusiness";
|
|
47856
|
+
}
|
|
47857
|
+
if (args.location) {
|
|
47858
|
+
eventBody.location = { displayName: args.location };
|
|
47859
|
+
}
|
|
47860
|
+
const event = await microsoftFetch(
|
|
47861
|
+
connector,
|
|
47862
|
+
`${prefix}/events`,
|
|
47863
|
+
{ method: "POST", userId: effectiveUserId, body: eventBody }
|
|
47864
|
+
);
|
|
47865
|
+
return {
|
|
47866
|
+
success: true,
|
|
47867
|
+
eventId: event.id,
|
|
47868
|
+
webLink: event.webLink,
|
|
47869
|
+
onlineMeetingUrl: event.onlineMeeting?.joinUrl
|
|
47870
|
+
};
|
|
47871
|
+
} catch (error) {
|
|
47872
|
+
return {
|
|
47873
|
+
success: false,
|
|
47874
|
+
error: `Failed to create meeting: ${error instanceof Error ? error.message : String(error)}`
|
|
47875
|
+
};
|
|
47876
|
+
}
|
|
47877
|
+
}
|
|
47878
|
+
};
|
|
47879
|
+
}
|
|
47880
|
+
|
|
47881
|
+
// src/tools/microsoft/editMeeting.ts
|
|
47882
|
+
function createEditMeetingTool(connector, userId) {
|
|
47883
|
+
return {
|
|
47884
|
+
definition: {
|
|
47885
|
+
type: "function",
|
|
47886
|
+
function: {
|
|
47887
|
+
name: "edit_meeting",
|
|
47888
|
+
description: `Update an existing Outlook calendar event via Microsoft Graph. Only the fields you provide will be changed \u2014 omitted fields keep their current values.
|
|
47889
|
+
|
|
47890
|
+
IMPORTANT: The "attendees" field REPLACES the entire attendee list. Include ALL desired attendees (both new and existing), not just the ones you want to add.
|
|
47891
|
+
|
|
47892
|
+
PARAMETER FORMATS:
|
|
47893
|
+
- eventId: Graph event ID string (starts with "AAMk..."). Get this from a previous create_meeting result.
|
|
47894
|
+
- subject: plain string. Example: "Updated: Sprint Review"
|
|
47895
|
+
- startDateTime/endDateTime: ISO 8601 string without timezone suffix. Example: "2025-01-15T10:00:00"
|
|
47896
|
+
- attendees: plain string array of email addresses. Example: ["alice@contoso.com", "charlie@contoso.com"]. Do NOT use objects. REPLACES all attendees.
|
|
47897
|
+
- body: HTML string. Example: "<p>Updated agenda</p>"
|
|
47898
|
+
- timeZone: IANA timezone string. Example: "Europe/Zurich". Default: "UTC".
|
|
47899
|
+
- isOnlineMeeting: boolean. true = add Teams link, false = remove it.
|
|
47900
|
+
- location: plain string. Example: "Room 201"
|
|
47901
|
+
|
|
47902
|
+
EXAMPLES:
|
|
47903
|
+
- Reschedule: { "eventId": "AAMkADI1...", "startDateTime": "2025-01-15T10:00:00", "endDateTime": "2025-01-15T10:30:00", "timeZone": "America/New_York" }
|
|
47904
|
+
- Change attendees: { "eventId": "AAMkADI1...", "attendees": ["alice@contoso.com", "charlie@contoso.com"] }
|
|
47905
|
+
- Add Teams link: { "eventId": "AAMkADI1...", "isOnlineMeeting": true }`,
|
|
47906
|
+
parameters: {
|
|
47907
|
+
type: "object",
|
|
47908
|
+
properties: {
|
|
47909
|
+
eventId: {
|
|
47910
|
+
type: "string",
|
|
47911
|
+
description: 'Calendar event ID string from create_meeting result. Example: "AAMkADI1M2I3YzgtODg..."'
|
|
47912
|
+
},
|
|
47913
|
+
subject: {
|
|
47914
|
+
type: "string",
|
|
47915
|
+
description: 'New meeting title as plain string. Example: "Updated: Sprint Review"'
|
|
47916
|
+
},
|
|
47917
|
+
startDateTime: {
|
|
47918
|
+
type: "string",
|
|
47919
|
+
description: 'New start date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T10:00:00"'
|
|
47920
|
+
},
|
|
47921
|
+
endDateTime: {
|
|
47922
|
+
type: "string",
|
|
47923
|
+
description: 'New end date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T10:30:00"'
|
|
47924
|
+
},
|
|
47925
|
+
attendees: {
|
|
47926
|
+
type: "array",
|
|
47927
|
+
items: { type: "string" },
|
|
47928
|
+
description: 'FULL replacement attendee list as plain email strings. Example: ["alice@contoso.com", "charlie@contoso.com"]. Include ALL attendees.'
|
|
47929
|
+
},
|
|
47930
|
+
body: {
|
|
47931
|
+
type: "string",
|
|
47932
|
+
description: 'New meeting description as HTML string. Example: "<p>Updated agenda</p>"'
|
|
47933
|
+
},
|
|
47934
|
+
isOnlineMeeting: {
|
|
47935
|
+
type: "boolean",
|
|
47936
|
+
description: "true to add Teams meeting link, false to remove it."
|
|
47937
|
+
},
|
|
47938
|
+
location: {
|
|
47939
|
+
type: "string",
|
|
47940
|
+
description: 'New location as plain string. Example: "Conference Room A"'
|
|
47941
|
+
},
|
|
47942
|
+
timeZone: {
|
|
47943
|
+
type: "string",
|
|
47944
|
+
description: 'IANA timezone string for start/end times. Example: "Europe/Zurich". Default: "UTC".'
|
|
47945
|
+
},
|
|
47946
|
+
targetUser: {
|
|
47947
|
+
type: "string",
|
|
47948
|
+
description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
|
|
47949
|
+
}
|
|
47950
|
+
},
|
|
47951
|
+
required: ["eventId"]
|
|
47952
|
+
}
|
|
47953
|
+
}
|
|
47954
|
+
},
|
|
47955
|
+
describeCall: (args) => {
|
|
47956
|
+
const fields = ["subject", "startDateTime", "endDateTime", "attendees", "body", "location"];
|
|
47957
|
+
const changed = fields.filter((f) => args[f] !== void 0);
|
|
47958
|
+
return `Edit meeting ${args.eventId.slice(0, 12)}... (${changed.join(", ") || "no changes"})`;
|
|
47959
|
+
},
|
|
47960
|
+
permission: {
|
|
47961
|
+
scope: "session",
|
|
47962
|
+
riskLevel: "medium",
|
|
47963
|
+
approvalMessage: `Update a calendar event via ${connector.displayName}`
|
|
47964
|
+
},
|
|
47965
|
+
execute: async (args, context) => {
|
|
47966
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
47967
|
+
try {
|
|
47968
|
+
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
47969
|
+
const tz = args.timeZone ?? "UTC";
|
|
47970
|
+
const patchBody = {};
|
|
47971
|
+
if (args.subject !== void 0) patchBody.subject = args.subject;
|
|
47972
|
+
if (args.body !== void 0) patchBody.body = { contentType: "HTML", content: args.body };
|
|
47973
|
+
if (args.startDateTime !== void 0) patchBody.start = { dateTime: args.startDateTime, timeZone: tz };
|
|
47974
|
+
if (args.endDateTime !== void 0) patchBody.end = { dateTime: args.endDateTime, timeZone: tz };
|
|
47975
|
+
if (args.attendees !== void 0) {
|
|
47976
|
+
patchBody.attendees = formatAttendees(args.attendees);
|
|
47977
|
+
}
|
|
47978
|
+
if (args.isOnlineMeeting !== void 0) {
|
|
47979
|
+
patchBody.isOnlineMeeting = args.isOnlineMeeting;
|
|
47980
|
+
if (args.isOnlineMeeting) {
|
|
47981
|
+
patchBody.onlineMeetingProvider = "teamsForBusiness";
|
|
47982
|
+
}
|
|
47983
|
+
}
|
|
47984
|
+
if (args.location !== void 0) {
|
|
47985
|
+
patchBody.location = { displayName: args.location };
|
|
47986
|
+
}
|
|
47987
|
+
const event = await microsoftFetch(
|
|
47988
|
+
connector,
|
|
47989
|
+
`${prefix}/events/${args.eventId}`,
|
|
47990
|
+
{ method: "PATCH", userId: effectiveUserId, body: patchBody }
|
|
47991
|
+
);
|
|
47992
|
+
return {
|
|
47993
|
+
success: true,
|
|
47994
|
+
eventId: event.id,
|
|
47995
|
+
webLink: event.webLink
|
|
47996
|
+
};
|
|
47997
|
+
} catch (error) {
|
|
47998
|
+
return {
|
|
47999
|
+
success: false,
|
|
48000
|
+
error: `Failed to edit meeting: ${error instanceof Error ? error.message : String(error)}`
|
|
48001
|
+
};
|
|
48002
|
+
}
|
|
48003
|
+
}
|
|
48004
|
+
};
|
|
48005
|
+
}
|
|
48006
|
+
|
|
48007
|
+
// src/tools/microsoft/getMeetingTranscript.ts
|
|
48008
|
+
function parseVttToText(vtt) {
|
|
48009
|
+
const lines = vtt.split("\n");
|
|
48010
|
+
const textLines = [];
|
|
48011
|
+
for (const line of lines) {
|
|
48012
|
+
const trimmed = line.trim();
|
|
48013
|
+
if (trimmed === "" || trimmed === "WEBVTT" || trimmed.startsWith("NOTE") || /^\d+$/.test(trimmed) || /^\d{2}:\d{2}/.test(trimmed)) {
|
|
48014
|
+
continue;
|
|
48015
|
+
}
|
|
48016
|
+
textLines.push(trimmed);
|
|
48017
|
+
}
|
|
48018
|
+
return textLines.join("\n");
|
|
48019
|
+
}
|
|
48020
|
+
function createGetMeetingTranscriptTool(connector, userId) {
|
|
48021
|
+
return {
|
|
48022
|
+
definition: {
|
|
48023
|
+
type: "function",
|
|
48024
|
+
function: {
|
|
48025
|
+
name: "get_meeting_transcript",
|
|
48026
|
+
description: `Retrieve the transcript from a Teams online meeting via Microsoft Graph. Returns plain text with speaker labels (VTT timestamps are stripped).
|
|
48027
|
+
|
|
48028
|
+
NOTE: Requires the OnlineMeetingTranscript.Read.All permission. Transcription must have been enabled during the meeting.
|
|
48029
|
+
|
|
48030
|
+
USAGE:
|
|
48031
|
+
- Provide the Teams online meeting ID (NOT the calendar event ID \u2014 this is different) or a Teams meeting join URL
|
|
48032
|
+
- The meetingId can be found in the Teams meeting details or extracted from the join URL
|
|
48033
|
+
|
|
48034
|
+
EXAMPLES:
|
|
48035
|
+
- By meeting ID: { "meetingId": "MSo1N2Y5ZGFjYy03MWJmLTQ3NDMtYjQxMy01M2EdFGkdRWHJlQ" }
|
|
48036
|
+
- By Teams join URL: { "meetingId": "https://teams.microsoft.com/l/meetup-join/19%3ameeting_MjA5YjFi..." }`,
|
|
48037
|
+
parameters: {
|
|
48038
|
+
type: "object",
|
|
48039
|
+
properties: {
|
|
48040
|
+
meetingId: {
|
|
48041
|
+
type: "string",
|
|
48042
|
+
description: 'Teams online meeting ID (e.g. "MSo1N2Y5...") or Teams meeting join URL. This is NOT the calendar event ID.'
|
|
48043
|
+
},
|
|
48044
|
+
targetUser: {
|
|
48045
|
+
type: "string",
|
|
48046
|
+
description: "User ID or email (UPN) to act on behalf of. Only needed for app-only (client_credentials) auth. Ignored in delegated auth."
|
|
48047
|
+
}
|
|
48048
|
+
},
|
|
48049
|
+
required: ["meetingId"]
|
|
48050
|
+
}
|
|
48051
|
+
}
|
|
48052
|
+
},
|
|
48053
|
+
describeCall: (args) => {
|
|
48054
|
+
return `Get transcript for meeting ${args.meetingId.slice(0, 20)}...`;
|
|
48055
|
+
},
|
|
48056
|
+
permission: {
|
|
48057
|
+
scope: "session",
|
|
48058
|
+
riskLevel: "low",
|
|
48059
|
+
approvalMessage: `Get a meeting transcript via ${connector.displayName}`
|
|
48060
|
+
},
|
|
48061
|
+
execute: async (args, context) => {
|
|
48062
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
48063
|
+
try {
|
|
48064
|
+
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
48065
|
+
const resolved = await resolveMeetingId(connector, args.meetingId, prefix, effectiveUserId);
|
|
48066
|
+
const meetingId = resolved.meetingId;
|
|
48067
|
+
const transcriptList = await microsoftFetch(
|
|
48068
|
+
connector,
|
|
48069
|
+
`${prefix}/onlineMeetings/${meetingId}/transcripts`,
|
|
48070
|
+
{ userId: effectiveUserId }
|
|
48071
|
+
);
|
|
48072
|
+
if (!transcriptList.value || transcriptList.value.length === 0) {
|
|
48073
|
+
return {
|
|
48074
|
+
success: false,
|
|
48075
|
+
error: "No transcripts found for this meeting. The meeting may not have had transcription enabled."
|
|
48076
|
+
};
|
|
48077
|
+
}
|
|
48078
|
+
const transcriptId = transcriptList.value[0].id;
|
|
48079
|
+
const contentUrl = `${prefix}/onlineMeetings/${meetingId}/transcripts/${transcriptId}/content`;
|
|
48080
|
+
const response = await connector.fetch(
|
|
48081
|
+
contentUrl + "?$format=text/vtt",
|
|
48082
|
+
{ method: "GET", headers: { "Accept": "text/vtt" } },
|
|
48083
|
+
effectiveUserId
|
|
48084
|
+
);
|
|
48085
|
+
if (!response.ok) {
|
|
48086
|
+
const errorText = await response.text();
|
|
48087
|
+
return {
|
|
48088
|
+
success: false,
|
|
48089
|
+
error: `Failed to fetch transcript content: ${response.status} ${errorText}`
|
|
48090
|
+
};
|
|
48091
|
+
}
|
|
48092
|
+
const vttContent = await response.text();
|
|
48093
|
+
const transcript = parseVttToText(vttContent);
|
|
48094
|
+
return {
|
|
48095
|
+
success: true,
|
|
48096
|
+
transcript,
|
|
48097
|
+
meetingSubject: resolved.subject
|
|
48098
|
+
};
|
|
48099
|
+
} catch (error) {
|
|
48100
|
+
return {
|
|
48101
|
+
success: false,
|
|
48102
|
+
error: `Failed to get meeting transcript: ${error instanceof Error ? error.message : String(error)}`
|
|
48103
|
+
};
|
|
48104
|
+
}
|
|
48105
|
+
}
|
|
48106
|
+
};
|
|
48107
|
+
}
|
|
48108
|
+
|
|
48109
|
+
// src/tools/microsoft/findMeetingSlots.ts
|
|
48110
|
+
function createFindMeetingSlotsTool(connector, userId) {
|
|
48111
|
+
return {
|
|
48112
|
+
definition: {
|
|
48113
|
+
type: "function",
|
|
48114
|
+
function: {
|
|
48115
|
+
name: "find_meeting_slots",
|
|
48116
|
+
description: `Find available meeting time slots when all attendees are free, via Microsoft Graph. Checks each attendee's Outlook calendar and suggests times when everyone is available.
|
|
48117
|
+
|
|
48118
|
+
PARAMETER FORMATS:
|
|
48119
|
+
- attendees: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects \u2014 just plain email strings.
|
|
48120
|
+
- startDateTime/endDateTime: ISO 8601 string without timezone suffix. Example: "2025-01-15T08:00:00". Can span multiple days.
|
|
48121
|
+
- duration: number of minutes as integer. Example: 30 or 60.
|
|
48122
|
+
- timeZone: IANA timezone string. Example: "America/New_York", "Europe/Zurich". Default: "UTC".
|
|
48123
|
+
- maxResults: integer. Default: 5.
|
|
48124
|
+
|
|
48125
|
+
EXAMPLES:
|
|
48126
|
+
- Find 30min slot: { "attendees": ["alice@contoso.com", "bob@contoso.com"], "startDateTime": "2025-01-15T08:00:00", "endDateTime": "2025-01-15T18:00:00", "duration": 30, "timeZone": "America/New_York" }
|
|
48127
|
+
- Find 1hr slot across days: { "attendees": ["alice@contoso.com"], "startDateTime": "2025-01-15T08:00:00", "endDateTime": "2025-01-17T18:00:00", "duration": 60, "maxResults": 10 }`,
|
|
48128
|
+
parameters: {
|
|
48129
|
+
type: "object",
|
|
48130
|
+
properties: {
|
|
48131
|
+
attendees: {
|
|
48132
|
+
type: "array",
|
|
48133
|
+
items: { type: "string" },
|
|
48134
|
+
description: 'Attendee email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT pass objects.'
|
|
48135
|
+
},
|
|
48136
|
+
startDateTime: {
|
|
48137
|
+
type: "string",
|
|
48138
|
+
description: 'Search window start as ISO 8601 string without timezone suffix. Example: "2025-01-15T08:00:00"'
|
|
48139
|
+
},
|
|
48140
|
+
endDateTime: {
|
|
48141
|
+
type: "string",
|
|
48142
|
+
description: 'Search window end as ISO 8601 string without timezone suffix. Example: "2025-01-15T18:00:00". Can span multiple days.'
|
|
48143
|
+
},
|
|
48144
|
+
duration: {
|
|
48145
|
+
type: "number",
|
|
48146
|
+
description: "Meeting duration in minutes as integer. Example: 30 or 60."
|
|
48147
|
+
},
|
|
48148
|
+
timeZone: {
|
|
48149
|
+
type: "string",
|
|
48150
|
+
description: 'IANA timezone string for start/end times. Example: "America/New_York", "Europe/Zurich". Default: "UTC".'
|
|
48151
|
+
},
|
|
48152
|
+
maxResults: {
|
|
48153
|
+
type: "number",
|
|
48154
|
+
description: "Maximum number of time slot suggestions as integer. Default: 5."
|
|
48155
|
+
},
|
|
48156
|
+
targetUser: {
|
|
48157
|
+
type: "string",
|
|
48158
|
+
description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
|
|
48159
|
+
}
|
|
48160
|
+
},
|
|
48161
|
+
required: ["attendees", "startDateTime", "endDateTime", "duration"]
|
|
48162
|
+
}
|
|
48163
|
+
}
|
|
48164
|
+
},
|
|
48165
|
+
describeCall: (args) => {
|
|
48166
|
+
return `Find ${args.duration}min slots for ${args.attendees.length} attendees`;
|
|
48167
|
+
},
|
|
48168
|
+
permission: {
|
|
48169
|
+
scope: "session",
|
|
48170
|
+
riskLevel: "low",
|
|
48171
|
+
approvalMessage: `Find meeting time slots via ${connector.displayName}`
|
|
48172
|
+
},
|
|
48173
|
+
execute: async (args, context) => {
|
|
48174
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
48175
|
+
try {
|
|
48176
|
+
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
48177
|
+
const tz = args.timeZone ?? "UTC";
|
|
48178
|
+
const result = await microsoftFetch(
|
|
48179
|
+
connector,
|
|
48180
|
+
`${prefix}/findMeetingTimes`,
|
|
48181
|
+
{
|
|
48182
|
+
method: "POST",
|
|
48183
|
+
userId: effectiveUserId,
|
|
48184
|
+
body: {
|
|
48185
|
+
attendees: formatAttendees(args.attendees),
|
|
48186
|
+
timeConstraint: {
|
|
48187
|
+
timeslots: [
|
|
48188
|
+
{
|
|
48189
|
+
start: { dateTime: args.startDateTime, timeZone: tz },
|
|
48190
|
+
end: { dateTime: args.endDateTime, timeZone: tz }
|
|
48191
|
+
}
|
|
48192
|
+
]
|
|
48193
|
+
},
|
|
48194
|
+
meetingDuration: `PT${args.duration}M`,
|
|
48195
|
+
maxCandidates: args.maxResults ?? 5
|
|
48196
|
+
}
|
|
48197
|
+
}
|
|
48198
|
+
);
|
|
48199
|
+
const slots = (result.meetingTimeSuggestions ?? []).map((s) => ({
|
|
48200
|
+
start: s.meetingTimeSlot.start.dateTime,
|
|
48201
|
+
end: s.meetingTimeSlot.end.dateTime,
|
|
48202
|
+
confidence: String(s.confidence),
|
|
48203
|
+
attendeeAvailability: (s.attendeeAvailability ?? []).map((a) => ({
|
|
48204
|
+
attendee: a.attendee.emailAddress.address,
|
|
48205
|
+
availability: a.availability
|
|
48206
|
+
}))
|
|
48207
|
+
}));
|
|
48208
|
+
return {
|
|
48209
|
+
success: true,
|
|
48210
|
+
slots,
|
|
48211
|
+
emptySuggestionsReason: result.emptySuggestionsReason
|
|
48212
|
+
};
|
|
48213
|
+
} catch (error) {
|
|
48214
|
+
return {
|
|
48215
|
+
success: false,
|
|
48216
|
+
error: `Failed to find meeting slots: ${error instanceof Error ? error.message : String(error)}`
|
|
48217
|
+
};
|
|
48218
|
+
}
|
|
48219
|
+
}
|
|
48220
|
+
};
|
|
48221
|
+
}
|
|
48222
|
+
|
|
48223
|
+
// src/tools/microsoft/register.ts
|
|
48224
|
+
function registerMicrosoftTools() {
|
|
48225
|
+
ConnectorTools.registerService("microsoft", (connector, userId) => {
|
|
48226
|
+
return [
|
|
48227
|
+
createDraftEmailTool(connector, userId),
|
|
48228
|
+
createSendEmailTool(connector, userId),
|
|
48229
|
+
createMeetingTool(connector, userId),
|
|
48230
|
+
createEditMeetingTool(connector, userId),
|
|
48231
|
+
createGetMeetingTranscriptTool(connector, userId),
|
|
48232
|
+
createFindMeetingSlotsTool(connector, userId)
|
|
48233
|
+
];
|
|
48234
|
+
});
|
|
48235
|
+
}
|
|
48236
|
+
|
|
48237
|
+
// src/tools/microsoft/index.ts
|
|
48238
|
+
registerMicrosoftTools();
|
|
48239
|
+
|
|
46545
48240
|
// src/tools/desktop/types.ts
|
|
46546
48241
|
var DEFAULT_DESKTOP_CONFIG = {
|
|
46547
48242
|
driver: null,
|
|
@@ -48528,6 +50223,6 @@ REMEMBER: Keep it conversational, ask one question at a time, and only output th
|
|
|
48528
50223
|
}
|
|
48529
50224
|
};
|
|
48530
50225
|
|
|
48531
|
-
export { AGENT_DEFINITION_FORMAT_VERSION, AIError, APPROVAL_STATE_VERSION, Agent, AgentContextNextGen, ApproximateTokenEstimator, BaseMediaProvider, BasePluginNextGen, BaseProvider, BaseTextProvider, BraveProvider, CONNECTOR_CONFIG_VERSION, CONTEXT_SESSION_FORMAT_VERSION, CUSTOM_TOOL_DEFINITION_VERSION, CheckpointManager, CircuitBreaker, CircuitOpenError, Connector, ConnectorConfigStore, ConnectorTools, ConsoleMetrics, ContentType, ContextOverflowError, DEFAULT_ALLOWLIST, DEFAULT_BACKOFF_CONFIG, DEFAULT_BASE_DELAY_MS, DEFAULT_CHECKPOINT_STRATEGY, DEFAULT_CIRCUIT_BREAKER_CONFIG, DEFAULT_CONFIG2 as DEFAULT_CONFIG, DEFAULT_CONNECTOR_TIMEOUT, DEFAULT_CONTEXT_CONFIG, DEFAULT_DESKTOP_CONFIG, DEFAULT_FEATURES, DEFAULT_FILESYSTEM_CONFIG, DEFAULT_HISTORY_MANAGER_CONFIG, DEFAULT_MAX_DELAY_MS, DEFAULT_MAX_RETRIES, DEFAULT_MEMORY_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_RATE_LIMITER_CONFIG, DEFAULT_RETRYABLE_STATUSES, DEFAULT_SHELL_CONFIG, DESKTOP_TOOL_NAMES, DefaultCompactionStrategy, DependencyCycleError, DocumentReader, ErrorHandler, ExecutionContext, ExternalDependencyHandler, FileAgentDefinitionStorage, FileConnectorStorage, FileContextStorage, FileCustomToolStorage, FileMediaStorage as FileMediaOutputHandler, FileMediaStorage, FilePersistentInstructionsStorage, FileStorage, FileUserInfoStorage, FormatDetector, FrameworkLogger, HookManager, IMAGE_MODELS, IMAGE_MODEL_REGISTRY, ImageGeneration, InContextMemoryPluginNextGen, InMemoryAgentStateStorage, InMemoryHistoryStorage, InMemoryMetrics, InMemoryPlanStorage, InMemoryStorage, InvalidConfigError, InvalidToolArgumentsError, LLM_MODELS, LoggingPlugin, MCPClient, MCPConnectionError, MCPError, MCPProtocolError, MCPRegistry, MCPResourceError, MCPTimeoutError, MCPToolError, MEMORY_PRIORITY_VALUES, MODEL_REGISTRY, MemoryConnectorStorage, MemoryEvictionCompactor, MemoryStorage, MessageBuilder, MessageRole, ModelNotSupportedError, NoOpMetrics, NutTreeDriver, OAuthManager, ParallelTasksError, PersistentInstructionsPluginNextGen, PlanningAgent, ProviderAuthError, ProviderConfigAgent, ProviderContextLengthError, ProviderError, ProviderErrorMapper, ProviderNotFoundError, ProviderRateLimitError, RapidAPIProvider, RateLimitError, SERVICE_DEFINITIONS, SERVICE_INFO, SERVICE_URL_PATTERNS, SIMPLE_ICONS_CDN, STT_MODELS, STT_MODEL_REGISTRY, ScopedConnectorRegistry, ScrapeProvider, SearchProvider, SerperProvider, Services, SpeechToText, StorageRegistry, 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, UserInfoPluginNextGen, 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, createCustomToolDelete, createCustomToolDraft, createCustomToolList, createCustomToolLoad, createCustomToolMetaTools, createCustomToolSave, createCustomToolTest, createDesktopGetCursorTool, createDesktopGetScreenSizeTool, createDesktopKeyboardKeyTool, createDesktopKeyboardTypeTool, createDesktopMouseClickTool, createDesktopMouseDragTool, createDesktopMouseMoveTool, createDesktopMouseScrollTool, createDesktopScreenshotTool, createDesktopWindowFocusTool, createDesktopWindowListTool, createEditFileTool, createEstimator, createExecuteJavaScriptTool, createFileAgentDefinitionStorage, createFileContextStorage, createFileCustomToolStorage, createFileMediaStorage, createGetPRTool, createGitHubReadFileTool, createGlobTool, createGrepTool, createImageGenerationTool, createImageProvider, createListDirectoryTool, createMessageWithImages, createMetricsCollector, createPRCommentsTool, createPRFilesTool, createPlan, createProvider, createReadFileTool, createSearchCodeTool, createSearchFilesTool, createSpeechToTextTool, createTask, createTextMessage, createTextToSpeechTool, createVideoProvider, createVideoTools, createWriteFileTool, customToolDelete, customToolDraft, customToolList, customToolLoad, customToolSave, customToolTest, defaultDescribeCall, desktopGetCursor, desktopGetScreenSize, desktopKeyboardKey, desktopKeyboardType, desktopMouseClick, desktopMouseDrag, desktopMouseMove, desktopMouseScroll, desktopScreenshot, desktopTools, desktopWindowFocus, desktopWindowList, detectDependencyCycle, detectServiceFromURL, developerTools, documentToContent, editFile, evaluateCondition, extractJSON, extractJSONField, extractNumber, findConnectorByServiceTypes, forPlan, forTasks, generateEncryptionKey, generateSimplePlan, generateWebAPITool, getActiveImageModels, getActiveModels, getActiveSTTModels, getActiveTTSModels, getActiveVideoModels, getAllBuiltInTools, getAllServiceIds, getAllVendorLogos, getAllVendorTemplates, getBackgroundOutput, getConnectorTools, getCredentialsSetupURL, getDesktopDriver, getDocsURL, getImageModelInfo, getImageModelsByVendor, getImageModelsWithFeature, getMediaOutputHandler, getMediaStorage, getModelInfo, getModelsByVendor, getNextExecutableTasks, getRegisteredScrapeProviders, getSTTModelInfo, getSTTModelsByVendor, getSTTModelsWithFeature, getServiceDefinition, getServiceInfo, getServicesByCategory, getTTSModelInfo, getTTSModelsByVendor, getTTSModelsWithFeature, getTaskDependencies, getToolByName, getToolCallDescription, getToolCategories, getToolRegistry, getToolsByCategory, getToolsRequiringConnector, getVendorAuthTemplate, getVendorColor, getVendorDefaultBaseURL, getVendorInfo, getVendorLogo, getVendorLogoCdnUrl, getVendorLogoSvg, getVendorTemplate, getVideoModelInfo, getVideoModelsByVendor, getVideoModelsWithAudio, getVideoModelsWithFeature, glob, globalErrorHandler, grep, hasClipboardImage, hasVendorLogo, hydrateCustomTool, isBlockedCommand, isErrorEvent, isExcludedExtension, isKnownService, isOutputTextDelta, isResponseComplete, isSimpleScope, isStreamEvent, isTaskAwareScope, isTaskBlocked, isTerminalMemoryStatus, isTerminalStatus, isToolCallArgumentsDelta, isToolCallArgumentsDone, isToolCallStart, isVendor, killBackgroundProcess, listConnectorsByServiceTypes, listDirectory, listVendorIds, listVendors, listVendorsByAuthType, listVendorsByCategory, listVendorsWithLogos, logger, mergeTextPieces, metrics, parseKeyCombo, parseRepository, readClipboardImage, readDocumentAsContent, readFile5 as readFile, registerScrapeProvider, resetDefaultDriver, resolveConnector, resolveDependencies, resolveMaxContextTokens, resolveModelCapabilities, resolveRepository, retryWithBackoff, sanitizeToolName, scopeEquals, scopeMatches, setMediaOutputHandler, setMediaStorage, setMetricsCollector, simpleTokenEstimator, toConnectorOptions, toolRegistry, tools_exports as tools, updateTaskStatus, validatePath, writeFile5 as writeFile };
|
|
50226
|
+
export { AGENT_DEFINITION_FORMAT_VERSION, AIError, APPROVAL_STATE_VERSION, Agent, AgentContextNextGen, ApproximateTokenEstimator, BaseMediaProvider, BasePluginNextGen, BaseProvider, BaseTextProvider, BraveProvider, CONNECTOR_CONFIG_VERSION, CONTEXT_SESSION_FORMAT_VERSION, CUSTOM_TOOL_DEFINITION_VERSION, CheckpointManager, CircuitBreaker, CircuitOpenError, Connector, ConnectorConfigStore, ConnectorTools, ConsoleMetrics, ContentType, ContextOverflowError, DEFAULT_ALLOWLIST, DEFAULT_BACKOFF_CONFIG, DEFAULT_BASE_DELAY_MS, DEFAULT_CHECKPOINT_STRATEGY, DEFAULT_CIRCUIT_BREAKER_CONFIG, DEFAULT_CONFIG2 as DEFAULT_CONFIG, DEFAULT_CONNECTOR_TIMEOUT, DEFAULT_CONTEXT_CONFIG, DEFAULT_DESKTOP_CONFIG, DEFAULT_FEATURES, DEFAULT_FILESYSTEM_CONFIG, DEFAULT_HISTORY_MANAGER_CONFIG, DEFAULT_MAX_DELAY_MS, DEFAULT_MAX_RETRIES, DEFAULT_MEMORY_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_RATE_LIMITER_CONFIG, DEFAULT_RETRYABLE_STATUSES, DEFAULT_SHELL_CONFIG, DESKTOP_TOOL_NAMES, DefaultCompactionStrategy, DependencyCycleError, DocumentReader, ErrorHandler, ExecutionContext, ExternalDependencyHandler, FileAgentDefinitionStorage, FileConnectorStorage, FileContextStorage, FileCustomToolStorage, FileMediaStorage as FileMediaOutputHandler, FileMediaStorage, FilePersistentInstructionsStorage, FileRoutineDefinitionStorage, FileStorage, FileUserInfoStorage, FormatDetector, FrameworkLogger, HookManager, IMAGE_MODELS, IMAGE_MODEL_REGISTRY, ImageGeneration, InContextMemoryPluginNextGen, InMemoryAgentStateStorage, InMemoryHistoryStorage, InMemoryMetrics, InMemoryPlanStorage, InMemoryStorage, InvalidConfigError, InvalidToolArgumentsError, LLM_MODELS, LoggingPlugin, MCPClient, MCPConnectionError, MCPError, MCPProtocolError, MCPRegistry, MCPResourceError, MCPTimeoutError, MCPToolError, MEMORY_PRIORITY_VALUES, MODEL_REGISTRY, MemoryConnectorStorage, MemoryEvictionCompactor, MemoryStorage, MessageBuilder, MessageRole, ModelNotSupportedError, NoOpMetrics, NutTreeDriver, OAuthManager, ParallelTasksError, PersistentInstructionsPluginNextGen, PlanningAgent, ProviderAuthError, ProviderConfigAgent, ProviderContextLengthError, ProviderError, ProviderErrorMapper, ProviderNotFoundError, ProviderRateLimitError, RapidAPIProvider, RateLimitError, SERVICE_DEFINITIONS, SERVICE_INFO, SERVICE_URL_PATTERNS, SIMPLE_ICONS_CDN, STT_MODELS, STT_MODEL_REGISTRY, ScopedConnectorRegistry, ScrapeProvider, SearchProvider, SerperProvider, Services, SpeechToText, StorageRegistry, 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, UserInfoPluginNextGen, 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, createCustomToolDelete, createCustomToolDraft, createCustomToolList, createCustomToolLoad, createCustomToolMetaTools, createCustomToolSave, createCustomToolTest, createDesktopGetCursorTool, createDesktopGetScreenSizeTool, createDesktopKeyboardKeyTool, createDesktopKeyboardTypeTool, createDesktopMouseClickTool, createDesktopMouseDragTool, createDesktopMouseMoveTool, createDesktopMouseScrollTool, createDesktopScreenshotTool, createDesktopWindowFocusTool, createDesktopWindowListTool, createDraftEmailTool, createEditFileTool, createEditMeetingTool, createEstimator, createExecuteJavaScriptTool, createFileAgentDefinitionStorage, createFileContextStorage, createFileCustomToolStorage, createFileMediaStorage, createFileRoutineDefinitionStorage, createFindMeetingSlotsTool, createGetMeetingTranscriptTool, createGetPRTool, createGitHubReadFileTool, createGlobTool, createGrepTool, createImageGenerationTool, createImageProvider, createListDirectoryTool, createMeetingTool, createMessageWithImages, createMetricsCollector, createPRCommentsTool, createPRFilesTool, createPlan, createProvider, createReadFileTool, createRoutineDefinition, createRoutineExecution, createSearchCodeTool, createSearchFilesTool, createSendEmailTool, createSpeechToTextTool, createTask, createTextMessage, createTextToSpeechTool, createVideoProvider, createVideoTools, createWriteFileTool, customToolDelete, customToolDraft, customToolList, customToolLoad, customToolSave, customToolTest, defaultDescribeCall, desktopGetCursor, desktopGetScreenSize, desktopKeyboardKey, desktopKeyboardType, desktopMouseClick, desktopMouseDrag, desktopMouseMove, desktopMouseScroll, desktopScreenshot, desktopTools, desktopWindowFocus, desktopWindowList, detectDependencyCycle, detectServiceFromURL, developerTools, documentToContent, editFile, evaluateCondition, executeRoutine, extractJSON, extractJSONField, extractNumber, findConnectorByServiceTypes, forPlan, forTasks, formatAttendees, formatRecipients, generateEncryptionKey, generateSimplePlan, generateWebAPITool, getActiveImageModels, getActiveModels, getActiveSTTModels, getActiveTTSModels, getActiveVideoModels, getAllBuiltInTools, getAllServiceIds, getAllVendorLogos, getAllVendorTemplates, getBackgroundOutput, getConnectorTools, getCredentialsSetupURL, getDesktopDriver, getDocsURL, getImageModelInfo, getImageModelsByVendor, getImageModelsWithFeature, getMediaOutputHandler, getMediaStorage, getModelInfo, getModelsByVendor, getNextExecutableTasks, getRegisteredScrapeProviders, getRoutineProgress, getSTTModelInfo, getSTTModelsByVendor, getSTTModelsWithFeature, getServiceDefinition, getServiceInfo, getServicesByCategory, getTTSModelInfo, getTTSModelsByVendor, getTTSModelsWithFeature, getTaskDependencies, getToolByName, getToolCallDescription, getToolCategories, getToolRegistry, getToolsByCategory, getToolsRequiringConnector, getUserPathPrefix, getVendorAuthTemplate, getVendorColor, getVendorDefaultBaseURL, getVendorInfo, getVendorLogo, getVendorLogoCdnUrl, getVendorLogoSvg, getVendorTemplate, getVideoModelInfo, getVideoModelsByVendor, getVideoModelsWithAudio, getVideoModelsWithFeature, glob, globalErrorHandler, grep, hasClipboardImage, hasVendorLogo, hydrateCustomTool, isBlockedCommand, isErrorEvent, isExcludedExtension, isKnownService, isOutputTextDelta, isResponseComplete, isSimpleScope, isStreamEvent, isTaskAwareScope, isTaskBlocked, isTeamsMeetingUrl, isTerminalMemoryStatus, isTerminalStatus, isToolCallArgumentsDelta, isToolCallArgumentsDone, isToolCallStart, isVendor, killBackgroundProcess, listConnectorsByServiceTypes, listDirectory, listVendorIds, listVendors, listVendorsByAuthType, listVendorsByCategory, listVendorsWithLogos, logger, mergeTextPieces, metrics, microsoftFetch, normalizeEmails, parseKeyCombo, parseRepository, readClipboardImage, readDocumentAsContent, readFile5 as readFile, registerScrapeProvider, resetDefaultDriver, resolveConnector, resolveDependencies, resolveMaxContextTokens, resolveMeetingId, resolveModelCapabilities, resolveRepository, retryWithBackoff, sanitizeToolName, scopeEquals, scopeMatches, setMediaOutputHandler, setMediaStorage, setMetricsCollector, simpleTokenEstimator, toConnectorOptions, toolRegistry, tools_exports as tools, updateTaskStatus, validatePath, writeFile5 as writeFile };
|
|
48532
50227
|
//# sourceMappingURL=index.js.map
|
|
48533
50228
|
//# sourceMappingURL=index.js.map
|