@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.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  var crypto2 = require('crypto');
4
4
  var jose = require('jose');
5
- var fs18 = require('fs');
5
+ var fs19 = require('fs');
6
6
  var eventemitter3 = require('eventemitter3');
7
7
  var path2 = require('path');
8
8
  var TurndownService = require('turndown');
@@ -17,7 +17,7 @@ var z = require('zod/v4');
17
17
  var spawn = require('cross-spawn');
18
18
  var process2 = require('process');
19
19
  var stream = require('stream');
20
- var fs17 = require('fs/promises');
20
+ var fs18 = require('fs/promises');
21
21
  var simpleIcons = require('simple-icons');
22
22
  var child_process = require('child_process');
23
23
  var util = require('util');
@@ -45,7 +45,7 @@ function _interopNamespace(e) {
45
45
  }
46
46
 
47
47
  var crypto2__namespace = /*#__PURE__*/_interopNamespace(crypto2);
48
- var fs18__namespace = /*#__PURE__*/_interopNamespace(fs18);
48
+ var fs19__namespace = /*#__PURE__*/_interopNamespace(fs19);
49
49
  var path2__namespace = /*#__PURE__*/_interopNamespace(path2);
50
50
  var TurndownService__default = /*#__PURE__*/_interopDefault(TurndownService);
51
51
  var os2__namespace = /*#__PURE__*/_interopNamespace(os2);
@@ -55,7 +55,7 @@ var z4mini__namespace = /*#__PURE__*/_interopNamespace(z4mini);
55
55
  var z__namespace = /*#__PURE__*/_interopNamespace(z);
56
56
  var spawn__default = /*#__PURE__*/_interopDefault(spawn);
57
57
  var process2__default = /*#__PURE__*/_interopDefault(process2);
58
- var fs17__namespace = /*#__PURE__*/_interopNamespace(fs17);
58
+ var fs18__namespace = /*#__PURE__*/_interopNamespace(fs18);
59
59
  var simpleIcons__namespace = /*#__PURE__*/_interopNamespace(simpleIcons);
60
60
  var vm__namespace = /*#__PURE__*/_interopNamespace(vm);
61
61
 
@@ -673,7 +673,7 @@ var init_JWTBearer = __esm({
673
673
  this.privateKey = config.privateKey;
674
674
  } else if (config.privateKeyPath) {
675
675
  try {
676
- this.privateKey = fs18__namespace.readFileSync(config.privateKeyPath, "utf8");
676
+ this.privateKey = fs19__namespace.readFileSync(config.privateKeyPath, "utf8");
677
677
  } catch (error) {
678
678
  throw new Error(`Failed to read private key from ${config.privateKeyPath}: ${error.message}`);
679
679
  }
@@ -1432,10 +1432,10 @@ var init_Logger = __esm({
1432
1432
  initFileStream(filePath) {
1433
1433
  try {
1434
1434
  const dir = path2__namespace.dirname(filePath);
1435
- if (!fs18__namespace.existsSync(dir)) {
1436
- fs18__namespace.mkdirSync(dir, { recursive: true });
1435
+ if (!fs19__namespace.existsSync(dir)) {
1436
+ fs19__namespace.mkdirSync(dir, { recursive: true });
1437
1437
  }
1438
- this.fileStream = fs18__namespace.createWriteStream(filePath, {
1438
+ this.fileStream = fs19__namespace.createWriteStream(filePath, {
1439
1439
  flags: "a",
1440
1440
  // append mode
1441
1441
  encoding: "utf8"
@@ -9165,12 +9165,12 @@ var require_dist = __commonJS({
9165
9165
  throw new Error(`Unknown format "${name}"`);
9166
9166
  return f;
9167
9167
  };
9168
- function addFormats(ajv, list, fs19, exportName) {
9168
+ function addFormats(ajv, list, fs20, exportName) {
9169
9169
  var _a;
9170
9170
  var _b;
9171
9171
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
9172
9172
  for (const f of list)
9173
- ajv.addFormat(f, fs19[f]);
9173
+ ajv.addFormat(f, fs20[f]);
9174
9174
  }
9175
9175
  module.exports = exports$1 = formatsPlugin;
9176
9176
  Object.defineProperty(exports$1, "__esModule", { value: true });
@@ -14505,7 +14505,7 @@ var PRIORITY_VALUES = {
14505
14505
  };
14506
14506
  var DEFAULT_CONFIG = {
14507
14507
  maxEntries: 20,
14508
- maxTotalTokens: 4e3,
14508
+ maxTotalTokens: 4e4,
14509
14509
  defaultPriority: "normal",
14510
14510
  showTimestamps: false
14511
14511
  };
@@ -14902,7 +14902,7 @@ var FilePersistentInstructionsStorage = class {
14902
14902
  */
14903
14903
  async load() {
14904
14904
  try {
14905
- const raw = await fs18.promises.readFile(this.filePath, "utf-8");
14905
+ const raw = await fs19.promises.readFile(this.filePath, "utf-8");
14906
14906
  const data = JSON.parse(raw);
14907
14907
  if (data.version === 2 && Array.isArray(data.entries)) {
14908
14908
  return data.entries.length > 0 ? data.entries : null;
@@ -14914,7 +14914,7 @@ var FilePersistentInstructionsStorage = class {
14914
14914
  }
14915
14915
  }
14916
14916
  try {
14917
- const content = await fs18.promises.readFile(this.legacyFilePath, "utf-8");
14917
+ const content = await fs19.promises.readFile(this.legacyFilePath, "utf-8");
14918
14918
  const trimmed = content.trim();
14919
14919
  if (!trimmed) return null;
14920
14920
  const now = Date.now();
@@ -14944,11 +14944,11 @@ var FilePersistentInstructionsStorage = class {
14944
14944
  };
14945
14945
  const tempPath = `${this.filePath}.tmp`;
14946
14946
  try {
14947
- await fs18.promises.writeFile(tempPath, JSON.stringify(data, null, 2), "utf-8");
14948
- await fs18.promises.rename(tempPath, this.filePath);
14947
+ await fs19.promises.writeFile(tempPath, JSON.stringify(data, null, 2), "utf-8");
14948
+ await fs19.promises.rename(tempPath, this.filePath);
14949
14949
  } catch (error) {
14950
14950
  try {
14951
- await fs18.promises.unlink(tempPath);
14951
+ await fs19.promises.unlink(tempPath);
14952
14952
  } catch {
14953
14953
  }
14954
14954
  throw error;
@@ -14960,7 +14960,7 @@ var FilePersistentInstructionsStorage = class {
14960
14960
  */
14961
14961
  async delete() {
14962
14962
  try {
14963
- await fs18.promises.unlink(this.filePath);
14963
+ await fs19.promises.unlink(this.filePath);
14964
14964
  } catch (error) {
14965
14965
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
14966
14966
  throw error;
@@ -14973,11 +14973,11 @@ var FilePersistentInstructionsStorage = class {
14973
14973
  */
14974
14974
  async exists() {
14975
14975
  try {
14976
- await fs18.promises.access(this.filePath);
14976
+ await fs19.promises.access(this.filePath);
14977
14977
  return true;
14978
14978
  } catch {
14979
14979
  try {
14980
- await fs18.promises.access(this.legacyFilePath);
14980
+ await fs19.promises.access(this.legacyFilePath);
14981
14981
  return true;
14982
14982
  } catch {
14983
14983
  return false;
@@ -15001,7 +15001,7 @@ var FilePersistentInstructionsStorage = class {
15001
15001
  */
15002
15002
  async ensureDirectory() {
15003
15003
  try {
15004
- await fs18.promises.mkdir(this.directory, { recursive: true });
15004
+ await fs19.promises.mkdir(this.directory, { recursive: true });
15005
15005
  } catch (error) {
15006
15006
  if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
15007
15007
  throw error;
@@ -15013,7 +15013,7 @@ var FilePersistentInstructionsStorage = class {
15013
15013
  */
15014
15014
  async removeLegacyFile() {
15015
15015
  try {
15016
- await fs18.promises.unlink(this.legacyFilePath);
15016
+ await fs19.promises.unlink(this.legacyFilePath);
15017
15017
  } catch (error) {
15018
15018
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
15019
15019
  console.warn(`Failed to remove legacy instructions file: ${this.legacyFilePath}`);
@@ -15518,7 +15518,7 @@ var FileUserInfoStorage = class {
15518
15518
  async load(userId) {
15519
15519
  const filePath = this.getUserFilePath(userId);
15520
15520
  try {
15521
- const raw = await fs18.promises.readFile(filePath, "utf-8");
15521
+ const raw = await fs19.promises.readFile(filePath, "utf-8");
15522
15522
  const data = JSON.parse(raw);
15523
15523
  if (data.version === 1 && Array.isArray(data.entries)) {
15524
15524
  return data.entries.length > 0 ? data.entries : null;
@@ -15546,11 +15546,11 @@ var FileUserInfoStorage = class {
15546
15546
  };
15547
15547
  const tempPath = `${filePath}.tmp`;
15548
15548
  try {
15549
- await fs18.promises.writeFile(tempPath, JSON.stringify(data, null, 2), "utf-8");
15550
- await fs18.promises.rename(tempPath, filePath);
15549
+ await fs19.promises.writeFile(tempPath, JSON.stringify(data, null, 2), "utf-8");
15550
+ await fs19.promises.rename(tempPath, filePath);
15551
15551
  } catch (error) {
15552
15552
  try {
15553
- await fs18.promises.unlink(tempPath);
15553
+ await fs19.promises.unlink(tempPath);
15554
15554
  } catch {
15555
15555
  }
15556
15556
  throw error;
@@ -15562,7 +15562,7 @@ var FileUserInfoStorage = class {
15562
15562
  async delete(userId) {
15563
15563
  const filePath = this.getUserFilePath(userId);
15564
15564
  try {
15565
- await fs18.promises.unlink(filePath);
15565
+ await fs19.promises.unlink(filePath);
15566
15566
  } catch (error) {
15567
15567
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
15568
15568
  throw error;
@@ -15575,7 +15575,7 @@ var FileUserInfoStorage = class {
15575
15575
  async exists(userId) {
15576
15576
  const filePath = this.getUserFilePath(userId);
15577
15577
  try {
15578
- await fs18.promises.access(filePath);
15578
+ await fs19.promises.access(filePath);
15579
15579
  return true;
15580
15580
  } catch {
15581
15581
  return false;
@@ -15592,7 +15592,7 @@ var FileUserInfoStorage = class {
15592
15592
  */
15593
15593
  async ensureDirectory(directory) {
15594
15594
  try {
15595
- await fs18.promises.mkdir(directory, { recursive: true });
15595
+ await fs19.promises.mkdir(directory, { recursive: true });
15596
15596
  } catch (error) {
15597
15597
  if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
15598
15598
  throw error;
@@ -16690,7 +16690,7 @@ var StrategyRegistry = class {
16690
16690
  // src/core/context-nextgen/types.ts
16691
16691
  var DEFAULT_FEATURES = {
16692
16692
  workingMemory: true,
16693
- inContextMemory: false,
16693
+ inContextMemory: true,
16694
16694
  persistentInstructions: false,
16695
16695
  userInfo: false
16696
16696
  };
@@ -17370,6 +17370,8 @@ ${content}`);
17370
17370
  breakdown.pluginContents[plugin.name] = plugin.getTokenSize();
17371
17371
  }
17372
17372
  }
17373
+ const now = /* @__PURE__ */ new Date();
17374
+ parts.push(`CURRENT DATE AND TIME: ${now.toLocaleString("en-US", { dateStyle: "full", timeStyle: "long", timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone })}`);
17373
17375
  const systemText = parts.join("\n\n---\n\n");
17374
17376
  const systemTokens = this._estimator.estimateTokens(systemText);
17375
17377
  const systemMessage = {
@@ -20828,6 +20830,7 @@ var BaseAgent = class extends eventemitter3.EventEmitter {
20828
20830
  _agentContext;
20829
20831
  // SINGLE SOURCE OF TRUTH for tools and sessions
20830
20832
  _permissionManager;
20833
+ _ownsContext = true;
20831
20834
  _isDestroyed = false;
20832
20835
  _cleanupCallbacks = [];
20833
20836
  _logger;
@@ -20880,8 +20883,10 @@ var BaseAgent = class extends eventemitter3.EventEmitter {
20880
20883
  */
20881
20884
  initializeAgentContext(config) {
20882
20885
  if (config.context instanceof AgentContextNextGen) {
20886
+ this._ownsContext = false;
20883
20887
  return config.context;
20884
20888
  }
20889
+ this._ownsContext = true;
20885
20890
  const contextConfig = {
20886
20891
  model: config.model,
20887
20892
  agentId: config.name,
@@ -21393,7 +21398,9 @@ var BaseAgent = class extends eventemitter3.EventEmitter {
21393
21398
  clearInterval(this._autoSaveInterval);
21394
21399
  this._autoSaveInterval = null;
21395
21400
  }
21396
- this._agentContext.destroy();
21401
+ if (this._ownsContext) {
21402
+ this._agentContext.destroy();
21403
+ }
21397
21404
  this._permissionManager.removeAllListeners();
21398
21405
  this.removeAllListeners();
21399
21406
  }
@@ -21734,6 +21741,18 @@ var HookManager = class {
21734
21741
  }
21735
21742
  existing.push(hook);
21736
21743
  }
21744
+ /**
21745
+ * Unregister a specific hook function by reference.
21746
+ * Returns true if the hook was found and removed.
21747
+ */
21748
+ unregister(name, hook) {
21749
+ const hooks = this.hooks.get(name);
21750
+ if (!hooks) return false;
21751
+ const index = hooks.indexOf(hook);
21752
+ if (index === -1) return false;
21753
+ hooks.splice(index, 1);
21754
+ return true;
21755
+ }
21737
21756
  /**
21738
21757
  * Execute hooks for a given name
21739
21758
  */
@@ -21756,7 +21775,7 @@ var HookManager = class {
21756
21775
  const hook = hooks[i];
21757
21776
  const hookKey = this.getHookKey(hook, i);
21758
21777
  const hookResult = await this.executeHookSafely(hook, context, hookKey);
21759
- if (hookResult === null) {
21778
+ if (hookResult == null) {
21760
21779
  continue;
21761
21780
  }
21762
21781
  result = { ...result, ...hookResult };
@@ -21776,7 +21795,7 @@ var HookManager = class {
21776
21795
  return this.executeHookSafely(hook, context, hookKey);
21777
21796
  })
21778
21797
  );
21779
- const validResults = results.filter((r) => r !== null);
21798
+ const validResults = results.filter((r) => r != null);
21780
21799
  return validResults.reduce(
21781
21800
  (acc, hookResult) => ({ ...acc, ...hookResult }),
21782
21801
  defaultResult
@@ -22452,7 +22471,6 @@ var Agent = class _Agent extends BaseAgent {
22452
22471
  _cleanupExecution(streamState) {
22453
22472
  streamState?.clear();
22454
22473
  this.executionContext?.cleanup();
22455
- this.hookManager.clear();
22456
22474
  }
22457
22475
  /**
22458
22476
  * Emit iteration complete event (helper for run loop)
@@ -23337,6 +23355,27 @@ var Agent = class _Agent extends BaseAgent {
23337
23355
  isCancelled() {
23338
23356
  return this._cancelled;
23339
23357
  }
23358
+ /**
23359
+ * Clear conversation history, resetting the context for a fresh interaction.
23360
+ * Plugins (working memory, in-context memory, etc.) are NOT affected.
23361
+ */
23362
+ clearConversation(reason) {
23363
+ this._agentContext.clearConversation(reason);
23364
+ this._logger.info({ reason }, "Conversation cleared");
23365
+ }
23366
+ // ===== Hook Management =====
23367
+ /**
23368
+ * Register a hook on the agent. Can be called after creation.
23369
+ */
23370
+ registerHook(name, hook) {
23371
+ this.hookManager.register(name, hook);
23372
+ }
23373
+ /**
23374
+ * Unregister a previously registered hook by reference.
23375
+ */
23376
+ unregisterHook(name, hook) {
23377
+ return this.hookManager.unregister(name, hook);
23378
+ }
23340
23379
  // ===== Cleanup =====
23341
23380
  destroy() {
23342
23381
  if (this._isDestroyed) {
@@ -23366,6 +23405,1006 @@ var Agent = class _Agent extends BaseAgent {
23366
23405
  }
23367
23406
  };
23368
23407
 
23408
+ // src/domain/entities/Task.ts
23409
+ var TERMINAL_TASK_STATUSES = ["completed", "failed", "skipped", "cancelled"];
23410
+ function isTerminalStatus(status) {
23411
+ return TERMINAL_TASK_STATUSES.includes(status);
23412
+ }
23413
+ function createTask(input) {
23414
+ const now = Date.now();
23415
+ const id = input.id ?? `task-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
23416
+ return {
23417
+ id,
23418
+ name: input.name,
23419
+ description: input.description,
23420
+ status: "pending",
23421
+ dependsOn: input.dependsOn ?? [],
23422
+ externalDependency: input.externalDependency,
23423
+ condition: input.condition,
23424
+ execution: input.execution,
23425
+ suggestedTools: input.suggestedTools,
23426
+ validation: input.validation,
23427
+ expectedOutput: input.expectedOutput,
23428
+ attempts: 0,
23429
+ maxAttempts: input.maxAttempts ?? 3,
23430
+ createdAt: now,
23431
+ lastUpdatedAt: now,
23432
+ metadata: input.metadata
23433
+ };
23434
+ }
23435
+ function createPlan(input) {
23436
+ const now = Date.now();
23437
+ const id = `plan-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
23438
+ const tasks = input.tasks.map((taskInput) => createTask(taskInput));
23439
+ const nameToId = /* @__PURE__ */ new Map();
23440
+ for (const task of tasks) {
23441
+ nameToId.set(task.name, task.id);
23442
+ }
23443
+ for (let i = 0; i < tasks.length; i++) {
23444
+ const taskInput = input.tasks[i];
23445
+ const task = tasks[i];
23446
+ if (taskInput.dependsOn && taskInput.dependsOn.length > 0) {
23447
+ task.dependsOn = taskInput.dependsOn.map((dep) => {
23448
+ if (dep.startsWith("task-")) {
23449
+ return dep;
23450
+ }
23451
+ const resolvedId = nameToId.get(dep);
23452
+ if (!resolvedId) {
23453
+ throw new Error(`Task dependency "${dep}" not found in plan`);
23454
+ }
23455
+ return resolvedId;
23456
+ });
23457
+ }
23458
+ }
23459
+ if (!input.skipCycleCheck) {
23460
+ const cycle = detectDependencyCycle(tasks);
23461
+ if (cycle) {
23462
+ const cycleNames = cycle.map((taskId) => {
23463
+ const task = tasks.find((t) => t.id === taskId);
23464
+ return task ? task.name : taskId;
23465
+ });
23466
+ throw new DependencyCycleError(cycleNames, id);
23467
+ }
23468
+ }
23469
+ return {
23470
+ id,
23471
+ goal: input.goal,
23472
+ context: input.context,
23473
+ tasks,
23474
+ concurrency: input.concurrency,
23475
+ allowDynamicTasks: input.allowDynamicTasks ?? true,
23476
+ status: "pending",
23477
+ createdAt: now,
23478
+ lastUpdatedAt: now,
23479
+ metadata: input.metadata
23480
+ };
23481
+ }
23482
+ function canTaskExecute(task, allTasks) {
23483
+ if (task.status !== "pending") {
23484
+ return false;
23485
+ }
23486
+ if (task.dependsOn.length > 0) {
23487
+ for (const depId of task.dependsOn) {
23488
+ const depTask = allTasks.find((t) => t.id === depId);
23489
+ if (!depTask || depTask.status !== "completed") {
23490
+ return false;
23491
+ }
23492
+ }
23493
+ }
23494
+ return true;
23495
+ }
23496
+ function getNextExecutableTasks(plan) {
23497
+ const executable = plan.tasks.filter((task) => canTaskExecute(task, plan.tasks));
23498
+ if (executable.length === 0) {
23499
+ return [];
23500
+ }
23501
+ if (!plan.concurrency) {
23502
+ return [executable[0]];
23503
+ }
23504
+ const runningCount = plan.tasks.filter((t) => t.status === "in_progress").length;
23505
+ const availableSlots = plan.concurrency.maxParallelTasks - runningCount;
23506
+ if (availableSlots <= 0) {
23507
+ return [];
23508
+ }
23509
+ const parallelTasks = executable.filter((task) => task.execution?.parallel === true);
23510
+ if (parallelTasks.length === 0) {
23511
+ return [executable[0]];
23512
+ }
23513
+ let sortedTasks = [...parallelTasks];
23514
+ if (plan.concurrency.strategy === "priority") {
23515
+ sortedTasks.sort((a, b) => (b.execution?.priority ?? 0) - (a.execution?.priority ?? 0));
23516
+ }
23517
+ return sortedTasks.slice(0, availableSlots);
23518
+ }
23519
+ async function evaluateCondition(condition, memory) {
23520
+ const value = await memory.get(condition.memoryKey);
23521
+ switch (condition.operator) {
23522
+ case "exists":
23523
+ return value !== void 0;
23524
+ case "not_exists":
23525
+ return value === void 0;
23526
+ case "equals":
23527
+ return value === condition.value;
23528
+ case "contains":
23529
+ if (Array.isArray(value)) {
23530
+ return value.includes(condition.value);
23531
+ }
23532
+ if (typeof value === "string" && typeof condition.value === "string") {
23533
+ return value.includes(condition.value);
23534
+ }
23535
+ return false;
23536
+ case "truthy":
23537
+ return !!value;
23538
+ case "greater_than":
23539
+ if (typeof value === "number" && typeof condition.value === "number") {
23540
+ return value > condition.value;
23541
+ }
23542
+ return false;
23543
+ case "less_than":
23544
+ if (typeof value === "number" && typeof condition.value === "number") {
23545
+ return value < condition.value;
23546
+ }
23547
+ return false;
23548
+ default:
23549
+ return false;
23550
+ }
23551
+ }
23552
+ function updateTaskStatus(task, status) {
23553
+ const now = Date.now();
23554
+ const updated = {
23555
+ ...task,
23556
+ status,
23557
+ lastUpdatedAt: now
23558
+ };
23559
+ if (status === "in_progress") {
23560
+ if (!updated.startedAt) {
23561
+ updated.startedAt = now;
23562
+ }
23563
+ updated.attempts += 1;
23564
+ }
23565
+ if ((status === "completed" || status === "failed") && !updated.completedAt) {
23566
+ updated.completedAt = now;
23567
+ }
23568
+ return updated;
23569
+ }
23570
+ function isTaskBlocked(task, allTasks) {
23571
+ if (task.dependsOn.length === 0) {
23572
+ return false;
23573
+ }
23574
+ for (const depId of task.dependsOn) {
23575
+ const depTask = allTasks.find((t) => t.id === depId);
23576
+ if (!depTask) {
23577
+ return true;
23578
+ }
23579
+ if (depTask.status !== "completed") {
23580
+ return true;
23581
+ }
23582
+ }
23583
+ return false;
23584
+ }
23585
+ function getTaskDependencies(task, allTasks) {
23586
+ if (task.dependsOn.length === 0) {
23587
+ return [];
23588
+ }
23589
+ return task.dependsOn.map((depId) => allTasks.find((t) => t.id === depId)).filter((t) => t !== void 0);
23590
+ }
23591
+ function resolveDependencies(taskInputs, tasks) {
23592
+ const nameToId = /* @__PURE__ */ new Map();
23593
+ for (const task of tasks) {
23594
+ nameToId.set(task.name, task.id);
23595
+ }
23596
+ for (const input of taskInputs) {
23597
+ if (input.dependsOn && input.dependsOn.length > 0) {
23598
+ input.dependsOn = input.dependsOn.map((dep) => {
23599
+ if (dep.startsWith("task-")) {
23600
+ return dep;
23601
+ }
23602
+ const resolvedId = nameToId.get(dep);
23603
+ if (!resolvedId) {
23604
+ throw new Error(`Task dependency "${dep}" not found`);
23605
+ }
23606
+ return resolvedId;
23607
+ });
23608
+ }
23609
+ }
23610
+ }
23611
+ function detectDependencyCycle(tasks) {
23612
+ const visited = /* @__PURE__ */ new Set();
23613
+ const recStack = /* @__PURE__ */ new Set();
23614
+ const taskMap = new Map(tasks.map((t) => [t.id, t]));
23615
+ function dfs(taskId, path6) {
23616
+ if (recStack.has(taskId)) {
23617
+ const cycleStart = path6.indexOf(taskId);
23618
+ return [...path6.slice(cycleStart), taskId];
23619
+ }
23620
+ if (visited.has(taskId)) {
23621
+ return null;
23622
+ }
23623
+ visited.add(taskId);
23624
+ recStack.add(taskId);
23625
+ const task = taskMap.get(taskId);
23626
+ if (task) {
23627
+ for (const depId of task.dependsOn) {
23628
+ const cycle = dfs(depId, [...path6, taskId]);
23629
+ if (cycle) {
23630
+ return cycle;
23631
+ }
23632
+ }
23633
+ }
23634
+ recStack.delete(taskId);
23635
+ return null;
23636
+ }
23637
+ for (const task of tasks) {
23638
+ if (!visited.has(task.id)) {
23639
+ const cycle = dfs(task.id, []);
23640
+ if (cycle) {
23641
+ return cycle;
23642
+ }
23643
+ }
23644
+ }
23645
+ return null;
23646
+ }
23647
+
23648
+ // src/domain/entities/Routine.ts
23649
+ function createRoutineDefinition(input) {
23650
+ const now = (/* @__PURE__ */ new Date()).toISOString();
23651
+ const id = input.id ?? `routine-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
23652
+ const taskNames = new Set(input.tasks.map((t) => t.name));
23653
+ const taskIds = new Set(input.tasks.filter((t) => t.id).map((t) => t.id));
23654
+ for (const task of input.tasks) {
23655
+ if (task.dependsOn) {
23656
+ for (const dep of task.dependsOn) {
23657
+ if (!taskNames.has(dep) && !taskIds.has(dep)) {
23658
+ throw new Error(
23659
+ `Routine "${input.name}": task "${task.name}" depends on unknown task "${dep}"`
23660
+ );
23661
+ }
23662
+ }
23663
+ }
23664
+ }
23665
+ createPlan({
23666
+ goal: input.name,
23667
+ tasks: input.tasks
23668
+ });
23669
+ return {
23670
+ id,
23671
+ name: input.name,
23672
+ description: input.description,
23673
+ version: input.version,
23674
+ tasks: input.tasks,
23675
+ requiredTools: input.requiredTools,
23676
+ requiredPlugins: input.requiredPlugins,
23677
+ instructions: input.instructions,
23678
+ concurrency: input.concurrency,
23679
+ allowDynamicTasks: input.allowDynamicTasks ?? false,
23680
+ tags: input.tags,
23681
+ author: input.author,
23682
+ createdAt: now,
23683
+ updatedAt: now,
23684
+ metadata: input.metadata
23685
+ };
23686
+ }
23687
+ function createRoutineExecution(definition) {
23688
+ const now = Date.now();
23689
+ const executionId = `rexec-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
23690
+ const plan = createPlan({
23691
+ goal: definition.name,
23692
+ context: definition.description,
23693
+ tasks: definition.tasks,
23694
+ concurrency: definition.concurrency,
23695
+ allowDynamicTasks: definition.allowDynamicTasks
23696
+ });
23697
+ return {
23698
+ id: executionId,
23699
+ routineId: definition.id,
23700
+ plan,
23701
+ status: "pending",
23702
+ progress: 0,
23703
+ lastUpdatedAt: now
23704
+ };
23705
+ }
23706
+ function getRoutineProgress(execution) {
23707
+ const { tasks } = execution.plan;
23708
+ if (tasks.length === 0) return 100;
23709
+ const completed = tasks.filter((t) => isTerminalStatus(t.status)).length;
23710
+ return Math.round(completed / tasks.length * 100);
23711
+ }
23712
+
23713
+ // src/utils/jsonExtractor.ts
23714
+ function extractJSON(text) {
23715
+ if (!text || typeof text !== "string") {
23716
+ return {
23717
+ success: false,
23718
+ error: "Input is empty or not a string"
23719
+ };
23720
+ }
23721
+ const trimmedText = text.trim();
23722
+ const codeBlockResult = extractFromCodeBlock(trimmedText);
23723
+ if (codeBlockResult.success) {
23724
+ return codeBlockResult;
23725
+ }
23726
+ const inlineResult = extractInlineJSON(trimmedText);
23727
+ if (inlineResult.success) {
23728
+ return inlineResult;
23729
+ }
23730
+ try {
23731
+ const data = JSON.parse(trimmedText);
23732
+ return {
23733
+ success: true,
23734
+ data,
23735
+ rawJson: trimmedText,
23736
+ method: "raw"
23737
+ };
23738
+ } catch (e) {
23739
+ return {
23740
+ success: false,
23741
+ error: `Could not extract JSON from text: ${e instanceof Error ? e.message : String(e)}`
23742
+ };
23743
+ }
23744
+ }
23745
+ function extractFromCodeBlock(text) {
23746
+ const codeBlockRegex = /```(?:json)?\s*([\s\S]*?)```/g;
23747
+ let match;
23748
+ while ((match = codeBlockRegex.exec(text)) !== null) {
23749
+ const content = match[1];
23750
+ if (content) {
23751
+ const trimmed = content.trim();
23752
+ try {
23753
+ const data = JSON.parse(trimmed);
23754
+ return {
23755
+ success: true,
23756
+ data,
23757
+ rawJson: trimmed,
23758
+ method: "code_block"
23759
+ };
23760
+ } catch {
23761
+ continue;
23762
+ }
23763
+ }
23764
+ }
23765
+ return { success: false };
23766
+ }
23767
+ function extractInlineJSON(text) {
23768
+ const objectMatch = findJSONObject(text);
23769
+ if (objectMatch) {
23770
+ try {
23771
+ const data = JSON.parse(objectMatch);
23772
+ return {
23773
+ success: true,
23774
+ data,
23775
+ rawJson: objectMatch,
23776
+ method: "inline"
23777
+ };
23778
+ } catch {
23779
+ }
23780
+ }
23781
+ const arrayMatch = findJSONArray(text);
23782
+ if (arrayMatch) {
23783
+ try {
23784
+ const data = JSON.parse(arrayMatch);
23785
+ return {
23786
+ success: true,
23787
+ data,
23788
+ rawJson: arrayMatch,
23789
+ method: "inline"
23790
+ };
23791
+ } catch {
23792
+ }
23793
+ }
23794
+ return { success: false };
23795
+ }
23796
+ function findJSONObject(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 findJSONArray(text) {
23829
+ const startIndex = text.indexOf("[");
23830
+ if (startIndex === -1) return null;
23831
+ let depth = 0;
23832
+ let inString = false;
23833
+ let escaped = false;
23834
+ for (let i = startIndex; i < text.length; i++) {
23835
+ const char = text[i];
23836
+ if (escaped) {
23837
+ escaped = false;
23838
+ continue;
23839
+ }
23840
+ if (char === "\\" && inString) {
23841
+ escaped = true;
23842
+ continue;
23843
+ }
23844
+ if (char === '"') {
23845
+ inString = !inString;
23846
+ continue;
23847
+ }
23848
+ if (inString) continue;
23849
+ if (char === "[") {
23850
+ depth++;
23851
+ } else if (char === "]") {
23852
+ depth--;
23853
+ if (depth === 0) {
23854
+ return text.slice(startIndex, i + 1);
23855
+ }
23856
+ }
23857
+ }
23858
+ return null;
23859
+ }
23860
+ function extractJSONField(text, field, defaultValue) {
23861
+ const result = extractJSON(text);
23862
+ if (result.success && result.data && field in result.data) {
23863
+ return result.data[field];
23864
+ }
23865
+ return defaultValue;
23866
+ }
23867
+ function extractNumber(text, patterns = [
23868
+ /(\d{1,3})%?\s*(?:complete|score|percent)/i,
23869
+ /(?:score|completion|rating)[:\s]+(\d{1,3})/i,
23870
+ /(\d{1,3})\s*(?:out of|\/)\s*100/i
23871
+ ], defaultValue = 0) {
23872
+ const jsonResult = extractJSON(text);
23873
+ if (jsonResult.success && jsonResult.data) {
23874
+ const scoreFields = ["score", "completionScore", "completion_score", "rating", "percent", "value"];
23875
+ for (const field of scoreFields) {
23876
+ if (field in jsonResult.data && typeof jsonResult.data[field] === "number") {
23877
+ return jsonResult.data[field];
23878
+ }
23879
+ }
23880
+ }
23881
+ for (const pattern of patterns) {
23882
+ const match = text.match(pattern);
23883
+ if (match && match[1]) {
23884
+ const num = parseInt(match[1], 10);
23885
+ if (!isNaN(num)) {
23886
+ return num;
23887
+ }
23888
+ }
23889
+ }
23890
+ return defaultValue;
23891
+ }
23892
+
23893
+ // src/core/routineRunner.ts
23894
+ init_Logger();
23895
+ function defaultSystemPrompt(definition) {
23896
+ const parts = [];
23897
+ if (definition.instructions) {
23898
+ parts.push(definition.instructions);
23899
+ }
23900
+ parts.push(
23901
+ `You are executing a routine called "${definition.name}".`,
23902
+ "",
23903
+ "Between tasks, your conversation history is cleared but your memory persists.",
23904
+ "Use these strategies to pass information between tasks:",
23905
+ "- Use context_set for small key results that subsequent tasks need immediately (visible in context, no retrieval needed).",
23906
+ '- Use memory_store with tier="findings" for larger data that may be needed later.',
23907
+ "- Use memory_retrieve to access data stored by previous tasks.",
23908
+ "",
23909
+ "IMPORTANT: When you have completed the current task, you MUST stop immediately.",
23910
+ "Do NOT repeat work you have already done. Do NOT re-fetch data you already have.",
23911
+ "Store key results in memory once, then produce a final text response (no more tool calls) to signal completion."
23912
+ );
23913
+ return parts.join("\n");
23914
+ }
23915
+ function defaultTaskPrompt(task) {
23916
+ const parts = [];
23917
+ parts.push(`## Current Task: ${task.name}`, "");
23918
+ parts.push(task.description, "");
23919
+ if (task.expectedOutput) {
23920
+ parts.push(`**Expected output:** ${task.expectedOutput}`, "");
23921
+ }
23922
+ if (task.suggestedTools && task.suggestedTools.length > 0) {
23923
+ parts.push(`**Suggested tools:** ${task.suggestedTools.join(", ")}`, "");
23924
+ }
23925
+ const criteria = task.validation?.completionCriteria;
23926
+ if (criteria && criteria.length > 0) {
23927
+ parts.push("### Completion Criteria");
23928
+ parts.push("When you are done, ensure the following are met:");
23929
+ for (const c of criteria) {
23930
+ parts.push(`- ${c}`);
23931
+ }
23932
+ parts.push("");
23933
+ }
23934
+ if (task.dependsOn.length > 0) {
23935
+ parts.push("Note: Results from prerequisite tasks are available in your live context.");
23936
+ parts.push("Small results appear directly; larger results are in working memory \u2014 use memory_retrieve to access them.");
23937
+ parts.push("Review the plan overview and dependency results before starting.");
23938
+ parts.push("");
23939
+ }
23940
+ parts.push("After completing the work, store key results in memory once, then respond with a text summary (no more tool calls).");
23941
+ return parts.join("\n");
23942
+ }
23943
+ function defaultValidationPrompt(task, context) {
23944
+ const criteria = task.validation?.completionCriteria ?? [];
23945
+ const criteriaList = criteria.length > 0 ? criteria.map((c, i) => `${i + 1}. ${c}`).join("\n") : "The task was completed as described.";
23946
+ const parts = [
23947
+ `Evaluate if the task "${task.name}" was completed successfully.`,
23948
+ "",
23949
+ `Task description: ${task.description}`,
23950
+ "",
23951
+ "Completion criteria:",
23952
+ criteriaList,
23953
+ "",
23954
+ "--- EVIDENCE ---",
23955
+ "",
23956
+ "Agent response (final text output):",
23957
+ context.responseText || "(no text output)",
23958
+ "",
23959
+ "Tool calls made during this task:",
23960
+ context.toolCallLog
23961
+ ];
23962
+ if (context.inContextMemory) {
23963
+ parts.push("", "In-context memory (current state):", context.inContextMemory);
23964
+ }
23965
+ if (context.workingMemoryIndex) {
23966
+ parts.push("", "Working memory index (stored data):", context.workingMemoryIndex);
23967
+ }
23968
+ parts.push(
23969
+ "",
23970
+ "--- END EVIDENCE ---",
23971
+ "",
23972
+ "Use the evidence above to verify each criterion. Check tool call results, not just the agent's claims.",
23973
+ "",
23974
+ "Return a JSON object with the following structure:",
23975
+ "```json",
23976
+ '{ "isComplete": boolean, "completionScore": number (0-100), "explanation": "..." }',
23977
+ "```",
23978
+ "",
23979
+ "Be strict: only mark isComplete=true if all criteria are clearly met based on the evidence."
23980
+ );
23981
+ return parts.join("\n");
23982
+ }
23983
+ function formatToolCallLog(conversation) {
23984
+ const calls = [];
23985
+ for (const item of conversation) {
23986
+ if (!("content" in item) || !Array.isArray(item.content)) continue;
23987
+ const msg = item;
23988
+ for (const c of msg.content) {
23989
+ if (c.type === "tool_use" /* TOOL_USE */) {
23990
+ let argsStr;
23991
+ try {
23992
+ const parsed = JSON.parse(c.arguments);
23993
+ argsStr = JSON.stringify(parsed, null, 2);
23994
+ if (argsStr.length > 500) argsStr = argsStr.slice(0, 500) + "... (truncated)";
23995
+ } catch {
23996
+ argsStr = c.arguments;
23997
+ }
23998
+ calls.push(`CALL: ${c.name}(${argsStr})`);
23999
+ } else if (c.type === "tool_result" /* TOOL_RESULT */) {
24000
+ let resultStr = typeof c.content === "string" ? c.content : JSON.stringify(c.content);
24001
+ if (resultStr.length > 500) resultStr = resultStr.slice(0, 500) + "... (truncated)";
24002
+ const prefix = c.error ? "ERROR" : "RESULT";
24003
+ calls.push(` ${prefix}: ${resultStr}`);
24004
+ }
24005
+ }
24006
+ }
24007
+ return calls.length > 0 ? calls.join("\n") : "(no tool calls)";
24008
+ }
24009
+ async function collectValidationContext(agent, responseText) {
24010
+ const icmPlugin = agent.context.getPlugin("in_context_memory");
24011
+ const inContextMemory = icmPlugin ? await icmPlugin.getContent() : null;
24012
+ const wmPlugin = agent.context.memory;
24013
+ const workingMemoryIndex = wmPlugin ? await wmPlugin.getContent() : null;
24014
+ const conversation = agent.context.getConversation();
24015
+ const toolCallLog = formatToolCallLog(conversation);
24016
+ return {
24017
+ responseText,
24018
+ inContextMemory,
24019
+ workingMemoryIndex,
24020
+ toolCallLog
24021
+ };
24022
+ }
24023
+ function estimateTokens(text) {
24024
+ return Math.ceil(text.length / 4);
24025
+ }
24026
+ function buildPlanOverview(execution, definition, currentTaskId) {
24027
+ const parts = [];
24028
+ const progress = execution.progress ?? 0;
24029
+ parts.push(`Routine: ${definition.name}`);
24030
+ if (definition.description) {
24031
+ parts.push(`Goal: ${definition.description}`);
24032
+ }
24033
+ parts.push(`Progress: ${Math.round(progress * 100)}%`);
24034
+ parts.push("");
24035
+ parts.push("Tasks:");
24036
+ for (const task of execution.plan.tasks) {
24037
+ let statusIcon;
24038
+ switch (task.status) {
24039
+ case "completed":
24040
+ statusIcon = "[x]";
24041
+ break;
24042
+ case "in_progress":
24043
+ statusIcon = "[>]";
24044
+ break;
24045
+ case "failed":
24046
+ statusIcon = "[!]";
24047
+ break;
24048
+ case "skipped":
24049
+ statusIcon = "[-]";
24050
+ break;
24051
+ default:
24052
+ statusIcon = "[ ]";
24053
+ }
24054
+ let line = `${statusIcon} ${task.name}`;
24055
+ if (task.dependsOn.length > 0) {
24056
+ const depNames = task.dependsOn.map((depId) => execution.plan.tasks.find((t) => t.id === depId)?.name ?? depId).join(", ");
24057
+ line += ` (after: ${depNames})`;
24058
+ }
24059
+ if (task.id === currentTaskId) {
24060
+ line += " \u2190 CURRENT";
24061
+ }
24062
+ parts.push(line);
24063
+ }
24064
+ return parts.join("\n");
24065
+ }
24066
+ async function injectRoutineContext(agent, execution, definition, currentTask) {
24067
+ const icmPlugin = agent.context.getPlugin("in_context_memory");
24068
+ const wmPlugin = agent.context.memory;
24069
+ if (!icmPlugin && !wmPlugin) {
24070
+ exports.logger.warn("injectRoutineContext: No ICM or WM plugin available \u2014 skipping context injection");
24071
+ return;
24072
+ }
24073
+ const planOverview = buildPlanOverview(execution, definition, currentTask.id);
24074
+ if (icmPlugin) {
24075
+ icmPlugin.set("__routine_plan", "Routine plan overview with task statuses", planOverview, "high");
24076
+ }
24077
+ if (icmPlugin) {
24078
+ for (const entry of icmPlugin.list()) {
24079
+ if (entry.key.startsWith("__dep_result_") || entry.key === "__routine_deps") {
24080
+ icmPlugin.delete(entry.key);
24081
+ }
24082
+ }
24083
+ }
24084
+ if (wmPlugin) {
24085
+ const { entries: wmEntries } = await wmPlugin.query();
24086
+ for (const entry of wmEntries) {
24087
+ if (entry.key.startsWith("__dep_result_") || entry.key.startsWith("findings/__dep_result_")) {
24088
+ await wmPlugin.delete(entry.key);
24089
+ }
24090
+ }
24091
+ }
24092
+ if (currentTask.dependsOn.length === 0) return;
24093
+ const inContextDeps = [];
24094
+ const workingMemoryDeps = [];
24095
+ for (const depId of currentTask.dependsOn) {
24096
+ const depTask = execution.plan.tasks.find((t) => t.id === depId);
24097
+ if (!depTask?.result?.output) continue;
24098
+ const output = typeof depTask.result.output === "string" ? depTask.result.output : JSON.stringify(depTask.result.output);
24099
+ const tokens = estimateTokens(output);
24100
+ const depKey = `__dep_result_${depId}`;
24101
+ const depLabel = `Result from task "${depTask.name}"`;
24102
+ if (tokens < 5e3 && icmPlugin) {
24103
+ icmPlugin.set(depKey, depLabel, output, "high");
24104
+ inContextDeps.push(depTask.name);
24105
+ } else if (wmPlugin) {
24106
+ await wmPlugin.store(depKey, depLabel, output, { tier: "findings" });
24107
+ workingMemoryDeps.push(depTask.name);
24108
+ } else if (icmPlugin) {
24109
+ const truncated = output.slice(0, 2e4) + "\n... (truncated, full result not available)";
24110
+ icmPlugin.set(depKey, depLabel, truncated, "high");
24111
+ inContextDeps.push(depTask.name + " (truncated)");
24112
+ }
24113
+ }
24114
+ if (icmPlugin && (inContextDeps.length > 0 || workingMemoryDeps.length > 0)) {
24115
+ const summaryParts = ["Dependency results available:"];
24116
+ if (inContextDeps.length > 0) {
24117
+ summaryParts.push(`In context (visible now): ${inContextDeps.join(", ")}`);
24118
+ }
24119
+ if (workingMemoryDeps.length > 0) {
24120
+ summaryParts.push(`In working memory (use memory_retrieve): ${workingMemoryDeps.join(", ")}`);
24121
+ }
24122
+ icmPlugin.set("__routine_deps", "Dependency results location guide", summaryParts.join("\n"), "high");
24123
+ }
24124
+ }
24125
+ async function cleanupRoutineContext(agent) {
24126
+ const icmPlugin = agent.context.getPlugin("in_context_memory");
24127
+ const wmPlugin = agent.context.memory;
24128
+ if (icmPlugin) {
24129
+ for (const entry of icmPlugin.list()) {
24130
+ if (entry.key.startsWith("__routine_") || entry.key.startsWith("__dep_result_")) {
24131
+ icmPlugin.delete(entry.key);
24132
+ }
24133
+ }
24134
+ }
24135
+ if (wmPlugin) {
24136
+ const { entries: wmEntries } = await wmPlugin.query();
24137
+ for (const entry of wmEntries) {
24138
+ if (entry.key.startsWith("__dep_result_") || entry.key.startsWith("findings/__dep_result_")) {
24139
+ await wmPlugin.delete(entry.key);
24140
+ }
24141
+ }
24142
+ }
24143
+ }
24144
+ async function validateTaskCompletion(agent, task, responseText, validationPromptBuilder) {
24145
+ const hasExplicitValidation = task.validation?.skipReflection === false && task.validation?.completionCriteria && task.validation.completionCriteria.length > 0;
24146
+ if (!hasExplicitValidation) {
24147
+ return {
24148
+ isComplete: true,
24149
+ completionScore: 100,
24150
+ explanation: "Auto-passed (LLM validation not enabled)",
24151
+ requiresUserApproval: false
24152
+ };
24153
+ }
24154
+ const validationContext = await collectValidationContext(agent, responseText);
24155
+ const prompt = validationPromptBuilder(task, validationContext);
24156
+ const response = await agent.runDirect(prompt, {
24157
+ instructions: "You are a task completion evaluator. Return only JSON.",
24158
+ temperature: 0.1
24159
+ });
24160
+ const text = response.output_text ?? "";
24161
+ const extracted = extractJSON(text);
24162
+ if (!extracted.success || !extracted.data) {
24163
+ return {
24164
+ isComplete: false,
24165
+ completionScore: 0,
24166
+ explanation: `Failed to parse validation response: ${extracted.error ?? "unknown error"}`,
24167
+ requiresUserApproval: false
24168
+ };
24169
+ }
24170
+ const { isComplete, completionScore, explanation } = extracted.data;
24171
+ const minScore = task.validation?.minCompletionScore ?? 80;
24172
+ return {
24173
+ isComplete: isComplete && completionScore >= minScore,
24174
+ completionScore,
24175
+ explanation,
24176
+ requiresUserApproval: false
24177
+ };
24178
+ }
24179
+ async function executeRoutine(options) {
24180
+ const {
24181
+ definition,
24182
+ agent: existingAgent,
24183
+ connector,
24184
+ model,
24185
+ tools: extraTools,
24186
+ onTaskStarted,
24187
+ onTaskComplete,
24188
+ onTaskFailed,
24189
+ onTaskValidation,
24190
+ hooks,
24191
+ prompts
24192
+ } = options;
24193
+ if (!existingAgent && (!connector || !model)) {
24194
+ throw new Error("executeRoutine requires either `agent` or both `connector` and `model`");
24195
+ }
24196
+ const ownsAgent = !existingAgent;
24197
+ const log = exports.logger.child({ routine: definition.name });
24198
+ const execution = createRoutineExecution(definition);
24199
+ execution.status = "running";
24200
+ execution.startedAt = Date.now();
24201
+ execution.lastUpdatedAt = Date.now();
24202
+ const buildSystemPrompt = prompts?.system ?? defaultSystemPrompt;
24203
+ const buildTaskPrompt = prompts?.task ?? defaultTaskPrompt;
24204
+ const buildValidationPrompt = prompts?.validation ?? defaultValidationPrompt;
24205
+ let agent;
24206
+ const registeredHooks = [];
24207
+ if (existingAgent) {
24208
+ agent = existingAgent;
24209
+ if (hooks) {
24210
+ const hookNames = [
24211
+ "before:execution",
24212
+ "after:execution",
24213
+ "before:llm",
24214
+ "after:llm",
24215
+ "before:tool",
24216
+ "after:tool",
24217
+ "approve:tool",
24218
+ "pause:check"
24219
+ ];
24220
+ for (const name of hookNames) {
24221
+ const hook = hooks[name];
24222
+ if (hook) {
24223
+ agent.registerHook(name, hook);
24224
+ registeredHooks.push({ name, hook });
24225
+ }
24226
+ }
24227
+ }
24228
+ } else {
24229
+ const allTools = [...extraTools ?? []];
24230
+ if (definition.requiredTools && definition.requiredTools.length > 0) {
24231
+ const availableToolNames = new Set(allTools.map((t) => t.definition.function.name));
24232
+ const missing = definition.requiredTools.filter((name) => !availableToolNames.has(name));
24233
+ if (missing.length > 0) {
24234
+ execution.status = "failed";
24235
+ execution.error = `Missing required tools: ${missing.join(", ")}`;
24236
+ execution.completedAt = Date.now();
24237
+ execution.lastUpdatedAt = Date.now();
24238
+ return execution;
24239
+ }
24240
+ }
24241
+ agent = Agent.create({
24242
+ connector,
24243
+ model,
24244
+ tools: allTools,
24245
+ instructions: buildSystemPrompt(definition),
24246
+ hooks,
24247
+ context: {
24248
+ model,
24249
+ features: {
24250
+ workingMemory: true,
24251
+ inContextMemory: true
24252
+ }
24253
+ }
24254
+ });
24255
+ }
24256
+ if (definition.requiredPlugins && definition.requiredPlugins.length > 0) {
24257
+ const missing = definition.requiredPlugins.filter(
24258
+ (name) => !agent.context.hasPlugin(name)
24259
+ );
24260
+ if (missing.length > 0) {
24261
+ if (ownsAgent) agent.destroy();
24262
+ execution.status = "failed";
24263
+ execution.error = `Missing required plugins: ${missing.join(", ")}`;
24264
+ execution.completedAt = Date.now();
24265
+ execution.lastUpdatedAt = Date.now();
24266
+ return execution;
24267
+ }
24268
+ }
24269
+ const failureMode = definition.concurrency?.failureMode ?? "fail-fast";
24270
+ try {
24271
+ let nextTasks = getNextExecutableTasks(execution.plan);
24272
+ while (nextTasks.length > 0) {
24273
+ const task = nextTasks[0];
24274
+ const taskIndex = execution.plan.tasks.findIndex((t) => t.id === task.id);
24275
+ log.info({ taskName: task.name, taskId: task.id }, "Starting task");
24276
+ execution.plan.tasks[taskIndex] = updateTaskStatus(task, "in_progress");
24277
+ execution.lastUpdatedAt = Date.now();
24278
+ onTaskStarted?.(execution.plan.tasks[taskIndex], execution);
24279
+ let taskCompleted = false;
24280
+ const maxTaskIterations = task.execution?.maxIterations ?? 15;
24281
+ const iterationLimiter = async (ctx) => {
24282
+ if (ctx.iteration >= maxTaskIterations) {
24283
+ agent.cancel(`Task "${task.name}" exceeded max iterations (${maxTaskIterations})`);
24284
+ }
24285
+ return { shouldPause: false };
24286
+ };
24287
+ agent.registerHook("pause:check", iterationLimiter);
24288
+ const getTask = () => execution.plan.tasks[taskIndex];
24289
+ await injectRoutineContext(agent, execution, definition, getTask());
24290
+ while (!taskCompleted) {
24291
+ try {
24292
+ const taskPrompt = buildTaskPrompt(getTask());
24293
+ const response = await agent.run(taskPrompt);
24294
+ const responseText = response.output_text ?? "";
24295
+ const validationResult = await validateTaskCompletion(
24296
+ agent,
24297
+ getTask(),
24298
+ responseText,
24299
+ buildValidationPrompt
24300
+ );
24301
+ onTaskValidation?.(getTask(), validationResult, execution);
24302
+ if (validationResult.isComplete) {
24303
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "completed");
24304
+ execution.plan.tasks[taskIndex].result = {
24305
+ success: true,
24306
+ output: responseText,
24307
+ validationScore: validationResult.completionScore,
24308
+ validationExplanation: validationResult.explanation
24309
+ };
24310
+ taskCompleted = true;
24311
+ log.info(
24312
+ { taskName: getTask().name, score: validationResult.completionScore },
24313
+ "Task completed"
24314
+ );
24315
+ execution.progress = getRoutineProgress(execution);
24316
+ execution.lastUpdatedAt = Date.now();
24317
+ onTaskComplete?.(execution.plan.tasks[taskIndex], execution);
24318
+ } else {
24319
+ log.warn(
24320
+ {
24321
+ taskName: getTask().name,
24322
+ score: validationResult.completionScore,
24323
+ attempt: getTask().attempts,
24324
+ maxAttempts: getTask().maxAttempts
24325
+ },
24326
+ "Task validation failed"
24327
+ );
24328
+ if (getTask().attempts >= getTask().maxAttempts) {
24329
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
24330
+ execution.plan.tasks[taskIndex].result = {
24331
+ success: false,
24332
+ error: validationResult.explanation,
24333
+ validationScore: validationResult.completionScore,
24334
+ validationExplanation: validationResult.explanation
24335
+ };
24336
+ break;
24337
+ }
24338
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
24339
+ }
24340
+ } catch (error) {
24341
+ const errorMessage = error.message;
24342
+ log.error({ taskName: getTask().name, error: errorMessage }, "Task execution error");
24343
+ if (getTask().attempts >= getTask().maxAttempts) {
24344
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
24345
+ execution.plan.tasks[taskIndex].result = {
24346
+ success: false,
24347
+ error: errorMessage
24348
+ };
24349
+ break;
24350
+ }
24351
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
24352
+ }
24353
+ }
24354
+ if (!taskCompleted) {
24355
+ execution.progress = getRoutineProgress(execution);
24356
+ execution.lastUpdatedAt = Date.now();
24357
+ onTaskFailed?.(execution.plan.tasks[taskIndex], execution);
24358
+ if (failureMode === "fail-fast") {
24359
+ execution.status = "failed";
24360
+ execution.error = `Task "${getTask().name}" failed after ${getTask().attempts} attempt(s)`;
24361
+ execution.completedAt = Date.now();
24362
+ execution.lastUpdatedAt = Date.now();
24363
+ break;
24364
+ }
24365
+ }
24366
+ agent.unregisterHook("pause:check", iterationLimiter);
24367
+ agent.clearConversation("task-boundary");
24368
+ nextTasks = getNextExecutableTasks(execution.plan);
24369
+ }
24370
+ if (execution.status === "running") {
24371
+ const allTerminal = execution.plan.tasks.every((t) => isTerminalStatus(t.status));
24372
+ const allCompleted = execution.plan.tasks.every((t) => t.status === "completed");
24373
+ if (allCompleted) {
24374
+ execution.status = "completed";
24375
+ } else if (allTerminal) {
24376
+ execution.status = "failed";
24377
+ execution.error = "Not all tasks completed successfully";
24378
+ } else {
24379
+ execution.status = "failed";
24380
+ execution.error = "Execution stalled: remaining tasks are blocked by incomplete dependencies";
24381
+ }
24382
+ execution.completedAt = Date.now();
24383
+ execution.lastUpdatedAt = Date.now();
24384
+ execution.progress = getRoutineProgress(execution);
24385
+ }
24386
+ log.info(
24387
+ { status: execution.status, progress: execution.progress },
24388
+ "Routine execution finished"
24389
+ );
24390
+ return execution;
24391
+ } finally {
24392
+ try {
24393
+ await cleanupRoutineContext(agent);
24394
+ } catch {
24395
+ }
24396
+ for (const { name, hook } of registeredHooks) {
24397
+ try {
24398
+ agent.unregisterHook(name, hook);
24399
+ } catch {
24400
+ }
24401
+ }
24402
+ if (ownsAgent) {
24403
+ agent.destroy();
24404
+ }
24405
+ }
24406
+ }
24407
+
23369
24408
  // src/core/index.ts
23370
24409
  init_constants();
23371
24410
  (class {
@@ -23382,7 +24421,7 @@ init_constants();
23382
24421
  throw new Error("Configuration file not found. Searched: " + this.DEFAULT_PATHS.join(", "));
23383
24422
  }
23384
24423
  try {
23385
- const content = await fs18.promises.readFile(configPath, "utf-8");
24424
+ const content = await fs19.promises.readFile(configPath, "utf-8");
23386
24425
  let config = JSON.parse(content);
23387
24426
  config = this.interpolateEnvVars(config);
23388
24427
  this.validate(config);
@@ -23403,8 +24442,8 @@ init_constants();
23403
24442
  throw new Error("Configuration file not found. Searched: " + this.DEFAULT_PATHS.join(", "));
23404
24443
  }
23405
24444
  try {
23406
- const fs19 = __require("fs");
23407
- const content = fs19.readFileSync(configPath, "utf-8");
24445
+ const fs20 = __require("fs");
24446
+ const content = fs20.readFileSync(configPath, "utf-8");
23408
24447
  let config = JSON.parse(content);
23409
24448
  config = this.interpolateEnvVars(config);
23410
24449
  this.validate(config);
@@ -23422,7 +24461,7 @@ init_constants();
23422
24461
  static async findConfig() {
23423
24462
  for (const path6 of this.DEFAULT_PATHS) {
23424
24463
  try {
23425
- await fs18.promises.access(path2.resolve(path6));
24464
+ await fs19.promises.access(path2.resolve(path6));
23426
24465
  return path2.resolve(path6);
23427
24466
  } catch {
23428
24467
  }
@@ -23433,10 +24472,10 @@ init_constants();
23433
24472
  * Find configuration file synchronously
23434
24473
  */
23435
24474
  static findConfigSync() {
23436
- const fs19 = __require("fs");
24475
+ const fs20 = __require("fs");
23437
24476
  for (const path6 of this.DEFAULT_PATHS) {
23438
24477
  try {
23439
- fs19.accessSync(path2.resolve(path6));
24478
+ fs20.accessSync(path2.resolve(path6));
23440
24479
  return path2.resolve(path6);
23441
24480
  } catch {
23442
24481
  }
@@ -29010,7 +30049,7 @@ var MCPRegistry = class {
29010
30049
  static async loadFromConfigFile(path6) {
29011
30050
  try {
29012
30051
  const configPath = path2.resolve(path6);
29013
- const content = await fs18.promises.readFile(configPath, "utf-8");
30052
+ const content = await fs19.promises.readFile(configPath, "utf-8");
29014
30053
  const config = JSON.parse(content);
29015
30054
  if (!config.mcp) {
29016
30055
  throw new MCPError("Configuration file does not contain MCP section");
@@ -29615,7 +30654,7 @@ var OpenAISTTProvider = class extends BaseMediaProvider {
29615
30654
  if (Buffer.isBuffer(audio)) {
29616
30655
  return new File([new Uint8Array(audio)], "audio.wav", { type: "audio/wav" });
29617
30656
  } else if (typeof audio === "string") {
29618
- return fs18__namespace.createReadStream(audio);
30657
+ return fs19__namespace.createReadStream(audio);
29619
30658
  } else {
29620
30659
  throw new Error("Invalid audio input: must be Buffer or file path");
29621
30660
  }
@@ -30168,7 +31207,7 @@ var TextToSpeech = class _TextToSpeech {
30168
31207
  */
30169
31208
  async toFile(text, filePath, options) {
30170
31209
  const response = await this.synthesize(text, options);
30171
- await fs17__namespace.writeFile(filePath, response.audio);
31210
+ await fs18__namespace.writeFile(filePath, response.audio);
30172
31211
  }
30173
31212
  // ======================== Introspection Methods ========================
30174
31213
  /**
@@ -30516,7 +31555,7 @@ var SpeechToText = class _SpeechToText {
30516
31555
  * @param options - Optional transcription parameters
30517
31556
  */
30518
31557
  async transcribeFile(filePath, options) {
30519
- const audio = await fs17__namespace.readFile(filePath);
31558
+ const audio = await fs18__namespace.readFile(filePath);
30520
31559
  return this.transcribe(audio, options);
30521
31560
  }
30522
31561
  /**
@@ -30842,7 +31881,7 @@ var OpenAIImageProvider = class extends BaseMediaProvider {
30842
31881
  if (Buffer.isBuffer(image)) {
30843
31882
  return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
30844
31883
  }
30845
- return fs18__namespace.createReadStream(image);
31884
+ return fs19__namespace.createReadStream(image);
30846
31885
  }
30847
31886
  /**
30848
31887
  * Handle OpenAI API errors
@@ -30989,8 +32028,8 @@ var GoogleImageProvider = class extends BaseMediaProvider {
30989
32028
  if (Buffer.isBuffer(image)) {
30990
32029
  imageBytes = image.toString("base64");
30991
32030
  } else {
30992
- const fs19 = await import('fs');
30993
- const buffer = fs19.readFileSync(image);
32031
+ const fs20 = await import('fs');
32032
+ const buffer = fs20.readFileSync(image);
30994
32033
  imageBytes = buffer.toString("base64");
30995
32034
  }
30996
32035
  return {
@@ -31151,7 +32190,7 @@ var GrokImageProvider = class extends BaseMediaProvider {
31151
32190
  if (Buffer.isBuffer(image)) {
31152
32191
  return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
31153
32192
  }
31154
- return fs18__namespace.createReadStream(image);
32193
+ return fs19__namespace.createReadStream(image);
31155
32194
  }
31156
32195
  /**
31157
32196
  * Handle API errors
@@ -32601,8 +33640,8 @@ var OpenAISoraProvider = class extends BaseMediaProvider {
32601
33640
  return new File([new Uint8Array(image)], "input.png", { type: "image/png" });
32602
33641
  }
32603
33642
  if (!image.startsWith("http")) {
32604
- const fs19 = await import('fs');
32605
- const data = fs19.readFileSync(image);
33643
+ const fs20 = await import('fs');
33644
+ const data = fs20.readFileSync(image);
32606
33645
  return new File([new Uint8Array(data)], "input.png", { type: "image/png" });
32607
33646
  }
32608
33647
  const response = await fetch(image);
@@ -32780,7 +33819,7 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
32780
33819
  if (video.videoBytes) {
32781
33820
  buffer = Buffer.from(video.videoBytes, "base64");
32782
33821
  } else if (video.uri) {
32783
- const fs19 = await import('fs/promises');
33822
+ const fs20 = await import('fs/promises');
32784
33823
  const os3 = await import('os');
32785
33824
  const path6 = await import('path');
32786
33825
  const tempDir = os3.tmpdir();
@@ -32791,11 +33830,11 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
32791
33830
  // Pass as GeneratedVideo
32792
33831
  downloadPath: tempFile
32793
33832
  });
32794
- buffer = await fs19.readFile(tempFile);
32795
- await fs19.unlink(tempFile).catch(() => {
33833
+ buffer = await fs20.readFile(tempFile);
33834
+ await fs20.unlink(tempFile).catch(() => {
32796
33835
  });
32797
33836
  } catch (downloadError) {
32798
- await fs19.unlink(tempFile).catch(() => {
33837
+ await fs20.unlink(tempFile).catch(() => {
32799
33838
  });
32800
33839
  throw new ProviderError(
32801
33840
  "google",
@@ -32917,8 +33956,8 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
32917
33956
  if (image.startsWith("http://") || image.startsWith("https://")) {
32918
33957
  return { imageUri: image };
32919
33958
  }
32920
- const fs19 = await import('fs/promises');
32921
- const data = await fs19.readFile(image);
33959
+ const fs20 = await import('fs/promises');
33960
+ const data = await fs20.readFile(image);
32922
33961
  return {
32923
33962
  imageBytes: data.toString("base64")
32924
33963
  };
@@ -33225,8 +34264,8 @@ var GrokImagineProvider = class extends BaseMediaProvider {
33225
34264
  if (image.startsWith("http") || image.startsWith("data:")) {
33226
34265
  return image;
33227
34266
  }
33228
- const fs19 = await import('fs');
33229
- const data = fs19.readFileSync(image);
34267
+ const fs20 = await import('fs');
34268
+ const data = fs20.readFileSync(image);
33230
34269
  const base64 = data.toString("base64");
33231
34270
  const ext = image.split(".").pop()?.toLowerCase() || "png";
33232
34271
  const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext}`;
@@ -34662,7 +35701,7 @@ var DocumentReader = class _DocumentReader {
34662
35701
  async resolveSource(source) {
34663
35702
  switch (source.type) {
34664
35703
  case "file": {
34665
- const buffer = await fs17.readFile(source.path);
35704
+ const buffer = await fs18.readFile(source.path);
34666
35705
  const filename = source.path.split("/").pop() || source.path;
34667
35706
  return { buffer, filename };
34668
35707
  }
@@ -35895,245 +36934,6 @@ var CheckpointManager = class {
35895
36934
  }
35896
36935
  };
35897
36936
 
35898
- // src/domain/entities/Task.ts
35899
- var TERMINAL_TASK_STATUSES = ["completed", "failed", "skipped", "cancelled"];
35900
- function isTerminalStatus(status) {
35901
- return TERMINAL_TASK_STATUSES.includes(status);
35902
- }
35903
- function createTask(input) {
35904
- const now = Date.now();
35905
- const id = input.id ?? `task-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
35906
- return {
35907
- id,
35908
- name: input.name,
35909
- description: input.description,
35910
- status: "pending",
35911
- dependsOn: input.dependsOn ?? [],
35912
- externalDependency: input.externalDependency,
35913
- condition: input.condition,
35914
- execution: input.execution,
35915
- validation: input.validation,
35916
- expectedOutput: input.expectedOutput,
35917
- attempts: 0,
35918
- maxAttempts: input.maxAttempts ?? 3,
35919
- createdAt: now,
35920
- lastUpdatedAt: now,
35921
- metadata: input.metadata
35922
- };
35923
- }
35924
- function createPlan(input) {
35925
- const now = Date.now();
35926
- const id = `plan-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
35927
- const tasks = input.tasks.map((taskInput) => createTask(taskInput));
35928
- const nameToId = /* @__PURE__ */ new Map();
35929
- for (const task of tasks) {
35930
- nameToId.set(task.name, task.id);
35931
- }
35932
- for (let i = 0; i < tasks.length; i++) {
35933
- const taskInput = input.tasks[i];
35934
- const task = tasks[i];
35935
- if (taskInput.dependsOn && taskInput.dependsOn.length > 0) {
35936
- task.dependsOn = taskInput.dependsOn.map((dep) => {
35937
- if (dep.startsWith("task-")) {
35938
- return dep;
35939
- }
35940
- const resolvedId = nameToId.get(dep);
35941
- if (!resolvedId) {
35942
- throw new Error(`Task dependency "${dep}" not found in plan`);
35943
- }
35944
- return resolvedId;
35945
- });
35946
- }
35947
- }
35948
- if (!input.skipCycleCheck) {
35949
- const cycle = detectDependencyCycle(tasks);
35950
- if (cycle) {
35951
- const cycleNames = cycle.map((taskId) => {
35952
- const task = tasks.find((t) => t.id === taskId);
35953
- return task ? task.name : taskId;
35954
- });
35955
- throw new DependencyCycleError(cycleNames, id);
35956
- }
35957
- }
35958
- return {
35959
- id,
35960
- goal: input.goal,
35961
- context: input.context,
35962
- tasks,
35963
- concurrency: input.concurrency,
35964
- allowDynamicTasks: input.allowDynamicTasks ?? true,
35965
- status: "pending",
35966
- createdAt: now,
35967
- lastUpdatedAt: now,
35968
- metadata: input.metadata
35969
- };
35970
- }
35971
- function canTaskExecute(task, allTasks) {
35972
- if (task.status !== "pending") {
35973
- return false;
35974
- }
35975
- if (task.dependsOn.length > 0) {
35976
- for (const depId of task.dependsOn) {
35977
- const depTask = allTasks.find((t) => t.id === depId);
35978
- if (!depTask || depTask.status !== "completed") {
35979
- return false;
35980
- }
35981
- }
35982
- }
35983
- return true;
35984
- }
35985
- function getNextExecutableTasks(plan) {
35986
- const executable = plan.tasks.filter((task) => canTaskExecute(task, plan.tasks));
35987
- if (executable.length === 0) {
35988
- return [];
35989
- }
35990
- if (!plan.concurrency) {
35991
- return [executable[0]];
35992
- }
35993
- const runningCount = plan.tasks.filter((t) => t.status === "in_progress").length;
35994
- const availableSlots = plan.concurrency.maxParallelTasks - runningCount;
35995
- if (availableSlots <= 0) {
35996
- return [];
35997
- }
35998
- const parallelTasks = executable.filter((task) => task.execution?.parallel === true);
35999
- if (parallelTasks.length === 0) {
36000
- return [executable[0]];
36001
- }
36002
- let sortedTasks = [...parallelTasks];
36003
- if (plan.concurrency.strategy === "priority") {
36004
- sortedTasks.sort((a, b) => (b.execution?.priority ?? 0) - (a.execution?.priority ?? 0));
36005
- }
36006
- return sortedTasks.slice(0, availableSlots);
36007
- }
36008
- async function evaluateCondition(condition, memory) {
36009
- const value = await memory.get(condition.memoryKey);
36010
- switch (condition.operator) {
36011
- case "exists":
36012
- return value !== void 0;
36013
- case "not_exists":
36014
- return value === void 0;
36015
- case "equals":
36016
- return value === condition.value;
36017
- case "contains":
36018
- if (Array.isArray(value)) {
36019
- return value.includes(condition.value);
36020
- }
36021
- if (typeof value === "string" && typeof condition.value === "string") {
36022
- return value.includes(condition.value);
36023
- }
36024
- return false;
36025
- case "truthy":
36026
- return !!value;
36027
- case "greater_than":
36028
- if (typeof value === "number" && typeof condition.value === "number") {
36029
- return value > condition.value;
36030
- }
36031
- return false;
36032
- case "less_than":
36033
- if (typeof value === "number" && typeof condition.value === "number") {
36034
- return value < condition.value;
36035
- }
36036
- return false;
36037
- default:
36038
- return false;
36039
- }
36040
- }
36041
- function updateTaskStatus(task, status) {
36042
- const now = Date.now();
36043
- const updated = {
36044
- ...task,
36045
- status,
36046
- lastUpdatedAt: now
36047
- };
36048
- if (status === "in_progress") {
36049
- if (!updated.startedAt) {
36050
- updated.startedAt = now;
36051
- }
36052
- updated.attempts += 1;
36053
- }
36054
- if ((status === "completed" || status === "failed") && !updated.completedAt) {
36055
- updated.completedAt = now;
36056
- }
36057
- return updated;
36058
- }
36059
- function isTaskBlocked(task, allTasks) {
36060
- if (task.dependsOn.length === 0) {
36061
- return false;
36062
- }
36063
- for (const depId of task.dependsOn) {
36064
- const depTask = allTasks.find((t) => t.id === depId);
36065
- if (!depTask) {
36066
- return true;
36067
- }
36068
- if (depTask.status !== "completed") {
36069
- return true;
36070
- }
36071
- }
36072
- return false;
36073
- }
36074
- function getTaskDependencies(task, allTasks) {
36075
- if (task.dependsOn.length === 0) {
36076
- return [];
36077
- }
36078
- return task.dependsOn.map((depId) => allTasks.find((t) => t.id === depId)).filter((t) => t !== void 0);
36079
- }
36080
- function resolveDependencies(taskInputs, tasks) {
36081
- const nameToId = /* @__PURE__ */ new Map();
36082
- for (const task of tasks) {
36083
- nameToId.set(task.name, task.id);
36084
- }
36085
- for (const input of taskInputs) {
36086
- if (input.dependsOn && input.dependsOn.length > 0) {
36087
- input.dependsOn = input.dependsOn.map((dep) => {
36088
- if (dep.startsWith("task-")) {
36089
- return dep;
36090
- }
36091
- const resolvedId = nameToId.get(dep);
36092
- if (!resolvedId) {
36093
- throw new Error(`Task dependency "${dep}" not found`);
36094
- }
36095
- return resolvedId;
36096
- });
36097
- }
36098
- }
36099
- }
36100
- function detectDependencyCycle(tasks) {
36101
- const visited = /* @__PURE__ */ new Set();
36102
- const recStack = /* @__PURE__ */ new Set();
36103
- const taskMap = new Map(tasks.map((t) => [t.id, t]));
36104
- function dfs(taskId, path6) {
36105
- if (recStack.has(taskId)) {
36106
- const cycleStart = path6.indexOf(taskId);
36107
- return [...path6.slice(cycleStart), taskId];
36108
- }
36109
- if (visited.has(taskId)) {
36110
- return null;
36111
- }
36112
- visited.add(taskId);
36113
- recStack.add(taskId);
36114
- const task = taskMap.get(taskId);
36115
- if (task) {
36116
- for (const depId of task.dependsOn) {
36117
- const cycle = dfs(depId, [...path6, taskId]);
36118
- if (cycle) {
36119
- return cycle;
36120
- }
36121
- }
36122
- }
36123
- recStack.delete(taskId);
36124
- return null;
36125
- }
36126
- for (const task of tasks) {
36127
- if (!visited.has(task.id)) {
36128
- const cycle = dfs(task.id, []);
36129
- if (cycle) {
36130
- return cycle;
36131
- }
36132
- }
36133
- }
36134
- return null;
36135
- }
36136
-
36137
36937
  // src/capabilities/taskAgent/PlanningAgent.ts
36138
36938
  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.
36139
36939
 
@@ -36981,11 +37781,11 @@ var FileContextStorage = class {
36981
37781
  const data = this.prettyPrint ? JSON.stringify(storedSession, null, 2) : JSON.stringify(storedSession);
36982
37782
  const tempPath = `${filePath}.tmp`;
36983
37783
  try {
36984
- await fs18.promises.writeFile(tempPath, data, "utf-8");
36985
- await fs18.promises.rename(tempPath, filePath);
37784
+ await fs19.promises.writeFile(tempPath, data, "utf-8");
37785
+ await fs19.promises.rename(tempPath, filePath);
36986
37786
  } catch (error) {
36987
37787
  try {
36988
- await fs18.promises.unlink(tempPath);
37788
+ await fs19.promises.unlink(tempPath);
36989
37789
  } catch {
36990
37790
  }
36991
37791
  throw error;
@@ -37006,7 +37806,7 @@ var FileContextStorage = class {
37006
37806
  const sanitizedSessionId = sanitizeId(sessionId);
37007
37807
  const filePath = this.getFilePath(sanitizedSessionId);
37008
37808
  try {
37009
- await fs18.promises.unlink(filePath);
37809
+ await fs19.promises.unlink(filePath);
37010
37810
  } catch (error) {
37011
37811
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
37012
37812
  throw error;
@@ -37021,7 +37821,7 @@ var FileContextStorage = class {
37021
37821
  const sanitizedSessionId = sanitizeId(sessionId);
37022
37822
  const filePath = this.getFilePath(sanitizedSessionId);
37023
37823
  try {
37024
- await fs18.promises.access(filePath);
37824
+ await fs19.promises.access(filePath);
37025
37825
  return true;
37026
37826
  } catch {
37027
37827
  return false;
@@ -37086,7 +37886,7 @@ var FileContextStorage = class {
37086
37886
  const sanitizedSessionId = sanitizeId(sessionId);
37087
37887
  const filePath = this.getFilePath(sanitizedSessionId);
37088
37888
  const data = this.prettyPrint ? JSON.stringify(stored, null, 2) : JSON.stringify(stored);
37089
- await fs18.promises.writeFile(filePath, data, "utf-8");
37889
+ await fs19.promises.writeFile(filePath, data, "utf-8");
37090
37890
  await this.updateIndex(stored);
37091
37891
  }
37092
37892
  /**
@@ -37114,13 +37914,13 @@ var FileContextStorage = class {
37114
37914
  */
37115
37915
  async rebuildIndex() {
37116
37916
  await this.ensureDirectory();
37117
- const files = await fs18.promises.readdir(this.sessionsDirectory);
37917
+ const files = await fs19.promises.readdir(this.sessionsDirectory);
37118
37918
  const sessionFiles = files.filter((f) => f.endsWith(".json") && !f.startsWith("_"));
37119
37919
  const entries = [];
37120
37920
  for (const file of sessionFiles) {
37121
37921
  try {
37122
37922
  const filePath = path2.join(this.sessionsDirectory, file);
37123
- const data = await fs18.promises.readFile(filePath, "utf-8");
37923
+ const data = await fs19.promises.readFile(filePath, "utf-8");
37124
37924
  const stored = JSON.parse(data);
37125
37925
  entries.push(this.storedToIndexEntry(stored));
37126
37926
  } catch {
@@ -37142,7 +37942,7 @@ var FileContextStorage = class {
37142
37942
  }
37143
37943
  async ensureDirectory() {
37144
37944
  try {
37145
- await fs18.promises.mkdir(this.sessionsDirectory, { recursive: true });
37945
+ await fs19.promises.mkdir(this.sessionsDirectory, { recursive: true });
37146
37946
  } catch (error) {
37147
37947
  if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
37148
37948
  throw error;
@@ -37152,7 +37952,7 @@ var FileContextStorage = class {
37152
37952
  async loadRaw(sanitizedSessionId) {
37153
37953
  const filePath = this.getFilePath(sanitizedSessionId);
37154
37954
  try {
37155
- const data = await fs18.promises.readFile(filePath, "utf-8");
37955
+ const data = await fs19.promises.readFile(filePath, "utf-8");
37156
37956
  return JSON.parse(data);
37157
37957
  } catch (error) {
37158
37958
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -37170,7 +37970,7 @@ var FileContextStorage = class {
37170
37970
  return this.index;
37171
37971
  }
37172
37972
  try {
37173
- const data = await fs18.promises.readFile(this.indexPath, "utf-8");
37973
+ const data = await fs19.promises.readFile(this.indexPath, "utf-8");
37174
37974
  this.index = JSON.parse(data);
37175
37975
  return this.index;
37176
37976
  } catch (error) {
@@ -37191,7 +37991,7 @@ var FileContextStorage = class {
37191
37991
  await this.ensureDirectory();
37192
37992
  this.index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
37193
37993
  const data = this.prettyPrint ? JSON.stringify(this.index, null, 2) : JSON.stringify(this.index);
37194
- await fs18.promises.writeFile(this.indexPath, data, "utf-8");
37994
+ await fs19.promises.writeFile(this.indexPath, data, "utf-8");
37195
37995
  }
37196
37996
  async updateIndex(stored) {
37197
37997
  const index = await this.loadIndex();
@@ -37265,11 +38065,11 @@ var FileAgentDefinitionStorage = class {
37265
38065
  const data = this.prettyPrint ? JSON.stringify(definition, null, 2) : JSON.stringify(definition);
37266
38066
  const tempPath = `${filePath}.tmp`;
37267
38067
  try {
37268
- await fs18.promises.writeFile(tempPath, data, "utf-8");
37269
- await fs18.promises.rename(tempPath, filePath);
38068
+ await fs19.promises.writeFile(tempPath, data, "utf-8");
38069
+ await fs19.promises.rename(tempPath, filePath);
37270
38070
  } catch (error) {
37271
38071
  try {
37272
- await fs18.promises.unlink(tempPath);
38072
+ await fs19.promises.unlink(tempPath);
37273
38073
  } catch {
37274
38074
  }
37275
38075
  throw error;
@@ -37291,7 +38091,7 @@ var FileAgentDefinitionStorage = class {
37291
38091
  const agentDir = path2.join(this.baseDirectory, sanitizedId);
37292
38092
  const filePath = path2.join(agentDir, "definition.json");
37293
38093
  try {
37294
- await fs18.promises.unlink(filePath);
38094
+ await fs19.promises.unlink(filePath);
37295
38095
  } catch (error) {
37296
38096
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
37297
38097
  throw error;
@@ -37306,7 +38106,7 @@ var FileAgentDefinitionStorage = class {
37306
38106
  const sanitizedId = sanitizeAgentId2(agentId);
37307
38107
  const filePath = path2.join(this.baseDirectory, sanitizedId, "definition.json");
37308
38108
  try {
37309
- await fs18.promises.access(filePath);
38109
+ await fs19.promises.access(filePath);
37310
38110
  return true;
37311
38111
  } catch {
37312
38112
  return false;
@@ -37368,13 +38168,13 @@ var FileAgentDefinitionStorage = class {
37368
38168
  */
37369
38169
  async rebuildIndex() {
37370
38170
  await this.ensureDirectory(this.baseDirectory);
37371
- const entries = await fs18.promises.readdir(this.baseDirectory, { withFileTypes: true });
38171
+ const entries = await fs19.promises.readdir(this.baseDirectory, { withFileTypes: true });
37372
38172
  const agentDirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith("_"));
37373
38173
  const indexEntries = [];
37374
38174
  for (const dir of agentDirs) {
37375
38175
  try {
37376
38176
  const filePath = path2.join(this.baseDirectory, dir.name, "definition.json");
37377
- const data = await fs18.promises.readFile(filePath, "utf-8");
38177
+ const data = await fs19.promises.readFile(filePath, "utf-8");
37378
38178
  const definition = JSON.parse(data);
37379
38179
  indexEntries.push(this.definitionToIndexEntry(definition));
37380
38180
  } catch {
@@ -37392,7 +38192,7 @@ var FileAgentDefinitionStorage = class {
37392
38192
  // ==========================================================================
37393
38193
  async ensureDirectory(dir) {
37394
38194
  try {
37395
- await fs18.promises.mkdir(dir, { recursive: true });
38195
+ await fs19.promises.mkdir(dir, { recursive: true });
37396
38196
  } catch (error) {
37397
38197
  if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
37398
38198
  throw error;
@@ -37402,7 +38202,7 @@ var FileAgentDefinitionStorage = class {
37402
38202
  async loadRaw(sanitizedId) {
37403
38203
  const filePath = path2.join(this.baseDirectory, sanitizedId, "definition.json");
37404
38204
  try {
37405
- const data = await fs18.promises.readFile(filePath, "utf-8");
38205
+ const data = await fs19.promises.readFile(filePath, "utf-8");
37406
38206
  return JSON.parse(data);
37407
38207
  } catch (error) {
37408
38208
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -37420,7 +38220,7 @@ var FileAgentDefinitionStorage = class {
37420
38220
  return this.index;
37421
38221
  }
37422
38222
  try {
37423
- const data = await fs18.promises.readFile(this.indexPath, "utf-8");
38223
+ const data = await fs19.promises.readFile(this.indexPath, "utf-8");
37424
38224
  this.index = JSON.parse(data);
37425
38225
  return this.index;
37426
38226
  } catch (error) {
@@ -37440,7 +38240,7 @@ var FileAgentDefinitionStorage = class {
37440
38240
  await this.ensureDirectory(this.baseDirectory);
37441
38241
  this.index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
37442
38242
  const data = this.prettyPrint ? JSON.stringify(this.index, null, 2) : JSON.stringify(this.index);
37443
- await fs18.promises.writeFile(this.indexPath, data, "utf-8");
38243
+ await fs19.promises.writeFile(this.indexPath, data, "utf-8");
37444
38244
  }
37445
38245
  async updateIndex(definition) {
37446
38246
  const index = await this.loadIndex();
@@ -37498,10 +38298,10 @@ var FileMediaStorage = class {
37498
38298
  }
37499
38299
  async save(data, metadata) {
37500
38300
  const dir = metadata.userId ? path2__namespace.join(this.outputDir, metadata.userId) : this.outputDir;
37501
- await fs17__namespace.mkdir(dir, { recursive: true });
38301
+ await fs18__namespace.mkdir(dir, { recursive: true });
37502
38302
  const filename = metadata.suggestedFilename ?? this.generateFilename(metadata);
37503
38303
  const filePath = path2__namespace.join(dir, filename);
37504
- await fs17__namespace.writeFile(filePath, data);
38304
+ await fs18__namespace.writeFile(filePath, data);
37505
38305
  const format = metadata.format.toLowerCase();
37506
38306
  const mimeType = MIME_TYPES2[format] ?? "application/octet-stream";
37507
38307
  return {
@@ -37512,7 +38312,7 @@ var FileMediaStorage = class {
37512
38312
  }
37513
38313
  async read(location) {
37514
38314
  try {
37515
- return await fs17__namespace.readFile(location);
38315
+ return await fs18__namespace.readFile(location);
37516
38316
  } catch (err) {
37517
38317
  if (err.code === "ENOENT") {
37518
38318
  return null;
@@ -37522,7 +38322,7 @@ var FileMediaStorage = class {
37522
38322
  }
37523
38323
  async delete(location) {
37524
38324
  try {
37525
- await fs17__namespace.unlink(location);
38325
+ await fs18__namespace.unlink(location);
37526
38326
  } catch (err) {
37527
38327
  if (err.code === "ENOENT") {
37528
38328
  return;
@@ -37532,7 +38332,7 @@ var FileMediaStorage = class {
37532
38332
  }
37533
38333
  async exists(location) {
37534
38334
  try {
37535
- await fs17__namespace.access(location);
38335
+ await fs18__namespace.access(location);
37536
38336
  return true;
37537
38337
  } catch {
37538
38338
  return false;
@@ -37541,11 +38341,11 @@ var FileMediaStorage = class {
37541
38341
  async list(options) {
37542
38342
  await this.ensureDir();
37543
38343
  let entries = [];
37544
- const files = await fs17__namespace.readdir(this.outputDir);
38344
+ const files = await fs18__namespace.readdir(this.outputDir);
37545
38345
  for (const file of files) {
37546
38346
  const filePath = path2__namespace.join(this.outputDir, file);
37547
38347
  try {
37548
- const stat6 = await fs17__namespace.stat(filePath);
38348
+ const stat6 = await fs18__namespace.stat(filePath);
37549
38349
  if (!stat6.isFile()) continue;
37550
38350
  const ext = path2__namespace.extname(file).slice(1).toLowerCase();
37551
38351
  const mimeType = MIME_TYPES2[ext] ?? "application/octet-stream";
@@ -37585,7 +38385,7 @@ var FileMediaStorage = class {
37585
38385
  }
37586
38386
  async ensureDir() {
37587
38387
  if (!this.initialized) {
37588
- await fs17__namespace.mkdir(this.outputDir, { recursive: true });
38388
+ await fs18__namespace.mkdir(this.outputDir, { recursive: true });
37589
38389
  this.initialized = true;
37590
38390
  }
37591
38391
  }
@@ -37650,11 +38450,11 @@ var FileCustomToolStorage = class {
37650
38450
  const data = this.prettyPrint ? JSON.stringify(definition, null, 2) : JSON.stringify(definition);
37651
38451
  const tempPath = `${filePath}.tmp`;
37652
38452
  try {
37653
- await fs18.promises.writeFile(tempPath, data, "utf-8");
37654
- await fs18.promises.rename(tempPath, filePath);
38453
+ await fs19.promises.writeFile(tempPath, data, "utf-8");
38454
+ await fs19.promises.rename(tempPath, filePath);
37655
38455
  } catch (error) {
37656
38456
  try {
37657
- await fs18.promises.unlink(tempPath);
38457
+ await fs19.promises.unlink(tempPath);
37658
38458
  } catch {
37659
38459
  }
37660
38460
  throw error;
@@ -37668,7 +38468,7 @@ var FileCustomToolStorage = class {
37668
38468
  const sanitized = sanitizeName(name);
37669
38469
  const filePath = this.getToolPath(userId, sanitized);
37670
38470
  try {
37671
- const data = await fs18.promises.readFile(filePath, "utf-8");
38471
+ const data = await fs19.promises.readFile(filePath, "utf-8");
37672
38472
  return JSON.parse(data);
37673
38473
  } catch (error) {
37674
38474
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -37687,7 +38487,7 @@ var FileCustomToolStorage = class {
37687
38487
  const sanitized = sanitizeName(name);
37688
38488
  const filePath = this.getToolPath(userId, sanitized);
37689
38489
  try {
37690
- await fs18.promises.unlink(filePath);
38490
+ await fs19.promises.unlink(filePath);
37691
38491
  } catch (error) {
37692
38492
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
37693
38493
  throw error;
@@ -37702,7 +38502,7 @@ var FileCustomToolStorage = class {
37702
38502
  const sanitized = sanitizeName(name);
37703
38503
  const filePath = this.getToolPath(userId, sanitized);
37704
38504
  try {
37705
- await fs18.promises.access(filePath);
38505
+ await fs19.promises.access(filePath);
37706
38506
  return true;
37707
38507
  } catch {
37708
38508
  return false;
@@ -37773,7 +38573,7 @@ var FileCustomToolStorage = class {
37773
38573
  // ==========================================================================
37774
38574
  async ensureDirectory(dir) {
37775
38575
  try {
37776
- await fs18.promises.mkdir(dir, { recursive: true });
38576
+ await fs19.promises.mkdir(dir, { recursive: true });
37777
38577
  } catch (error) {
37778
38578
  if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
37779
38579
  throw error;
@@ -37783,7 +38583,7 @@ var FileCustomToolStorage = class {
37783
38583
  async loadIndex(userId) {
37784
38584
  const indexPath = this.getUserIndexPath(userId);
37785
38585
  try {
37786
- const data = await fs18.promises.readFile(indexPath, "utf-8");
38586
+ const data = await fs19.promises.readFile(indexPath, "utf-8");
37787
38587
  return JSON.parse(data);
37788
38588
  } catch (error) {
37789
38589
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -37802,7 +38602,7 @@ var FileCustomToolStorage = class {
37802
38602
  await this.ensureDirectory(directory);
37803
38603
  index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
37804
38604
  const data = this.prettyPrint ? JSON.stringify(index, null, 2) : JSON.stringify(index);
37805
- await fs18.promises.writeFile(indexPath, data, "utf-8");
38605
+ await fs19.promises.writeFile(indexPath, data, "utf-8");
37806
38606
  }
37807
38607
  async updateIndex(userId, definition) {
37808
38608
  const index = await this.loadIndex(userId);
@@ -37835,6 +38635,234 @@ var FileCustomToolStorage = class {
37835
38635
  function createFileCustomToolStorage(config) {
37836
38636
  return new FileCustomToolStorage(config);
37837
38637
  }
38638
+ var STORAGE_VERSION = 1;
38639
+ var DEFAULT_USER_ID3 = "default";
38640
+ function getDefaultBaseDirectory6() {
38641
+ const platform2 = process.platform;
38642
+ if (platform2 === "win32") {
38643
+ const appData = process.env.APPDATA || process.env.LOCALAPPDATA;
38644
+ if (appData) {
38645
+ return path2.join(appData, "oneringai", "users");
38646
+ }
38647
+ }
38648
+ return path2.join(os2.homedir(), ".oneringai", "users");
38649
+ }
38650
+ function sanitizeUserId3(userId) {
38651
+ if (!userId) {
38652
+ return DEFAULT_USER_ID3;
38653
+ }
38654
+ return userId.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase() || DEFAULT_USER_ID3;
38655
+ }
38656
+ function sanitizeId2(id) {
38657
+ return id.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase() || "default";
38658
+ }
38659
+ var FileRoutineDefinitionStorage = class {
38660
+ baseDirectory;
38661
+ prettyPrint;
38662
+ constructor(config = {}) {
38663
+ this.baseDirectory = config.baseDirectory ?? getDefaultBaseDirectory6();
38664
+ this.prettyPrint = config.prettyPrint ?? true;
38665
+ }
38666
+ getUserDirectory(userId) {
38667
+ const sanitizedId = sanitizeUserId3(userId);
38668
+ return path2.join(this.baseDirectory, sanitizedId, "routines");
38669
+ }
38670
+ getIndexPath(userId) {
38671
+ return path2.join(this.getUserDirectory(userId), "_index.json");
38672
+ }
38673
+ getRoutinePath(userId, sanitizedId) {
38674
+ return path2.join(this.getUserDirectory(userId), `${sanitizedId}.json`);
38675
+ }
38676
+ async save(userId, definition) {
38677
+ const directory = this.getUserDirectory(userId);
38678
+ const sanitized = sanitizeId2(definition.id);
38679
+ const filePath = this.getRoutinePath(userId, sanitized);
38680
+ await this.ensureDirectory(directory);
38681
+ const stored = { version: STORAGE_VERSION, definition };
38682
+ const data = this.prettyPrint ? JSON.stringify(stored, null, 2) : JSON.stringify(stored);
38683
+ const tempPath = `${filePath}.tmp`;
38684
+ try {
38685
+ await fs19.promises.writeFile(tempPath, data, "utf-8");
38686
+ await fs19.promises.rename(tempPath, filePath);
38687
+ } catch (error) {
38688
+ try {
38689
+ await fs19.promises.unlink(tempPath);
38690
+ } catch {
38691
+ }
38692
+ throw error;
38693
+ }
38694
+ await this.updateIndex(userId, definition);
38695
+ }
38696
+ async load(userId, id) {
38697
+ const sanitized = sanitizeId2(id);
38698
+ const filePath = this.getRoutinePath(userId, sanitized);
38699
+ try {
38700
+ const data = await fs19.promises.readFile(filePath, "utf-8");
38701
+ const stored = JSON.parse(data);
38702
+ return stored.definition;
38703
+ } catch (error) {
38704
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
38705
+ return null;
38706
+ }
38707
+ if (error instanceof SyntaxError) {
38708
+ return null;
38709
+ }
38710
+ throw error;
38711
+ }
38712
+ }
38713
+ async delete(userId, id) {
38714
+ const sanitized = sanitizeId2(id);
38715
+ const filePath = this.getRoutinePath(userId, sanitized);
38716
+ try {
38717
+ await fs19.promises.unlink(filePath);
38718
+ } catch (error) {
38719
+ if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
38720
+ throw error;
38721
+ }
38722
+ }
38723
+ await this.removeFromIndex(userId, id);
38724
+ }
38725
+ async exists(userId, id) {
38726
+ const sanitized = sanitizeId2(id);
38727
+ const filePath = this.getRoutinePath(userId, sanitized);
38728
+ try {
38729
+ await fs19.promises.access(filePath);
38730
+ return true;
38731
+ } catch {
38732
+ return false;
38733
+ }
38734
+ }
38735
+ async list(userId, options) {
38736
+ const index = await this.loadIndex(userId);
38737
+ let entries = [...index.routines];
38738
+ if (options?.tags && options.tags.length > 0) {
38739
+ entries = entries.filter((e) => {
38740
+ const entryTags = e.tags ?? [];
38741
+ return options.tags.some((t) => entryTags.includes(t));
38742
+ });
38743
+ }
38744
+ if (options?.search) {
38745
+ const searchLower = options.search.toLowerCase();
38746
+ entries = entries.filter(
38747
+ (e) => e.name.toLowerCase().includes(searchLower) || e.description.toLowerCase().includes(searchLower)
38748
+ );
38749
+ }
38750
+ entries.sort(
38751
+ (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
38752
+ );
38753
+ if (options?.offset) {
38754
+ entries = entries.slice(options.offset);
38755
+ }
38756
+ if (options?.limit) {
38757
+ entries = entries.slice(0, options.limit);
38758
+ }
38759
+ const results = [];
38760
+ for (const entry of entries) {
38761
+ const def = await this.load(userId, entry.id);
38762
+ if (def) {
38763
+ results.push(def);
38764
+ }
38765
+ }
38766
+ return results;
38767
+ }
38768
+ getPath(userId) {
38769
+ return this.getUserDirectory(userId);
38770
+ }
38771
+ // ==========================================================================
38772
+ // Private Helpers
38773
+ // ==========================================================================
38774
+ async ensureDirectory(dir) {
38775
+ try {
38776
+ await fs19.promises.mkdir(dir, { recursive: true });
38777
+ } catch (error) {
38778
+ if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
38779
+ throw error;
38780
+ }
38781
+ }
38782
+ }
38783
+ async loadIndex(userId) {
38784
+ const indexPath = this.getIndexPath(userId);
38785
+ try {
38786
+ const data = await fs19.promises.readFile(indexPath, "utf-8");
38787
+ return JSON.parse(data);
38788
+ } catch (error) {
38789
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
38790
+ return await this.rebuildIndex(userId);
38791
+ }
38792
+ throw error;
38793
+ }
38794
+ }
38795
+ async saveIndex(userId, index) {
38796
+ const directory = this.getUserDirectory(userId);
38797
+ const indexPath = this.getIndexPath(userId);
38798
+ await this.ensureDirectory(directory);
38799
+ index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
38800
+ const data = this.prettyPrint ? JSON.stringify(index, null, 2) : JSON.stringify(index);
38801
+ await fs19.promises.writeFile(indexPath, data, "utf-8");
38802
+ }
38803
+ async updateIndex(userId, definition) {
38804
+ const index = await this.loadIndex(userId);
38805
+ const entry = this.definitionToIndexEntry(definition);
38806
+ const existingIdx = index.routines.findIndex((e) => e.id === definition.id);
38807
+ if (existingIdx >= 0) {
38808
+ index.routines[existingIdx] = entry;
38809
+ } else {
38810
+ index.routines.push(entry);
38811
+ }
38812
+ await this.saveIndex(userId, index);
38813
+ }
38814
+ async removeFromIndex(userId, id) {
38815
+ const index = await this.loadIndex(userId);
38816
+ index.routines = index.routines.filter((e) => e.id !== id);
38817
+ await this.saveIndex(userId, index);
38818
+ }
38819
+ definitionToIndexEntry(definition) {
38820
+ return {
38821
+ id: definition.id,
38822
+ name: definition.name,
38823
+ description: definition.description,
38824
+ tags: definition.tags,
38825
+ author: definition.author,
38826
+ updatedAt: definition.updatedAt
38827
+ };
38828
+ }
38829
+ /**
38830
+ * Rebuild index by scanning directory for .json files (excluding _index.json).
38831
+ * Returns empty index if directory doesn't exist.
38832
+ */
38833
+ async rebuildIndex(userId) {
38834
+ const directory = this.getUserDirectory(userId);
38835
+ const index = {
38836
+ version: 1,
38837
+ routines: [],
38838
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
38839
+ };
38840
+ let files;
38841
+ try {
38842
+ files = await fs19.promises.readdir(directory);
38843
+ } catch {
38844
+ return index;
38845
+ }
38846
+ for (const file of files) {
38847
+ if (!file.endsWith(".json") || file === "_index.json") continue;
38848
+ try {
38849
+ const data = await fs19.promises.readFile(path2.join(directory, file), "utf-8");
38850
+ const stored = JSON.parse(data);
38851
+ if (stored.definition) {
38852
+ index.routines.push(this.definitionToIndexEntry(stored.definition));
38853
+ }
38854
+ } catch {
38855
+ }
38856
+ }
38857
+ if (index.routines.length > 0) {
38858
+ await this.saveIndex(userId, index);
38859
+ }
38860
+ return index;
38861
+ }
38862
+ };
38863
+ function createFileRoutineDefinitionStorage(config) {
38864
+ return new FileRoutineDefinitionStorage(config);
38865
+ }
37838
38866
 
37839
38867
  // src/domain/entities/CustomToolDefinition.ts
37840
38868
  var CUSTOM_TOOL_DEFINITION_VERSION = 1;
@@ -38935,8 +39963,8 @@ var FileStorage = class {
38935
39963
  }
38936
39964
  async ensureDirectory() {
38937
39965
  try {
38938
- await fs17__namespace.mkdir(this.directory, { recursive: true });
38939
- await fs17__namespace.chmod(this.directory, 448);
39966
+ await fs18__namespace.mkdir(this.directory, { recursive: true });
39967
+ await fs18__namespace.chmod(this.directory, 448);
38940
39968
  } catch (error) {
38941
39969
  }
38942
39970
  }
@@ -38952,13 +39980,13 @@ var FileStorage = class {
38952
39980
  const filePath = this.getFilePath(key);
38953
39981
  const plaintext = JSON.stringify(token);
38954
39982
  const encrypted = encrypt(plaintext, this.encryptionKey);
38955
- await fs17__namespace.writeFile(filePath, encrypted, "utf8");
38956
- await fs17__namespace.chmod(filePath, 384);
39983
+ await fs18__namespace.writeFile(filePath, encrypted, "utf8");
39984
+ await fs18__namespace.chmod(filePath, 384);
38957
39985
  }
38958
39986
  async getToken(key) {
38959
39987
  const filePath = this.getFilePath(key);
38960
39988
  try {
38961
- const encrypted = await fs17__namespace.readFile(filePath, "utf8");
39989
+ const encrypted = await fs18__namespace.readFile(filePath, "utf8");
38962
39990
  const decrypted = decrypt(encrypted, this.encryptionKey);
38963
39991
  return JSON.parse(decrypted);
38964
39992
  } catch (error) {
@@ -38967,7 +39995,7 @@ var FileStorage = class {
38967
39995
  }
38968
39996
  console.error("Failed to read/decrypt token file:", error);
38969
39997
  try {
38970
- await fs17__namespace.unlink(filePath);
39998
+ await fs18__namespace.unlink(filePath);
38971
39999
  } catch {
38972
40000
  }
38973
40001
  return null;
@@ -38976,7 +40004,7 @@ var FileStorage = class {
38976
40004
  async deleteToken(key) {
38977
40005
  const filePath = this.getFilePath(key);
38978
40006
  try {
38979
- await fs17__namespace.unlink(filePath);
40007
+ await fs18__namespace.unlink(filePath);
38980
40008
  } catch (error) {
38981
40009
  if (error.code !== "ENOENT") {
38982
40010
  throw error;
@@ -38986,7 +40014,7 @@ var FileStorage = class {
38986
40014
  async hasToken(key) {
38987
40015
  const filePath = this.getFilePath(key);
38988
40016
  try {
38989
- await fs17__namespace.access(filePath);
40017
+ await fs18__namespace.access(filePath);
38990
40018
  return true;
38991
40019
  } catch {
38992
40020
  return false;
@@ -38997,7 +40025,7 @@ var FileStorage = class {
38997
40025
  */
38998
40026
  async listTokens() {
38999
40027
  try {
39000
- const files = await fs17__namespace.readdir(this.directory);
40028
+ const files = await fs18__namespace.readdir(this.directory);
39001
40029
  return files.filter((f) => f.endsWith(".token")).map((f) => f.replace(".token", ""));
39002
40030
  } catch {
39003
40031
  return [];
@@ -39008,10 +40036,10 @@ var FileStorage = class {
39008
40036
  */
39009
40037
  async clearAll() {
39010
40038
  try {
39011
- const files = await fs17__namespace.readdir(this.directory);
40039
+ const files = await fs18__namespace.readdir(this.directory);
39012
40040
  const tokenFiles = files.filter((f) => f.endsWith(".token"));
39013
40041
  await Promise.all(
39014
- tokenFiles.map((f) => fs17__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
40042
+ tokenFiles.map((f) => fs18__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
39015
40043
  }))
39016
40044
  );
39017
40045
  } catch {
@@ -39459,14 +40487,14 @@ var FileConnectorStorage = class {
39459
40487
  await this.ensureDirectory();
39460
40488
  const filePath = this.getFilePath(name);
39461
40489
  const json = JSON.stringify(stored, null, 2);
39462
- await fs17__namespace.writeFile(filePath, json, "utf8");
39463
- await fs17__namespace.chmod(filePath, 384);
40490
+ await fs18__namespace.writeFile(filePath, json, "utf8");
40491
+ await fs18__namespace.chmod(filePath, 384);
39464
40492
  await this.updateIndex(name, "add");
39465
40493
  }
39466
40494
  async get(name) {
39467
40495
  const filePath = this.getFilePath(name);
39468
40496
  try {
39469
- const json = await fs17__namespace.readFile(filePath, "utf8");
40497
+ const json = await fs18__namespace.readFile(filePath, "utf8");
39470
40498
  return JSON.parse(json);
39471
40499
  } catch (error) {
39472
40500
  const err = error;
@@ -39479,7 +40507,7 @@ var FileConnectorStorage = class {
39479
40507
  async delete(name) {
39480
40508
  const filePath = this.getFilePath(name);
39481
40509
  try {
39482
- await fs17__namespace.unlink(filePath);
40510
+ await fs18__namespace.unlink(filePath);
39483
40511
  await this.updateIndex(name, "remove");
39484
40512
  return true;
39485
40513
  } catch (error) {
@@ -39493,7 +40521,7 @@ var FileConnectorStorage = class {
39493
40521
  async has(name) {
39494
40522
  const filePath = this.getFilePath(name);
39495
40523
  try {
39496
- await fs17__namespace.access(filePath);
40524
+ await fs18__namespace.access(filePath);
39497
40525
  return true;
39498
40526
  } catch {
39499
40527
  return false;
@@ -39519,13 +40547,13 @@ var FileConnectorStorage = class {
39519
40547
  */
39520
40548
  async clear() {
39521
40549
  try {
39522
- const files = await fs17__namespace.readdir(this.directory);
40550
+ const files = await fs18__namespace.readdir(this.directory);
39523
40551
  const connectorFiles = files.filter(
39524
40552
  (f) => f.endsWith(".connector.json") || f === "_index.json"
39525
40553
  );
39526
40554
  await Promise.all(
39527
40555
  connectorFiles.map(
39528
- (f) => fs17__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
40556
+ (f) => fs18__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
39529
40557
  })
39530
40558
  )
39531
40559
  );
@@ -39552,8 +40580,8 @@ var FileConnectorStorage = class {
39552
40580
  async ensureDirectory() {
39553
40581
  if (this.initialized) return;
39554
40582
  try {
39555
- await fs17__namespace.mkdir(this.directory, { recursive: true });
39556
- await fs17__namespace.chmod(this.directory, 448);
40583
+ await fs18__namespace.mkdir(this.directory, { recursive: true });
40584
+ await fs18__namespace.chmod(this.directory, 448);
39557
40585
  this.initialized = true;
39558
40586
  } catch {
39559
40587
  this.initialized = true;
@@ -39564,7 +40592,7 @@ var FileConnectorStorage = class {
39564
40592
  */
39565
40593
  async loadIndex() {
39566
40594
  try {
39567
- const json = await fs17__namespace.readFile(this.indexPath, "utf8");
40595
+ const json = await fs18__namespace.readFile(this.indexPath, "utf8");
39568
40596
  return JSON.parse(json);
39569
40597
  } catch {
39570
40598
  return { connectors: {} };
@@ -39582,8 +40610,8 @@ var FileConnectorStorage = class {
39582
40610
  delete index.connectors[hash];
39583
40611
  }
39584
40612
  const json = JSON.stringify(index, null, 2);
39585
- await fs17__namespace.writeFile(this.indexPath, json, "utf8");
39586
- await fs17__namespace.chmod(this.indexPath, 384);
40613
+ await fs18__namespace.writeFile(this.indexPath, json, "utf8");
40614
+ await fs18__namespace.chmod(this.indexPath, 384);
39587
40615
  }
39588
40616
  };
39589
40617
 
@@ -42038,8 +43066,8 @@ function createMessageWithImages(text, imageUrls, role = "user" /* USER */) {
42038
43066
  var execAsync = util.promisify(child_process.exec);
42039
43067
  function cleanupTempFile(filePath) {
42040
43068
  try {
42041
- if (fs18__namespace.existsSync(filePath)) {
42042
- fs18__namespace.unlinkSync(filePath);
43069
+ if (fs19__namespace.existsSync(filePath)) {
43070
+ fs19__namespace.unlinkSync(filePath);
42043
43071
  }
42044
43072
  } catch {
42045
43073
  }
@@ -42090,7 +43118,7 @@ async function readClipboardImageMac() {
42090
43118
  end try
42091
43119
  `;
42092
43120
  const { stdout } = await execAsync(`osascript -e '${script}'`);
42093
- if (stdout.includes("success") || fs18__namespace.existsSync(tempFile)) {
43121
+ if (stdout.includes("success") || fs19__namespace.existsSync(tempFile)) {
42094
43122
  return await convertFileToDataUri(tempFile);
42095
43123
  }
42096
43124
  return {
@@ -42107,14 +43135,14 @@ async function readClipboardImageLinux() {
42107
43135
  try {
42108
43136
  try {
42109
43137
  await execAsync(`xclip -selection clipboard -t image/png -o > "${tempFile}"`);
42110
- if (fs18__namespace.existsSync(tempFile) && fs18__namespace.statSync(tempFile).size > 0) {
43138
+ if (fs19__namespace.existsSync(tempFile) && fs19__namespace.statSync(tempFile).size > 0) {
42111
43139
  return await convertFileToDataUri(tempFile);
42112
43140
  }
42113
43141
  } catch {
42114
43142
  }
42115
43143
  try {
42116
43144
  await execAsync(`wl-paste -t image/png > "${tempFile}"`);
42117
- if (fs18__namespace.existsSync(tempFile) && fs18__namespace.statSync(tempFile).size > 0) {
43145
+ if (fs19__namespace.existsSync(tempFile) && fs19__namespace.statSync(tempFile).size > 0) {
42118
43146
  return await convertFileToDataUri(tempFile);
42119
43147
  }
42120
43148
  } catch {
@@ -42141,7 +43169,7 @@ async function readClipboardImageWindows() {
42141
43169
  }
42142
43170
  `;
42143
43171
  await execAsync(`powershell -Command "${psScript}"`);
42144
- if (fs18__namespace.existsSync(tempFile) && fs18__namespace.statSync(tempFile).size > 0) {
43172
+ if (fs19__namespace.existsSync(tempFile) && fs19__namespace.statSync(tempFile).size > 0) {
42145
43173
  return await convertFileToDataUri(tempFile);
42146
43174
  }
42147
43175
  return {
@@ -42154,7 +43182,7 @@ async function readClipboardImageWindows() {
42154
43182
  }
42155
43183
  async function convertFileToDataUri(filePath) {
42156
43184
  try {
42157
- const imageBuffer = fs18__namespace.readFileSync(filePath);
43185
+ const imageBuffer = fs19__namespace.readFileSync(filePath);
42158
43186
  const base64Image = imageBuffer.toString("base64");
42159
43187
  const magic = imageBuffer.slice(0, 4).toString("hex");
42160
43188
  let mimeType = "image/png";
@@ -42213,186 +43241,6 @@ async function hasClipboardImage() {
42213
43241
  }
42214
43242
  }
42215
43243
 
42216
- // src/utils/jsonExtractor.ts
42217
- function extractJSON(text) {
42218
- if (!text || typeof text !== "string") {
42219
- return {
42220
- success: false,
42221
- error: "Input is empty or not a string"
42222
- };
42223
- }
42224
- const trimmedText = text.trim();
42225
- const codeBlockResult = extractFromCodeBlock(trimmedText);
42226
- if (codeBlockResult.success) {
42227
- return codeBlockResult;
42228
- }
42229
- const inlineResult = extractInlineJSON(trimmedText);
42230
- if (inlineResult.success) {
42231
- return inlineResult;
42232
- }
42233
- try {
42234
- const data = JSON.parse(trimmedText);
42235
- return {
42236
- success: true,
42237
- data,
42238
- rawJson: trimmedText,
42239
- method: "raw"
42240
- };
42241
- } catch (e) {
42242
- return {
42243
- success: false,
42244
- error: `Could not extract JSON from text: ${e instanceof Error ? e.message : String(e)}`
42245
- };
42246
- }
42247
- }
42248
- function extractFromCodeBlock(text) {
42249
- const codeBlockRegex = /```(?:json)?\s*([\s\S]*?)```/g;
42250
- let match;
42251
- while ((match = codeBlockRegex.exec(text)) !== null) {
42252
- const content = match[1];
42253
- if (content) {
42254
- const trimmed = content.trim();
42255
- try {
42256
- const data = JSON.parse(trimmed);
42257
- return {
42258
- success: true,
42259
- data,
42260
- rawJson: trimmed,
42261
- method: "code_block"
42262
- };
42263
- } catch {
42264
- continue;
42265
- }
42266
- }
42267
- }
42268
- return { success: false };
42269
- }
42270
- function extractInlineJSON(text) {
42271
- const objectMatch = findJSONObject(text);
42272
- if (objectMatch) {
42273
- try {
42274
- const data = JSON.parse(objectMatch);
42275
- return {
42276
- success: true,
42277
- data,
42278
- rawJson: objectMatch,
42279
- method: "inline"
42280
- };
42281
- } catch {
42282
- }
42283
- }
42284
- const arrayMatch = findJSONArray(text);
42285
- if (arrayMatch) {
42286
- try {
42287
- const data = JSON.parse(arrayMatch);
42288
- return {
42289
- success: true,
42290
- data,
42291
- rawJson: arrayMatch,
42292
- method: "inline"
42293
- };
42294
- } catch {
42295
- }
42296
- }
42297
- return { success: false };
42298
- }
42299
- function findJSONObject(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 findJSONArray(text) {
42332
- const startIndex = text.indexOf("[");
42333
- if (startIndex === -1) return null;
42334
- let depth = 0;
42335
- let inString = false;
42336
- let escaped = false;
42337
- for (let i = startIndex; i < text.length; i++) {
42338
- const char = text[i];
42339
- if (escaped) {
42340
- escaped = false;
42341
- continue;
42342
- }
42343
- if (char === "\\" && inString) {
42344
- escaped = true;
42345
- continue;
42346
- }
42347
- if (char === '"') {
42348
- inString = !inString;
42349
- continue;
42350
- }
42351
- if (inString) continue;
42352
- if (char === "[") {
42353
- depth++;
42354
- } else if (char === "]") {
42355
- depth--;
42356
- if (depth === 0) {
42357
- return text.slice(startIndex, i + 1);
42358
- }
42359
- }
42360
- }
42361
- return null;
42362
- }
42363
- function extractJSONField(text, field, defaultValue) {
42364
- const result = extractJSON(text);
42365
- if (result.success && result.data && field in result.data) {
42366
- return result.data[field];
42367
- }
42368
- return defaultValue;
42369
- }
42370
- function extractNumber(text, patterns = [
42371
- /(\d{1,3})%?\s*(?:complete|score|percent)/i,
42372
- /(?:score|completion|rating)[:\s]+(\d{1,3})/i,
42373
- /(\d{1,3})\s*(?:out of|\/)\s*100/i
42374
- ], defaultValue = 0) {
42375
- const jsonResult = extractJSON(text);
42376
- if (jsonResult.success && jsonResult.data) {
42377
- const scoreFields = ["score", "completionScore", "completion_score", "rating", "percent", "value"];
42378
- for (const field of scoreFields) {
42379
- if (field in jsonResult.data && typeof jsonResult.data[field] === "number") {
42380
- return jsonResult.data[field];
42381
- }
42382
- }
42383
- }
42384
- for (const pattern of patterns) {
42385
- const match = text.match(pattern);
42386
- if (match && match[1]) {
42387
- const num = parseInt(match[1], 10);
42388
- if (!isNaN(num)) {
42389
- return num;
42390
- }
42391
- }
42392
- }
42393
- return defaultValue;
42394
- }
42395
-
42396
43244
  // src/tools/index.ts
42397
43245
  var tools_exports = {};
42398
43246
  __export(tools_exports, {
@@ -42428,19 +43276,25 @@ __export(tools_exports, {
42428
43276
  createDesktopScreenshotTool: () => createDesktopScreenshotTool,
42429
43277
  createDesktopWindowFocusTool: () => createDesktopWindowFocusTool,
42430
43278
  createDesktopWindowListTool: () => createDesktopWindowListTool,
43279
+ createDraftEmailTool: () => createDraftEmailTool,
42431
43280
  createEditFileTool: () => createEditFileTool,
43281
+ createEditMeetingTool: () => createEditMeetingTool,
42432
43282
  createExecuteJavaScriptTool: () => createExecuteJavaScriptTool,
43283
+ createFindMeetingSlotsTool: () => createFindMeetingSlotsTool,
43284
+ createGetMeetingTranscriptTool: () => createGetMeetingTranscriptTool,
42433
43285
  createGetPRTool: () => createGetPRTool,
42434
43286
  createGitHubReadFileTool: () => createGitHubReadFileTool,
42435
43287
  createGlobTool: () => createGlobTool,
42436
43288
  createGrepTool: () => createGrepTool,
42437
43289
  createImageGenerationTool: () => createImageGenerationTool,
42438
43290
  createListDirectoryTool: () => createListDirectoryTool,
43291
+ createMeetingTool: () => createMeetingTool,
42439
43292
  createPRCommentsTool: () => createPRCommentsTool,
42440
43293
  createPRFilesTool: () => createPRFilesTool,
42441
43294
  createReadFileTool: () => createReadFileTool,
42442
43295
  createSearchCodeTool: () => createSearchCodeTool,
42443
43296
  createSearchFilesTool: () => createSearchFilesTool,
43297
+ createSendEmailTool: () => createSendEmailTool,
42444
43298
  createSpeechToTextTool: () => createSpeechToTextTool,
42445
43299
  createTextToSpeechTool: () => createTextToSpeechTool,
42446
43300
  createVideoTools: () => createVideoTools,
@@ -42470,6 +43324,8 @@ __export(tools_exports, {
42470
43324
  executeInVM: () => executeInVM,
42471
43325
  executeJavaScript: () => executeJavaScript,
42472
43326
  expandTilde: () => expandTilde,
43327
+ formatAttendees: () => formatAttendees,
43328
+ formatRecipients: () => formatRecipients,
42473
43329
  getAllBuiltInTools: () => getAllBuiltInTools,
42474
43330
  getBackgroundOutput: () => getBackgroundOutput,
42475
43331
  getDesktopDriver: () => getDesktopDriver,
@@ -42480,19 +43336,24 @@ __export(tools_exports, {
42480
43336
  getToolRegistry: () => getToolRegistry,
42481
43337
  getToolsByCategory: () => getToolsByCategory,
42482
43338
  getToolsRequiringConnector: () => getToolsRequiringConnector,
43339
+ getUserPathPrefix: () => getUserPathPrefix,
42483
43340
  glob: () => glob,
42484
43341
  grep: () => grep,
42485
43342
  hydrateCustomTool: () => hydrateCustomTool,
42486
43343
  isBlockedCommand: () => isBlockedCommand,
42487
43344
  isExcludedExtension: () => isExcludedExtension,
43345
+ isTeamsMeetingUrl: () => isTeamsMeetingUrl,
42488
43346
  jsonManipulator: () => jsonManipulator,
42489
43347
  killBackgroundProcess: () => killBackgroundProcess,
42490
43348
  listDirectory: () => listDirectory,
42491
43349
  mergeTextPieces: () => mergeTextPieces,
43350
+ microsoftFetch: () => microsoftFetch,
43351
+ normalizeEmails: () => normalizeEmails,
42492
43352
  parseKeyCombo: () => parseKeyCombo,
42493
43353
  parseRepository: () => parseRepository,
42494
43354
  readFile: () => readFile5,
42495
43355
  resetDefaultDriver: () => resetDefaultDriver,
43356
+ resolveMeetingId: () => resolveMeetingId,
42496
43357
  resolveRepository: () => resolveRepository,
42497
43358
  setMediaOutputHandler: () => setMediaOutputHandler,
42498
43359
  setMediaStorage: () => setMediaStorage,
@@ -42703,7 +43564,7 @@ EXAMPLES:
42703
43564
  };
42704
43565
  }
42705
43566
  const resolvedPath = validation.resolvedPath;
42706
- if (!fs18.existsSync(resolvedPath)) {
43567
+ if (!fs19.existsSync(resolvedPath)) {
42707
43568
  return {
42708
43569
  success: false,
42709
43570
  error: `File not found: ${file_path}`,
@@ -42711,7 +43572,7 @@ EXAMPLES:
42711
43572
  };
42712
43573
  }
42713
43574
  try {
42714
- const stats = await fs17.stat(resolvedPath);
43575
+ const stats = await fs18.stat(resolvedPath);
42715
43576
  if (!stats.isFile()) {
42716
43577
  return {
42717
43578
  success: false,
@@ -42753,7 +43614,7 @@ EXAMPLES:
42753
43614
  } catch {
42754
43615
  }
42755
43616
  }
42756
- const content = await fs17.readFile(resolvedPath, "utf-8");
43617
+ const content = await fs18.readFile(resolvedPath, "utf-8");
42757
43618
  const allLines = content.split("\n");
42758
43619
  const totalLines = allLines.length;
42759
43620
  const startIndex = Math.max(0, offset - 1);
@@ -42858,13 +43719,13 @@ EXAMPLES:
42858
43719
  };
42859
43720
  }
42860
43721
  const resolvedPath = validation.resolvedPath;
42861
- const fileExists = fs18.existsSync(resolvedPath);
43722
+ const fileExists = fs19.existsSync(resolvedPath);
42862
43723
  try {
42863
43724
  const parentDir = path2.dirname(resolvedPath);
42864
- if (!fs18.existsSync(parentDir)) {
42865
- await fs17.mkdir(parentDir, { recursive: true });
43725
+ if (!fs19.existsSync(parentDir)) {
43726
+ await fs18.mkdir(parentDir, { recursive: true });
42866
43727
  }
42867
- await fs17.writeFile(resolvedPath, content, "utf-8");
43728
+ await fs18.writeFile(resolvedPath, content, "utf-8");
42868
43729
  return {
42869
43730
  success: true,
42870
43731
  path: file_path,
@@ -42967,7 +43828,7 @@ EXAMPLES:
42967
43828
  };
42968
43829
  }
42969
43830
  const resolvedPath = validation.resolvedPath;
42970
- if (!fs18.existsSync(resolvedPath)) {
43831
+ if (!fs19.existsSync(resolvedPath)) {
42971
43832
  return {
42972
43833
  success: false,
42973
43834
  error: `File not found: ${file_path}`,
@@ -42975,7 +43836,7 @@ EXAMPLES:
42975
43836
  };
42976
43837
  }
42977
43838
  try {
42978
- const content = await fs17.readFile(resolvedPath, "utf-8");
43839
+ const content = await fs18.readFile(resolvedPath, "utf-8");
42979
43840
  let occurrences = 0;
42980
43841
  let searchIndex = 0;
42981
43842
  while (true) {
@@ -43014,7 +43875,7 @@ EXAMPLES:
43014
43875
  } else {
43015
43876
  newContent = content.replace(old_string, new_string);
43016
43877
  }
43017
- await fs17.writeFile(resolvedPath, newContent, "utf-8");
43878
+ await fs18.writeFile(resolvedPath, newContent, "utf-8");
43018
43879
  const diffPreview = generateDiffPreview(old_string, new_string);
43019
43880
  return {
43020
43881
  success: true,
@@ -43070,7 +43931,7 @@ async function findFiles(dir, pattern, baseDir, config, results = [], depth = 0)
43070
43931
  return results;
43071
43932
  }
43072
43933
  try {
43073
- const entries = await fs17.readdir(dir, { withFileTypes: true });
43934
+ const entries = await fs18.readdir(dir, { withFileTypes: true });
43074
43935
  for (const entry of entries) {
43075
43936
  if (results.length >= config.maxResults) break;
43076
43937
  const fullPath = path2.join(dir, entry.name);
@@ -43084,7 +43945,7 @@ async function findFiles(dir, pattern, baseDir, config, results = [], depth = 0)
43084
43945
  } else if (entry.isFile()) {
43085
43946
  if (matchGlobPattern(pattern, relativePath)) {
43086
43947
  try {
43087
- const stats = await fs17.stat(fullPath);
43948
+ const stats = await fs18.stat(fullPath);
43088
43949
  results.push({
43089
43950
  path: relativePath,
43090
43951
  mtime: stats.mtimeMs
@@ -43166,7 +44027,7 @@ WHEN TO USE:
43166
44027
  };
43167
44028
  }
43168
44029
  const resolvedDir = validation.resolvedPath;
43169
- if (!fs18.existsSync(resolvedDir)) {
44030
+ if (!fs19.existsSync(resolvedDir)) {
43170
44031
  return {
43171
44032
  success: false,
43172
44033
  error: `Directory not found: ${searchDir}`
@@ -43221,7 +44082,7 @@ async function findFilesToSearch(dir, baseDir, config, globPattern, fileType, fi
43221
44082
  return files;
43222
44083
  }
43223
44084
  try {
43224
- const entries = await fs17.readdir(dir, { withFileTypes: true });
44085
+ const entries = await fs18.readdir(dir, { withFileTypes: true });
43225
44086
  for (const entry of entries) {
43226
44087
  const fullPath = path2.join(dir, entry.name);
43227
44088
  if (entry.isDirectory()) {
@@ -43254,7 +44115,7 @@ async function findFilesToSearch(dir, baseDir, config, globPattern, fileType, fi
43254
44115
  async function searchFile(filePath, regex, contextBefore, contextAfter) {
43255
44116
  const matches = [];
43256
44117
  try {
43257
- const content = await fs17.readFile(filePath, "utf-8");
44118
+ const content = await fs18.readFile(filePath, "utf-8");
43258
44119
  const lines = content.split("\n");
43259
44120
  for (let i = 0; i < lines.length; i++) {
43260
44121
  const line = lines[i] ?? "";
@@ -43395,7 +44256,7 @@ WHEN TO USE:
43395
44256
  };
43396
44257
  }
43397
44258
  const resolvedPath = validation.resolvedPath;
43398
- if (!fs18.existsSync(resolvedPath)) {
44259
+ if (!fs19.existsSync(resolvedPath)) {
43399
44260
  return {
43400
44261
  success: false,
43401
44262
  error: `Path not found: ${searchPath}`
@@ -43411,7 +44272,7 @@ WHEN TO USE:
43411
44272
  };
43412
44273
  }
43413
44274
  try {
43414
- const stats = await fs17.stat(resolvedPath);
44275
+ const stats = await fs18.stat(resolvedPath);
43415
44276
  let filesToSearch;
43416
44277
  if (stats.isFile()) {
43417
44278
  filesToSearch = [resolvedPath];
@@ -43499,7 +44360,7 @@ async function listDir(dir, baseDir, config, recursive, filter, maxDepth = 3, cu
43499
44360
  return entries;
43500
44361
  }
43501
44362
  try {
43502
- const dirEntries = await fs17.readdir(dir, { withFileTypes: true });
44363
+ const dirEntries = await fs18.readdir(dir, { withFileTypes: true });
43503
44364
  for (const entry of dirEntries) {
43504
44365
  if (entries.length >= config.maxResults) break;
43505
44366
  const fullPath = path2.join(dir, entry.name);
@@ -43517,7 +44378,7 @@ async function listDir(dir, baseDir, config, recursive, filter, maxDepth = 3, cu
43517
44378
  }
43518
44379
  if (filter === "directories" && !isDir) continue;
43519
44380
  try {
43520
- const stats = await fs17.stat(fullPath);
44381
+ const stats = await fs18.stat(fullPath);
43521
44382
  const dirEntry = {
43522
44383
  name: entry.name,
43523
44384
  path: relativePath,
@@ -43613,14 +44474,14 @@ EXAMPLES:
43613
44474
  };
43614
44475
  }
43615
44476
  const resolvedPath = validation.resolvedPath;
43616
- if (!fs18.existsSync(resolvedPath)) {
44477
+ if (!fs19.existsSync(resolvedPath)) {
43617
44478
  return {
43618
44479
  success: false,
43619
44480
  error: `Directory not found: ${path6}`
43620
44481
  };
43621
44482
  }
43622
44483
  try {
43623
- const stats = await fs17.stat(resolvedPath);
44484
+ const stats = await fs18.stat(resolvedPath);
43624
44485
  if (!stats.isDirectory()) {
43625
44486
  return {
43626
44487
  success: false,
@@ -46574,6 +47435,840 @@ function registerGitHubTools() {
46574
47435
  // src/tools/github/index.ts
46575
47436
  registerGitHubTools();
46576
47437
 
47438
+ // src/tools/microsoft/types.ts
47439
+ function getUserPathPrefix(connector, targetUser) {
47440
+ const auth2 = connector.config.auth;
47441
+ if (auth2.type === "oauth" && auth2.flow === "client_credentials") {
47442
+ if (!targetUser) {
47443
+ throw new Error(
47444
+ 'targetUser is required when using client_credentials (application) flow. Provide a user ID or UPN (e.g., "user@domain.com").'
47445
+ );
47446
+ }
47447
+ return `/users/${targetUser}`;
47448
+ }
47449
+ return "/me";
47450
+ }
47451
+ var MicrosoftAPIError = class extends Error {
47452
+ constructor(status, statusText, body) {
47453
+ const msg = typeof body === "object" && body !== null && "error" in body ? body.error?.message ?? statusText : statusText;
47454
+ super(`Microsoft Graph API error ${status}: ${msg}`);
47455
+ this.status = status;
47456
+ this.statusText = statusText;
47457
+ this.body = body;
47458
+ this.name = "MicrosoftAPIError";
47459
+ }
47460
+ };
47461
+ async function microsoftFetch(connector, endpoint, options) {
47462
+ let url2 = endpoint;
47463
+ if (options?.queryParams && Object.keys(options.queryParams).length > 0) {
47464
+ const params = new URLSearchParams();
47465
+ for (const [key, value] of Object.entries(options.queryParams)) {
47466
+ params.append(key, String(value));
47467
+ }
47468
+ url2 += (url2.includes("?") ? "&" : "?") + params.toString();
47469
+ }
47470
+ const headers = {
47471
+ "Accept": options?.accept ?? "application/json"
47472
+ };
47473
+ if (options?.body) {
47474
+ headers["Content-Type"] = "application/json";
47475
+ }
47476
+ const response = await connector.fetch(
47477
+ url2,
47478
+ {
47479
+ method: options?.method ?? "GET",
47480
+ headers,
47481
+ body: options?.body ? JSON.stringify(options.body) : void 0
47482
+ },
47483
+ options?.userId
47484
+ );
47485
+ const text = await response.text();
47486
+ if (!response.ok) {
47487
+ let data;
47488
+ try {
47489
+ data = JSON.parse(text);
47490
+ } catch {
47491
+ data = text;
47492
+ }
47493
+ throw new MicrosoftAPIError(response.status, response.statusText, data);
47494
+ }
47495
+ if (!text || text.trim().length === 0) {
47496
+ return void 0;
47497
+ }
47498
+ try {
47499
+ return JSON.parse(text);
47500
+ } catch {
47501
+ return text;
47502
+ }
47503
+ }
47504
+ function normalizeEmails(input) {
47505
+ return input.map((item) => {
47506
+ if (typeof item === "string") return item;
47507
+ if (typeof item === "object" && item !== null) {
47508
+ const obj = item;
47509
+ if (obj.emailAddress && typeof obj.emailAddress === "object") {
47510
+ const ea = obj.emailAddress;
47511
+ if (typeof ea.address === "string") return ea.address;
47512
+ }
47513
+ if (typeof obj.address === "string") return obj.address;
47514
+ if (typeof obj.email === "string") return obj.email;
47515
+ }
47516
+ return String(item);
47517
+ });
47518
+ }
47519
+ function formatRecipients(emails) {
47520
+ return normalizeEmails(emails).map((address) => ({ emailAddress: { address } }));
47521
+ }
47522
+ function formatAttendees(emails) {
47523
+ return normalizeEmails(emails).map((address) => ({
47524
+ emailAddress: { address },
47525
+ type: "required"
47526
+ }));
47527
+ }
47528
+ function isTeamsMeetingUrl(input) {
47529
+ try {
47530
+ const url2 = new URL(input.trim());
47531
+ return (url2.hostname === "teams.microsoft.com" || url2.hostname === "teams.live.com") && url2.pathname.includes("meetup-join");
47532
+ } catch {
47533
+ return false;
47534
+ }
47535
+ }
47536
+ async function resolveMeetingId(connector, input, prefix, effectiveUserId) {
47537
+ if (!input || input.trim().length === 0) {
47538
+ throw new Error("Meeting ID cannot be empty");
47539
+ }
47540
+ const trimmed = input.trim();
47541
+ if (!isTeamsMeetingUrl(trimmed)) {
47542
+ return { meetingId: trimmed };
47543
+ }
47544
+ const meetings = await microsoftFetch(
47545
+ connector,
47546
+ `${prefix}/onlineMeetings`,
47547
+ {
47548
+ userId: effectiveUserId,
47549
+ queryParams: { "$filter": `JoinWebUrl eq '${trimmed}'` }
47550
+ }
47551
+ );
47552
+ if (!meetings.value || meetings.value.length === 0) {
47553
+ throw new Error(
47554
+ `Could not find an online meeting matching the provided Teams URL. Make sure the URL is correct and you have access to this meeting.`
47555
+ );
47556
+ }
47557
+ return {
47558
+ meetingId: meetings.value[0].id,
47559
+ subject: meetings.value[0].subject
47560
+ };
47561
+ }
47562
+
47563
+ // src/tools/microsoft/createDraftEmail.ts
47564
+ function createDraftEmailTool(connector, userId) {
47565
+ return {
47566
+ definition: {
47567
+ type: "function",
47568
+ function: {
47569
+ name: "create_draft_email",
47570
+ 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.
47571
+
47572
+ PARAMETER FORMATS:
47573
+ - to/cc: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects.
47574
+ - subject: plain string. Example: "Project update" or "Re: Project update" for replies.
47575
+ - body: HTML string. Example: "<p>Hi Alice,</p><p>Here is the update.</p>". Use <p>, <br>, <b>, <ul> tags for formatting.
47576
+ - replyToMessageId: Graph message ID string (starts with "AAMk..."). Only set when replying to an existing email.
47577
+
47578
+ EXAMPLES:
47579
+ - New draft: { "to": ["alice@contoso.com"], "subject": "Project update", "body": "<p>Hi Alice,</p><p>Here is the update.</p>" }
47580
+ - Reply draft: { "to": ["alice@contoso.com"], "subject": "Re: Project update", "body": "<p>Thanks!</p>", "replyToMessageId": "AAMkADI1..." }
47581
+ - With CC: { "to": ["alice@contoso.com"], "subject": "Notes", "body": "<p>See attached.</p>", "cc": ["bob@contoso.com"] }`,
47582
+ parameters: {
47583
+ type: "object",
47584
+ properties: {
47585
+ to: {
47586
+ type: "array",
47587
+ items: { type: "string" },
47588
+ description: 'Recipient email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]'
47589
+ },
47590
+ subject: {
47591
+ type: "string",
47592
+ description: 'Email subject as plain string. Example: "Project update" or "Re: Original subject" for replies.'
47593
+ },
47594
+ body: {
47595
+ type: "string",
47596
+ description: 'Email body as an HTML string. Example: "<p>Hello!</p><p>See you tomorrow.</p>"'
47597
+ },
47598
+ cc: {
47599
+ type: "array",
47600
+ items: { type: "string" },
47601
+ description: 'CC email addresses as plain strings. Example: ["bob@contoso.com"]. Optional.'
47602
+ },
47603
+ replyToMessageId: {
47604
+ type: "string",
47605
+ description: 'Graph message ID of the email to reply to. Example: "AAMkADI1M2I3YzgtODg...". When set, creates a threaded reply draft.'
47606
+ },
47607
+ targetUser: {
47608
+ type: "string",
47609
+ description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
47610
+ }
47611
+ },
47612
+ required: ["to", "subject", "body"]
47613
+ }
47614
+ }
47615
+ },
47616
+ describeCall: (args) => {
47617
+ const action = args.replyToMessageId ? "Reply draft" : "Draft";
47618
+ return `${action} to ${args.to.join(", ")}: ${args.subject}`;
47619
+ },
47620
+ permission: {
47621
+ scope: "session",
47622
+ riskLevel: "medium",
47623
+ approvalMessage: `Create a draft email via ${connector.displayName}`
47624
+ },
47625
+ execute: async (args, context) => {
47626
+ const effectiveUserId = context?.userId ?? userId;
47627
+ try {
47628
+ const prefix = getUserPathPrefix(connector, args.targetUser);
47629
+ if (args.replyToMessageId) {
47630
+ const replyDraft = await microsoftFetch(
47631
+ connector,
47632
+ `${prefix}/messages/${args.replyToMessageId}/createReply`,
47633
+ { method: "POST", userId: effectiveUserId, body: {} }
47634
+ );
47635
+ const updated = await microsoftFetch(
47636
+ connector,
47637
+ `${prefix}/messages/${replyDraft.id}`,
47638
+ {
47639
+ method: "PATCH",
47640
+ userId: effectiveUserId,
47641
+ body: {
47642
+ subject: args.subject,
47643
+ body: { contentType: "HTML", content: args.body },
47644
+ toRecipients: formatRecipients(args.to),
47645
+ ...args.cc && { ccRecipients: formatRecipients(args.cc) }
47646
+ }
47647
+ }
47648
+ );
47649
+ return {
47650
+ success: true,
47651
+ draftId: updated.id,
47652
+ webLink: updated.webLink
47653
+ };
47654
+ }
47655
+ const draft = await microsoftFetch(
47656
+ connector,
47657
+ `${prefix}/messages`,
47658
+ {
47659
+ method: "POST",
47660
+ userId: effectiveUserId,
47661
+ body: {
47662
+ isDraft: true,
47663
+ subject: args.subject,
47664
+ body: { contentType: "HTML", content: args.body },
47665
+ toRecipients: formatRecipients(args.to),
47666
+ ...args.cc && { ccRecipients: formatRecipients(args.cc) }
47667
+ }
47668
+ }
47669
+ );
47670
+ return {
47671
+ success: true,
47672
+ draftId: draft.id,
47673
+ webLink: draft.webLink
47674
+ };
47675
+ } catch (error) {
47676
+ return {
47677
+ success: false,
47678
+ error: `Failed to create draft email: ${error instanceof Error ? error.message : String(error)}`
47679
+ };
47680
+ }
47681
+ }
47682
+ };
47683
+ }
47684
+
47685
+ // src/tools/microsoft/sendEmail.ts
47686
+ function createSendEmailTool(connector, userId) {
47687
+ return {
47688
+ definition: {
47689
+ type: "function",
47690
+ function: {
47691
+ name: "send_email",
47692
+ 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.
47693
+
47694
+ PARAMETER FORMATS:
47695
+ - to/cc: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects.
47696
+ - subject: plain string. Example: "Meeting tomorrow" or "Re: Meeting tomorrow" for replies.
47697
+ - body: HTML string. Example: "<p>Hi Alice,</p><p>Can we meet at 2pm?</p>". Use <p>, <br>, <b>, <ul> tags.
47698
+ - replyToMessageId: Graph message ID string (starts with "AAMk..."). Only set when replying to an existing email.
47699
+
47700
+ EXAMPLES:
47701
+ - Send email: { "to": ["alice@contoso.com"], "subject": "Meeting tomorrow", "body": "<p>Can we meet at 2pm?</p>" }
47702
+ - Reply: { "to": ["alice@contoso.com"], "subject": "Re: Meeting", "body": "<p>Confirmed!</p>", "replyToMessageId": "AAMkADI1..." }
47703
+ - With CC: { "to": ["alice@contoso.com"], "subject": "Update", "body": "<p>FYI</p>", "cc": ["bob@contoso.com"] }`,
47704
+ parameters: {
47705
+ type: "object",
47706
+ properties: {
47707
+ to: {
47708
+ type: "array",
47709
+ items: { type: "string" },
47710
+ description: 'Recipient email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]'
47711
+ },
47712
+ subject: {
47713
+ type: "string",
47714
+ description: 'Email subject as plain string. Example: "Meeting tomorrow" or "Re: Original subject" for replies.'
47715
+ },
47716
+ body: {
47717
+ type: "string",
47718
+ description: 'Email body as an HTML string. Example: "<p>Hi!</p><p>Can we meet at 2pm?</p>"'
47719
+ },
47720
+ cc: {
47721
+ type: "array",
47722
+ items: { type: "string" },
47723
+ description: 'CC email addresses as plain strings. Example: ["bob@contoso.com"]. Optional.'
47724
+ },
47725
+ replyToMessageId: {
47726
+ type: "string",
47727
+ description: 'Graph message ID of the email to reply to. Example: "AAMkADI1M2I3YzgtODg...". When set, sends a threaded reply.'
47728
+ },
47729
+ targetUser: {
47730
+ type: "string",
47731
+ description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
47732
+ }
47733
+ },
47734
+ required: ["to", "subject", "body"]
47735
+ }
47736
+ }
47737
+ },
47738
+ describeCall: (args) => {
47739
+ const action = args.replyToMessageId ? "Reply" : "Send";
47740
+ return `${action} to ${args.to.join(", ")}: ${args.subject}`;
47741
+ },
47742
+ permission: {
47743
+ scope: "session",
47744
+ riskLevel: "medium",
47745
+ approvalMessage: `Send an email via ${connector.displayName}`
47746
+ },
47747
+ execute: async (args, context) => {
47748
+ const effectiveUserId = context?.userId ?? userId;
47749
+ try {
47750
+ const prefix = getUserPathPrefix(connector, args.targetUser);
47751
+ if (args.replyToMessageId) {
47752
+ await microsoftFetch(
47753
+ connector,
47754
+ `${prefix}/messages/${args.replyToMessageId}/reply`,
47755
+ {
47756
+ method: "POST",
47757
+ userId: effectiveUserId,
47758
+ body: {
47759
+ message: {
47760
+ toRecipients: formatRecipients(args.to),
47761
+ ...args.cc && { ccRecipients: formatRecipients(args.cc) }
47762
+ },
47763
+ comment: args.body
47764
+ }
47765
+ }
47766
+ );
47767
+ } else {
47768
+ await microsoftFetch(
47769
+ connector,
47770
+ `${prefix}/sendMail`,
47771
+ {
47772
+ method: "POST",
47773
+ userId: effectiveUserId,
47774
+ body: {
47775
+ message: {
47776
+ subject: args.subject,
47777
+ body: { contentType: "HTML", content: args.body },
47778
+ toRecipients: formatRecipients(args.to),
47779
+ ...args.cc && { ccRecipients: formatRecipients(args.cc) }
47780
+ },
47781
+ saveToSentItems: true
47782
+ }
47783
+ }
47784
+ );
47785
+ }
47786
+ return { success: true };
47787
+ } catch (error) {
47788
+ return {
47789
+ success: false,
47790
+ error: `Failed to send email: ${error instanceof Error ? error.message : String(error)}`
47791
+ };
47792
+ }
47793
+ }
47794
+ };
47795
+ }
47796
+
47797
+ // src/tools/microsoft/createMeeting.ts
47798
+ function createMeetingTool(connector, userId) {
47799
+ return {
47800
+ definition: {
47801
+ type: "function",
47802
+ function: {
47803
+ name: "create_meeting",
47804
+ description: `Create a calendar event on the user's Outlook calendar via Microsoft Graph, optionally with a Teams online meeting link.
47805
+
47806
+ PARAMETER FORMATS:
47807
+ - subject: plain string. Example: "Sprint Review"
47808
+ - startDateTime/endDateTime: ISO 8601 string WITHOUT timezone suffix (timezone is a separate param). Example: "2025-01-15T09:00:00"
47809
+ - attendees: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects.
47810
+ - body: HTML string for the invitation body. Example: "<p>Agenda: discuss Q1 goals</p>". Optional.
47811
+ - timeZone: IANA timezone string. Example: "America/New_York", "Europe/Zurich". Default: "UTC".
47812
+ - isOnlineMeeting: boolean. Set true to auto-generate a Teams meeting link.
47813
+ - location: plain string. Example: "Conference Room A". Optional.
47814
+
47815
+ EXAMPLES:
47816
+ - Simple: { "subject": "Standup", "startDateTime": "2025-01-15T09:00:00", "endDateTime": "2025-01-15T09:30:00", "attendees": ["alice@contoso.com"], "timeZone": "America/New_York" }
47817
+ - 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 }`,
47818
+ parameters: {
47819
+ type: "object",
47820
+ properties: {
47821
+ subject: {
47822
+ type: "string",
47823
+ description: 'Meeting title as plain string. Example: "Sprint Review"'
47824
+ },
47825
+ startDateTime: {
47826
+ type: "string",
47827
+ description: 'Start date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T09:00:00"'
47828
+ },
47829
+ endDateTime: {
47830
+ type: "string",
47831
+ description: 'End date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T09:30:00"'
47832
+ },
47833
+ attendees: {
47834
+ type: "array",
47835
+ items: { type: "string" },
47836
+ description: 'Attendee email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]'
47837
+ },
47838
+ body: {
47839
+ type: "string",
47840
+ description: 'Meeting description as HTML string. Example: "<p>Agenda: discuss Q1 goals</p>". Optional.'
47841
+ },
47842
+ isOnlineMeeting: {
47843
+ type: "boolean",
47844
+ description: "Set to true to generate a Teams online meeting link. Default: false."
47845
+ },
47846
+ location: {
47847
+ type: "string",
47848
+ description: 'Physical location as plain string. Example: "Conference Room A". Optional.'
47849
+ },
47850
+ timeZone: {
47851
+ type: "string",
47852
+ description: 'IANA timezone string for start/end times. Example: "America/New_York", "Europe/Zurich". Default: "UTC".'
47853
+ },
47854
+ targetUser: {
47855
+ type: "string",
47856
+ description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
47857
+ }
47858
+ },
47859
+ required: ["subject", "startDateTime", "endDateTime", "attendees"]
47860
+ }
47861
+ }
47862
+ },
47863
+ describeCall: (args) => {
47864
+ return `Create meeting: ${args.subject} (${args.attendees.length} attendees)`;
47865
+ },
47866
+ permission: {
47867
+ scope: "session",
47868
+ riskLevel: "medium",
47869
+ approvalMessage: `Create a calendar event via ${connector.displayName}`
47870
+ },
47871
+ execute: async (args, context) => {
47872
+ const effectiveUserId = context?.userId ?? userId;
47873
+ try {
47874
+ const prefix = getUserPathPrefix(connector, args.targetUser);
47875
+ const tz = args.timeZone ?? "UTC";
47876
+ const eventBody = {
47877
+ subject: args.subject,
47878
+ start: { dateTime: args.startDateTime, timeZone: tz },
47879
+ end: { dateTime: args.endDateTime, timeZone: tz },
47880
+ attendees: formatAttendees(args.attendees)
47881
+ };
47882
+ if (args.body) {
47883
+ eventBody.body = { contentType: "HTML", content: args.body };
47884
+ }
47885
+ if (args.isOnlineMeeting) {
47886
+ eventBody.isOnlineMeeting = true;
47887
+ eventBody.onlineMeetingProvider = "teamsForBusiness";
47888
+ }
47889
+ if (args.location) {
47890
+ eventBody.location = { displayName: args.location };
47891
+ }
47892
+ const event = await microsoftFetch(
47893
+ connector,
47894
+ `${prefix}/events`,
47895
+ { method: "POST", userId: effectiveUserId, body: eventBody }
47896
+ );
47897
+ return {
47898
+ success: true,
47899
+ eventId: event.id,
47900
+ webLink: event.webLink,
47901
+ onlineMeetingUrl: event.onlineMeeting?.joinUrl
47902
+ };
47903
+ } catch (error) {
47904
+ return {
47905
+ success: false,
47906
+ error: `Failed to create meeting: ${error instanceof Error ? error.message : String(error)}`
47907
+ };
47908
+ }
47909
+ }
47910
+ };
47911
+ }
47912
+
47913
+ // src/tools/microsoft/editMeeting.ts
47914
+ function createEditMeetingTool(connector, userId) {
47915
+ return {
47916
+ definition: {
47917
+ type: "function",
47918
+ function: {
47919
+ name: "edit_meeting",
47920
+ 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.
47921
+
47922
+ 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.
47923
+
47924
+ PARAMETER FORMATS:
47925
+ - eventId: Graph event ID string (starts with "AAMk..."). Get this from a previous create_meeting result.
47926
+ - subject: plain string. Example: "Updated: Sprint Review"
47927
+ - startDateTime/endDateTime: ISO 8601 string without timezone suffix. Example: "2025-01-15T10:00:00"
47928
+ - attendees: plain string array of email addresses. Example: ["alice@contoso.com", "charlie@contoso.com"]. Do NOT use objects. REPLACES all attendees.
47929
+ - body: HTML string. Example: "<p>Updated agenda</p>"
47930
+ - timeZone: IANA timezone string. Example: "Europe/Zurich". Default: "UTC".
47931
+ - isOnlineMeeting: boolean. true = add Teams link, false = remove it.
47932
+ - location: plain string. Example: "Room 201"
47933
+
47934
+ EXAMPLES:
47935
+ - Reschedule: { "eventId": "AAMkADI1...", "startDateTime": "2025-01-15T10:00:00", "endDateTime": "2025-01-15T10:30:00", "timeZone": "America/New_York" }
47936
+ - Change attendees: { "eventId": "AAMkADI1...", "attendees": ["alice@contoso.com", "charlie@contoso.com"] }
47937
+ - Add Teams link: { "eventId": "AAMkADI1...", "isOnlineMeeting": true }`,
47938
+ parameters: {
47939
+ type: "object",
47940
+ properties: {
47941
+ eventId: {
47942
+ type: "string",
47943
+ description: 'Calendar event ID string from create_meeting result. Example: "AAMkADI1M2I3YzgtODg..."'
47944
+ },
47945
+ subject: {
47946
+ type: "string",
47947
+ description: 'New meeting title as plain string. Example: "Updated: Sprint Review"'
47948
+ },
47949
+ startDateTime: {
47950
+ type: "string",
47951
+ description: 'New start date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T10:00:00"'
47952
+ },
47953
+ endDateTime: {
47954
+ type: "string",
47955
+ description: 'New end date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T10:30:00"'
47956
+ },
47957
+ attendees: {
47958
+ type: "array",
47959
+ items: { type: "string" },
47960
+ description: 'FULL replacement attendee list as plain email strings. Example: ["alice@contoso.com", "charlie@contoso.com"]. Include ALL attendees.'
47961
+ },
47962
+ body: {
47963
+ type: "string",
47964
+ description: 'New meeting description as HTML string. Example: "<p>Updated agenda</p>"'
47965
+ },
47966
+ isOnlineMeeting: {
47967
+ type: "boolean",
47968
+ description: "true to add Teams meeting link, false to remove it."
47969
+ },
47970
+ location: {
47971
+ type: "string",
47972
+ description: 'New location as plain string. Example: "Conference Room A"'
47973
+ },
47974
+ timeZone: {
47975
+ type: "string",
47976
+ description: 'IANA timezone string for start/end times. Example: "Europe/Zurich". Default: "UTC".'
47977
+ },
47978
+ targetUser: {
47979
+ type: "string",
47980
+ description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
47981
+ }
47982
+ },
47983
+ required: ["eventId"]
47984
+ }
47985
+ }
47986
+ },
47987
+ describeCall: (args) => {
47988
+ const fields = ["subject", "startDateTime", "endDateTime", "attendees", "body", "location"];
47989
+ const changed = fields.filter((f) => args[f] !== void 0);
47990
+ return `Edit meeting ${args.eventId.slice(0, 12)}... (${changed.join(", ") || "no changes"})`;
47991
+ },
47992
+ permission: {
47993
+ scope: "session",
47994
+ riskLevel: "medium",
47995
+ approvalMessage: `Update a calendar event via ${connector.displayName}`
47996
+ },
47997
+ execute: async (args, context) => {
47998
+ const effectiveUserId = context?.userId ?? userId;
47999
+ try {
48000
+ const prefix = getUserPathPrefix(connector, args.targetUser);
48001
+ const tz = args.timeZone ?? "UTC";
48002
+ const patchBody = {};
48003
+ if (args.subject !== void 0) patchBody.subject = args.subject;
48004
+ if (args.body !== void 0) patchBody.body = { contentType: "HTML", content: args.body };
48005
+ if (args.startDateTime !== void 0) patchBody.start = { dateTime: args.startDateTime, timeZone: tz };
48006
+ if (args.endDateTime !== void 0) patchBody.end = { dateTime: args.endDateTime, timeZone: tz };
48007
+ if (args.attendees !== void 0) {
48008
+ patchBody.attendees = formatAttendees(args.attendees);
48009
+ }
48010
+ if (args.isOnlineMeeting !== void 0) {
48011
+ patchBody.isOnlineMeeting = args.isOnlineMeeting;
48012
+ if (args.isOnlineMeeting) {
48013
+ patchBody.onlineMeetingProvider = "teamsForBusiness";
48014
+ }
48015
+ }
48016
+ if (args.location !== void 0) {
48017
+ patchBody.location = { displayName: args.location };
48018
+ }
48019
+ const event = await microsoftFetch(
48020
+ connector,
48021
+ `${prefix}/events/${args.eventId}`,
48022
+ { method: "PATCH", userId: effectiveUserId, body: patchBody }
48023
+ );
48024
+ return {
48025
+ success: true,
48026
+ eventId: event.id,
48027
+ webLink: event.webLink
48028
+ };
48029
+ } catch (error) {
48030
+ return {
48031
+ success: false,
48032
+ error: `Failed to edit meeting: ${error instanceof Error ? error.message : String(error)}`
48033
+ };
48034
+ }
48035
+ }
48036
+ };
48037
+ }
48038
+
48039
+ // src/tools/microsoft/getMeetingTranscript.ts
48040
+ function parseVttToText(vtt) {
48041
+ const lines = vtt.split("\n");
48042
+ const textLines = [];
48043
+ for (const line of lines) {
48044
+ const trimmed = line.trim();
48045
+ if (trimmed === "" || trimmed === "WEBVTT" || trimmed.startsWith("NOTE") || /^\d+$/.test(trimmed) || /^\d{2}:\d{2}/.test(trimmed)) {
48046
+ continue;
48047
+ }
48048
+ textLines.push(trimmed);
48049
+ }
48050
+ return textLines.join("\n");
48051
+ }
48052
+ function createGetMeetingTranscriptTool(connector, userId) {
48053
+ return {
48054
+ definition: {
48055
+ type: "function",
48056
+ function: {
48057
+ name: "get_meeting_transcript",
48058
+ description: `Retrieve the transcript from a Teams online meeting via Microsoft Graph. Returns plain text with speaker labels (VTT timestamps are stripped).
48059
+
48060
+ NOTE: Requires the OnlineMeetingTranscript.Read.All permission. Transcription must have been enabled during the meeting.
48061
+
48062
+ USAGE:
48063
+ - Provide the Teams online meeting ID (NOT the calendar event ID \u2014 this is different) or a Teams meeting join URL
48064
+ - The meetingId can be found in the Teams meeting details or extracted from the join URL
48065
+
48066
+ EXAMPLES:
48067
+ - By meeting ID: { "meetingId": "MSo1N2Y5ZGFjYy03MWJmLTQ3NDMtYjQxMy01M2EdFGkdRWHJlQ" }
48068
+ - By Teams join URL: { "meetingId": "https://teams.microsoft.com/l/meetup-join/19%3ameeting_MjA5YjFi..." }`,
48069
+ parameters: {
48070
+ type: "object",
48071
+ properties: {
48072
+ meetingId: {
48073
+ type: "string",
48074
+ description: 'Teams online meeting ID (e.g. "MSo1N2Y5...") or Teams meeting join URL. This is NOT the calendar event ID.'
48075
+ },
48076
+ targetUser: {
48077
+ type: "string",
48078
+ description: "User ID or email (UPN) to act on behalf of. Only needed for app-only (client_credentials) auth. Ignored in delegated auth."
48079
+ }
48080
+ },
48081
+ required: ["meetingId"]
48082
+ }
48083
+ }
48084
+ },
48085
+ describeCall: (args) => {
48086
+ return `Get transcript for meeting ${args.meetingId.slice(0, 20)}...`;
48087
+ },
48088
+ permission: {
48089
+ scope: "session",
48090
+ riskLevel: "low",
48091
+ approvalMessage: `Get a meeting transcript via ${connector.displayName}`
48092
+ },
48093
+ execute: async (args, context) => {
48094
+ const effectiveUserId = context?.userId ?? userId;
48095
+ try {
48096
+ const prefix = getUserPathPrefix(connector, args.targetUser);
48097
+ const resolved = await resolveMeetingId(connector, args.meetingId, prefix, effectiveUserId);
48098
+ const meetingId = resolved.meetingId;
48099
+ const transcriptList = await microsoftFetch(
48100
+ connector,
48101
+ `${prefix}/onlineMeetings/${meetingId}/transcripts`,
48102
+ { userId: effectiveUserId }
48103
+ );
48104
+ if (!transcriptList.value || transcriptList.value.length === 0) {
48105
+ return {
48106
+ success: false,
48107
+ error: "No transcripts found for this meeting. The meeting may not have had transcription enabled."
48108
+ };
48109
+ }
48110
+ const transcriptId = transcriptList.value[0].id;
48111
+ const contentUrl = `${prefix}/onlineMeetings/${meetingId}/transcripts/${transcriptId}/content`;
48112
+ const response = await connector.fetch(
48113
+ contentUrl + "?$format=text/vtt",
48114
+ { method: "GET", headers: { "Accept": "text/vtt" } },
48115
+ effectiveUserId
48116
+ );
48117
+ if (!response.ok) {
48118
+ const errorText = await response.text();
48119
+ return {
48120
+ success: false,
48121
+ error: `Failed to fetch transcript content: ${response.status} ${errorText}`
48122
+ };
48123
+ }
48124
+ const vttContent = await response.text();
48125
+ const transcript = parseVttToText(vttContent);
48126
+ return {
48127
+ success: true,
48128
+ transcript,
48129
+ meetingSubject: resolved.subject
48130
+ };
48131
+ } catch (error) {
48132
+ return {
48133
+ success: false,
48134
+ error: `Failed to get meeting transcript: ${error instanceof Error ? error.message : String(error)}`
48135
+ };
48136
+ }
48137
+ }
48138
+ };
48139
+ }
48140
+
48141
+ // src/tools/microsoft/findMeetingSlots.ts
48142
+ function createFindMeetingSlotsTool(connector, userId) {
48143
+ return {
48144
+ definition: {
48145
+ type: "function",
48146
+ function: {
48147
+ name: "find_meeting_slots",
48148
+ 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.
48149
+
48150
+ PARAMETER FORMATS:
48151
+ - attendees: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects \u2014 just plain email strings.
48152
+ - startDateTime/endDateTime: ISO 8601 string without timezone suffix. Example: "2025-01-15T08:00:00". Can span multiple days.
48153
+ - duration: number of minutes as integer. Example: 30 or 60.
48154
+ - timeZone: IANA timezone string. Example: "America/New_York", "Europe/Zurich". Default: "UTC".
48155
+ - maxResults: integer. Default: 5.
48156
+
48157
+ EXAMPLES:
48158
+ - 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" }
48159
+ - 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 }`,
48160
+ parameters: {
48161
+ type: "object",
48162
+ properties: {
48163
+ attendees: {
48164
+ type: "array",
48165
+ items: { type: "string" },
48166
+ description: 'Attendee email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT pass objects.'
48167
+ },
48168
+ startDateTime: {
48169
+ type: "string",
48170
+ description: 'Search window start as ISO 8601 string without timezone suffix. Example: "2025-01-15T08:00:00"'
48171
+ },
48172
+ endDateTime: {
48173
+ type: "string",
48174
+ description: 'Search window end as ISO 8601 string without timezone suffix. Example: "2025-01-15T18:00:00". Can span multiple days.'
48175
+ },
48176
+ duration: {
48177
+ type: "number",
48178
+ description: "Meeting duration in minutes as integer. Example: 30 or 60."
48179
+ },
48180
+ timeZone: {
48181
+ type: "string",
48182
+ description: 'IANA timezone string for start/end times. Example: "America/New_York", "Europe/Zurich". Default: "UTC".'
48183
+ },
48184
+ maxResults: {
48185
+ type: "number",
48186
+ description: "Maximum number of time slot suggestions as integer. Default: 5."
48187
+ },
48188
+ targetUser: {
48189
+ type: "string",
48190
+ description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
48191
+ }
48192
+ },
48193
+ required: ["attendees", "startDateTime", "endDateTime", "duration"]
48194
+ }
48195
+ }
48196
+ },
48197
+ describeCall: (args) => {
48198
+ return `Find ${args.duration}min slots for ${args.attendees.length} attendees`;
48199
+ },
48200
+ permission: {
48201
+ scope: "session",
48202
+ riskLevel: "low",
48203
+ approvalMessage: `Find meeting time slots via ${connector.displayName}`
48204
+ },
48205
+ execute: async (args, context) => {
48206
+ const effectiveUserId = context?.userId ?? userId;
48207
+ try {
48208
+ const prefix = getUserPathPrefix(connector, args.targetUser);
48209
+ const tz = args.timeZone ?? "UTC";
48210
+ const result = await microsoftFetch(
48211
+ connector,
48212
+ `${prefix}/findMeetingTimes`,
48213
+ {
48214
+ method: "POST",
48215
+ userId: effectiveUserId,
48216
+ body: {
48217
+ attendees: formatAttendees(args.attendees),
48218
+ timeConstraint: {
48219
+ timeslots: [
48220
+ {
48221
+ start: { dateTime: args.startDateTime, timeZone: tz },
48222
+ end: { dateTime: args.endDateTime, timeZone: tz }
48223
+ }
48224
+ ]
48225
+ },
48226
+ meetingDuration: `PT${args.duration}M`,
48227
+ maxCandidates: args.maxResults ?? 5
48228
+ }
48229
+ }
48230
+ );
48231
+ const slots = (result.meetingTimeSuggestions ?? []).map((s) => ({
48232
+ start: s.meetingTimeSlot.start.dateTime,
48233
+ end: s.meetingTimeSlot.end.dateTime,
48234
+ confidence: String(s.confidence),
48235
+ attendeeAvailability: (s.attendeeAvailability ?? []).map((a) => ({
48236
+ attendee: a.attendee.emailAddress.address,
48237
+ availability: a.availability
48238
+ }))
48239
+ }));
48240
+ return {
48241
+ success: true,
48242
+ slots,
48243
+ emptySuggestionsReason: result.emptySuggestionsReason
48244
+ };
48245
+ } catch (error) {
48246
+ return {
48247
+ success: false,
48248
+ error: `Failed to find meeting slots: ${error instanceof Error ? error.message : String(error)}`
48249
+ };
48250
+ }
48251
+ }
48252
+ };
48253
+ }
48254
+
48255
+ // src/tools/microsoft/register.ts
48256
+ function registerMicrosoftTools() {
48257
+ ConnectorTools.registerService("microsoft", (connector, userId) => {
48258
+ return [
48259
+ createDraftEmailTool(connector, userId),
48260
+ createSendEmailTool(connector, userId),
48261
+ createMeetingTool(connector, userId),
48262
+ createEditMeetingTool(connector, userId),
48263
+ createGetMeetingTranscriptTool(connector, userId),
48264
+ createFindMeetingSlotsTool(connector, userId)
48265
+ ];
48266
+ });
48267
+ }
48268
+
48269
+ // src/tools/microsoft/index.ts
48270
+ registerMicrosoftTools();
48271
+
46577
48272
  // src/tools/desktop/types.ts
46578
48273
  var DEFAULT_DESKTOP_CONFIG = {
46579
48274
  driver: null,
@@ -48605,6 +50300,7 @@ exports.FileCustomToolStorage = FileCustomToolStorage;
48605
50300
  exports.FileMediaOutputHandler = FileMediaStorage;
48606
50301
  exports.FileMediaStorage = FileMediaStorage;
48607
50302
  exports.FilePersistentInstructionsStorage = FilePersistentInstructionsStorage;
50303
+ exports.FileRoutineDefinitionStorage = FileRoutineDefinitionStorage;
48608
50304
  exports.FileStorage = FileStorage;
48609
50305
  exports.FileUserInfoStorage = FileUserInfoStorage;
48610
50306
  exports.FormatDetector = FormatDetector;
@@ -48732,13 +50428,18 @@ exports.createDesktopMouseScrollTool = createDesktopMouseScrollTool;
48732
50428
  exports.createDesktopScreenshotTool = createDesktopScreenshotTool;
48733
50429
  exports.createDesktopWindowFocusTool = createDesktopWindowFocusTool;
48734
50430
  exports.createDesktopWindowListTool = createDesktopWindowListTool;
50431
+ exports.createDraftEmailTool = createDraftEmailTool;
48735
50432
  exports.createEditFileTool = createEditFileTool;
50433
+ exports.createEditMeetingTool = createEditMeetingTool;
48736
50434
  exports.createEstimator = createEstimator;
48737
50435
  exports.createExecuteJavaScriptTool = createExecuteJavaScriptTool;
48738
50436
  exports.createFileAgentDefinitionStorage = createFileAgentDefinitionStorage;
48739
50437
  exports.createFileContextStorage = createFileContextStorage;
48740
50438
  exports.createFileCustomToolStorage = createFileCustomToolStorage;
48741
50439
  exports.createFileMediaStorage = createFileMediaStorage;
50440
+ exports.createFileRoutineDefinitionStorage = createFileRoutineDefinitionStorage;
50441
+ exports.createFindMeetingSlotsTool = createFindMeetingSlotsTool;
50442
+ exports.createGetMeetingTranscriptTool = createGetMeetingTranscriptTool;
48742
50443
  exports.createGetPRTool = createGetPRTool;
48743
50444
  exports.createGitHubReadFileTool = createGitHubReadFileTool;
48744
50445
  exports.createGlobTool = createGlobTool;
@@ -48746,6 +50447,7 @@ exports.createGrepTool = createGrepTool;
48746
50447
  exports.createImageGenerationTool = createImageGenerationTool;
48747
50448
  exports.createImageProvider = createImageProvider;
48748
50449
  exports.createListDirectoryTool = createListDirectoryTool;
50450
+ exports.createMeetingTool = createMeetingTool;
48749
50451
  exports.createMessageWithImages = createMessageWithImages;
48750
50452
  exports.createMetricsCollector = createMetricsCollector;
48751
50453
  exports.createPRCommentsTool = createPRCommentsTool;
@@ -48753,8 +50455,11 @@ exports.createPRFilesTool = createPRFilesTool;
48753
50455
  exports.createPlan = createPlan;
48754
50456
  exports.createProvider = createProvider;
48755
50457
  exports.createReadFileTool = createReadFileTool;
50458
+ exports.createRoutineDefinition = createRoutineDefinition;
50459
+ exports.createRoutineExecution = createRoutineExecution;
48756
50460
  exports.createSearchCodeTool = createSearchCodeTool;
48757
50461
  exports.createSearchFilesTool = createSearchFilesTool;
50462
+ exports.createSendEmailTool = createSendEmailTool;
48758
50463
  exports.createSpeechToTextTool = createSpeechToTextTool;
48759
50464
  exports.createTask = createTask;
48760
50465
  exports.createTextMessage = createTextMessage;
@@ -48787,12 +50492,15 @@ exports.developerTools = developerTools;
48787
50492
  exports.documentToContent = documentToContent;
48788
50493
  exports.editFile = editFile;
48789
50494
  exports.evaluateCondition = evaluateCondition;
50495
+ exports.executeRoutine = executeRoutine;
48790
50496
  exports.extractJSON = extractJSON;
48791
50497
  exports.extractJSONField = extractJSONField;
48792
50498
  exports.extractNumber = extractNumber;
48793
50499
  exports.findConnectorByServiceTypes = findConnectorByServiceTypes;
48794
50500
  exports.forPlan = forPlan;
48795
50501
  exports.forTasks = forTasks;
50502
+ exports.formatAttendees = formatAttendees;
50503
+ exports.formatRecipients = formatRecipients;
48796
50504
  exports.generateEncryptionKey = generateEncryptionKey;
48797
50505
  exports.generateSimplePlan = generateSimplePlan;
48798
50506
  exports.generateWebAPITool = generateWebAPITool;
@@ -48819,6 +50527,7 @@ exports.getModelInfo = getModelInfo;
48819
50527
  exports.getModelsByVendor = getModelsByVendor;
48820
50528
  exports.getNextExecutableTasks = getNextExecutableTasks;
48821
50529
  exports.getRegisteredScrapeProviders = getRegisteredScrapeProviders;
50530
+ exports.getRoutineProgress = getRoutineProgress;
48822
50531
  exports.getSTTModelInfo = getSTTModelInfo;
48823
50532
  exports.getSTTModelsByVendor = getSTTModelsByVendor;
48824
50533
  exports.getSTTModelsWithFeature = getSTTModelsWithFeature;
@@ -48835,6 +50544,7 @@ exports.getToolCategories = getToolCategories;
48835
50544
  exports.getToolRegistry = getToolRegistry;
48836
50545
  exports.getToolsByCategory = getToolsByCategory;
48837
50546
  exports.getToolsRequiringConnector = getToolsRequiringConnector;
50547
+ exports.getUserPathPrefix = getUserPathPrefix;
48838
50548
  exports.getVendorAuthTemplate = getVendorAuthTemplate;
48839
50549
  exports.getVendorColor = getVendorColor;
48840
50550
  exports.getVendorDefaultBaseURL = getVendorDefaultBaseURL;
@@ -48863,6 +50573,7 @@ exports.isSimpleScope = isSimpleScope;
48863
50573
  exports.isStreamEvent = isStreamEvent;
48864
50574
  exports.isTaskAwareScope = isTaskAwareScope;
48865
50575
  exports.isTaskBlocked = isTaskBlocked;
50576
+ exports.isTeamsMeetingUrl = isTeamsMeetingUrl;
48866
50577
  exports.isTerminalMemoryStatus = isTerminalMemoryStatus;
48867
50578
  exports.isTerminalStatus = isTerminalStatus;
48868
50579
  exports.isToolCallArgumentsDelta = isToolCallArgumentsDelta;
@@ -48878,6 +50589,8 @@ exports.listVendorsByAuthType = listVendorsByAuthType;
48878
50589
  exports.listVendorsByCategory = listVendorsByCategory;
48879
50590
  exports.listVendorsWithLogos = listVendorsWithLogos;
48880
50591
  exports.mergeTextPieces = mergeTextPieces;
50592
+ exports.microsoftFetch = microsoftFetch;
50593
+ exports.normalizeEmails = normalizeEmails;
48881
50594
  exports.parseKeyCombo = parseKeyCombo;
48882
50595
  exports.parseRepository = parseRepository;
48883
50596
  exports.readClipboardImage = readClipboardImage;
@@ -48888,6 +50601,7 @@ exports.resetDefaultDriver = resetDefaultDriver;
48888
50601
  exports.resolveConnector = resolveConnector;
48889
50602
  exports.resolveDependencies = resolveDependencies;
48890
50603
  exports.resolveMaxContextTokens = resolveMaxContextTokens;
50604
+ exports.resolveMeetingId = resolveMeetingId;
48891
50605
  exports.resolveModelCapabilities = resolveModelCapabilities;
48892
50606
  exports.resolveRepository = resolveRepository;
48893
50607
  exports.retryWithBackoff = retryWithBackoff;