@everworker/oneringai 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +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 +2148 -566
- 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 +2054 -491
- 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 });
|
|
@@ -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,874 @@ 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
|
+
parts.push("After completing the work, store key results in memory once, then respond with a text summary (no more tool calls).");
|
|
23903
|
+
return parts.join("\n");
|
|
23904
|
+
}
|
|
23905
|
+
function defaultValidationPrompt(task, context) {
|
|
23906
|
+
const criteria = task.validation?.completionCriteria ?? [];
|
|
23907
|
+
const criteriaList = criteria.length > 0 ? criteria.map((c, i) => `${i + 1}. ${c}`).join("\n") : "The task was completed as described.";
|
|
23908
|
+
const parts = [
|
|
23909
|
+
`Evaluate if the task "${task.name}" was completed successfully.`,
|
|
23910
|
+
"",
|
|
23911
|
+
`Task description: ${task.description}`,
|
|
23912
|
+
"",
|
|
23913
|
+
"Completion criteria:",
|
|
23914
|
+
criteriaList,
|
|
23915
|
+
"",
|
|
23916
|
+
"--- EVIDENCE ---",
|
|
23917
|
+
"",
|
|
23918
|
+
"Agent response (final text output):",
|
|
23919
|
+
context.responseText || "(no text output)",
|
|
23920
|
+
"",
|
|
23921
|
+
"Tool calls made during this task:",
|
|
23922
|
+
context.toolCallLog
|
|
23923
|
+
];
|
|
23924
|
+
if (context.inContextMemory) {
|
|
23925
|
+
parts.push("", "In-context memory (current state):", context.inContextMemory);
|
|
23926
|
+
}
|
|
23927
|
+
if (context.workingMemoryIndex) {
|
|
23928
|
+
parts.push("", "Working memory index (stored data):", context.workingMemoryIndex);
|
|
23929
|
+
}
|
|
23930
|
+
parts.push(
|
|
23931
|
+
"",
|
|
23932
|
+
"--- END EVIDENCE ---",
|
|
23933
|
+
"",
|
|
23934
|
+
"Use the evidence above to verify each criterion. Check tool call results, not just the agent's claims.",
|
|
23935
|
+
"",
|
|
23936
|
+
"Return a JSON object with the following structure:",
|
|
23937
|
+
"```json",
|
|
23938
|
+
'{ "isComplete": boolean, "completionScore": number (0-100), "explanation": "..." }',
|
|
23939
|
+
"```",
|
|
23940
|
+
"",
|
|
23941
|
+
"Be strict: only mark isComplete=true if all criteria are clearly met based on the evidence."
|
|
23942
|
+
);
|
|
23943
|
+
return parts.join("\n");
|
|
23944
|
+
}
|
|
23945
|
+
function formatToolCallLog(conversation) {
|
|
23946
|
+
const calls = [];
|
|
23947
|
+
for (const item of conversation) {
|
|
23948
|
+
if (!("content" in item) || !Array.isArray(item.content)) continue;
|
|
23949
|
+
const msg = item;
|
|
23950
|
+
for (const c of msg.content) {
|
|
23951
|
+
if (c.type === "tool_use" /* TOOL_USE */) {
|
|
23952
|
+
let argsStr;
|
|
23953
|
+
try {
|
|
23954
|
+
const parsed = JSON.parse(c.arguments);
|
|
23955
|
+
argsStr = JSON.stringify(parsed, null, 2);
|
|
23956
|
+
if (argsStr.length > 500) argsStr = argsStr.slice(0, 500) + "... (truncated)";
|
|
23957
|
+
} catch {
|
|
23958
|
+
argsStr = c.arguments;
|
|
23959
|
+
}
|
|
23960
|
+
calls.push(`CALL: ${c.name}(${argsStr})`);
|
|
23961
|
+
} else if (c.type === "tool_result" /* TOOL_RESULT */) {
|
|
23962
|
+
let resultStr = typeof c.content === "string" ? c.content : JSON.stringify(c.content);
|
|
23963
|
+
if (resultStr.length > 500) resultStr = resultStr.slice(0, 500) + "... (truncated)";
|
|
23964
|
+
const prefix = c.error ? "ERROR" : "RESULT";
|
|
23965
|
+
calls.push(` ${prefix}: ${resultStr}`);
|
|
23966
|
+
}
|
|
23967
|
+
}
|
|
23968
|
+
}
|
|
23969
|
+
return calls.length > 0 ? calls.join("\n") : "(no tool calls)";
|
|
23970
|
+
}
|
|
23971
|
+
async function collectValidationContext(agent, responseText) {
|
|
23972
|
+
const icmPlugin = agent.context.getPlugin("in_context_memory");
|
|
23973
|
+
const inContextMemory = icmPlugin ? await icmPlugin.getContent() : null;
|
|
23974
|
+
const wmPlugin = agent.context.memory;
|
|
23975
|
+
const workingMemoryIndex = wmPlugin ? await wmPlugin.getContent() : null;
|
|
23976
|
+
const conversation = agent.context.getConversation();
|
|
23977
|
+
const toolCallLog = formatToolCallLog(conversation);
|
|
23978
|
+
return {
|
|
23979
|
+
responseText,
|
|
23980
|
+
inContextMemory,
|
|
23981
|
+
workingMemoryIndex,
|
|
23982
|
+
toolCallLog
|
|
23983
|
+
};
|
|
23984
|
+
}
|
|
23985
|
+
async function validateTaskCompletion(agent, task, responseText, validationPromptBuilder) {
|
|
23986
|
+
const hasExplicitValidation = task.validation?.skipReflection === false && task.validation?.completionCriteria && task.validation.completionCriteria.length > 0;
|
|
23987
|
+
if (!hasExplicitValidation) {
|
|
23988
|
+
return {
|
|
23989
|
+
isComplete: true,
|
|
23990
|
+
completionScore: 100,
|
|
23991
|
+
explanation: "Auto-passed (LLM validation not enabled)",
|
|
23992
|
+
requiresUserApproval: false
|
|
23993
|
+
};
|
|
23994
|
+
}
|
|
23995
|
+
const validationContext = await collectValidationContext(agent, responseText);
|
|
23996
|
+
const prompt = validationPromptBuilder(task, validationContext);
|
|
23997
|
+
const response = await agent.runDirect(prompt, {
|
|
23998
|
+
instructions: "You are a task completion evaluator. Return only JSON.",
|
|
23999
|
+
temperature: 0.1
|
|
24000
|
+
});
|
|
24001
|
+
const text = response.output_text ?? "";
|
|
24002
|
+
const extracted = extractJSON(text);
|
|
24003
|
+
if (!extracted.success || !extracted.data) {
|
|
24004
|
+
return {
|
|
24005
|
+
isComplete: false,
|
|
24006
|
+
completionScore: 0,
|
|
24007
|
+
explanation: `Failed to parse validation response: ${extracted.error ?? "unknown error"}`,
|
|
24008
|
+
requiresUserApproval: false
|
|
24009
|
+
};
|
|
24010
|
+
}
|
|
24011
|
+
const { isComplete, completionScore, explanation } = extracted.data;
|
|
24012
|
+
const minScore = task.validation?.minCompletionScore ?? 80;
|
|
24013
|
+
return {
|
|
24014
|
+
isComplete: isComplete && completionScore >= minScore,
|
|
24015
|
+
completionScore,
|
|
24016
|
+
explanation,
|
|
24017
|
+
requiresUserApproval: false
|
|
24018
|
+
};
|
|
24019
|
+
}
|
|
24020
|
+
async function executeRoutine(options) {
|
|
24021
|
+
const {
|
|
24022
|
+
definition,
|
|
24023
|
+
agent: existingAgent,
|
|
24024
|
+
connector,
|
|
24025
|
+
model,
|
|
24026
|
+
tools: extraTools,
|
|
24027
|
+
onTaskStarted,
|
|
24028
|
+
onTaskComplete,
|
|
24029
|
+
onTaskFailed,
|
|
24030
|
+
onTaskValidation,
|
|
24031
|
+
hooks,
|
|
24032
|
+
prompts
|
|
24033
|
+
} = options;
|
|
24034
|
+
if (!existingAgent && (!connector || !model)) {
|
|
24035
|
+
throw new Error("executeRoutine requires either `agent` or both `connector` and `model`");
|
|
24036
|
+
}
|
|
24037
|
+
const ownsAgent = !existingAgent;
|
|
24038
|
+
const log = logger.child({ routine: definition.name });
|
|
24039
|
+
const execution = createRoutineExecution(definition);
|
|
24040
|
+
execution.status = "running";
|
|
24041
|
+
execution.startedAt = Date.now();
|
|
24042
|
+
execution.lastUpdatedAt = Date.now();
|
|
24043
|
+
const buildSystemPrompt = prompts?.system ?? defaultSystemPrompt;
|
|
24044
|
+
const buildTaskPrompt = prompts?.task ?? defaultTaskPrompt;
|
|
24045
|
+
const buildValidationPrompt = prompts?.validation ?? defaultValidationPrompt;
|
|
24046
|
+
let agent;
|
|
24047
|
+
const registeredHooks = [];
|
|
24048
|
+
if (existingAgent) {
|
|
24049
|
+
agent = existingAgent;
|
|
24050
|
+
if (hooks) {
|
|
24051
|
+
const hookNames = [
|
|
24052
|
+
"before:execution",
|
|
24053
|
+
"after:execution",
|
|
24054
|
+
"before:llm",
|
|
24055
|
+
"after:llm",
|
|
24056
|
+
"before:tool",
|
|
24057
|
+
"after:tool",
|
|
24058
|
+
"approve:tool",
|
|
24059
|
+
"pause:check"
|
|
24060
|
+
];
|
|
24061
|
+
for (const name of hookNames) {
|
|
24062
|
+
const hook = hooks[name];
|
|
24063
|
+
if (hook) {
|
|
24064
|
+
agent.registerHook(name, hook);
|
|
24065
|
+
registeredHooks.push({ name, hook });
|
|
24066
|
+
}
|
|
24067
|
+
}
|
|
24068
|
+
}
|
|
24069
|
+
} else {
|
|
24070
|
+
const allTools = [...extraTools ?? []];
|
|
24071
|
+
if (definition.requiredTools && definition.requiredTools.length > 0) {
|
|
24072
|
+
const availableToolNames = new Set(allTools.map((t) => t.definition.function.name));
|
|
24073
|
+
const missing = definition.requiredTools.filter((name) => !availableToolNames.has(name));
|
|
24074
|
+
if (missing.length > 0) {
|
|
24075
|
+
execution.status = "failed";
|
|
24076
|
+
execution.error = `Missing required tools: ${missing.join(", ")}`;
|
|
24077
|
+
execution.completedAt = Date.now();
|
|
24078
|
+
execution.lastUpdatedAt = Date.now();
|
|
24079
|
+
return execution;
|
|
24080
|
+
}
|
|
24081
|
+
}
|
|
24082
|
+
agent = Agent.create({
|
|
24083
|
+
connector,
|
|
24084
|
+
model,
|
|
24085
|
+
tools: allTools,
|
|
24086
|
+
instructions: buildSystemPrompt(definition),
|
|
24087
|
+
hooks,
|
|
24088
|
+
context: {
|
|
24089
|
+
model,
|
|
24090
|
+
features: {
|
|
24091
|
+
workingMemory: true,
|
|
24092
|
+
inContextMemory: true
|
|
24093
|
+
}
|
|
24094
|
+
}
|
|
24095
|
+
});
|
|
24096
|
+
}
|
|
24097
|
+
if (definition.requiredPlugins && definition.requiredPlugins.length > 0) {
|
|
24098
|
+
const missing = definition.requiredPlugins.filter(
|
|
24099
|
+
(name) => !agent.context.hasPlugin(name)
|
|
24100
|
+
);
|
|
24101
|
+
if (missing.length > 0) {
|
|
24102
|
+
if (ownsAgent) agent.destroy();
|
|
24103
|
+
execution.status = "failed";
|
|
24104
|
+
execution.error = `Missing required plugins: ${missing.join(", ")}`;
|
|
24105
|
+
execution.completedAt = Date.now();
|
|
24106
|
+
execution.lastUpdatedAt = Date.now();
|
|
24107
|
+
return execution;
|
|
24108
|
+
}
|
|
24109
|
+
}
|
|
24110
|
+
const failureMode = definition.concurrency?.failureMode ?? "fail-fast";
|
|
24111
|
+
try {
|
|
24112
|
+
let nextTasks = getNextExecutableTasks(execution.plan);
|
|
24113
|
+
while (nextTasks.length > 0) {
|
|
24114
|
+
const task = nextTasks[0];
|
|
24115
|
+
const taskIndex = execution.plan.tasks.findIndex((t) => t.id === task.id);
|
|
24116
|
+
log.info({ taskName: task.name, taskId: task.id }, "Starting task");
|
|
24117
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(task, "in_progress");
|
|
24118
|
+
execution.lastUpdatedAt = Date.now();
|
|
24119
|
+
onTaskStarted?.(execution.plan.tasks[taskIndex], execution);
|
|
24120
|
+
let taskCompleted = false;
|
|
24121
|
+
const maxTaskIterations = task.execution?.maxIterations ?? 15;
|
|
24122
|
+
const iterationLimiter = async (ctx) => {
|
|
24123
|
+
if (ctx.iteration >= maxTaskIterations) {
|
|
24124
|
+
agent.cancel(`Task "${task.name}" exceeded max iterations (${maxTaskIterations})`);
|
|
24125
|
+
}
|
|
24126
|
+
return { shouldPause: false };
|
|
24127
|
+
};
|
|
24128
|
+
agent.registerHook("pause:check", iterationLimiter);
|
|
24129
|
+
const getTask = () => execution.plan.tasks[taskIndex];
|
|
24130
|
+
while (!taskCompleted) {
|
|
24131
|
+
try {
|
|
24132
|
+
const taskPrompt = buildTaskPrompt(getTask());
|
|
24133
|
+
const response = await agent.run(taskPrompt);
|
|
24134
|
+
const responseText = response.output_text ?? "";
|
|
24135
|
+
const validationResult = await validateTaskCompletion(
|
|
24136
|
+
agent,
|
|
24137
|
+
getTask(),
|
|
24138
|
+
responseText,
|
|
24139
|
+
buildValidationPrompt
|
|
24140
|
+
);
|
|
24141
|
+
onTaskValidation?.(getTask(), validationResult, execution);
|
|
24142
|
+
if (validationResult.isComplete) {
|
|
24143
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "completed");
|
|
24144
|
+
execution.plan.tasks[taskIndex].result = {
|
|
24145
|
+
success: true,
|
|
24146
|
+
output: responseText,
|
|
24147
|
+
validationScore: validationResult.completionScore,
|
|
24148
|
+
validationExplanation: validationResult.explanation
|
|
24149
|
+
};
|
|
24150
|
+
taskCompleted = true;
|
|
24151
|
+
log.info(
|
|
24152
|
+
{ taskName: getTask().name, score: validationResult.completionScore },
|
|
24153
|
+
"Task completed"
|
|
24154
|
+
);
|
|
24155
|
+
execution.progress = getRoutineProgress(execution);
|
|
24156
|
+
execution.lastUpdatedAt = Date.now();
|
|
24157
|
+
onTaskComplete?.(execution.plan.tasks[taskIndex], execution);
|
|
24158
|
+
} else {
|
|
24159
|
+
log.warn(
|
|
24160
|
+
{
|
|
24161
|
+
taskName: getTask().name,
|
|
24162
|
+
score: validationResult.completionScore,
|
|
24163
|
+
attempt: getTask().attempts,
|
|
24164
|
+
maxAttempts: getTask().maxAttempts
|
|
24165
|
+
},
|
|
24166
|
+
"Task validation failed"
|
|
24167
|
+
);
|
|
24168
|
+
if (getTask().attempts >= getTask().maxAttempts) {
|
|
24169
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
|
|
24170
|
+
execution.plan.tasks[taskIndex].result = {
|
|
24171
|
+
success: false,
|
|
24172
|
+
error: validationResult.explanation,
|
|
24173
|
+
validationScore: validationResult.completionScore,
|
|
24174
|
+
validationExplanation: validationResult.explanation
|
|
24175
|
+
};
|
|
24176
|
+
break;
|
|
24177
|
+
}
|
|
24178
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
|
|
24179
|
+
}
|
|
24180
|
+
} catch (error) {
|
|
24181
|
+
const errorMessage = error.message;
|
|
24182
|
+
log.error({ taskName: getTask().name, error: errorMessage }, "Task execution error");
|
|
24183
|
+
if (getTask().attempts >= getTask().maxAttempts) {
|
|
24184
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
|
|
24185
|
+
execution.plan.tasks[taskIndex].result = {
|
|
24186
|
+
success: false,
|
|
24187
|
+
error: errorMessage
|
|
24188
|
+
};
|
|
24189
|
+
break;
|
|
24190
|
+
}
|
|
24191
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
|
|
24192
|
+
}
|
|
24193
|
+
}
|
|
24194
|
+
if (!taskCompleted) {
|
|
24195
|
+
execution.progress = getRoutineProgress(execution);
|
|
24196
|
+
execution.lastUpdatedAt = Date.now();
|
|
24197
|
+
onTaskFailed?.(execution.plan.tasks[taskIndex], execution);
|
|
24198
|
+
if (failureMode === "fail-fast") {
|
|
24199
|
+
execution.status = "failed";
|
|
24200
|
+
execution.error = `Task "${getTask().name}" failed after ${getTask().attempts} attempt(s)`;
|
|
24201
|
+
execution.completedAt = Date.now();
|
|
24202
|
+
execution.lastUpdatedAt = Date.now();
|
|
24203
|
+
break;
|
|
24204
|
+
}
|
|
24205
|
+
}
|
|
24206
|
+
agent.unregisterHook("pause:check", iterationLimiter);
|
|
24207
|
+
agent.clearConversation("task-boundary");
|
|
24208
|
+
nextTasks = getNextExecutableTasks(execution.plan);
|
|
24209
|
+
}
|
|
24210
|
+
if (execution.status === "running") {
|
|
24211
|
+
const allTerminal = execution.plan.tasks.every((t) => isTerminalStatus(t.status));
|
|
24212
|
+
const allCompleted = execution.plan.tasks.every((t) => t.status === "completed");
|
|
24213
|
+
if (allCompleted) {
|
|
24214
|
+
execution.status = "completed";
|
|
24215
|
+
} else if (allTerminal) {
|
|
24216
|
+
execution.status = "failed";
|
|
24217
|
+
execution.error = "Not all tasks completed successfully";
|
|
24218
|
+
} else {
|
|
24219
|
+
execution.status = "failed";
|
|
24220
|
+
execution.error = "Execution stalled: remaining tasks are blocked by incomplete dependencies";
|
|
24221
|
+
}
|
|
24222
|
+
execution.completedAt = Date.now();
|
|
24223
|
+
execution.lastUpdatedAt = Date.now();
|
|
24224
|
+
execution.progress = getRoutineProgress(execution);
|
|
24225
|
+
}
|
|
24226
|
+
log.info(
|
|
24227
|
+
{ status: execution.status, progress: execution.progress },
|
|
24228
|
+
"Routine execution finished"
|
|
24229
|
+
);
|
|
24230
|
+
return execution;
|
|
24231
|
+
} finally {
|
|
24232
|
+
for (const { name, hook } of registeredHooks) {
|
|
24233
|
+
try {
|
|
24234
|
+
agent.unregisterHook(name, hook);
|
|
24235
|
+
} catch {
|
|
24236
|
+
}
|
|
24237
|
+
}
|
|
24238
|
+
if (ownsAgent) {
|
|
24239
|
+
agent.destroy();
|
|
24240
|
+
}
|
|
24241
|
+
}
|
|
24242
|
+
}
|
|
24243
|
+
|
|
23337
24244
|
// src/core/index.ts
|
|
23338
24245
|
init_constants();
|
|
23339
24246
|
(class {
|
|
@@ -23371,8 +24278,8 @@ init_constants();
|
|
|
23371
24278
|
throw new Error("Configuration file not found. Searched: " + this.DEFAULT_PATHS.join(", "));
|
|
23372
24279
|
}
|
|
23373
24280
|
try {
|
|
23374
|
-
const
|
|
23375
|
-
const content =
|
|
24281
|
+
const fs20 = __require("fs");
|
|
24282
|
+
const content = fs20.readFileSync(configPath, "utf-8");
|
|
23376
24283
|
let config = JSON.parse(content);
|
|
23377
24284
|
config = this.interpolateEnvVars(config);
|
|
23378
24285
|
this.validate(config);
|
|
@@ -23401,10 +24308,10 @@ init_constants();
|
|
|
23401
24308
|
* Find configuration file synchronously
|
|
23402
24309
|
*/
|
|
23403
24310
|
static findConfigSync() {
|
|
23404
|
-
const
|
|
24311
|
+
const fs20 = __require("fs");
|
|
23405
24312
|
for (const path6 of this.DEFAULT_PATHS) {
|
|
23406
24313
|
try {
|
|
23407
|
-
|
|
24314
|
+
fs20.accessSync(resolve(path6));
|
|
23408
24315
|
return resolve(path6);
|
|
23409
24316
|
} catch {
|
|
23410
24317
|
}
|
|
@@ -29583,7 +30490,7 @@ var OpenAISTTProvider = class extends BaseMediaProvider {
|
|
|
29583
30490
|
if (Buffer.isBuffer(audio)) {
|
|
29584
30491
|
return new File([new Uint8Array(audio)], "audio.wav", { type: "audio/wav" });
|
|
29585
30492
|
} else if (typeof audio === "string") {
|
|
29586
|
-
return
|
|
30493
|
+
return fs19.createReadStream(audio);
|
|
29587
30494
|
} else {
|
|
29588
30495
|
throw new Error("Invalid audio input: must be Buffer or file path");
|
|
29589
30496
|
}
|
|
@@ -30136,7 +31043,7 @@ var TextToSpeech = class _TextToSpeech {
|
|
|
30136
31043
|
*/
|
|
30137
31044
|
async toFile(text, filePath, options) {
|
|
30138
31045
|
const response = await this.synthesize(text, options);
|
|
30139
|
-
await
|
|
31046
|
+
await fs18.writeFile(filePath, response.audio);
|
|
30140
31047
|
}
|
|
30141
31048
|
// ======================== Introspection Methods ========================
|
|
30142
31049
|
/**
|
|
@@ -30484,7 +31391,7 @@ var SpeechToText = class _SpeechToText {
|
|
|
30484
31391
|
* @param options - Optional transcription parameters
|
|
30485
31392
|
*/
|
|
30486
31393
|
async transcribeFile(filePath, options) {
|
|
30487
|
-
const audio = await
|
|
31394
|
+
const audio = await fs18.readFile(filePath);
|
|
30488
31395
|
return this.transcribe(audio, options);
|
|
30489
31396
|
}
|
|
30490
31397
|
/**
|
|
@@ -30810,7 +31717,7 @@ var OpenAIImageProvider = class extends BaseMediaProvider {
|
|
|
30810
31717
|
if (Buffer.isBuffer(image)) {
|
|
30811
31718
|
return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
|
|
30812
31719
|
}
|
|
30813
|
-
return
|
|
31720
|
+
return fs19.createReadStream(image);
|
|
30814
31721
|
}
|
|
30815
31722
|
/**
|
|
30816
31723
|
* Handle OpenAI API errors
|
|
@@ -30957,8 +31864,8 @@ var GoogleImageProvider = class extends BaseMediaProvider {
|
|
|
30957
31864
|
if (Buffer.isBuffer(image)) {
|
|
30958
31865
|
imageBytes = image.toString("base64");
|
|
30959
31866
|
} else {
|
|
30960
|
-
const
|
|
30961
|
-
const buffer =
|
|
31867
|
+
const fs20 = await import('fs');
|
|
31868
|
+
const buffer = fs20.readFileSync(image);
|
|
30962
31869
|
imageBytes = buffer.toString("base64");
|
|
30963
31870
|
}
|
|
30964
31871
|
return {
|
|
@@ -31119,7 +32026,7 @@ var GrokImageProvider = class extends BaseMediaProvider {
|
|
|
31119
32026
|
if (Buffer.isBuffer(image)) {
|
|
31120
32027
|
return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
|
|
31121
32028
|
}
|
|
31122
|
-
return
|
|
32029
|
+
return fs19.createReadStream(image);
|
|
31123
32030
|
}
|
|
31124
32031
|
/**
|
|
31125
32032
|
* Handle API errors
|
|
@@ -32569,8 +33476,8 @@ var OpenAISoraProvider = class extends BaseMediaProvider {
|
|
|
32569
33476
|
return new File([new Uint8Array(image)], "input.png", { type: "image/png" });
|
|
32570
33477
|
}
|
|
32571
33478
|
if (!image.startsWith("http")) {
|
|
32572
|
-
const
|
|
32573
|
-
const data =
|
|
33479
|
+
const fs20 = await import('fs');
|
|
33480
|
+
const data = fs20.readFileSync(image);
|
|
32574
33481
|
return new File([new Uint8Array(data)], "input.png", { type: "image/png" });
|
|
32575
33482
|
}
|
|
32576
33483
|
const response = await fetch(image);
|
|
@@ -32748,7 +33655,7 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
|
|
|
32748
33655
|
if (video.videoBytes) {
|
|
32749
33656
|
buffer = Buffer.from(video.videoBytes, "base64");
|
|
32750
33657
|
} else if (video.uri) {
|
|
32751
|
-
const
|
|
33658
|
+
const fs20 = await import('fs/promises');
|
|
32752
33659
|
const os3 = await import('os');
|
|
32753
33660
|
const path6 = await import('path');
|
|
32754
33661
|
const tempDir = os3.tmpdir();
|
|
@@ -32759,11 +33666,11 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
|
|
|
32759
33666
|
// Pass as GeneratedVideo
|
|
32760
33667
|
downloadPath: tempFile
|
|
32761
33668
|
});
|
|
32762
|
-
buffer = await
|
|
32763
|
-
await
|
|
33669
|
+
buffer = await fs20.readFile(tempFile);
|
|
33670
|
+
await fs20.unlink(tempFile).catch(() => {
|
|
32764
33671
|
});
|
|
32765
33672
|
} catch (downloadError) {
|
|
32766
|
-
await
|
|
33673
|
+
await fs20.unlink(tempFile).catch(() => {
|
|
32767
33674
|
});
|
|
32768
33675
|
throw new ProviderError(
|
|
32769
33676
|
"google",
|
|
@@ -32885,8 +33792,8 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
|
|
|
32885
33792
|
if (image.startsWith("http://") || image.startsWith("https://")) {
|
|
32886
33793
|
return { imageUri: image };
|
|
32887
33794
|
}
|
|
32888
|
-
const
|
|
32889
|
-
const data = await
|
|
33795
|
+
const fs20 = await import('fs/promises');
|
|
33796
|
+
const data = await fs20.readFile(image);
|
|
32890
33797
|
return {
|
|
32891
33798
|
imageBytes: data.toString("base64")
|
|
32892
33799
|
};
|
|
@@ -33193,8 +34100,8 @@ var GrokImagineProvider = class extends BaseMediaProvider {
|
|
|
33193
34100
|
if (image.startsWith("http") || image.startsWith("data:")) {
|
|
33194
34101
|
return image;
|
|
33195
34102
|
}
|
|
33196
|
-
const
|
|
33197
|
-
const data =
|
|
34103
|
+
const fs20 = await import('fs');
|
|
34104
|
+
const data = fs20.readFileSync(image);
|
|
33198
34105
|
const base64 = data.toString("base64");
|
|
33199
34106
|
const ext = image.split(".").pop()?.toLowerCase() || "png";
|
|
33200
34107
|
const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext}`;
|
|
@@ -35863,245 +36770,6 @@ var CheckpointManager = class {
|
|
|
35863
36770
|
}
|
|
35864
36771
|
};
|
|
35865
36772
|
|
|
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
36773
|
// src/capabilities/taskAgent/PlanningAgent.ts
|
|
36106
36774
|
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
36775
|
|
|
@@ -37466,10 +38134,10 @@ var FileMediaStorage = class {
|
|
|
37466
38134
|
}
|
|
37467
38135
|
async save(data, metadata) {
|
|
37468
38136
|
const dir = metadata.userId ? path2.join(this.outputDir, metadata.userId) : this.outputDir;
|
|
37469
|
-
await
|
|
38137
|
+
await fs18.mkdir(dir, { recursive: true });
|
|
37470
38138
|
const filename = metadata.suggestedFilename ?? this.generateFilename(metadata);
|
|
37471
38139
|
const filePath = path2.join(dir, filename);
|
|
37472
|
-
await
|
|
38140
|
+
await fs18.writeFile(filePath, data);
|
|
37473
38141
|
const format = metadata.format.toLowerCase();
|
|
37474
38142
|
const mimeType = MIME_TYPES2[format] ?? "application/octet-stream";
|
|
37475
38143
|
return {
|
|
@@ -37480,7 +38148,7 @@ var FileMediaStorage = class {
|
|
|
37480
38148
|
}
|
|
37481
38149
|
async read(location) {
|
|
37482
38150
|
try {
|
|
37483
|
-
return await
|
|
38151
|
+
return await fs18.readFile(location);
|
|
37484
38152
|
} catch (err) {
|
|
37485
38153
|
if (err.code === "ENOENT") {
|
|
37486
38154
|
return null;
|
|
@@ -37490,7 +38158,7 @@ var FileMediaStorage = class {
|
|
|
37490
38158
|
}
|
|
37491
38159
|
async delete(location) {
|
|
37492
38160
|
try {
|
|
37493
|
-
await
|
|
38161
|
+
await fs18.unlink(location);
|
|
37494
38162
|
} catch (err) {
|
|
37495
38163
|
if (err.code === "ENOENT") {
|
|
37496
38164
|
return;
|
|
@@ -37500,7 +38168,7 @@ var FileMediaStorage = class {
|
|
|
37500
38168
|
}
|
|
37501
38169
|
async exists(location) {
|
|
37502
38170
|
try {
|
|
37503
|
-
await
|
|
38171
|
+
await fs18.access(location);
|
|
37504
38172
|
return true;
|
|
37505
38173
|
} catch {
|
|
37506
38174
|
return false;
|
|
@@ -37509,11 +38177,11 @@ var FileMediaStorage = class {
|
|
|
37509
38177
|
async list(options) {
|
|
37510
38178
|
await this.ensureDir();
|
|
37511
38179
|
let entries = [];
|
|
37512
|
-
const files = await
|
|
38180
|
+
const files = await fs18.readdir(this.outputDir);
|
|
37513
38181
|
for (const file of files) {
|
|
37514
38182
|
const filePath = path2.join(this.outputDir, file);
|
|
37515
38183
|
try {
|
|
37516
|
-
const stat6 = await
|
|
38184
|
+
const stat6 = await fs18.stat(filePath);
|
|
37517
38185
|
if (!stat6.isFile()) continue;
|
|
37518
38186
|
const ext = path2.extname(file).slice(1).toLowerCase();
|
|
37519
38187
|
const mimeType = MIME_TYPES2[ext] ?? "application/octet-stream";
|
|
@@ -37553,7 +38221,7 @@ var FileMediaStorage = class {
|
|
|
37553
38221
|
}
|
|
37554
38222
|
async ensureDir() {
|
|
37555
38223
|
if (!this.initialized) {
|
|
37556
|
-
await
|
|
38224
|
+
await fs18.mkdir(this.outputDir, { recursive: true });
|
|
37557
38225
|
this.initialized = true;
|
|
37558
38226
|
}
|
|
37559
38227
|
}
|
|
@@ -37803,6 +38471,234 @@ var FileCustomToolStorage = class {
|
|
|
37803
38471
|
function createFileCustomToolStorage(config) {
|
|
37804
38472
|
return new FileCustomToolStorage(config);
|
|
37805
38473
|
}
|
|
38474
|
+
var STORAGE_VERSION = 1;
|
|
38475
|
+
var DEFAULT_USER_ID3 = "default";
|
|
38476
|
+
function getDefaultBaseDirectory6() {
|
|
38477
|
+
const platform2 = process.platform;
|
|
38478
|
+
if (platform2 === "win32") {
|
|
38479
|
+
const appData = process.env.APPDATA || process.env.LOCALAPPDATA;
|
|
38480
|
+
if (appData) {
|
|
38481
|
+
return join(appData, "oneringai", "users");
|
|
38482
|
+
}
|
|
38483
|
+
}
|
|
38484
|
+
return join(homedir(), ".oneringai", "users");
|
|
38485
|
+
}
|
|
38486
|
+
function sanitizeUserId3(userId) {
|
|
38487
|
+
if (!userId) {
|
|
38488
|
+
return DEFAULT_USER_ID3;
|
|
38489
|
+
}
|
|
38490
|
+
return userId.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase() || DEFAULT_USER_ID3;
|
|
38491
|
+
}
|
|
38492
|
+
function sanitizeId2(id) {
|
|
38493
|
+
return id.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase() || "default";
|
|
38494
|
+
}
|
|
38495
|
+
var FileRoutineDefinitionStorage = class {
|
|
38496
|
+
baseDirectory;
|
|
38497
|
+
prettyPrint;
|
|
38498
|
+
constructor(config = {}) {
|
|
38499
|
+
this.baseDirectory = config.baseDirectory ?? getDefaultBaseDirectory6();
|
|
38500
|
+
this.prettyPrint = config.prettyPrint ?? true;
|
|
38501
|
+
}
|
|
38502
|
+
getUserDirectory(userId) {
|
|
38503
|
+
const sanitizedId = sanitizeUserId3(userId);
|
|
38504
|
+
return join(this.baseDirectory, sanitizedId, "routines");
|
|
38505
|
+
}
|
|
38506
|
+
getIndexPath(userId) {
|
|
38507
|
+
return join(this.getUserDirectory(userId), "_index.json");
|
|
38508
|
+
}
|
|
38509
|
+
getRoutinePath(userId, sanitizedId) {
|
|
38510
|
+
return join(this.getUserDirectory(userId), `${sanitizedId}.json`);
|
|
38511
|
+
}
|
|
38512
|
+
async save(userId, definition) {
|
|
38513
|
+
const directory = this.getUserDirectory(userId);
|
|
38514
|
+
const sanitized = sanitizeId2(definition.id);
|
|
38515
|
+
const filePath = this.getRoutinePath(userId, sanitized);
|
|
38516
|
+
await this.ensureDirectory(directory);
|
|
38517
|
+
const stored = { version: STORAGE_VERSION, definition };
|
|
38518
|
+
const data = this.prettyPrint ? JSON.stringify(stored, null, 2) : JSON.stringify(stored);
|
|
38519
|
+
const tempPath = `${filePath}.tmp`;
|
|
38520
|
+
try {
|
|
38521
|
+
await promises.writeFile(tempPath, data, "utf-8");
|
|
38522
|
+
await promises.rename(tempPath, filePath);
|
|
38523
|
+
} catch (error) {
|
|
38524
|
+
try {
|
|
38525
|
+
await promises.unlink(tempPath);
|
|
38526
|
+
} catch {
|
|
38527
|
+
}
|
|
38528
|
+
throw error;
|
|
38529
|
+
}
|
|
38530
|
+
await this.updateIndex(userId, definition);
|
|
38531
|
+
}
|
|
38532
|
+
async load(userId, id) {
|
|
38533
|
+
const sanitized = sanitizeId2(id);
|
|
38534
|
+
const filePath = this.getRoutinePath(userId, sanitized);
|
|
38535
|
+
try {
|
|
38536
|
+
const data = await promises.readFile(filePath, "utf-8");
|
|
38537
|
+
const stored = JSON.parse(data);
|
|
38538
|
+
return stored.definition;
|
|
38539
|
+
} catch (error) {
|
|
38540
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
38541
|
+
return null;
|
|
38542
|
+
}
|
|
38543
|
+
if (error instanceof SyntaxError) {
|
|
38544
|
+
return null;
|
|
38545
|
+
}
|
|
38546
|
+
throw error;
|
|
38547
|
+
}
|
|
38548
|
+
}
|
|
38549
|
+
async delete(userId, id) {
|
|
38550
|
+
const sanitized = sanitizeId2(id);
|
|
38551
|
+
const filePath = this.getRoutinePath(userId, sanitized);
|
|
38552
|
+
try {
|
|
38553
|
+
await promises.unlink(filePath);
|
|
38554
|
+
} catch (error) {
|
|
38555
|
+
if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
|
|
38556
|
+
throw error;
|
|
38557
|
+
}
|
|
38558
|
+
}
|
|
38559
|
+
await this.removeFromIndex(userId, id);
|
|
38560
|
+
}
|
|
38561
|
+
async exists(userId, id) {
|
|
38562
|
+
const sanitized = sanitizeId2(id);
|
|
38563
|
+
const filePath = this.getRoutinePath(userId, sanitized);
|
|
38564
|
+
try {
|
|
38565
|
+
await promises.access(filePath);
|
|
38566
|
+
return true;
|
|
38567
|
+
} catch {
|
|
38568
|
+
return false;
|
|
38569
|
+
}
|
|
38570
|
+
}
|
|
38571
|
+
async list(userId, options) {
|
|
38572
|
+
const index = await this.loadIndex(userId);
|
|
38573
|
+
let entries = [...index.routines];
|
|
38574
|
+
if (options?.tags && options.tags.length > 0) {
|
|
38575
|
+
entries = entries.filter((e) => {
|
|
38576
|
+
const entryTags = e.tags ?? [];
|
|
38577
|
+
return options.tags.some((t) => entryTags.includes(t));
|
|
38578
|
+
});
|
|
38579
|
+
}
|
|
38580
|
+
if (options?.search) {
|
|
38581
|
+
const searchLower = options.search.toLowerCase();
|
|
38582
|
+
entries = entries.filter(
|
|
38583
|
+
(e) => e.name.toLowerCase().includes(searchLower) || e.description.toLowerCase().includes(searchLower)
|
|
38584
|
+
);
|
|
38585
|
+
}
|
|
38586
|
+
entries.sort(
|
|
38587
|
+
(a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
|
|
38588
|
+
);
|
|
38589
|
+
if (options?.offset) {
|
|
38590
|
+
entries = entries.slice(options.offset);
|
|
38591
|
+
}
|
|
38592
|
+
if (options?.limit) {
|
|
38593
|
+
entries = entries.slice(0, options.limit);
|
|
38594
|
+
}
|
|
38595
|
+
const results = [];
|
|
38596
|
+
for (const entry of entries) {
|
|
38597
|
+
const def = await this.load(userId, entry.id);
|
|
38598
|
+
if (def) {
|
|
38599
|
+
results.push(def);
|
|
38600
|
+
}
|
|
38601
|
+
}
|
|
38602
|
+
return results;
|
|
38603
|
+
}
|
|
38604
|
+
getPath(userId) {
|
|
38605
|
+
return this.getUserDirectory(userId);
|
|
38606
|
+
}
|
|
38607
|
+
// ==========================================================================
|
|
38608
|
+
// Private Helpers
|
|
38609
|
+
// ==========================================================================
|
|
38610
|
+
async ensureDirectory(dir) {
|
|
38611
|
+
try {
|
|
38612
|
+
await promises.mkdir(dir, { recursive: true });
|
|
38613
|
+
} catch (error) {
|
|
38614
|
+
if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
|
|
38615
|
+
throw error;
|
|
38616
|
+
}
|
|
38617
|
+
}
|
|
38618
|
+
}
|
|
38619
|
+
async loadIndex(userId) {
|
|
38620
|
+
const indexPath = this.getIndexPath(userId);
|
|
38621
|
+
try {
|
|
38622
|
+
const data = await promises.readFile(indexPath, "utf-8");
|
|
38623
|
+
return JSON.parse(data);
|
|
38624
|
+
} catch (error) {
|
|
38625
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
38626
|
+
return await this.rebuildIndex(userId);
|
|
38627
|
+
}
|
|
38628
|
+
throw error;
|
|
38629
|
+
}
|
|
38630
|
+
}
|
|
38631
|
+
async saveIndex(userId, index) {
|
|
38632
|
+
const directory = this.getUserDirectory(userId);
|
|
38633
|
+
const indexPath = this.getIndexPath(userId);
|
|
38634
|
+
await this.ensureDirectory(directory);
|
|
38635
|
+
index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
38636
|
+
const data = this.prettyPrint ? JSON.stringify(index, null, 2) : JSON.stringify(index);
|
|
38637
|
+
await promises.writeFile(indexPath, data, "utf-8");
|
|
38638
|
+
}
|
|
38639
|
+
async updateIndex(userId, definition) {
|
|
38640
|
+
const index = await this.loadIndex(userId);
|
|
38641
|
+
const entry = this.definitionToIndexEntry(definition);
|
|
38642
|
+
const existingIdx = index.routines.findIndex((e) => e.id === definition.id);
|
|
38643
|
+
if (existingIdx >= 0) {
|
|
38644
|
+
index.routines[existingIdx] = entry;
|
|
38645
|
+
} else {
|
|
38646
|
+
index.routines.push(entry);
|
|
38647
|
+
}
|
|
38648
|
+
await this.saveIndex(userId, index);
|
|
38649
|
+
}
|
|
38650
|
+
async removeFromIndex(userId, id) {
|
|
38651
|
+
const index = await this.loadIndex(userId);
|
|
38652
|
+
index.routines = index.routines.filter((e) => e.id !== id);
|
|
38653
|
+
await this.saveIndex(userId, index);
|
|
38654
|
+
}
|
|
38655
|
+
definitionToIndexEntry(definition) {
|
|
38656
|
+
return {
|
|
38657
|
+
id: definition.id,
|
|
38658
|
+
name: definition.name,
|
|
38659
|
+
description: definition.description,
|
|
38660
|
+
tags: definition.tags,
|
|
38661
|
+
author: definition.author,
|
|
38662
|
+
updatedAt: definition.updatedAt
|
|
38663
|
+
};
|
|
38664
|
+
}
|
|
38665
|
+
/**
|
|
38666
|
+
* Rebuild index by scanning directory for .json files (excluding _index.json).
|
|
38667
|
+
* Returns empty index if directory doesn't exist.
|
|
38668
|
+
*/
|
|
38669
|
+
async rebuildIndex(userId) {
|
|
38670
|
+
const directory = this.getUserDirectory(userId);
|
|
38671
|
+
const index = {
|
|
38672
|
+
version: 1,
|
|
38673
|
+
routines: [],
|
|
38674
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
38675
|
+
};
|
|
38676
|
+
let files;
|
|
38677
|
+
try {
|
|
38678
|
+
files = await promises.readdir(directory);
|
|
38679
|
+
} catch {
|
|
38680
|
+
return index;
|
|
38681
|
+
}
|
|
38682
|
+
for (const file of files) {
|
|
38683
|
+
if (!file.endsWith(".json") || file === "_index.json") continue;
|
|
38684
|
+
try {
|
|
38685
|
+
const data = await promises.readFile(join(directory, file), "utf-8");
|
|
38686
|
+
const stored = JSON.parse(data);
|
|
38687
|
+
if (stored.definition) {
|
|
38688
|
+
index.routines.push(this.definitionToIndexEntry(stored.definition));
|
|
38689
|
+
}
|
|
38690
|
+
} catch {
|
|
38691
|
+
}
|
|
38692
|
+
}
|
|
38693
|
+
if (index.routines.length > 0) {
|
|
38694
|
+
await this.saveIndex(userId, index);
|
|
38695
|
+
}
|
|
38696
|
+
return index;
|
|
38697
|
+
}
|
|
38698
|
+
};
|
|
38699
|
+
function createFileRoutineDefinitionStorage(config) {
|
|
38700
|
+
return new FileRoutineDefinitionStorage(config);
|
|
38701
|
+
}
|
|
37806
38702
|
|
|
37807
38703
|
// src/domain/entities/CustomToolDefinition.ts
|
|
37808
38704
|
var CUSTOM_TOOL_DEFINITION_VERSION = 1;
|
|
@@ -38903,8 +39799,8 @@ var FileStorage = class {
|
|
|
38903
39799
|
}
|
|
38904
39800
|
async ensureDirectory() {
|
|
38905
39801
|
try {
|
|
38906
|
-
await
|
|
38907
|
-
await
|
|
39802
|
+
await fs18.mkdir(this.directory, { recursive: true });
|
|
39803
|
+
await fs18.chmod(this.directory, 448);
|
|
38908
39804
|
} catch (error) {
|
|
38909
39805
|
}
|
|
38910
39806
|
}
|
|
@@ -38920,13 +39816,13 @@ var FileStorage = class {
|
|
|
38920
39816
|
const filePath = this.getFilePath(key);
|
|
38921
39817
|
const plaintext = JSON.stringify(token);
|
|
38922
39818
|
const encrypted = encrypt(plaintext, this.encryptionKey);
|
|
38923
|
-
await
|
|
38924
|
-
await
|
|
39819
|
+
await fs18.writeFile(filePath, encrypted, "utf8");
|
|
39820
|
+
await fs18.chmod(filePath, 384);
|
|
38925
39821
|
}
|
|
38926
39822
|
async getToken(key) {
|
|
38927
39823
|
const filePath = this.getFilePath(key);
|
|
38928
39824
|
try {
|
|
38929
|
-
const encrypted = await
|
|
39825
|
+
const encrypted = await fs18.readFile(filePath, "utf8");
|
|
38930
39826
|
const decrypted = decrypt(encrypted, this.encryptionKey);
|
|
38931
39827
|
return JSON.parse(decrypted);
|
|
38932
39828
|
} catch (error) {
|
|
@@ -38935,7 +39831,7 @@ var FileStorage = class {
|
|
|
38935
39831
|
}
|
|
38936
39832
|
console.error("Failed to read/decrypt token file:", error);
|
|
38937
39833
|
try {
|
|
38938
|
-
await
|
|
39834
|
+
await fs18.unlink(filePath);
|
|
38939
39835
|
} catch {
|
|
38940
39836
|
}
|
|
38941
39837
|
return null;
|
|
@@ -38944,7 +39840,7 @@ var FileStorage = class {
|
|
|
38944
39840
|
async deleteToken(key) {
|
|
38945
39841
|
const filePath = this.getFilePath(key);
|
|
38946
39842
|
try {
|
|
38947
|
-
await
|
|
39843
|
+
await fs18.unlink(filePath);
|
|
38948
39844
|
} catch (error) {
|
|
38949
39845
|
if (error.code !== "ENOENT") {
|
|
38950
39846
|
throw error;
|
|
@@ -38954,7 +39850,7 @@ var FileStorage = class {
|
|
|
38954
39850
|
async hasToken(key) {
|
|
38955
39851
|
const filePath = this.getFilePath(key);
|
|
38956
39852
|
try {
|
|
38957
|
-
await
|
|
39853
|
+
await fs18.access(filePath);
|
|
38958
39854
|
return true;
|
|
38959
39855
|
} catch {
|
|
38960
39856
|
return false;
|
|
@@ -38965,7 +39861,7 @@ var FileStorage = class {
|
|
|
38965
39861
|
*/
|
|
38966
39862
|
async listTokens() {
|
|
38967
39863
|
try {
|
|
38968
|
-
const files = await
|
|
39864
|
+
const files = await fs18.readdir(this.directory);
|
|
38969
39865
|
return files.filter((f) => f.endsWith(".token")).map((f) => f.replace(".token", ""));
|
|
38970
39866
|
} catch {
|
|
38971
39867
|
return [];
|
|
@@ -38976,10 +39872,10 @@ var FileStorage = class {
|
|
|
38976
39872
|
*/
|
|
38977
39873
|
async clearAll() {
|
|
38978
39874
|
try {
|
|
38979
|
-
const files = await
|
|
39875
|
+
const files = await fs18.readdir(this.directory);
|
|
38980
39876
|
const tokenFiles = files.filter((f) => f.endsWith(".token"));
|
|
38981
39877
|
await Promise.all(
|
|
38982
|
-
tokenFiles.map((f) =>
|
|
39878
|
+
tokenFiles.map((f) => fs18.unlink(path2.join(this.directory, f)).catch(() => {
|
|
38983
39879
|
}))
|
|
38984
39880
|
);
|
|
38985
39881
|
} catch {
|
|
@@ -39427,14 +40323,14 @@ var FileConnectorStorage = class {
|
|
|
39427
40323
|
await this.ensureDirectory();
|
|
39428
40324
|
const filePath = this.getFilePath(name);
|
|
39429
40325
|
const json = JSON.stringify(stored, null, 2);
|
|
39430
|
-
await
|
|
39431
|
-
await
|
|
40326
|
+
await fs18.writeFile(filePath, json, "utf8");
|
|
40327
|
+
await fs18.chmod(filePath, 384);
|
|
39432
40328
|
await this.updateIndex(name, "add");
|
|
39433
40329
|
}
|
|
39434
40330
|
async get(name) {
|
|
39435
40331
|
const filePath = this.getFilePath(name);
|
|
39436
40332
|
try {
|
|
39437
|
-
const json = await
|
|
40333
|
+
const json = await fs18.readFile(filePath, "utf8");
|
|
39438
40334
|
return JSON.parse(json);
|
|
39439
40335
|
} catch (error) {
|
|
39440
40336
|
const err = error;
|
|
@@ -39447,7 +40343,7 @@ var FileConnectorStorage = class {
|
|
|
39447
40343
|
async delete(name) {
|
|
39448
40344
|
const filePath = this.getFilePath(name);
|
|
39449
40345
|
try {
|
|
39450
|
-
await
|
|
40346
|
+
await fs18.unlink(filePath);
|
|
39451
40347
|
await this.updateIndex(name, "remove");
|
|
39452
40348
|
return true;
|
|
39453
40349
|
} catch (error) {
|
|
@@ -39461,7 +40357,7 @@ var FileConnectorStorage = class {
|
|
|
39461
40357
|
async has(name) {
|
|
39462
40358
|
const filePath = this.getFilePath(name);
|
|
39463
40359
|
try {
|
|
39464
|
-
await
|
|
40360
|
+
await fs18.access(filePath);
|
|
39465
40361
|
return true;
|
|
39466
40362
|
} catch {
|
|
39467
40363
|
return false;
|
|
@@ -39487,13 +40383,13 @@ var FileConnectorStorage = class {
|
|
|
39487
40383
|
*/
|
|
39488
40384
|
async clear() {
|
|
39489
40385
|
try {
|
|
39490
|
-
const files = await
|
|
40386
|
+
const files = await fs18.readdir(this.directory);
|
|
39491
40387
|
const connectorFiles = files.filter(
|
|
39492
40388
|
(f) => f.endsWith(".connector.json") || f === "_index.json"
|
|
39493
40389
|
);
|
|
39494
40390
|
await Promise.all(
|
|
39495
40391
|
connectorFiles.map(
|
|
39496
|
-
(f) =>
|
|
40392
|
+
(f) => fs18.unlink(path2.join(this.directory, f)).catch(() => {
|
|
39497
40393
|
})
|
|
39498
40394
|
)
|
|
39499
40395
|
);
|
|
@@ -39520,8 +40416,8 @@ var FileConnectorStorage = class {
|
|
|
39520
40416
|
async ensureDirectory() {
|
|
39521
40417
|
if (this.initialized) return;
|
|
39522
40418
|
try {
|
|
39523
|
-
await
|
|
39524
|
-
await
|
|
40419
|
+
await fs18.mkdir(this.directory, { recursive: true });
|
|
40420
|
+
await fs18.chmod(this.directory, 448);
|
|
39525
40421
|
this.initialized = true;
|
|
39526
40422
|
} catch {
|
|
39527
40423
|
this.initialized = true;
|
|
@@ -39532,7 +40428,7 @@ var FileConnectorStorage = class {
|
|
|
39532
40428
|
*/
|
|
39533
40429
|
async loadIndex() {
|
|
39534
40430
|
try {
|
|
39535
|
-
const json = await
|
|
40431
|
+
const json = await fs18.readFile(this.indexPath, "utf8");
|
|
39536
40432
|
return JSON.parse(json);
|
|
39537
40433
|
} catch {
|
|
39538
40434
|
return { connectors: {} };
|
|
@@ -39550,8 +40446,8 @@ var FileConnectorStorage = class {
|
|
|
39550
40446
|
delete index.connectors[hash];
|
|
39551
40447
|
}
|
|
39552
40448
|
const json = JSON.stringify(index, null, 2);
|
|
39553
|
-
await
|
|
39554
|
-
await
|
|
40449
|
+
await fs18.writeFile(this.indexPath, json, "utf8");
|
|
40450
|
+
await fs18.chmod(this.indexPath, 384);
|
|
39555
40451
|
}
|
|
39556
40452
|
};
|
|
39557
40453
|
|
|
@@ -42006,8 +42902,8 @@ function createMessageWithImages(text, imageUrls, role = "user" /* USER */) {
|
|
|
42006
42902
|
var execAsync = promisify(exec);
|
|
42007
42903
|
function cleanupTempFile(filePath) {
|
|
42008
42904
|
try {
|
|
42009
|
-
if (
|
|
42010
|
-
|
|
42905
|
+
if (fs19.existsSync(filePath)) {
|
|
42906
|
+
fs19.unlinkSync(filePath);
|
|
42011
42907
|
}
|
|
42012
42908
|
} catch {
|
|
42013
42909
|
}
|
|
@@ -42058,7 +42954,7 @@ async function readClipboardImageMac() {
|
|
|
42058
42954
|
end try
|
|
42059
42955
|
`;
|
|
42060
42956
|
const { stdout } = await execAsync(`osascript -e '${script}'`);
|
|
42061
|
-
if (stdout.includes("success") ||
|
|
42957
|
+
if (stdout.includes("success") || fs19.existsSync(tempFile)) {
|
|
42062
42958
|
return await convertFileToDataUri(tempFile);
|
|
42063
42959
|
}
|
|
42064
42960
|
return {
|
|
@@ -42075,14 +42971,14 @@ async function readClipboardImageLinux() {
|
|
|
42075
42971
|
try {
|
|
42076
42972
|
try {
|
|
42077
42973
|
await execAsync(`xclip -selection clipboard -t image/png -o > "${tempFile}"`);
|
|
42078
|
-
if (
|
|
42974
|
+
if (fs19.existsSync(tempFile) && fs19.statSync(tempFile).size > 0) {
|
|
42079
42975
|
return await convertFileToDataUri(tempFile);
|
|
42080
42976
|
}
|
|
42081
42977
|
} catch {
|
|
42082
42978
|
}
|
|
42083
42979
|
try {
|
|
42084
42980
|
await execAsync(`wl-paste -t image/png > "${tempFile}"`);
|
|
42085
|
-
if (
|
|
42981
|
+
if (fs19.existsSync(tempFile) && fs19.statSync(tempFile).size > 0) {
|
|
42086
42982
|
return await convertFileToDataUri(tempFile);
|
|
42087
42983
|
}
|
|
42088
42984
|
} catch {
|
|
@@ -42109,7 +43005,7 @@ async function readClipboardImageWindows() {
|
|
|
42109
43005
|
}
|
|
42110
43006
|
`;
|
|
42111
43007
|
await execAsync(`powershell -Command "${psScript}"`);
|
|
42112
|
-
if (
|
|
43008
|
+
if (fs19.existsSync(tempFile) && fs19.statSync(tempFile).size > 0) {
|
|
42113
43009
|
return await convertFileToDataUri(tempFile);
|
|
42114
43010
|
}
|
|
42115
43011
|
return {
|
|
@@ -42122,7 +43018,7 @@ async function readClipboardImageWindows() {
|
|
|
42122
43018
|
}
|
|
42123
43019
|
async function convertFileToDataUri(filePath) {
|
|
42124
43020
|
try {
|
|
42125
|
-
const imageBuffer =
|
|
43021
|
+
const imageBuffer = fs19.readFileSync(filePath);
|
|
42126
43022
|
const base64Image = imageBuffer.toString("base64");
|
|
42127
43023
|
const magic = imageBuffer.slice(0, 4).toString("hex");
|
|
42128
43024
|
let mimeType = "image/png";
|
|
@@ -42181,186 +43077,6 @@ async function hasClipboardImage() {
|
|
|
42181
43077
|
}
|
|
42182
43078
|
}
|
|
42183
43079
|
|
|
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
43080
|
// src/tools/index.ts
|
|
42365
43081
|
var tools_exports = {};
|
|
42366
43082
|
__export(tools_exports, {
|
|
@@ -42396,19 +43112,25 @@ __export(tools_exports, {
|
|
|
42396
43112
|
createDesktopScreenshotTool: () => createDesktopScreenshotTool,
|
|
42397
43113
|
createDesktopWindowFocusTool: () => createDesktopWindowFocusTool,
|
|
42398
43114
|
createDesktopWindowListTool: () => createDesktopWindowListTool,
|
|
43115
|
+
createDraftEmailTool: () => createDraftEmailTool,
|
|
42399
43116
|
createEditFileTool: () => createEditFileTool,
|
|
43117
|
+
createEditMeetingTool: () => createEditMeetingTool,
|
|
42400
43118
|
createExecuteJavaScriptTool: () => createExecuteJavaScriptTool,
|
|
43119
|
+
createFindMeetingSlotsTool: () => createFindMeetingSlotsTool,
|
|
43120
|
+
createGetMeetingTranscriptTool: () => createGetMeetingTranscriptTool,
|
|
42401
43121
|
createGetPRTool: () => createGetPRTool,
|
|
42402
43122
|
createGitHubReadFileTool: () => createGitHubReadFileTool,
|
|
42403
43123
|
createGlobTool: () => createGlobTool,
|
|
42404
43124
|
createGrepTool: () => createGrepTool,
|
|
42405
43125
|
createImageGenerationTool: () => createImageGenerationTool,
|
|
42406
43126
|
createListDirectoryTool: () => createListDirectoryTool,
|
|
43127
|
+
createMeetingTool: () => createMeetingTool,
|
|
42407
43128
|
createPRCommentsTool: () => createPRCommentsTool,
|
|
42408
43129
|
createPRFilesTool: () => createPRFilesTool,
|
|
42409
43130
|
createReadFileTool: () => createReadFileTool,
|
|
42410
43131
|
createSearchCodeTool: () => createSearchCodeTool,
|
|
42411
43132
|
createSearchFilesTool: () => createSearchFilesTool,
|
|
43133
|
+
createSendEmailTool: () => createSendEmailTool,
|
|
42412
43134
|
createSpeechToTextTool: () => createSpeechToTextTool,
|
|
42413
43135
|
createTextToSpeechTool: () => createTextToSpeechTool,
|
|
42414
43136
|
createVideoTools: () => createVideoTools,
|
|
@@ -42438,6 +43160,8 @@ __export(tools_exports, {
|
|
|
42438
43160
|
executeInVM: () => executeInVM,
|
|
42439
43161
|
executeJavaScript: () => executeJavaScript,
|
|
42440
43162
|
expandTilde: () => expandTilde,
|
|
43163
|
+
formatAttendees: () => formatAttendees,
|
|
43164
|
+
formatRecipients: () => formatRecipients,
|
|
42441
43165
|
getAllBuiltInTools: () => getAllBuiltInTools,
|
|
42442
43166
|
getBackgroundOutput: () => getBackgroundOutput,
|
|
42443
43167
|
getDesktopDriver: () => getDesktopDriver,
|
|
@@ -42448,19 +43172,24 @@ __export(tools_exports, {
|
|
|
42448
43172
|
getToolRegistry: () => getToolRegistry,
|
|
42449
43173
|
getToolsByCategory: () => getToolsByCategory,
|
|
42450
43174
|
getToolsRequiringConnector: () => getToolsRequiringConnector,
|
|
43175
|
+
getUserPathPrefix: () => getUserPathPrefix,
|
|
42451
43176
|
glob: () => glob,
|
|
42452
43177
|
grep: () => grep,
|
|
42453
43178
|
hydrateCustomTool: () => hydrateCustomTool,
|
|
42454
43179
|
isBlockedCommand: () => isBlockedCommand,
|
|
42455
43180
|
isExcludedExtension: () => isExcludedExtension,
|
|
43181
|
+
isTeamsMeetingUrl: () => isTeamsMeetingUrl,
|
|
42456
43182
|
jsonManipulator: () => jsonManipulator,
|
|
42457
43183
|
killBackgroundProcess: () => killBackgroundProcess,
|
|
42458
43184
|
listDirectory: () => listDirectory,
|
|
42459
43185
|
mergeTextPieces: () => mergeTextPieces,
|
|
43186
|
+
microsoftFetch: () => microsoftFetch,
|
|
43187
|
+
normalizeEmails: () => normalizeEmails,
|
|
42460
43188
|
parseKeyCombo: () => parseKeyCombo,
|
|
42461
43189
|
parseRepository: () => parseRepository,
|
|
42462
43190
|
readFile: () => readFile5,
|
|
42463
43191
|
resetDefaultDriver: () => resetDefaultDriver,
|
|
43192
|
+
resolveMeetingId: () => resolveMeetingId,
|
|
42464
43193
|
resolveRepository: () => resolveRepository,
|
|
42465
43194
|
setMediaOutputHandler: () => setMediaOutputHandler,
|
|
42466
43195
|
setMediaStorage: () => setMediaStorage,
|
|
@@ -46542,6 +47271,840 @@ function registerGitHubTools() {
|
|
|
46542
47271
|
// src/tools/github/index.ts
|
|
46543
47272
|
registerGitHubTools();
|
|
46544
47273
|
|
|
47274
|
+
// src/tools/microsoft/types.ts
|
|
47275
|
+
function getUserPathPrefix(connector, targetUser) {
|
|
47276
|
+
const auth2 = connector.config.auth;
|
|
47277
|
+
if (auth2.type === "oauth" && auth2.flow === "client_credentials") {
|
|
47278
|
+
if (!targetUser) {
|
|
47279
|
+
throw new Error(
|
|
47280
|
+
'targetUser is required when using client_credentials (application) flow. Provide a user ID or UPN (e.g., "user@domain.com").'
|
|
47281
|
+
);
|
|
47282
|
+
}
|
|
47283
|
+
return `/users/${targetUser}`;
|
|
47284
|
+
}
|
|
47285
|
+
return "/me";
|
|
47286
|
+
}
|
|
47287
|
+
var MicrosoftAPIError = class extends Error {
|
|
47288
|
+
constructor(status, statusText, body) {
|
|
47289
|
+
const msg = typeof body === "object" && body !== null && "error" in body ? body.error?.message ?? statusText : statusText;
|
|
47290
|
+
super(`Microsoft Graph API error ${status}: ${msg}`);
|
|
47291
|
+
this.status = status;
|
|
47292
|
+
this.statusText = statusText;
|
|
47293
|
+
this.body = body;
|
|
47294
|
+
this.name = "MicrosoftAPIError";
|
|
47295
|
+
}
|
|
47296
|
+
};
|
|
47297
|
+
async function microsoftFetch(connector, endpoint, options) {
|
|
47298
|
+
let url2 = endpoint;
|
|
47299
|
+
if (options?.queryParams && Object.keys(options.queryParams).length > 0) {
|
|
47300
|
+
const params = new URLSearchParams();
|
|
47301
|
+
for (const [key, value] of Object.entries(options.queryParams)) {
|
|
47302
|
+
params.append(key, String(value));
|
|
47303
|
+
}
|
|
47304
|
+
url2 += (url2.includes("?") ? "&" : "?") + params.toString();
|
|
47305
|
+
}
|
|
47306
|
+
const headers = {
|
|
47307
|
+
"Accept": options?.accept ?? "application/json"
|
|
47308
|
+
};
|
|
47309
|
+
if (options?.body) {
|
|
47310
|
+
headers["Content-Type"] = "application/json";
|
|
47311
|
+
}
|
|
47312
|
+
const response = await connector.fetch(
|
|
47313
|
+
url2,
|
|
47314
|
+
{
|
|
47315
|
+
method: options?.method ?? "GET",
|
|
47316
|
+
headers,
|
|
47317
|
+
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
47318
|
+
},
|
|
47319
|
+
options?.userId
|
|
47320
|
+
);
|
|
47321
|
+
const text = await response.text();
|
|
47322
|
+
if (!response.ok) {
|
|
47323
|
+
let data;
|
|
47324
|
+
try {
|
|
47325
|
+
data = JSON.parse(text);
|
|
47326
|
+
} catch {
|
|
47327
|
+
data = text;
|
|
47328
|
+
}
|
|
47329
|
+
throw new MicrosoftAPIError(response.status, response.statusText, data);
|
|
47330
|
+
}
|
|
47331
|
+
if (!text || text.trim().length === 0) {
|
|
47332
|
+
return void 0;
|
|
47333
|
+
}
|
|
47334
|
+
try {
|
|
47335
|
+
return JSON.parse(text);
|
|
47336
|
+
} catch {
|
|
47337
|
+
return text;
|
|
47338
|
+
}
|
|
47339
|
+
}
|
|
47340
|
+
function normalizeEmails(input) {
|
|
47341
|
+
return input.map((item) => {
|
|
47342
|
+
if (typeof item === "string") return item;
|
|
47343
|
+
if (typeof item === "object" && item !== null) {
|
|
47344
|
+
const obj = item;
|
|
47345
|
+
if (obj.emailAddress && typeof obj.emailAddress === "object") {
|
|
47346
|
+
const ea = obj.emailAddress;
|
|
47347
|
+
if (typeof ea.address === "string") return ea.address;
|
|
47348
|
+
}
|
|
47349
|
+
if (typeof obj.address === "string") return obj.address;
|
|
47350
|
+
if (typeof obj.email === "string") return obj.email;
|
|
47351
|
+
}
|
|
47352
|
+
return String(item);
|
|
47353
|
+
});
|
|
47354
|
+
}
|
|
47355
|
+
function formatRecipients(emails) {
|
|
47356
|
+
return normalizeEmails(emails).map((address) => ({ emailAddress: { address } }));
|
|
47357
|
+
}
|
|
47358
|
+
function formatAttendees(emails) {
|
|
47359
|
+
return normalizeEmails(emails).map((address) => ({
|
|
47360
|
+
emailAddress: { address },
|
|
47361
|
+
type: "required"
|
|
47362
|
+
}));
|
|
47363
|
+
}
|
|
47364
|
+
function isTeamsMeetingUrl(input) {
|
|
47365
|
+
try {
|
|
47366
|
+
const url2 = new URL(input.trim());
|
|
47367
|
+
return (url2.hostname === "teams.microsoft.com" || url2.hostname === "teams.live.com") && url2.pathname.includes("meetup-join");
|
|
47368
|
+
} catch {
|
|
47369
|
+
return false;
|
|
47370
|
+
}
|
|
47371
|
+
}
|
|
47372
|
+
async function resolveMeetingId(connector, input, prefix, effectiveUserId) {
|
|
47373
|
+
if (!input || input.trim().length === 0) {
|
|
47374
|
+
throw new Error("Meeting ID cannot be empty");
|
|
47375
|
+
}
|
|
47376
|
+
const trimmed = input.trim();
|
|
47377
|
+
if (!isTeamsMeetingUrl(trimmed)) {
|
|
47378
|
+
return { meetingId: trimmed };
|
|
47379
|
+
}
|
|
47380
|
+
const meetings = await microsoftFetch(
|
|
47381
|
+
connector,
|
|
47382
|
+
`${prefix}/onlineMeetings`,
|
|
47383
|
+
{
|
|
47384
|
+
userId: effectiveUserId,
|
|
47385
|
+
queryParams: { "$filter": `JoinWebUrl eq '${trimmed}'` }
|
|
47386
|
+
}
|
|
47387
|
+
);
|
|
47388
|
+
if (!meetings.value || meetings.value.length === 0) {
|
|
47389
|
+
throw new Error(
|
|
47390
|
+
`Could not find an online meeting matching the provided Teams URL. Make sure the URL is correct and you have access to this meeting.`
|
|
47391
|
+
);
|
|
47392
|
+
}
|
|
47393
|
+
return {
|
|
47394
|
+
meetingId: meetings.value[0].id,
|
|
47395
|
+
subject: meetings.value[0].subject
|
|
47396
|
+
};
|
|
47397
|
+
}
|
|
47398
|
+
|
|
47399
|
+
// src/tools/microsoft/createDraftEmail.ts
|
|
47400
|
+
function createDraftEmailTool(connector, userId) {
|
|
47401
|
+
return {
|
|
47402
|
+
definition: {
|
|
47403
|
+
type: "function",
|
|
47404
|
+
function: {
|
|
47405
|
+
name: "create_draft_email",
|
|
47406
|
+
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.
|
|
47407
|
+
|
|
47408
|
+
PARAMETER FORMATS:
|
|
47409
|
+
- to/cc: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects.
|
|
47410
|
+
- subject: plain string. Example: "Project update" or "Re: Project update" for replies.
|
|
47411
|
+
- body: HTML string. Example: "<p>Hi Alice,</p><p>Here is the update.</p>". Use <p>, <br>, <b>, <ul> tags for formatting.
|
|
47412
|
+
- replyToMessageId: Graph message ID string (starts with "AAMk..."). Only set when replying to an existing email.
|
|
47413
|
+
|
|
47414
|
+
EXAMPLES:
|
|
47415
|
+
- New draft: { "to": ["alice@contoso.com"], "subject": "Project update", "body": "<p>Hi Alice,</p><p>Here is the update.</p>" }
|
|
47416
|
+
- Reply draft: { "to": ["alice@contoso.com"], "subject": "Re: Project update", "body": "<p>Thanks!</p>", "replyToMessageId": "AAMkADI1..." }
|
|
47417
|
+
- With CC: { "to": ["alice@contoso.com"], "subject": "Notes", "body": "<p>See attached.</p>", "cc": ["bob@contoso.com"] }`,
|
|
47418
|
+
parameters: {
|
|
47419
|
+
type: "object",
|
|
47420
|
+
properties: {
|
|
47421
|
+
to: {
|
|
47422
|
+
type: "array",
|
|
47423
|
+
items: { type: "string" },
|
|
47424
|
+
description: 'Recipient email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]'
|
|
47425
|
+
},
|
|
47426
|
+
subject: {
|
|
47427
|
+
type: "string",
|
|
47428
|
+
description: 'Email subject as plain string. Example: "Project update" or "Re: Original subject" for replies.'
|
|
47429
|
+
},
|
|
47430
|
+
body: {
|
|
47431
|
+
type: "string",
|
|
47432
|
+
description: 'Email body as an HTML string. Example: "<p>Hello!</p><p>See you tomorrow.</p>"'
|
|
47433
|
+
},
|
|
47434
|
+
cc: {
|
|
47435
|
+
type: "array",
|
|
47436
|
+
items: { type: "string" },
|
|
47437
|
+
description: 'CC email addresses as plain strings. Example: ["bob@contoso.com"]. Optional.'
|
|
47438
|
+
},
|
|
47439
|
+
replyToMessageId: {
|
|
47440
|
+
type: "string",
|
|
47441
|
+
description: 'Graph message ID of the email to reply to. Example: "AAMkADI1M2I3YzgtODg...". When set, creates a threaded reply draft.'
|
|
47442
|
+
},
|
|
47443
|
+
targetUser: {
|
|
47444
|
+
type: "string",
|
|
47445
|
+
description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
|
|
47446
|
+
}
|
|
47447
|
+
},
|
|
47448
|
+
required: ["to", "subject", "body"]
|
|
47449
|
+
}
|
|
47450
|
+
}
|
|
47451
|
+
},
|
|
47452
|
+
describeCall: (args) => {
|
|
47453
|
+
const action = args.replyToMessageId ? "Reply draft" : "Draft";
|
|
47454
|
+
return `${action} to ${args.to.join(", ")}: ${args.subject}`;
|
|
47455
|
+
},
|
|
47456
|
+
permission: {
|
|
47457
|
+
scope: "session",
|
|
47458
|
+
riskLevel: "medium",
|
|
47459
|
+
approvalMessage: `Create a draft email via ${connector.displayName}`
|
|
47460
|
+
},
|
|
47461
|
+
execute: async (args, context) => {
|
|
47462
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
47463
|
+
try {
|
|
47464
|
+
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
47465
|
+
if (args.replyToMessageId) {
|
|
47466
|
+
const replyDraft = await microsoftFetch(
|
|
47467
|
+
connector,
|
|
47468
|
+
`${prefix}/messages/${args.replyToMessageId}/createReply`,
|
|
47469
|
+
{ method: "POST", userId: effectiveUserId, body: {} }
|
|
47470
|
+
);
|
|
47471
|
+
const updated = await microsoftFetch(
|
|
47472
|
+
connector,
|
|
47473
|
+
`${prefix}/messages/${replyDraft.id}`,
|
|
47474
|
+
{
|
|
47475
|
+
method: "PATCH",
|
|
47476
|
+
userId: effectiveUserId,
|
|
47477
|
+
body: {
|
|
47478
|
+
subject: args.subject,
|
|
47479
|
+
body: { contentType: "HTML", content: args.body },
|
|
47480
|
+
toRecipients: formatRecipients(args.to),
|
|
47481
|
+
...args.cc && { ccRecipients: formatRecipients(args.cc) }
|
|
47482
|
+
}
|
|
47483
|
+
}
|
|
47484
|
+
);
|
|
47485
|
+
return {
|
|
47486
|
+
success: true,
|
|
47487
|
+
draftId: updated.id,
|
|
47488
|
+
webLink: updated.webLink
|
|
47489
|
+
};
|
|
47490
|
+
}
|
|
47491
|
+
const draft = await microsoftFetch(
|
|
47492
|
+
connector,
|
|
47493
|
+
`${prefix}/messages`,
|
|
47494
|
+
{
|
|
47495
|
+
method: "POST",
|
|
47496
|
+
userId: effectiveUserId,
|
|
47497
|
+
body: {
|
|
47498
|
+
isDraft: true,
|
|
47499
|
+
subject: args.subject,
|
|
47500
|
+
body: { contentType: "HTML", content: args.body },
|
|
47501
|
+
toRecipients: formatRecipients(args.to),
|
|
47502
|
+
...args.cc && { ccRecipients: formatRecipients(args.cc) }
|
|
47503
|
+
}
|
|
47504
|
+
}
|
|
47505
|
+
);
|
|
47506
|
+
return {
|
|
47507
|
+
success: true,
|
|
47508
|
+
draftId: draft.id,
|
|
47509
|
+
webLink: draft.webLink
|
|
47510
|
+
};
|
|
47511
|
+
} catch (error) {
|
|
47512
|
+
return {
|
|
47513
|
+
success: false,
|
|
47514
|
+
error: `Failed to create draft email: ${error instanceof Error ? error.message : String(error)}`
|
|
47515
|
+
};
|
|
47516
|
+
}
|
|
47517
|
+
}
|
|
47518
|
+
};
|
|
47519
|
+
}
|
|
47520
|
+
|
|
47521
|
+
// src/tools/microsoft/sendEmail.ts
|
|
47522
|
+
function createSendEmailTool(connector, userId) {
|
|
47523
|
+
return {
|
|
47524
|
+
definition: {
|
|
47525
|
+
type: "function",
|
|
47526
|
+
function: {
|
|
47527
|
+
name: "send_email",
|
|
47528
|
+
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.
|
|
47529
|
+
|
|
47530
|
+
PARAMETER FORMATS:
|
|
47531
|
+
- to/cc: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects.
|
|
47532
|
+
- subject: plain string. Example: "Meeting tomorrow" or "Re: Meeting tomorrow" for replies.
|
|
47533
|
+
- body: HTML string. Example: "<p>Hi Alice,</p><p>Can we meet at 2pm?</p>". Use <p>, <br>, <b>, <ul> tags.
|
|
47534
|
+
- replyToMessageId: Graph message ID string (starts with "AAMk..."). Only set when replying to an existing email.
|
|
47535
|
+
|
|
47536
|
+
EXAMPLES:
|
|
47537
|
+
- Send email: { "to": ["alice@contoso.com"], "subject": "Meeting tomorrow", "body": "<p>Can we meet at 2pm?</p>" }
|
|
47538
|
+
- Reply: { "to": ["alice@contoso.com"], "subject": "Re: Meeting", "body": "<p>Confirmed!</p>", "replyToMessageId": "AAMkADI1..." }
|
|
47539
|
+
- With CC: { "to": ["alice@contoso.com"], "subject": "Update", "body": "<p>FYI</p>", "cc": ["bob@contoso.com"] }`,
|
|
47540
|
+
parameters: {
|
|
47541
|
+
type: "object",
|
|
47542
|
+
properties: {
|
|
47543
|
+
to: {
|
|
47544
|
+
type: "array",
|
|
47545
|
+
items: { type: "string" },
|
|
47546
|
+
description: 'Recipient email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]'
|
|
47547
|
+
},
|
|
47548
|
+
subject: {
|
|
47549
|
+
type: "string",
|
|
47550
|
+
description: 'Email subject as plain string. Example: "Meeting tomorrow" or "Re: Original subject" for replies.'
|
|
47551
|
+
},
|
|
47552
|
+
body: {
|
|
47553
|
+
type: "string",
|
|
47554
|
+
description: 'Email body as an HTML string. Example: "<p>Hi!</p><p>Can we meet at 2pm?</p>"'
|
|
47555
|
+
},
|
|
47556
|
+
cc: {
|
|
47557
|
+
type: "array",
|
|
47558
|
+
items: { type: "string" },
|
|
47559
|
+
description: 'CC email addresses as plain strings. Example: ["bob@contoso.com"]. Optional.'
|
|
47560
|
+
},
|
|
47561
|
+
replyToMessageId: {
|
|
47562
|
+
type: "string",
|
|
47563
|
+
description: 'Graph message ID of the email to reply to. Example: "AAMkADI1M2I3YzgtODg...". When set, sends a threaded reply.'
|
|
47564
|
+
},
|
|
47565
|
+
targetUser: {
|
|
47566
|
+
type: "string",
|
|
47567
|
+
description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
|
|
47568
|
+
}
|
|
47569
|
+
},
|
|
47570
|
+
required: ["to", "subject", "body"]
|
|
47571
|
+
}
|
|
47572
|
+
}
|
|
47573
|
+
},
|
|
47574
|
+
describeCall: (args) => {
|
|
47575
|
+
const action = args.replyToMessageId ? "Reply" : "Send";
|
|
47576
|
+
return `${action} to ${args.to.join(", ")}: ${args.subject}`;
|
|
47577
|
+
},
|
|
47578
|
+
permission: {
|
|
47579
|
+
scope: "session",
|
|
47580
|
+
riskLevel: "medium",
|
|
47581
|
+
approvalMessage: `Send an email via ${connector.displayName}`
|
|
47582
|
+
},
|
|
47583
|
+
execute: async (args, context) => {
|
|
47584
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
47585
|
+
try {
|
|
47586
|
+
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
47587
|
+
if (args.replyToMessageId) {
|
|
47588
|
+
await microsoftFetch(
|
|
47589
|
+
connector,
|
|
47590
|
+
`${prefix}/messages/${args.replyToMessageId}/reply`,
|
|
47591
|
+
{
|
|
47592
|
+
method: "POST",
|
|
47593
|
+
userId: effectiveUserId,
|
|
47594
|
+
body: {
|
|
47595
|
+
message: {
|
|
47596
|
+
toRecipients: formatRecipients(args.to),
|
|
47597
|
+
...args.cc && { ccRecipients: formatRecipients(args.cc) }
|
|
47598
|
+
},
|
|
47599
|
+
comment: args.body
|
|
47600
|
+
}
|
|
47601
|
+
}
|
|
47602
|
+
);
|
|
47603
|
+
} else {
|
|
47604
|
+
await microsoftFetch(
|
|
47605
|
+
connector,
|
|
47606
|
+
`${prefix}/sendMail`,
|
|
47607
|
+
{
|
|
47608
|
+
method: "POST",
|
|
47609
|
+
userId: effectiveUserId,
|
|
47610
|
+
body: {
|
|
47611
|
+
message: {
|
|
47612
|
+
subject: args.subject,
|
|
47613
|
+
body: { contentType: "HTML", content: args.body },
|
|
47614
|
+
toRecipients: formatRecipients(args.to),
|
|
47615
|
+
...args.cc && { ccRecipients: formatRecipients(args.cc) }
|
|
47616
|
+
},
|
|
47617
|
+
saveToSentItems: true
|
|
47618
|
+
}
|
|
47619
|
+
}
|
|
47620
|
+
);
|
|
47621
|
+
}
|
|
47622
|
+
return { success: true };
|
|
47623
|
+
} catch (error) {
|
|
47624
|
+
return {
|
|
47625
|
+
success: false,
|
|
47626
|
+
error: `Failed to send email: ${error instanceof Error ? error.message : String(error)}`
|
|
47627
|
+
};
|
|
47628
|
+
}
|
|
47629
|
+
}
|
|
47630
|
+
};
|
|
47631
|
+
}
|
|
47632
|
+
|
|
47633
|
+
// src/tools/microsoft/createMeeting.ts
|
|
47634
|
+
function createMeetingTool(connector, userId) {
|
|
47635
|
+
return {
|
|
47636
|
+
definition: {
|
|
47637
|
+
type: "function",
|
|
47638
|
+
function: {
|
|
47639
|
+
name: "create_meeting",
|
|
47640
|
+
description: `Create a calendar event on the user's Outlook calendar via Microsoft Graph, optionally with a Teams online meeting link.
|
|
47641
|
+
|
|
47642
|
+
PARAMETER FORMATS:
|
|
47643
|
+
- subject: plain string. Example: "Sprint Review"
|
|
47644
|
+
- startDateTime/endDateTime: ISO 8601 string WITHOUT timezone suffix (timezone is a separate param). Example: "2025-01-15T09:00:00"
|
|
47645
|
+
- attendees: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects.
|
|
47646
|
+
- body: HTML string for the invitation body. Example: "<p>Agenda: discuss Q1 goals</p>". Optional.
|
|
47647
|
+
- timeZone: IANA timezone string. Example: "America/New_York", "Europe/Zurich". Default: "UTC".
|
|
47648
|
+
- isOnlineMeeting: boolean. Set true to auto-generate a Teams meeting link.
|
|
47649
|
+
- location: plain string. Example: "Conference Room A". Optional.
|
|
47650
|
+
|
|
47651
|
+
EXAMPLES:
|
|
47652
|
+
- Simple: { "subject": "Standup", "startDateTime": "2025-01-15T09:00:00", "endDateTime": "2025-01-15T09:30:00", "attendees": ["alice@contoso.com"], "timeZone": "America/New_York" }
|
|
47653
|
+
- 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 }`,
|
|
47654
|
+
parameters: {
|
|
47655
|
+
type: "object",
|
|
47656
|
+
properties: {
|
|
47657
|
+
subject: {
|
|
47658
|
+
type: "string",
|
|
47659
|
+
description: 'Meeting title as plain string. Example: "Sprint Review"'
|
|
47660
|
+
},
|
|
47661
|
+
startDateTime: {
|
|
47662
|
+
type: "string",
|
|
47663
|
+
description: 'Start date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T09:00:00"'
|
|
47664
|
+
},
|
|
47665
|
+
endDateTime: {
|
|
47666
|
+
type: "string",
|
|
47667
|
+
description: 'End date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T09:30:00"'
|
|
47668
|
+
},
|
|
47669
|
+
attendees: {
|
|
47670
|
+
type: "array",
|
|
47671
|
+
items: { type: "string" },
|
|
47672
|
+
description: 'Attendee email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]'
|
|
47673
|
+
},
|
|
47674
|
+
body: {
|
|
47675
|
+
type: "string",
|
|
47676
|
+
description: 'Meeting description as HTML string. Example: "<p>Agenda: discuss Q1 goals</p>". Optional.'
|
|
47677
|
+
},
|
|
47678
|
+
isOnlineMeeting: {
|
|
47679
|
+
type: "boolean",
|
|
47680
|
+
description: "Set to true to generate a Teams online meeting link. Default: false."
|
|
47681
|
+
},
|
|
47682
|
+
location: {
|
|
47683
|
+
type: "string",
|
|
47684
|
+
description: 'Physical location as plain string. Example: "Conference Room A". Optional.'
|
|
47685
|
+
},
|
|
47686
|
+
timeZone: {
|
|
47687
|
+
type: "string",
|
|
47688
|
+
description: 'IANA timezone string for start/end times. Example: "America/New_York", "Europe/Zurich". Default: "UTC".'
|
|
47689
|
+
},
|
|
47690
|
+
targetUser: {
|
|
47691
|
+
type: "string",
|
|
47692
|
+
description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
|
|
47693
|
+
}
|
|
47694
|
+
},
|
|
47695
|
+
required: ["subject", "startDateTime", "endDateTime", "attendees"]
|
|
47696
|
+
}
|
|
47697
|
+
}
|
|
47698
|
+
},
|
|
47699
|
+
describeCall: (args) => {
|
|
47700
|
+
return `Create meeting: ${args.subject} (${args.attendees.length} attendees)`;
|
|
47701
|
+
},
|
|
47702
|
+
permission: {
|
|
47703
|
+
scope: "session",
|
|
47704
|
+
riskLevel: "medium",
|
|
47705
|
+
approvalMessage: `Create a calendar event via ${connector.displayName}`
|
|
47706
|
+
},
|
|
47707
|
+
execute: async (args, context) => {
|
|
47708
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
47709
|
+
try {
|
|
47710
|
+
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
47711
|
+
const tz = args.timeZone ?? "UTC";
|
|
47712
|
+
const eventBody = {
|
|
47713
|
+
subject: args.subject,
|
|
47714
|
+
start: { dateTime: args.startDateTime, timeZone: tz },
|
|
47715
|
+
end: { dateTime: args.endDateTime, timeZone: tz },
|
|
47716
|
+
attendees: formatAttendees(args.attendees)
|
|
47717
|
+
};
|
|
47718
|
+
if (args.body) {
|
|
47719
|
+
eventBody.body = { contentType: "HTML", content: args.body };
|
|
47720
|
+
}
|
|
47721
|
+
if (args.isOnlineMeeting) {
|
|
47722
|
+
eventBody.isOnlineMeeting = true;
|
|
47723
|
+
eventBody.onlineMeetingProvider = "teamsForBusiness";
|
|
47724
|
+
}
|
|
47725
|
+
if (args.location) {
|
|
47726
|
+
eventBody.location = { displayName: args.location };
|
|
47727
|
+
}
|
|
47728
|
+
const event = await microsoftFetch(
|
|
47729
|
+
connector,
|
|
47730
|
+
`${prefix}/events`,
|
|
47731
|
+
{ method: "POST", userId: effectiveUserId, body: eventBody }
|
|
47732
|
+
);
|
|
47733
|
+
return {
|
|
47734
|
+
success: true,
|
|
47735
|
+
eventId: event.id,
|
|
47736
|
+
webLink: event.webLink,
|
|
47737
|
+
onlineMeetingUrl: event.onlineMeeting?.joinUrl
|
|
47738
|
+
};
|
|
47739
|
+
} catch (error) {
|
|
47740
|
+
return {
|
|
47741
|
+
success: false,
|
|
47742
|
+
error: `Failed to create meeting: ${error instanceof Error ? error.message : String(error)}`
|
|
47743
|
+
};
|
|
47744
|
+
}
|
|
47745
|
+
}
|
|
47746
|
+
};
|
|
47747
|
+
}
|
|
47748
|
+
|
|
47749
|
+
// src/tools/microsoft/editMeeting.ts
|
|
47750
|
+
function createEditMeetingTool(connector, userId) {
|
|
47751
|
+
return {
|
|
47752
|
+
definition: {
|
|
47753
|
+
type: "function",
|
|
47754
|
+
function: {
|
|
47755
|
+
name: "edit_meeting",
|
|
47756
|
+
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.
|
|
47757
|
+
|
|
47758
|
+
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.
|
|
47759
|
+
|
|
47760
|
+
PARAMETER FORMATS:
|
|
47761
|
+
- eventId: Graph event ID string (starts with "AAMk..."). Get this from a previous create_meeting result.
|
|
47762
|
+
- subject: plain string. Example: "Updated: Sprint Review"
|
|
47763
|
+
- startDateTime/endDateTime: ISO 8601 string without timezone suffix. Example: "2025-01-15T10:00:00"
|
|
47764
|
+
- attendees: plain string array of email addresses. Example: ["alice@contoso.com", "charlie@contoso.com"]. Do NOT use objects. REPLACES all attendees.
|
|
47765
|
+
- body: HTML string. Example: "<p>Updated agenda</p>"
|
|
47766
|
+
- timeZone: IANA timezone string. Example: "Europe/Zurich". Default: "UTC".
|
|
47767
|
+
- isOnlineMeeting: boolean. true = add Teams link, false = remove it.
|
|
47768
|
+
- location: plain string. Example: "Room 201"
|
|
47769
|
+
|
|
47770
|
+
EXAMPLES:
|
|
47771
|
+
- Reschedule: { "eventId": "AAMkADI1...", "startDateTime": "2025-01-15T10:00:00", "endDateTime": "2025-01-15T10:30:00", "timeZone": "America/New_York" }
|
|
47772
|
+
- Change attendees: { "eventId": "AAMkADI1...", "attendees": ["alice@contoso.com", "charlie@contoso.com"] }
|
|
47773
|
+
- Add Teams link: { "eventId": "AAMkADI1...", "isOnlineMeeting": true }`,
|
|
47774
|
+
parameters: {
|
|
47775
|
+
type: "object",
|
|
47776
|
+
properties: {
|
|
47777
|
+
eventId: {
|
|
47778
|
+
type: "string",
|
|
47779
|
+
description: 'Calendar event ID string from create_meeting result. Example: "AAMkADI1M2I3YzgtODg..."'
|
|
47780
|
+
},
|
|
47781
|
+
subject: {
|
|
47782
|
+
type: "string",
|
|
47783
|
+
description: 'New meeting title as plain string. Example: "Updated: Sprint Review"'
|
|
47784
|
+
},
|
|
47785
|
+
startDateTime: {
|
|
47786
|
+
type: "string",
|
|
47787
|
+
description: 'New start date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T10:00:00"'
|
|
47788
|
+
},
|
|
47789
|
+
endDateTime: {
|
|
47790
|
+
type: "string",
|
|
47791
|
+
description: 'New end date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T10:30:00"'
|
|
47792
|
+
},
|
|
47793
|
+
attendees: {
|
|
47794
|
+
type: "array",
|
|
47795
|
+
items: { type: "string" },
|
|
47796
|
+
description: 'FULL replacement attendee list as plain email strings. Example: ["alice@contoso.com", "charlie@contoso.com"]. Include ALL attendees.'
|
|
47797
|
+
},
|
|
47798
|
+
body: {
|
|
47799
|
+
type: "string",
|
|
47800
|
+
description: 'New meeting description as HTML string. Example: "<p>Updated agenda</p>"'
|
|
47801
|
+
},
|
|
47802
|
+
isOnlineMeeting: {
|
|
47803
|
+
type: "boolean",
|
|
47804
|
+
description: "true to add Teams meeting link, false to remove it."
|
|
47805
|
+
},
|
|
47806
|
+
location: {
|
|
47807
|
+
type: "string",
|
|
47808
|
+
description: 'New location as plain string. Example: "Conference Room A"'
|
|
47809
|
+
},
|
|
47810
|
+
timeZone: {
|
|
47811
|
+
type: "string",
|
|
47812
|
+
description: 'IANA timezone string for start/end times. Example: "Europe/Zurich". Default: "UTC".'
|
|
47813
|
+
},
|
|
47814
|
+
targetUser: {
|
|
47815
|
+
type: "string",
|
|
47816
|
+
description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
|
|
47817
|
+
}
|
|
47818
|
+
},
|
|
47819
|
+
required: ["eventId"]
|
|
47820
|
+
}
|
|
47821
|
+
}
|
|
47822
|
+
},
|
|
47823
|
+
describeCall: (args) => {
|
|
47824
|
+
const fields = ["subject", "startDateTime", "endDateTime", "attendees", "body", "location"];
|
|
47825
|
+
const changed = fields.filter((f) => args[f] !== void 0);
|
|
47826
|
+
return `Edit meeting ${args.eventId.slice(0, 12)}... (${changed.join(", ") || "no changes"})`;
|
|
47827
|
+
},
|
|
47828
|
+
permission: {
|
|
47829
|
+
scope: "session",
|
|
47830
|
+
riskLevel: "medium",
|
|
47831
|
+
approvalMessage: `Update a calendar event via ${connector.displayName}`
|
|
47832
|
+
},
|
|
47833
|
+
execute: async (args, context) => {
|
|
47834
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
47835
|
+
try {
|
|
47836
|
+
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
47837
|
+
const tz = args.timeZone ?? "UTC";
|
|
47838
|
+
const patchBody = {};
|
|
47839
|
+
if (args.subject !== void 0) patchBody.subject = args.subject;
|
|
47840
|
+
if (args.body !== void 0) patchBody.body = { contentType: "HTML", content: args.body };
|
|
47841
|
+
if (args.startDateTime !== void 0) patchBody.start = { dateTime: args.startDateTime, timeZone: tz };
|
|
47842
|
+
if (args.endDateTime !== void 0) patchBody.end = { dateTime: args.endDateTime, timeZone: tz };
|
|
47843
|
+
if (args.attendees !== void 0) {
|
|
47844
|
+
patchBody.attendees = formatAttendees(args.attendees);
|
|
47845
|
+
}
|
|
47846
|
+
if (args.isOnlineMeeting !== void 0) {
|
|
47847
|
+
patchBody.isOnlineMeeting = args.isOnlineMeeting;
|
|
47848
|
+
if (args.isOnlineMeeting) {
|
|
47849
|
+
patchBody.onlineMeetingProvider = "teamsForBusiness";
|
|
47850
|
+
}
|
|
47851
|
+
}
|
|
47852
|
+
if (args.location !== void 0) {
|
|
47853
|
+
patchBody.location = { displayName: args.location };
|
|
47854
|
+
}
|
|
47855
|
+
const event = await microsoftFetch(
|
|
47856
|
+
connector,
|
|
47857
|
+
`${prefix}/events/${args.eventId}`,
|
|
47858
|
+
{ method: "PATCH", userId: effectiveUserId, body: patchBody }
|
|
47859
|
+
);
|
|
47860
|
+
return {
|
|
47861
|
+
success: true,
|
|
47862
|
+
eventId: event.id,
|
|
47863
|
+
webLink: event.webLink
|
|
47864
|
+
};
|
|
47865
|
+
} catch (error) {
|
|
47866
|
+
return {
|
|
47867
|
+
success: false,
|
|
47868
|
+
error: `Failed to edit meeting: ${error instanceof Error ? error.message : String(error)}`
|
|
47869
|
+
};
|
|
47870
|
+
}
|
|
47871
|
+
}
|
|
47872
|
+
};
|
|
47873
|
+
}
|
|
47874
|
+
|
|
47875
|
+
// src/tools/microsoft/getMeetingTranscript.ts
|
|
47876
|
+
function parseVttToText(vtt) {
|
|
47877
|
+
const lines = vtt.split("\n");
|
|
47878
|
+
const textLines = [];
|
|
47879
|
+
for (const line of lines) {
|
|
47880
|
+
const trimmed = line.trim();
|
|
47881
|
+
if (trimmed === "" || trimmed === "WEBVTT" || trimmed.startsWith("NOTE") || /^\d+$/.test(trimmed) || /^\d{2}:\d{2}/.test(trimmed)) {
|
|
47882
|
+
continue;
|
|
47883
|
+
}
|
|
47884
|
+
textLines.push(trimmed);
|
|
47885
|
+
}
|
|
47886
|
+
return textLines.join("\n");
|
|
47887
|
+
}
|
|
47888
|
+
function createGetMeetingTranscriptTool(connector, userId) {
|
|
47889
|
+
return {
|
|
47890
|
+
definition: {
|
|
47891
|
+
type: "function",
|
|
47892
|
+
function: {
|
|
47893
|
+
name: "get_meeting_transcript",
|
|
47894
|
+
description: `Retrieve the transcript from a Teams online meeting via Microsoft Graph. Returns plain text with speaker labels (VTT timestamps are stripped).
|
|
47895
|
+
|
|
47896
|
+
NOTE: Requires the OnlineMeetingTranscript.Read.All permission. Transcription must have been enabled during the meeting.
|
|
47897
|
+
|
|
47898
|
+
USAGE:
|
|
47899
|
+
- Provide the Teams online meeting ID (NOT the calendar event ID \u2014 this is different) or a Teams meeting join URL
|
|
47900
|
+
- The meetingId can be found in the Teams meeting details or extracted from the join URL
|
|
47901
|
+
|
|
47902
|
+
EXAMPLES:
|
|
47903
|
+
- By meeting ID: { "meetingId": "MSo1N2Y5ZGFjYy03MWJmLTQ3NDMtYjQxMy01M2EdFGkdRWHJlQ" }
|
|
47904
|
+
- By Teams join URL: { "meetingId": "https://teams.microsoft.com/l/meetup-join/19%3ameeting_MjA5YjFi..." }`,
|
|
47905
|
+
parameters: {
|
|
47906
|
+
type: "object",
|
|
47907
|
+
properties: {
|
|
47908
|
+
meetingId: {
|
|
47909
|
+
type: "string",
|
|
47910
|
+
description: 'Teams online meeting ID (e.g. "MSo1N2Y5...") or Teams meeting join URL. This is NOT the calendar event ID.'
|
|
47911
|
+
},
|
|
47912
|
+
targetUser: {
|
|
47913
|
+
type: "string",
|
|
47914
|
+
description: "User ID or email (UPN) to act on behalf of. Only needed for app-only (client_credentials) auth. Ignored in delegated auth."
|
|
47915
|
+
}
|
|
47916
|
+
},
|
|
47917
|
+
required: ["meetingId"]
|
|
47918
|
+
}
|
|
47919
|
+
}
|
|
47920
|
+
},
|
|
47921
|
+
describeCall: (args) => {
|
|
47922
|
+
return `Get transcript for meeting ${args.meetingId.slice(0, 20)}...`;
|
|
47923
|
+
},
|
|
47924
|
+
permission: {
|
|
47925
|
+
scope: "session",
|
|
47926
|
+
riskLevel: "low",
|
|
47927
|
+
approvalMessage: `Get a meeting transcript via ${connector.displayName}`
|
|
47928
|
+
},
|
|
47929
|
+
execute: async (args, context) => {
|
|
47930
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
47931
|
+
try {
|
|
47932
|
+
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
47933
|
+
const resolved = await resolveMeetingId(connector, args.meetingId, prefix, effectiveUserId);
|
|
47934
|
+
const meetingId = resolved.meetingId;
|
|
47935
|
+
const transcriptList = await microsoftFetch(
|
|
47936
|
+
connector,
|
|
47937
|
+
`${prefix}/onlineMeetings/${meetingId}/transcripts`,
|
|
47938
|
+
{ userId: effectiveUserId }
|
|
47939
|
+
);
|
|
47940
|
+
if (!transcriptList.value || transcriptList.value.length === 0) {
|
|
47941
|
+
return {
|
|
47942
|
+
success: false,
|
|
47943
|
+
error: "No transcripts found for this meeting. The meeting may not have had transcription enabled."
|
|
47944
|
+
};
|
|
47945
|
+
}
|
|
47946
|
+
const transcriptId = transcriptList.value[0].id;
|
|
47947
|
+
const contentUrl = `${prefix}/onlineMeetings/${meetingId}/transcripts/${transcriptId}/content`;
|
|
47948
|
+
const response = await connector.fetch(
|
|
47949
|
+
contentUrl + "?$format=text/vtt",
|
|
47950
|
+
{ method: "GET", headers: { "Accept": "text/vtt" } },
|
|
47951
|
+
effectiveUserId
|
|
47952
|
+
);
|
|
47953
|
+
if (!response.ok) {
|
|
47954
|
+
const errorText = await response.text();
|
|
47955
|
+
return {
|
|
47956
|
+
success: false,
|
|
47957
|
+
error: `Failed to fetch transcript content: ${response.status} ${errorText}`
|
|
47958
|
+
};
|
|
47959
|
+
}
|
|
47960
|
+
const vttContent = await response.text();
|
|
47961
|
+
const transcript = parseVttToText(vttContent);
|
|
47962
|
+
return {
|
|
47963
|
+
success: true,
|
|
47964
|
+
transcript,
|
|
47965
|
+
meetingSubject: resolved.subject
|
|
47966
|
+
};
|
|
47967
|
+
} catch (error) {
|
|
47968
|
+
return {
|
|
47969
|
+
success: false,
|
|
47970
|
+
error: `Failed to get meeting transcript: ${error instanceof Error ? error.message : String(error)}`
|
|
47971
|
+
};
|
|
47972
|
+
}
|
|
47973
|
+
}
|
|
47974
|
+
};
|
|
47975
|
+
}
|
|
47976
|
+
|
|
47977
|
+
// src/tools/microsoft/findMeetingSlots.ts
|
|
47978
|
+
function createFindMeetingSlotsTool(connector, userId) {
|
|
47979
|
+
return {
|
|
47980
|
+
definition: {
|
|
47981
|
+
type: "function",
|
|
47982
|
+
function: {
|
|
47983
|
+
name: "find_meeting_slots",
|
|
47984
|
+
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.
|
|
47985
|
+
|
|
47986
|
+
PARAMETER FORMATS:
|
|
47987
|
+
- attendees: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects \u2014 just plain email strings.
|
|
47988
|
+
- startDateTime/endDateTime: ISO 8601 string without timezone suffix. Example: "2025-01-15T08:00:00". Can span multiple days.
|
|
47989
|
+
- duration: number of minutes as integer. Example: 30 or 60.
|
|
47990
|
+
- timeZone: IANA timezone string. Example: "America/New_York", "Europe/Zurich". Default: "UTC".
|
|
47991
|
+
- maxResults: integer. Default: 5.
|
|
47992
|
+
|
|
47993
|
+
EXAMPLES:
|
|
47994
|
+
- 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" }
|
|
47995
|
+
- 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 }`,
|
|
47996
|
+
parameters: {
|
|
47997
|
+
type: "object",
|
|
47998
|
+
properties: {
|
|
47999
|
+
attendees: {
|
|
48000
|
+
type: "array",
|
|
48001
|
+
items: { type: "string" },
|
|
48002
|
+
description: 'Attendee email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT pass objects.'
|
|
48003
|
+
},
|
|
48004
|
+
startDateTime: {
|
|
48005
|
+
type: "string",
|
|
48006
|
+
description: 'Search window start as ISO 8601 string without timezone suffix. Example: "2025-01-15T08:00:00"'
|
|
48007
|
+
},
|
|
48008
|
+
endDateTime: {
|
|
48009
|
+
type: "string",
|
|
48010
|
+
description: 'Search window end as ISO 8601 string without timezone suffix. Example: "2025-01-15T18:00:00". Can span multiple days.'
|
|
48011
|
+
},
|
|
48012
|
+
duration: {
|
|
48013
|
+
type: "number",
|
|
48014
|
+
description: "Meeting duration in minutes as integer. Example: 30 or 60."
|
|
48015
|
+
},
|
|
48016
|
+
timeZone: {
|
|
48017
|
+
type: "string",
|
|
48018
|
+
description: 'IANA timezone string for start/end times. Example: "America/New_York", "Europe/Zurich". Default: "UTC".'
|
|
48019
|
+
},
|
|
48020
|
+
maxResults: {
|
|
48021
|
+
type: "number",
|
|
48022
|
+
description: "Maximum number of time slot suggestions as integer. Default: 5."
|
|
48023
|
+
},
|
|
48024
|
+
targetUser: {
|
|
48025
|
+
type: "string",
|
|
48026
|
+
description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
|
|
48027
|
+
}
|
|
48028
|
+
},
|
|
48029
|
+
required: ["attendees", "startDateTime", "endDateTime", "duration"]
|
|
48030
|
+
}
|
|
48031
|
+
}
|
|
48032
|
+
},
|
|
48033
|
+
describeCall: (args) => {
|
|
48034
|
+
return `Find ${args.duration}min slots for ${args.attendees.length} attendees`;
|
|
48035
|
+
},
|
|
48036
|
+
permission: {
|
|
48037
|
+
scope: "session",
|
|
48038
|
+
riskLevel: "low",
|
|
48039
|
+
approvalMessage: `Find meeting time slots via ${connector.displayName}`
|
|
48040
|
+
},
|
|
48041
|
+
execute: async (args, context) => {
|
|
48042
|
+
const effectiveUserId = context?.userId ?? userId;
|
|
48043
|
+
try {
|
|
48044
|
+
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
48045
|
+
const tz = args.timeZone ?? "UTC";
|
|
48046
|
+
const result = await microsoftFetch(
|
|
48047
|
+
connector,
|
|
48048
|
+
`${prefix}/findMeetingTimes`,
|
|
48049
|
+
{
|
|
48050
|
+
method: "POST",
|
|
48051
|
+
userId: effectiveUserId,
|
|
48052
|
+
body: {
|
|
48053
|
+
attendees: formatAttendees(args.attendees),
|
|
48054
|
+
timeConstraint: {
|
|
48055
|
+
timeslots: [
|
|
48056
|
+
{
|
|
48057
|
+
start: { dateTime: args.startDateTime, timeZone: tz },
|
|
48058
|
+
end: { dateTime: args.endDateTime, timeZone: tz }
|
|
48059
|
+
}
|
|
48060
|
+
]
|
|
48061
|
+
},
|
|
48062
|
+
meetingDuration: `PT${args.duration}M`,
|
|
48063
|
+
maxCandidates: args.maxResults ?? 5
|
|
48064
|
+
}
|
|
48065
|
+
}
|
|
48066
|
+
);
|
|
48067
|
+
const slots = (result.meetingTimeSuggestions ?? []).map((s) => ({
|
|
48068
|
+
start: s.meetingTimeSlot.start.dateTime,
|
|
48069
|
+
end: s.meetingTimeSlot.end.dateTime,
|
|
48070
|
+
confidence: String(s.confidence),
|
|
48071
|
+
attendeeAvailability: (s.attendeeAvailability ?? []).map((a) => ({
|
|
48072
|
+
attendee: a.attendee.emailAddress.address,
|
|
48073
|
+
availability: a.availability
|
|
48074
|
+
}))
|
|
48075
|
+
}));
|
|
48076
|
+
return {
|
|
48077
|
+
success: true,
|
|
48078
|
+
slots,
|
|
48079
|
+
emptySuggestionsReason: result.emptySuggestionsReason
|
|
48080
|
+
};
|
|
48081
|
+
} catch (error) {
|
|
48082
|
+
return {
|
|
48083
|
+
success: false,
|
|
48084
|
+
error: `Failed to find meeting slots: ${error instanceof Error ? error.message : String(error)}`
|
|
48085
|
+
};
|
|
48086
|
+
}
|
|
48087
|
+
}
|
|
48088
|
+
};
|
|
48089
|
+
}
|
|
48090
|
+
|
|
48091
|
+
// src/tools/microsoft/register.ts
|
|
48092
|
+
function registerMicrosoftTools() {
|
|
48093
|
+
ConnectorTools.registerService("microsoft", (connector, userId) => {
|
|
48094
|
+
return [
|
|
48095
|
+
createDraftEmailTool(connector, userId),
|
|
48096
|
+
createSendEmailTool(connector, userId),
|
|
48097
|
+
createMeetingTool(connector, userId),
|
|
48098
|
+
createEditMeetingTool(connector, userId),
|
|
48099
|
+
createGetMeetingTranscriptTool(connector, userId),
|
|
48100
|
+
createFindMeetingSlotsTool(connector, userId)
|
|
48101
|
+
];
|
|
48102
|
+
});
|
|
48103
|
+
}
|
|
48104
|
+
|
|
48105
|
+
// src/tools/microsoft/index.ts
|
|
48106
|
+
registerMicrosoftTools();
|
|
48107
|
+
|
|
46545
48108
|
// src/tools/desktop/types.ts
|
|
46546
48109
|
var DEFAULT_DESKTOP_CONFIG = {
|
|
46547
48110
|
driver: null,
|
|
@@ -48528,6 +50091,6 @@ REMEMBER: Keep it conversational, ask one question at a time, and only output th
|
|
|
48528
50091
|
}
|
|
48529
50092
|
};
|
|
48530
50093
|
|
|
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 };
|
|
50094
|
+
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
50095
|
//# sourceMappingURL=index.js.map
|
|
48533
50096
|
//# sourceMappingURL=index.js.map
|