@everworker/oneringai 0.3.2 → 0.4.1

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