@everworker/oneringai 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as crypto2 from 'crypto';
2
2
  import { randomUUID } from 'crypto';
3
3
  import { importPKCS8, SignJWT } from 'jose';
4
- import * as fs18 from 'fs';
4
+ import * as fs19 from 'fs';
5
5
  import { promises, existsSync } from 'fs';
6
6
  import { EventEmitter } from 'eventemitter3';
7
7
  import * as path2 from 'path';
@@ -19,7 +19,7 @@ import * as z from 'zod/v4';
19
19
  import spawn$1 from 'cross-spawn';
20
20
  import process2 from 'process';
21
21
  import { PassThrough } from 'stream';
22
- import * as fs17 from 'fs/promises';
22
+ import * as fs18 from 'fs/promises';
23
23
  import { stat, readFile, mkdir, writeFile, readdir } from 'fs/promises';
24
24
  import * as simpleIcons from 'simple-icons';
25
25
  import { exec, spawn } from 'child_process';
@@ -641,7 +641,7 @@ var init_JWTBearer = __esm({
641
641
  this.privateKey = config.privateKey;
642
642
  } else if (config.privateKeyPath) {
643
643
  try {
644
- this.privateKey = fs18.readFileSync(config.privateKeyPath, "utf8");
644
+ this.privateKey = fs19.readFileSync(config.privateKeyPath, "utf8");
645
645
  } catch (error) {
646
646
  throw new Error(`Failed to read private key from ${config.privateKeyPath}: ${error.message}`);
647
647
  }
@@ -1400,10 +1400,10 @@ var init_Logger = __esm({
1400
1400
  initFileStream(filePath) {
1401
1401
  try {
1402
1402
  const dir = path2.dirname(filePath);
1403
- if (!fs18.existsSync(dir)) {
1404
- fs18.mkdirSync(dir, { recursive: true });
1403
+ if (!fs19.existsSync(dir)) {
1404
+ fs19.mkdirSync(dir, { recursive: true });
1405
1405
  }
1406
- this.fileStream = fs18.createWriteStream(filePath, {
1406
+ this.fileStream = fs19.createWriteStream(filePath, {
1407
1407
  flags: "a",
1408
1408
  // append mode
1409
1409
  encoding: "utf8"
@@ -9133,12 +9133,12 @@ var require_dist = __commonJS({
9133
9133
  throw new Error(`Unknown format "${name}"`);
9134
9134
  return f;
9135
9135
  };
9136
- function addFormats(ajv, list, fs19, exportName) {
9136
+ function addFormats(ajv, list, fs20, exportName) {
9137
9137
  var _a;
9138
9138
  var _b;
9139
9139
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
9140
9140
  for (const f of list)
9141
- ajv.addFormat(f, fs19[f]);
9141
+ ajv.addFormat(f, fs20[f]);
9142
9142
  }
9143
9143
  module.exports = exports$1 = formatsPlugin;
9144
9144
  Object.defineProperty(exports$1, "__esModule", { value: true });
@@ -17338,6 +17338,8 @@ ${content}`);
17338
17338
  breakdown.pluginContents[plugin.name] = plugin.getTokenSize();
17339
17339
  }
17340
17340
  }
17341
+ const now = /* @__PURE__ */ new Date();
17342
+ parts.push(`CURRENT DATE AND TIME: ${now.toLocaleString("en-US", { dateStyle: "full", timeStyle: "long", timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone })}`);
17341
17343
  const systemText = parts.join("\n\n---\n\n");
17342
17344
  const systemTokens = this._estimator.estimateTokens(systemText);
17343
17345
  const systemMessage = {
@@ -20796,6 +20798,7 @@ var BaseAgent = class extends EventEmitter {
20796
20798
  _agentContext;
20797
20799
  // SINGLE SOURCE OF TRUTH for tools and sessions
20798
20800
  _permissionManager;
20801
+ _ownsContext = true;
20799
20802
  _isDestroyed = false;
20800
20803
  _cleanupCallbacks = [];
20801
20804
  _logger;
@@ -20848,8 +20851,10 @@ var BaseAgent = class extends EventEmitter {
20848
20851
  */
20849
20852
  initializeAgentContext(config) {
20850
20853
  if (config.context instanceof AgentContextNextGen) {
20854
+ this._ownsContext = false;
20851
20855
  return config.context;
20852
20856
  }
20857
+ this._ownsContext = true;
20853
20858
  const contextConfig = {
20854
20859
  model: config.model,
20855
20860
  agentId: config.name,
@@ -21361,7 +21366,9 @@ var BaseAgent = class extends EventEmitter {
21361
21366
  clearInterval(this._autoSaveInterval);
21362
21367
  this._autoSaveInterval = null;
21363
21368
  }
21364
- this._agentContext.destroy();
21369
+ if (this._ownsContext) {
21370
+ this._agentContext.destroy();
21371
+ }
21365
21372
  this._permissionManager.removeAllListeners();
21366
21373
  this.removeAllListeners();
21367
21374
  }
@@ -21702,6 +21709,18 @@ var HookManager = class {
21702
21709
  }
21703
21710
  existing.push(hook);
21704
21711
  }
21712
+ /**
21713
+ * Unregister a specific hook function by reference.
21714
+ * Returns true if the hook was found and removed.
21715
+ */
21716
+ unregister(name, hook) {
21717
+ const hooks = this.hooks.get(name);
21718
+ if (!hooks) return false;
21719
+ const index = hooks.indexOf(hook);
21720
+ if (index === -1) return false;
21721
+ hooks.splice(index, 1);
21722
+ return true;
21723
+ }
21705
21724
  /**
21706
21725
  * Execute hooks for a given name
21707
21726
  */
@@ -21724,7 +21743,7 @@ var HookManager = class {
21724
21743
  const hook = hooks[i];
21725
21744
  const hookKey = this.getHookKey(hook, i);
21726
21745
  const hookResult = await this.executeHookSafely(hook, context, hookKey);
21727
- if (hookResult === null) {
21746
+ if (hookResult == null) {
21728
21747
  continue;
21729
21748
  }
21730
21749
  result = { ...result, ...hookResult };
@@ -21744,7 +21763,7 @@ var HookManager = class {
21744
21763
  return this.executeHookSafely(hook, context, hookKey);
21745
21764
  })
21746
21765
  );
21747
- const validResults = results.filter((r) => r !== null);
21766
+ const validResults = results.filter((r) => r != null);
21748
21767
  return validResults.reduce(
21749
21768
  (acc, hookResult) => ({ ...acc, ...hookResult }),
21750
21769
  defaultResult
@@ -22420,7 +22439,6 @@ var Agent = class _Agent extends BaseAgent {
22420
22439
  _cleanupExecution(streamState) {
22421
22440
  streamState?.clear();
22422
22441
  this.executionContext?.cleanup();
22423
- this.hookManager.clear();
22424
22442
  }
22425
22443
  /**
22426
22444
  * Emit iteration complete event (helper for run loop)
@@ -23305,6 +23323,27 @@ var Agent = class _Agent extends BaseAgent {
23305
23323
  isCancelled() {
23306
23324
  return this._cancelled;
23307
23325
  }
23326
+ /**
23327
+ * Clear conversation history, resetting the context for a fresh interaction.
23328
+ * Plugins (working memory, in-context memory, etc.) are NOT affected.
23329
+ */
23330
+ clearConversation(reason) {
23331
+ this._agentContext.clearConversation(reason);
23332
+ this._logger.info({ reason }, "Conversation cleared");
23333
+ }
23334
+ // ===== Hook Management =====
23335
+ /**
23336
+ * Register a hook on the agent. Can be called after creation.
23337
+ */
23338
+ registerHook(name, hook) {
23339
+ this.hookManager.register(name, hook);
23340
+ }
23341
+ /**
23342
+ * Unregister a previously registered hook by reference.
23343
+ */
23344
+ unregisterHook(name, hook) {
23345
+ return this.hookManager.unregister(name, hook);
23346
+ }
23308
23347
  // ===== Cleanup =====
23309
23348
  destroy() {
23310
23349
  if (this._isDestroyed) {
@@ -23334,6 +23373,874 @@ var Agent = class _Agent extends BaseAgent {
23334
23373
  }
23335
23374
  };
23336
23375
 
23376
+ // src/domain/entities/Task.ts
23377
+ var TERMINAL_TASK_STATUSES = ["completed", "failed", "skipped", "cancelled"];
23378
+ function isTerminalStatus(status) {
23379
+ return TERMINAL_TASK_STATUSES.includes(status);
23380
+ }
23381
+ function createTask(input) {
23382
+ const now = Date.now();
23383
+ const id = input.id ?? `task-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
23384
+ return {
23385
+ id,
23386
+ name: input.name,
23387
+ description: input.description,
23388
+ status: "pending",
23389
+ dependsOn: input.dependsOn ?? [],
23390
+ externalDependency: input.externalDependency,
23391
+ condition: input.condition,
23392
+ execution: input.execution,
23393
+ suggestedTools: input.suggestedTools,
23394
+ validation: input.validation,
23395
+ expectedOutput: input.expectedOutput,
23396
+ attempts: 0,
23397
+ maxAttempts: input.maxAttempts ?? 3,
23398
+ createdAt: now,
23399
+ lastUpdatedAt: now,
23400
+ metadata: input.metadata
23401
+ };
23402
+ }
23403
+ function createPlan(input) {
23404
+ const now = Date.now();
23405
+ const id = `plan-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
23406
+ const tasks = input.tasks.map((taskInput) => createTask(taskInput));
23407
+ const nameToId = /* @__PURE__ */ new Map();
23408
+ for (const task of tasks) {
23409
+ nameToId.set(task.name, task.id);
23410
+ }
23411
+ for (let i = 0; i < tasks.length; i++) {
23412
+ const taskInput = input.tasks[i];
23413
+ const task = tasks[i];
23414
+ if (taskInput.dependsOn && taskInput.dependsOn.length > 0) {
23415
+ task.dependsOn = taskInput.dependsOn.map((dep) => {
23416
+ if (dep.startsWith("task-")) {
23417
+ return dep;
23418
+ }
23419
+ const resolvedId = nameToId.get(dep);
23420
+ if (!resolvedId) {
23421
+ throw new Error(`Task dependency "${dep}" not found in plan`);
23422
+ }
23423
+ return resolvedId;
23424
+ });
23425
+ }
23426
+ }
23427
+ if (!input.skipCycleCheck) {
23428
+ const cycle = detectDependencyCycle(tasks);
23429
+ if (cycle) {
23430
+ const cycleNames = cycle.map((taskId) => {
23431
+ const task = tasks.find((t) => t.id === taskId);
23432
+ return task ? task.name : taskId;
23433
+ });
23434
+ throw new DependencyCycleError(cycleNames, id);
23435
+ }
23436
+ }
23437
+ return {
23438
+ id,
23439
+ goal: input.goal,
23440
+ context: input.context,
23441
+ tasks,
23442
+ concurrency: input.concurrency,
23443
+ allowDynamicTasks: input.allowDynamicTasks ?? true,
23444
+ status: "pending",
23445
+ createdAt: now,
23446
+ lastUpdatedAt: now,
23447
+ metadata: input.metadata
23448
+ };
23449
+ }
23450
+ function canTaskExecute(task, allTasks) {
23451
+ if (task.status !== "pending") {
23452
+ return false;
23453
+ }
23454
+ if (task.dependsOn.length > 0) {
23455
+ for (const depId of task.dependsOn) {
23456
+ const depTask = allTasks.find((t) => t.id === depId);
23457
+ if (!depTask || depTask.status !== "completed") {
23458
+ return false;
23459
+ }
23460
+ }
23461
+ }
23462
+ return true;
23463
+ }
23464
+ function getNextExecutableTasks(plan) {
23465
+ const executable = plan.tasks.filter((task) => canTaskExecute(task, plan.tasks));
23466
+ if (executable.length === 0) {
23467
+ return [];
23468
+ }
23469
+ if (!plan.concurrency) {
23470
+ return [executable[0]];
23471
+ }
23472
+ const runningCount = plan.tasks.filter((t) => t.status === "in_progress").length;
23473
+ const availableSlots = plan.concurrency.maxParallelTasks - runningCount;
23474
+ if (availableSlots <= 0) {
23475
+ return [];
23476
+ }
23477
+ const parallelTasks = executable.filter((task) => task.execution?.parallel === true);
23478
+ if (parallelTasks.length === 0) {
23479
+ return [executable[0]];
23480
+ }
23481
+ let sortedTasks = [...parallelTasks];
23482
+ if (plan.concurrency.strategy === "priority") {
23483
+ sortedTasks.sort((a, b) => (b.execution?.priority ?? 0) - (a.execution?.priority ?? 0));
23484
+ }
23485
+ return sortedTasks.slice(0, availableSlots);
23486
+ }
23487
+ async function evaluateCondition(condition, memory) {
23488
+ const value = await memory.get(condition.memoryKey);
23489
+ switch (condition.operator) {
23490
+ case "exists":
23491
+ return value !== void 0;
23492
+ case "not_exists":
23493
+ return value === void 0;
23494
+ case "equals":
23495
+ return value === condition.value;
23496
+ case "contains":
23497
+ if (Array.isArray(value)) {
23498
+ return value.includes(condition.value);
23499
+ }
23500
+ if (typeof value === "string" && typeof condition.value === "string") {
23501
+ return value.includes(condition.value);
23502
+ }
23503
+ return false;
23504
+ case "truthy":
23505
+ return !!value;
23506
+ case "greater_than":
23507
+ if (typeof value === "number" && typeof condition.value === "number") {
23508
+ return value > condition.value;
23509
+ }
23510
+ return false;
23511
+ case "less_than":
23512
+ if (typeof value === "number" && typeof condition.value === "number") {
23513
+ return value < condition.value;
23514
+ }
23515
+ return false;
23516
+ default:
23517
+ return false;
23518
+ }
23519
+ }
23520
+ function updateTaskStatus(task, status) {
23521
+ const now = Date.now();
23522
+ const updated = {
23523
+ ...task,
23524
+ status,
23525
+ lastUpdatedAt: now
23526
+ };
23527
+ if (status === "in_progress") {
23528
+ if (!updated.startedAt) {
23529
+ updated.startedAt = now;
23530
+ }
23531
+ updated.attempts += 1;
23532
+ }
23533
+ if ((status === "completed" || status === "failed") && !updated.completedAt) {
23534
+ updated.completedAt = now;
23535
+ }
23536
+ return updated;
23537
+ }
23538
+ function isTaskBlocked(task, allTasks) {
23539
+ if (task.dependsOn.length === 0) {
23540
+ return false;
23541
+ }
23542
+ for (const depId of task.dependsOn) {
23543
+ const depTask = allTasks.find((t) => t.id === depId);
23544
+ if (!depTask) {
23545
+ return true;
23546
+ }
23547
+ if (depTask.status !== "completed") {
23548
+ return true;
23549
+ }
23550
+ }
23551
+ return false;
23552
+ }
23553
+ function getTaskDependencies(task, allTasks) {
23554
+ if (task.dependsOn.length === 0) {
23555
+ return [];
23556
+ }
23557
+ return task.dependsOn.map((depId) => allTasks.find((t) => t.id === depId)).filter((t) => t !== void 0);
23558
+ }
23559
+ function resolveDependencies(taskInputs, tasks) {
23560
+ const nameToId = /* @__PURE__ */ new Map();
23561
+ for (const task of tasks) {
23562
+ nameToId.set(task.name, task.id);
23563
+ }
23564
+ for (const input of taskInputs) {
23565
+ if (input.dependsOn && input.dependsOn.length > 0) {
23566
+ input.dependsOn = input.dependsOn.map((dep) => {
23567
+ if (dep.startsWith("task-")) {
23568
+ return dep;
23569
+ }
23570
+ const resolvedId = nameToId.get(dep);
23571
+ if (!resolvedId) {
23572
+ throw new Error(`Task dependency "${dep}" not found`);
23573
+ }
23574
+ return resolvedId;
23575
+ });
23576
+ }
23577
+ }
23578
+ }
23579
+ function detectDependencyCycle(tasks) {
23580
+ const visited = /* @__PURE__ */ new Set();
23581
+ const recStack = /* @__PURE__ */ new Set();
23582
+ const taskMap = new Map(tasks.map((t) => [t.id, t]));
23583
+ function dfs(taskId, path6) {
23584
+ if (recStack.has(taskId)) {
23585
+ const cycleStart = path6.indexOf(taskId);
23586
+ return [...path6.slice(cycleStart), taskId];
23587
+ }
23588
+ if (visited.has(taskId)) {
23589
+ return null;
23590
+ }
23591
+ visited.add(taskId);
23592
+ recStack.add(taskId);
23593
+ const task = taskMap.get(taskId);
23594
+ if (task) {
23595
+ for (const depId of task.dependsOn) {
23596
+ const cycle = dfs(depId, [...path6, taskId]);
23597
+ if (cycle) {
23598
+ return cycle;
23599
+ }
23600
+ }
23601
+ }
23602
+ recStack.delete(taskId);
23603
+ return null;
23604
+ }
23605
+ for (const task of tasks) {
23606
+ if (!visited.has(task.id)) {
23607
+ const cycle = dfs(task.id, []);
23608
+ if (cycle) {
23609
+ return cycle;
23610
+ }
23611
+ }
23612
+ }
23613
+ return null;
23614
+ }
23615
+
23616
+ // src/domain/entities/Routine.ts
23617
+ function createRoutineDefinition(input) {
23618
+ const now = (/* @__PURE__ */ new Date()).toISOString();
23619
+ const id = input.id ?? `routine-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
23620
+ const taskNames = new Set(input.tasks.map((t) => t.name));
23621
+ const taskIds = new Set(input.tasks.filter((t) => t.id).map((t) => t.id));
23622
+ for (const task of input.tasks) {
23623
+ if (task.dependsOn) {
23624
+ for (const dep of task.dependsOn) {
23625
+ if (!taskNames.has(dep) && !taskIds.has(dep)) {
23626
+ throw new Error(
23627
+ `Routine "${input.name}": task "${task.name}" depends on unknown task "${dep}"`
23628
+ );
23629
+ }
23630
+ }
23631
+ }
23632
+ }
23633
+ createPlan({
23634
+ goal: input.name,
23635
+ tasks: input.tasks
23636
+ });
23637
+ return {
23638
+ id,
23639
+ name: input.name,
23640
+ description: input.description,
23641
+ version: input.version,
23642
+ tasks: input.tasks,
23643
+ requiredTools: input.requiredTools,
23644
+ requiredPlugins: input.requiredPlugins,
23645
+ instructions: input.instructions,
23646
+ concurrency: input.concurrency,
23647
+ allowDynamicTasks: input.allowDynamicTasks ?? false,
23648
+ tags: input.tags,
23649
+ author: input.author,
23650
+ createdAt: now,
23651
+ updatedAt: now,
23652
+ metadata: input.metadata
23653
+ };
23654
+ }
23655
+ function createRoutineExecution(definition) {
23656
+ const now = Date.now();
23657
+ const executionId = `rexec-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
23658
+ const plan = createPlan({
23659
+ goal: definition.name,
23660
+ context: definition.description,
23661
+ tasks: definition.tasks,
23662
+ concurrency: definition.concurrency,
23663
+ allowDynamicTasks: definition.allowDynamicTasks
23664
+ });
23665
+ return {
23666
+ id: executionId,
23667
+ routineId: definition.id,
23668
+ plan,
23669
+ status: "pending",
23670
+ progress: 0,
23671
+ lastUpdatedAt: now
23672
+ };
23673
+ }
23674
+ function getRoutineProgress(execution) {
23675
+ const { tasks } = execution.plan;
23676
+ if (tasks.length === 0) return 100;
23677
+ const completed = tasks.filter((t) => isTerminalStatus(t.status)).length;
23678
+ return Math.round(completed / tasks.length * 100);
23679
+ }
23680
+
23681
+ // src/utils/jsonExtractor.ts
23682
+ function extractJSON(text) {
23683
+ if (!text || typeof text !== "string") {
23684
+ return {
23685
+ success: false,
23686
+ error: "Input is empty or not a string"
23687
+ };
23688
+ }
23689
+ const trimmedText = text.trim();
23690
+ const codeBlockResult = extractFromCodeBlock(trimmedText);
23691
+ if (codeBlockResult.success) {
23692
+ return codeBlockResult;
23693
+ }
23694
+ const inlineResult = extractInlineJSON(trimmedText);
23695
+ if (inlineResult.success) {
23696
+ return inlineResult;
23697
+ }
23698
+ try {
23699
+ const data = JSON.parse(trimmedText);
23700
+ return {
23701
+ success: true,
23702
+ data,
23703
+ rawJson: trimmedText,
23704
+ method: "raw"
23705
+ };
23706
+ } catch (e) {
23707
+ return {
23708
+ success: false,
23709
+ error: `Could not extract JSON from text: ${e instanceof Error ? e.message : String(e)}`
23710
+ };
23711
+ }
23712
+ }
23713
+ function extractFromCodeBlock(text) {
23714
+ const codeBlockRegex = /```(?:json)?\s*([\s\S]*?)```/g;
23715
+ let match;
23716
+ while ((match = codeBlockRegex.exec(text)) !== null) {
23717
+ const content = match[1];
23718
+ if (content) {
23719
+ const trimmed = content.trim();
23720
+ try {
23721
+ const data = JSON.parse(trimmed);
23722
+ return {
23723
+ success: true,
23724
+ data,
23725
+ rawJson: trimmed,
23726
+ method: "code_block"
23727
+ };
23728
+ } catch {
23729
+ continue;
23730
+ }
23731
+ }
23732
+ }
23733
+ return { success: false };
23734
+ }
23735
+ function extractInlineJSON(text) {
23736
+ const objectMatch = findJSONObject(text);
23737
+ if (objectMatch) {
23738
+ try {
23739
+ const data = JSON.parse(objectMatch);
23740
+ return {
23741
+ success: true,
23742
+ data,
23743
+ rawJson: objectMatch,
23744
+ method: "inline"
23745
+ };
23746
+ } catch {
23747
+ }
23748
+ }
23749
+ const arrayMatch = findJSONArray(text);
23750
+ if (arrayMatch) {
23751
+ try {
23752
+ const data = JSON.parse(arrayMatch);
23753
+ return {
23754
+ success: true,
23755
+ data,
23756
+ rawJson: arrayMatch,
23757
+ method: "inline"
23758
+ };
23759
+ } catch {
23760
+ }
23761
+ }
23762
+ return { success: false };
23763
+ }
23764
+ function findJSONObject(text) {
23765
+ const startIndex = text.indexOf("{");
23766
+ if (startIndex === -1) return null;
23767
+ let depth = 0;
23768
+ let inString = false;
23769
+ let escaped = false;
23770
+ for (let i = startIndex; i < text.length; i++) {
23771
+ const char = text[i];
23772
+ if (escaped) {
23773
+ escaped = false;
23774
+ continue;
23775
+ }
23776
+ if (char === "\\" && inString) {
23777
+ escaped = true;
23778
+ continue;
23779
+ }
23780
+ if (char === '"') {
23781
+ inString = !inString;
23782
+ continue;
23783
+ }
23784
+ if (inString) continue;
23785
+ if (char === "{") {
23786
+ depth++;
23787
+ } else if (char === "}") {
23788
+ depth--;
23789
+ if (depth === 0) {
23790
+ return text.slice(startIndex, i + 1);
23791
+ }
23792
+ }
23793
+ }
23794
+ return null;
23795
+ }
23796
+ function findJSONArray(text) {
23797
+ const startIndex = text.indexOf("[");
23798
+ if (startIndex === -1) return null;
23799
+ let depth = 0;
23800
+ let inString = false;
23801
+ let escaped = false;
23802
+ for (let i = startIndex; i < text.length; i++) {
23803
+ const char = text[i];
23804
+ if (escaped) {
23805
+ escaped = false;
23806
+ continue;
23807
+ }
23808
+ if (char === "\\" && inString) {
23809
+ escaped = true;
23810
+ continue;
23811
+ }
23812
+ if (char === '"') {
23813
+ inString = !inString;
23814
+ continue;
23815
+ }
23816
+ if (inString) continue;
23817
+ if (char === "[") {
23818
+ depth++;
23819
+ } else if (char === "]") {
23820
+ depth--;
23821
+ if (depth === 0) {
23822
+ return text.slice(startIndex, i + 1);
23823
+ }
23824
+ }
23825
+ }
23826
+ return null;
23827
+ }
23828
+ function extractJSONField(text, field, defaultValue) {
23829
+ const result = extractJSON(text);
23830
+ if (result.success && result.data && field in result.data) {
23831
+ return result.data[field];
23832
+ }
23833
+ return defaultValue;
23834
+ }
23835
+ function extractNumber(text, patterns = [
23836
+ /(\d{1,3})%?\s*(?:complete|score|percent)/i,
23837
+ /(?:score|completion|rating)[:\s]+(\d{1,3})/i,
23838
+ /(\d{1,3})\s*(?:out of|\/)\s*100/i
23839
+ ], defaultValue = 0) {
23840
+ const jsonResult = extractJSON(text);
23841
+ if (jsonResult.success && jsonResult.data) {
23842
+ const scoreFields = ["score", "completionScore", "completion_score", "rating", "percent", "value"];
23843
+ for (const field of scoreFields) {
23844
+ if (field in jsonResult.data && typeof jsonResult.data[field] === "number") {
23845
+ return jsonResult.data[field];
23846
+ }
23847
+ }
23848
+ }
23849
+ for (const pattern of patterns) {
23850
+ const match = text.match(pattern);
23851
+ if (match && match[1]) {
23852
+ const num = parseInt(match[1], 10);
23853
+ if (!isNaN(num)) {
23854
+ return num;
23855
+ }
23856
+ }
23857
+ }
23858
+ return defaultValue;
23859
+ }
23860
+
23861
+ // src/core/routineRunner.ts
23862
+ init_Logger();
23863
+ function defaultSystemPrompt(definition) {
23864
+ const parts = [];
23865
+ if (definition.instructions) {
23866
+ parts.push(definition.instructions);
23867
+ }
23868
+ parts.push(
23869
+ `You are executing a routine called "${definition.name}".`,
23870
+ "",
23871
+ "Between tasks, your conversation history is cleared but your memory persists.",
23872
+ "Use these strategies to pass information between tasks:",
23873
+ "- Use context_set for small key results that subsequent tasks need immediately (visible in context, no retrieval needed).",
23874
+ '- Use memory_store with tier="findings" for larger data that may be needed later.',
23875
+ "- Use memory_retrieve to access data stored by previous tasks.",
23876
+ "",
23877
+ "IMPORTANT: When you have completed the current task, you MUST stop immediately.",
23878
+ "Do NOT repeat work you have already done. Do NOT re-fetch data you already have.",
23879
+ "Store key results in memory once, then produce a final text response (no more tool calls) to signal completion."
23880
+ );
23881
+ return parts.join("\n");
23882
+ }
23883
+ function defaultTaskPrompt(task) {
23884
+ const parts = [];
23885
+ parts.push(`## Current Task: ${task.name}`, "");
23886
+ parts.push(task.description, "");
23887
+ if (task.expectedOutput) {
23888
+ parts.push(`**Expected output:** ${task.expectedOutput}`, "");
23889
+ }
23890
+ if (task.suggestedTools && task.suggestedTools.length > 0) {
23891
+ parts.push(`**Suggested tools:** ${task.suggestedTools.join(", ")}`, "");
23892
+ }
23893
+ const criteria = task.validation?.completionCriteria;
23894
+ if (criteria && criteria.length > 0) {
23895
+ parts.push("### Completion Criteria");
23896
+ parts.push("When you are done, ensure the following are met:");
23897
+ for (const c of criteria) {
23898
+ parts.push(`- ${c}`);
23899
+ }
23900
+ parts.push("");
23901
+ }
23902
+ parts.push("After completing the work, store key results in memory once, then respond with a text summary (no more tool calls).");
23903
+ return parts.join("\n");
23904
+ }
23905
+ function defaultValidationPrompt(task, context) {
23906
+ const criteria = task.validation?.completionCriteria ?? [];
23907
+ const criteriaList = criteria.length > 0 ? criteria.map((c, i) => `${i + 1}. ${c}`).join("\n") : "The task was completed as described.";
23908
+ const parts = [
23909
+ `Evaluate if the task "${task.name}" was completed successfully.`,
23910
+ "",
23911
+ `Task description: ${task.description}`,
23912
+ "",
23913
+ "Completion criteria:",
23914
+ criteriaList,
23915
+ "",
23916
+ "--- EVIDENCE ---",
23917
+ "",
23918
+ "Agent response (final text output):",
23919
+ context.responseText || "(no text output)",
23920
+ "",
23921
+ "Tool calls made during this task:",
23922
+ context.toolCallLog
23923
+ ];
23924
+ if (context.inContextMemory) {
23925
+ parts.push("", "In-context memory (current state):", context.inContextMemory);
23926
+ }
23927
+ if (context.workingMemoryIndex) {
23928
+ parts.push("", "Working memory index (stored data):", context.workingMemoryIndex);
23929
+ }
23930
+ parts.push(
23931
+ "",
23932
+ "--- END EVIDENCE ---",
23933
+ "",
23934
+ "Use the evidence above to verify each criterion. Check tool call results, not just the agent's claims.",
23935
+ "",
23936
+ "Return a JSON object with the following structure:",
23937
+ "```json",
23938
+ '{ "isComplete": boolean, "completionScore": number (0-100), "explanation": "..." }',
23939
+ "```",
23940
+ "",
23941
+ "Be strict: only mark isComplete=true if all criteria are clearly met based on the evidence."
23942
+ );
23943
+ return parts.join("\n");
23944
+ }
23945
+ function formatToolCallLog(conversation) {
23946
+ const calls = [];
23947
+ for (const item of conversation) {
23948
+ if (!("content" in item) || !Array.isArray(item.content)) continue;
23949
+ const msg = item;
23950
+ for (const c of msg.content) {
23951
+ if (c.type === "tool_use" /* TOOL_USE */) {
23952
+ let argsStr;
23953
+ try {
23954
+ const parsed = JSON.parse(c.arguments);
23955
+ argsStr = JSON.stringify(parsed, null, 2);
23956
+ if (argsStr.length > 500) argsStr = argsStr.slice(0, 500) + "... (truncated)";
23957
+ } catch {
23958
+ argsStr = c.arguments;
23959
+ }
23960
+ calls.push(`CALL: ${c.name}(${argsStr})`);
23961
+ } else if (c.type === "tool_result" /* TOOL_RESULT */) {
23962
+ let resultStr = typeof c.content === "string" ? c.content : JSON.stringify(c.content);
23963
+ if (resultStr.length > 500) resultStr = resultStr.slice(0, 500) + "... (truncated)";
23964
+ const prefix = c.error ? "ERROR" : "RESULT";
23965
+ calls.push(` ${prefix}: ${resultStr}`);
23966
+ }
23967
+ }
23968
+ }
23969
+ return calls.length > 0 ? calls.join("\n") : "(no tool calls)";
23970
+ }
23971
+ async function collectValidationContext(agent, responseText) {
23972
+ const icmPlugin = agent.context.getPlugin("in_context_memory");
23973
+ const inContextMemory = icmPlugin ? await icmPlugin.getContent() : null;
23974
+ const wmPlugin = agent.context.memory;
23975
+ const workingMemoryIndex = wmPlugin ? await wmPlugin.getContent() : null;
23976
+ const conversation = agent.context.getConversation();
23977
+ const toolCallLog = formatToolCallLog(conversation);
23978
+ return {
23979
+ responseText,
23980
+ inContextMemory,
23981
+ workingMemoryIndex,
23982
+ toolCallLog
23983
+ };
23984
+ }
23985
+ async function validateTaskCompletion(agent, task, responseText, validationPromptBuilder) {
23986
+ const hasExplicitValidation = task.validation?.skipReflection === false && task.validation?.completionCriteria && task.validation.completionCriteria.length > 0;
23987
+ if (!hasExplicitValidation) {
23988
+ return {
23989
+ isComplete: true,
23990
+ completionScore: 100,
23991
+ explanation: "Auto-passed (LLM validation not enabled)",
23992
+ requiresUserApproval: false
23993
+ };
23994
+ }
23995
+ const validationContext = await collectValidationContext(agent, responseText);
23996
+ const prompt = validationPromptBuilder(task, validationContext);
23997
+ const response = await agent.runDirect(prompt, {
23998
+ instructions: "You are a task completion evaluator. Return only JSON.",
23999
+ temperature: 0.1
24000
+ });
24001
+ const text = response.output_text ?? "";
24002
+ const extracted = extractJSON(text);
24003
+ if (!extracted.success || !extracted.data) {
24004
+ return {
24005
+ isComplete: false,
24006
+ completionScore: 0,
24007
+ explanation: `Failed to parse validation response: ${extracted.error ?? "unknown error"}`,
24008
+ requiresUserApproval: false
24009
+ };
24010
+ }
24011
+ const { isComplete, completionScore, explanation } = extracted.data;
24012
+ const minScore = task.validation?.minCompletionScore ?? 80;
24013
+ return {
24014
+ isComplete: isComplete && completionScore >= minScore,
24015
+ completionScore,
24016
+ explanation,
24017
+ requiresUserApproval: false
24018
+ };
24019
+ }
24020
+ async function executeRoutine(options) {
24021
+ const {
24022
+ definition,
24023
+ agent: existingAgent,
24024
+ connector,
24025
+ model,
24026
+ tools: extraTools,
24027
+ onTaskStarted,
24028
+ onTaskComplete,
24029
+ onTaskFailed,
24030
+ onTaskValidation,
24031
+ hooks,
24032
+ prompts
24033
+ } = options;
24034
+ if (!existingAgent && (!connector || !model)) {
24035
+ throw new Error("executeRoutine requires either `agent` or both `connector` and `model`");
24036
+ }
24037
+ const ownsAgent = !existingAgent;
24038
+ const log = logger.child({ routine: definition.name });
24039
+ const execution = createRoutineExecution(definition);
24040
+ execution.status = "running";
24041
+ execution.startedAt = Date.now();
24042
+ execution.lastUpdatedAt = Date.now();
24043
+ const buildSystemPrompt = prompts?.system ?? defaultSystemPrompt;
24044
+ const buildTaskPrompt = prompts?.task ?? defaultTaskPrompt;
24045
+ const buildValidationPrompt = prompts?.validation ?? defaultValidationPrompt;
24046
+ let agent;
24047
+ const registeredHooks = [];
24048
+ if (existingAgent) {
24049
+ agent = existingAgent;
24050
+ if (hooks) {
24051
+ const hookNames = [
24052
+ "before:execution",
24053
+ "after:execution",
24054
+ "before:llm",
24055
+ "after:llm",
24056
+ "before:tool",
24057
+ "after:tool",
24058
+ "approve:tool",
24059
+ "pause:check"
24060
+ ];
24061
+ for (const name of hookNames) {
24062
+ const hook = hooks[name];
24063
+ if (hook) {
24064
+ agent.registerHook(name, hook);
24065
+ registeredHooks.push({ name, hook });
24066
+ }
24067
+ }
24068
+ }
24069
+ } else {
24070
+ const allTools = [...extraTools ?? []];
24071
+ if (definition.requiredTools && definition.requiredTools.length > 0) {
24072
+ const availableToolNames = new Set(allTools.map((t) => t.definition.function.name));
24073
+ const missing = definition.requiredTools.filter((name) => !availableToolNames.has(name));
24074
+ if (missing.length > 0) {
24075
+ execution.status = "failed";
24076
+ execution.error = `Missing required tools: ${missing.join(", ")}`;
24077
+ execution.completedAt = Date.now();
24078
+ execution.lastUpdatedAt = Date.now();
24079
+ return execution;
24080
+ }
24081
+ }
24082
+ agent = Agent.create({
24083
+ connector,
24084
+ model,
24085
+ tools: allTools,
24086
+ instructions: buildSystemPrompt(definition),
24087
+ hooks,
24088
+ context: {
24089
+ model,
24090
+ features: {
24091
+ workingMemory: true,
24092
+ inContextMemory: true
24093
+ }
24094
+ }
24095
+ });
24096
+ }
24097
+ if (definition.requiredPlugins && definition.requiredPlugins.length > 0) {
24098
+ const missing = definition.requiredPlugins.filter(
24099
+ (name) => !agent.context.hasPlugin(name)
24100
+ );
24101
+ if (missing.length > 0) {
24102
+ if (ownsAgent) agent.destroy();
24103
+ execution.status = "failed";
24104
+ execution.error = `Missing required plugins: ${missing.join(", ")}`;
24105
+ execution.completedAt = Date.now();
24106
+ execution.lastUpdatedAt = Date.now();
24107
+ return execution;
24108
+ }
24109
+ }
24110
+ const failureMode = definition.concurrency?.failureMode ?? "fail-fast";
24111
+ try {
24112
+ let nextTasks = getNextExecutableTasks(execution.plan);
24113
+ while (nextTasks.length > 0) {
24114
+ const task = nextTasks[0];
24115
+ const taskIndex = execution.plan.tasks.findIndex((t) => t.id === task.id);
24116
+ log.info({ taskName: task.name, taskId: task.id }, "Starting task");
24117
+ execution.plan.tasks[taskIndex] = updateTaskStatus(task, "in_progress");
24118
+ execution.lastUpdatedAt = Date.now();
24119
+ onTaskStarted?.(execution.plan.tasks[taskIndex], execution);
24120
+ let taskCompleted = false;
24121
+ const maxTaskIterations = task.execution?.maxIterations ?? 15;
24122
+ const iterationLimiter = async (ctx) => {
24123
+ if (ctx.iteration >= maxTaskIterations) {
24124
+ agent.cancel(`Task "${task.name}" exceeded max iterations (${maxTaskIterations})`);
24125
+ }
24126
+ return { shouldPause: false };
24127
+ };
24128
+ agent.registerHook("pause:check", iterationLimiter);
24129
+ const getTask = () => execution.plan.tasks[taskIndex];
24130
+ while (!taskCompleted) {
24131
+ try {
24132
+ const taskPrompt = buildTaskPrompt(getTask());
24133
+ const response = await agent.run(taskPrompt);
24134
+ const responseText = response.output_text ?? "";
24135
+ const validationResult = await validateTaskCompletion(
24136
+ agent,
24137
+ getTask(),
24138
+ responseText,
24139
+ buildValidationPrompt
24140
+ );
24141
+ onTaskValidation?.(getTask(), validationResult, execution);
24142
+ if (validationResult.isComplete) {
24143
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "completed");
24144
+ execution.plan.tasks[taskIndex].result = {
24145
+ success: true,
24146
+ output: responseText,
24147
+ validationScore: validationResult.completionScore,
24148
+ validationExplanation: validationResult.explanation
24149
+ };
24150
+ taskCompleted = true;
24151
+ log.info(
24152
+ { taskName: getTask().name, score: validationResult.completionScore },
24153
+ "Task completed"
24154
+ );
24155
+ execution.progress = getRoutineProgress(execution);
24156
+ execution.lastUpdatedAt = Date.now();
24157
+ onTaskComplete?.(execution.plan.tasks[taskIndex], execution);
24158
+ } else {
24159
+ log.warn(
24160
+ {
24161
+ taskName: getTask().name,
24162
+ score: validationResult.completionScore,
24163
+ attempt: getTask().attempts,
24164
+ maxAttempts: getTask().maxAttempts
24165
+ },
24166
+ "Task validation failed"
24167
+ );
24168
+ if (getTask().attempts >= getTask().maxAttempts) {
24169
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
24170
+ execution.plan.tasks[taskIndex].result = {
24171
+ success: false,
24172
+ error: validationResult.explanation,
24173
+ validationScore: validationResult.completionScore,
24174
+ validationExplanation: validationResult.explanation
24175
+ };
24176
+ break;
24177
+ }
24178
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
24179
+ }
24180
+ } catch (error) {
24181
+ const errorMessage = error.message;
24182
+ log.error({ taskName: getTask().name, error: errorMessage }, "Task execution error");
24183
+ if (getTask().attempts >= getTask().maxAttempts) {
24184
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
24185
+ execution.plan.tasks[taskIndex].result = {
24186
+ success: false,
24187
+ error: errorMessage
24188
+ };
24189
+ break;
24190
+ }
24191
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
24192
+ }
24193
+ }
24194
+ if (!taskCompleted) {
24195
+ execution.progress = getRoutineProgress(execution);
24196
+ execution.lastUpdatedAt = Date.now();
24197
+ onTaskFailed?.(execution.plan.tasks[taskIndex], execution);
24198
+ if (failureMode === "fail-fast") {
24199
+ execution.status = "failed";
24200
+ execution.error = `Task "${getTask().name}" failed after ${getTask().attempts} attempt(s)`;
24201
+ execution.completedAt = Date.now();
24202
+ execution.lastUpdatedAt = Date.now();
24203
+ break;
24204
+ }
24205
+ }
24206
+ agent.unregisterHook("pause:check", iterationLimiter);
24207
+ agent.clearConversation("task-boundary");
24208
+ nextTasks = getNextExecutableTasks(execution.plan);
24209
+ }
24210
+ if (execution.status === "running") {
24211
+ const allTerminal = execution.plan.tasks.every((t) => isTerminalStatus(t.status));
24212
+ const allCompleted = execution.plan.tasks.every((t) => t.status === "completed");
24213
+ if (allCompleted) {
24214
+ execution.status = "completed";
24215
+ } else if (allTerminal) {
24216
+ execution.status = "failed";
24217
+ execution.error = "Not all tasks completed successfully";
24218
+ } else {
24219
+ execution.status = "failed";
24220
+ execution.error = "Execution stalled: remaining tasks are blocked by incomplete dependencies";
24221
+ }
24222
+ execution.completedAt = Date.now();
24223
+ execution.lastUpdatedAt = Date.now();
24224
+ execution.progress = getRoutineProgress(execution);
24225
+ }
24226
+ log.info(
24227
+ { status: execution.status, progress: execution.progress },
24228
+ "Routine execution finished"
24229
+ );
24230
+ return execution;
24231
+ } finally {
24232
+ for (const { name, hook } of registeredHooks) {
24233
+ try {
24234
+ agent.unregisterHook(name, hook);
24235
+ } catch {
24236
+ }
24237
+ }
24238
+ if (ownsAgent) {
24239
+ agent.destroy();
24240
+ }
24241
+ }
24242
+ }
24243
+
23337
24244
  // src/core/index.ts
23338
24245
  init_constants();
23339
24246
  (class {
@@ -23371,8 +24278,8 @@ init_constants();
23371
24278
  throw new Error("Configuration file not found. Searched: " + this.DEFAULT_PATHS.join(", "));
23372
24279
  }
23373
24280
  try {
23374
- const fs19 = __require("fs");
23375
- const content = fs19.readFileSync(configPath, "utf-8");
24281
+ const fs20 = __require("fs");
24282
+ const content = fs20.readFileSync(configPath, "utf-8");
23376
24283
  let config = JSON.parse(content);
23377
24284
  config = this.interpolateEnvVars(config);
23378
24285
  this.validate(config);
@@ -23401,10 +24308,10 @@ init_constants();
23401
24308
  * Find configuration file synchronously
23402
24309
  */
23403
24310
  static findConfigSync() {
23404
- const fs19 = __require("fs");
24311
+ const fs20 = __require("fs");
23405
24312
  for (const path6 of this.DEFAULT_PATHS) {
23406
24313
  try {
23407
- fs19.accessSync(resolve(path6));
24314
+ fs20.accessSync(resolve(path6));
23408
24315
  return resolve(path6);
23409
24316
  } catch {
23410
24317
  }
@@ -29583,7 +30490,7 @@ var OpenAISTTProvider = class extends BaseMediaProvider {
29583
30490
  if (Buffer.isBuffer(audio)) {
29584
30491
  return new File([new Uint8Array(audio)], "audio.wav", { type: "audio/wav" });
29585
30492
  } else if (typeof audio === "string") {
29586
- return fs18.createReadStream(audio);
30493
+ return fs19.createReadStream(audio);
29587
30494
  } else {
29588
30495
  throw new Error("Invalid audio input: must be Buffer or file path");
29589
30496
  }
@@ -30136,7 +31043,7 @@ var TextToSpeech = class _TextToSpeech {
30136
31043
  */
30137
31044
  async toFile(text, filePath, options) {
30138
31045
  const response = await this.synthesize(text, options);
30139
- await fs17.writeFile(filePath, response.audio);
31046
+ await fs18.writeFile(filePath, response.audio);
30140
31047
  }
30141
31048
  // ======================== Introspection Methods ========================
30142
31049
  /**
@@ -30484,7 +31391,7 @@ var SpeechToText = class _SpeechToText {
30484
31391
  * @param options - Optional transcription parameters
30485
31392
  */
30486
31393
  async transcribeFile(filePath, options) {
30487
- const audio = await fs17.readFile(filePath);
31394
+ const audio = await fs18.readFile(filePath);
30488
31395
  return this.transcribe(audio, options);
30489
31396
  }
30490
31397
  /**
@@ -30810,7 +31717,7 @@ var OpenAIImageProvider = class extends BaseMediaProvider {
30810
31717
  if (Buffer.isBuffer(image)) {
30811
31718
  return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
30812
31719
  }
30813
- return fs18.createReadStream(image);
31720
+ return fs19.createReadStream(image);
30814
31721
  }
30815
31722
  /**
30816
31723
  * Handle OpenAI API errors
@@ -30957,8 +31864,8 @@ var GoogleImageProvider = class extends BaseMediaProvider {
30957
31864
  if (Buffer.isBuffer(image)) {
30958
31865
  imageBytes = image.toString("base64");
30959
31866
  } else {
30960
- const fs19 = await import('fs');
30961
- const buffer = fs19.readFileSync(image);
31867
+ const fs20 = await import('fs');
31868
+ const buffer = fs20.readFileSync(image);
30962
31869
  imageBytes = buffer.toString("base64");
30963
31870
  }
30964
31871
  return {
@@ -31119,7 +32026,7 @@ var GrokImageProvider = class extends BaseMediaProvider {
31119
32026
  if (Buffer.isBuffer(image)) {
31120
32027
  return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
31121
32028
  }
31122
- return fs18.createReadStream(image);
32029
+ return fs19.createReadStream(image);
31123
32030
  }
31124
32031
  /**
31125
32032
  * Handle API errors
@@ -32569,8 +33476,8 @@ var OpenAISoraProvider = class extends BaseMediaProvider {
32569
33476
  return new File([new Uint8Array(image)], "input.png", { type: "image/png" });
32570
33477
  }
32571
33478
  if (!image.startsWith("http")) {
32572
- const fs19 = await import('fs');
32573
- const data = fs19.readFileSync(image);
33479
+ const fs20 = await import('fs');
33480
+ const data = fs20.readFileSync(image);
32574
33481
  return new File([new Uint8Array(data)], "input.png", { type: "image/png" });
32575
33482
  }
32576
33483
  const response = await fetch(image);
@@ -32748,7 +33655,7 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
32748
33655
  if (video.videoBytes) {
32749
33656
  buffer = Buffer.from(video.videoBytes, "base64");
32750
33657
  } else if (video.uri) {
32751
- const fs19 = await import('fs/promises');
33658
+ const fs20 = await import('fs/promises');
32752
33659
  const os3 = await import('os');
32753
33660
  const path6 = await import('path');
32754
33661
  const tempDir = os3.tmpdir();
@@ -32759,11 +33666,11 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
32759
33666
  // Pass as GeneratedVideo
32760
33667
  downloadPath: tempFile
32761
33668
  });
32762
- buffer = await fs19.readFile(tempFile);
32763
- await fs19.unlink(tempFile).catch(() => {
33669
+ buffer = await fs20.readFile(tempFile);
33670
+ await fs20.unlink(tempFile).catch(() => {
32764
33671
  });
32765
33672
  } catch (downloadError) {
32766
- await fs19.unlink(tempFile).catch(() => {
33673
+ await fs20.unlink(tempFile).catch(() => {
32767
33674
  });
32768
33675
  throw new ProviderError(
32769
33676
  "google",
@@ -32885,8 +33792,8 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
32885
33792
  if (image.startsWith("http://") || image.startsWith("https://")) {
32886
33793
  return { imageUri: image };
32887
33794
  }
32888
- const fs19 = await import('fs/promises');
32889
- const data = await fs19.readFile(image);
33795
+ const fs20 = await import('fs/promises');
33796
+ const data = await fs20.readFile(image);
32890
33797
  return {
32891
33798
  imageBytes: data.toString("base64")
32892
33799
  };
@@ -33193,8 +34100,8 @@ var GrokImagineProvider = class extends BaseMediaProvider {
33193
34100
  if (image.startsWith("http") || image.startsWith("data:")) {
33194
34101
  return image;
33195
34102
  }
33196
- const fs19 = await import('fs');
33197
- const data = fs19.readFileSync(image);
34103
+ const fs20 = await import('fs');
34104
+ const data = fs20.readFileSync(image);
33198
34105
  const base64 = data.toString("base64");
33199
34106
  const ext = image.split(".").pop()?.toLowerCase() || "png";
33200
34107
  const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext}`;
@@ -35863,245 +36770,6 @@ var CheckpointManager = class {
35863
36770
  }
35864
36771
  };
35865
36772
 
35866
- // src/domain/entities/Task.ts
35867
- var TERMINAL_TASK_STATUSES = ["completed", "failed", "skipped", "cancelled"];
35868
- function isTerminalStatus(status) {
35869
- return TERMINAL_TASK_STATUSES.includes(status);
35870
- }
35871
- function createTask(input) {
35872
- const now = Date.now();
35873
- const id = input.id ?? `task-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
35874
- return {
35875
- id,
35876
- name: input.name,
35877
- description: input.description,
35878
- status: "pending",
35879
- dependsOn: input.dependsOn ?? [],
35880
- externalDependency: input.externalDependency,
35881
- condition: input.condition,
35882
- execution: input.execution,
35883
- validation: input.validation,
35884
- expectedOutput: input.expectedOutput,
35885
- attempts: 0,
35886
- maxAttempts: input.maxAttempts ?? 3,
35887
- createdAt: now,
35888
- lastUpdatedAt: now,
35889
- metadata: input.metadata
35890
- };
35891
- }
35892
- function createPlan(input) {
35893
- const now = Date.now();
35894
- const id = `plan-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
35895
- const tasks = input.tasks.map((taskInput) => createTask(taskInput));
35896
- const nameToId = /* @__PURE__ */ new Map();
35897
- for (const task of tasks) {
35898
- nameToId.set(task.name, task.id);
35899
- }
35900
- for (let i = 0; i < tasks.length; i++) {
35901
- const taskInput = input.tasks[i];
35902
- const task = tasks[i];
35903
- if (taskInput.dependsOn && taskInput.dependsOn.length > 0) {
35904
- task.dependsOn = taskInput.dependsOn.map((dep) => {
35905
- if (dep.startsWith("task-")) {
35906
- return dep;
35907
- }
35908
- const resolvedId = nameToId.get(dep);
35909
- if (!resolvedId) {
35910
- throw new Error(`Task dependency "${dep}" not found in plan`);
35911
- }
35912
- return resolvedId;
35913
- });
35914
- }
35915
- }
35916
- if (!input.skipCycleCheck) {
35917
- const cycle = detectDependencyCycle(tasks);
35918
- if (cycle) {
35919
- const cycleNames = cycle.map((taskId) => {
35920
- const task = tasks.find((t) => t.id === taskId);
35921
- return task ? task.name : taskId;
35922
- });
35923
- throw new DependencyCycleError(cycleNames, id);
35924
- }
35925
- }
35926
- return {
35927
- id,
35928
- goal: input.goal,
35929
- context: input.context,
35930
- tasks,
35931
- concurrency: input.concurrency,
35932
- allowDynamicTasks: input.allowDynamicTasks ?? true,
35933
- status: "pending",
35934
- createdAt: now,
35935
- lastUpdatedAt: now,
35936
- metadata: input.metadata
35937
- };
35938
- }
35939
- function canTaskExecute(task, allTasks) {
35940
- if (task.status !== "pending") {
35941
- return false;
35942
- }
35943
- if (task.dependsOn.length > 0) {
35944
- for (const depId of task.dependsOn) {
35945
- const depTask = allTasks.find((t) => t.id === depId);
35946
- if (!depTask || depTask.status !== "completed") {
35947
- return false;
35948
- }
35949
- }
35950
- }
35951
- return true;
35952
- }
35953
- function getNextExecutableTasks(plan) {
35954
- const executable = plan.tasks.filter((task) => canTaskExecute(task, plan.tasks));
35955
- if (executable.length === 0) {
35956
- return [];
35957
- }
35958
- if (!plan.concurrency) {
35959
- return [executable[0]];
35960
- }
35961
- const runningCount = plan.tasks.filter((t) => t.status === "in_progress").length;
35962
- const availableSlots = plan.concurrency.maxParallelTasks - runningCount;
35963
- if (availableSlots <= 0) {
35964
- return [];
35965
- }
35966
- const parallelTasks = executable.filter((task) => task.execution?.parallel === true);
35967
- if (parallelTasks.length === 0) {
35968
- return [executable[0]];
35969
- }
35970
- let sortedTasks = [...parallelTasks];
35971
- if (plan.concurrency.strategy === "priority") {
35972
- sortedTasks.sort((a, b) => (b.execution?.priority ?? 0) - (a.execution?.priority ?? 0));
35973
- }
35974
- return sortedTasks.slice(0, availableSlots);
35975
- }
35976
- async function evaluateCondition(condition, memory) {
35977
- const value = await memory.get(condition.memoryKey);
35978
- switch (condition.operator) {
35979
- case "exists":
35980
- return value !== void 0;
35981
- case "not_exists":
35982
- return value === void 0;
35983
- case "equals":
35984
- return value === condition.value;
35985
- case "contains":
35986
- if (Array.isArray(value)) {
35987
- return value.includes(condition.value);
35988
- }
35989
- if (typeof value === "string" && typeof condition.value === "string") {
35990
- return value.includes(condition.value);
35991
- }
35992
- return false;
35993
- case "truthy":
35994
- return !!value;
35995
- case "greater_than":
35996
- if (typeof value === "number" && typeof condition.value === "number") {
35997
- return value > condition.value;
35998
- }
35999
- return false;
36000
- case "less_than":
36001
- if (typeof value === "number" && typeof condition.value === "number") {
36002
- return value < condition.value;
36003
- }
36004
- return false;
36005
- default:
36006
- return false;
36007
- }
36008
- }
36009
- function updateTaskStatus(task, status) {
36010
- const now = Date.now();
36011
- const updated = {
36012
- ...task,
36013
- status,
36014
- lastUpdatedAt: now
36015
- };
36016
- if (status === "in_progress") {
36017
- if (!updated.startedAt) {
36018
- updated.startedAt = now;
36019
- }
36020
- updated.attempts += 1;
36021
- }
36022
- if ((status === "completed" || status === "failed") && !updated.completedAt) {
36023
- updated.completedAt = now;
36024
- }
36025
- return updated;
36026
- }
36027
- function isTaskBlocked(task, allTasks) {
36028
- if (task.dependsOn.length === 0) {
36029
- return false;
36030
- }
36031
- for (const depId of task.dependsOn) {
36032
- const depTask = allTasks.find((t) => t.id === depId);
36033
- if (!depTask) {
36034
- return true;
36035
- }
36036
- if (depTask.status !== "completed") {
36037
- return true;
36038
- }
36039
- }
36040
- return false;
36041
- }
36042
- function getTaskDependencies(task, allTasks) {
36043
- if (task.dependsOn.length === 0) {
36044
- return [];
36045
- }
36046
- return task.dependsOn.map((depId) => allTasks.find((t) => t.id === depId)).filter((t) => t !== void 0);
36047
- }
36048
- function resolveDependencies(taskInputs, tasks) {
36049
- const nameToId = /* @__PURE__ */ new Map();
36050
- for (const task of tasks) {
36051
- nameToId.set(task.name, task.id);
36052
- }
36053
- for (const input of taskInputs) {
36054
- if (input.dependsOn && input.dependsOn.length > 0) {
36055
- input.dependsOn = input.dependsOn.map((dep) => {
36056
- if (dep.startsWith("task-")) {
36057
- return dep;
36058
- }
36059
- const resolvedId = nameToId.get(dep);
36060
- if (!resolvedId) {
36061
- throw new Error(`Task dependency "${dep}" not found`);
36062
- }
36063
- return resolvedId;
36064
- });
36065
- }
36066
- }
36067
- }
36068
- function detectDependencyCycle(tasks) {
36069
- const visited = /* @__PURE__ */ new Set();
36070
- const recStack = /* @__PURE__ */ new Set();
36071
- const taskMap = new Map(tasks.map((t) => [t.id, t]));
36072
- function dfs(taskId, path6) {
36073
- if (recStack.has(taskId)) {
36074
- const cycleStart = path6.indexOf(taskId);
36075
- return [...path6.slice(cycleStart), taskId];
36076
- }
36077
- if (visited.has(taskId)) {
36078
- return null;
36079
- }
36080
- visited.add(taskId);
36081
- recStack.add(taskId);
36082
- const task = taskMap.get(taskId);
36083
- if (task) {
36084
- for (const depId of task.dependsOn) {
36085
- const cycle = dfs(depId, [...path6, taskId]);
36086
- if (cycle) {
36087
- return cycle;
36088
- }
36089
- }
36090
- }
36091
- recStack.delete(taskId);
36092
- return null;
36093
- }
36094
- for (const task of tasks) {
36095
- if (!visited.has(task.id)) {
36096
- const cycle = dfs(task.id, []);
36097
- if (cycle) {
36098
- return cycle;
36099
- }
36100
- }
36101
- }
36102
- return null;
36103
- }
36104
-
36105
36773
  // src/capabilities/taskAgent/PlanningAgent.ts
36106
36774
  var PLANNING_SYSTEM_PROMPT = `You are an AI planning agent. Your job is to analyze goals and break them down into structured, executable task plans.
36107
36775
 
@@ -37466,10 +38134,10 @@ var FileMediaStorage = class {
37466
38134
  }
37467
38135
  async save(data, metadata) {
37468
38136
  const dir = metadata.userId ? path2.join(this.outputDir, metadata.userId) : this.outputDir;
37469
- await fs17.mkdir(dir, { recursive: true });
38137
+ await fs18.mkdir(dir, { recursive: true });
37470
38138
  const filename = metadata.suggestedFilename ?? this.generateFilename(metadata);
37471
38139
  const filePath = path2.join(dir, filename);
37472
- await fs17.writeFile(filePath, data);
38140
+ await fs18.writeFile(filePath, data);
37473
38141
  const format = metadata.format.toLowerCase();
37474
38142
  const mimeType = MIME_TYPES2[format] ?? "application/octet-stream";
37475
38143
  return {
@@ -37480,7 +38148,7 @@ var FileMediaStorage = class {
37480
38148
  }
37481
38149
  async read(location) {
37482
38150
  try {
37483
- return await fs17.readFile(location);
38151
+ return await fs18.readFile(location);
37484
38152
  } catch (err) {
37485
38153
  if (err.code === "ENOENT") {
37486
38154
  return null;
@@ -37490,7 +38158,7 @@ var FileMediaStorage = class {
37490
38158
  }
37491
38159
  async delete(location) {
37492
38160
  try {
37493
- await fs17.unlink(location);
38161
+ await fs18.unlink(location);
37494
38162
  } catch (err) {
37495
38163
  if (err.code === "ENOENT") {
37496
38164
  return;
@@ -37500,7 +38168,7 @@ var FileMediaStorage = class {
37500
38168
  }
37501
38169
  async exists(location) {
37502
38170
  try {
37503
- await fs17.access(location);
38171
+ await fs18.access(location);
37504
38172
  return true;
37505
38173
  } catch {
37506
38174
  return false;
@@ -37509,11 +38177,11 @@ var FileMediaStorage = class {
37509
38177
  async list(options) {
37510
38178
  await this.ensureDir();
37511
38179
  let entries = [];
37512
- const files = await fs17.readdir(this.outputDir);
38180
+ const files = await fs18.readdir(this.outputDir);
37513
38181
  for (const file of files) {
37514
38182
  const filePath = path2.join(this.outputDir, file);
37515
38183
  try {
37516
- const stat6 = await fs17.stat(filePath);
38184
+ const stat6 = await fs18.stat(filePath);
37517
38185
  if (!stat6.isFile()) continue;
37518
38186
  const ext = path2.extname(file).slice(1).toLowerCase();
37519
38187
  const mimeType = MIME_TYPES2[ext] ?? "application/octet-stream";
@@ -37553,7 +38221,7 @@ var FileMediaStorage = class {
37553
38221
  }
37554
38222
  async ensureDir() {
37555
38223
  if (!this.initialized) {
37556
- await fs17.mkdir(this.outputDir, { recursive: true });
38224
+ await fs18.mkdir(this.outputDir, { recursive: true });
37557
38225
  this.initialized = true;
37558
38226
  }
37559
38227
  }
@@ -37803,6 +38471,234 @@ var FileCustomToolStorage = class {
37803
38471
  function createFileCustomToolStorage(config) {
37804
38472
  return new FileCustomToolStorage(config);
37805
38473
  }
38474
+ var STORAGE_VERSION = 1;
38475
+ var DEFAULT_USER_ID3 = "default";
38476
+ function getDefaultBaseDirectory6() {
38477
+ const platform2 = process.platform;
38478
+ if (platform2 === "win32") {
38479
+ const appData = process.env.APPDATA || process.env.LOCALAPPDATA;
38480
+ if (appData) {
38481
+ return join(appData, "oneringai", "users");
38482
+ }
38483
+ }
38484
+ return join(homedir(), ".oneringai", "users");
38485
+ }
38486
+ function sanitizeUserId3(userId) {
38487
+ if (!userId) {
38488
+ return DEFAULT_USER_ID3;
38489
+ }
38490
+ return userId.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase() || DEFAULT_USER_ID3;
38491
+ }
38492
+ function sanitizeId2(id) {
38493
+ return id.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase() || "default";
38494
+ }
38495
+ var FileRoutineDefinitionStorage = class {
38496
+ baseDirectory;
38497
+ prettyPrint;
38498
+ constructor(config = {}) {
38499
+ this.baseDirectory = config.baseDirectory ?? getDefaultBaseDirectory6();
38500
+ this.prettyPrint = config.prettyPrint ?? true;
38501
+ }
38502
+ getUserDirectory(userId) {
38503
+ const sanitizedId = sanitizeUserId3(userId);
38504
+ return join(this.baseDirectory, sanitizedId, "routines");
38505
+ }
38506
+ getIndexPath(userId) {
38507
+ return join(this.getUserDirectory(userId), "_index.json");
38508
+ }
38509
+ getRoutinePath(userId, sanitizedId) {
38510
+ return join(this.getUserDirectory(userId), `${sanitizedId}.json`);
38511
+ }
38512
+ async save(userId, definition) {
38513
+ const directory = this.getUserDirectory(userId);
38514
+ const sanitized = sanitizeId2(definition.id);
38515
+ const filePath = this.getRoutinePath(userId, sanitized);
38516
+ await this.ensureDirectory(directory);
38517
+ const stored = { version: STORAGE_VERSION, definition };
38518
+ const data = this.prettyPrint ? JSON.stringify(stored, null, 2) : JSON.stringify(stored);
38519
+ const tempPath = `${filePath}.tmp`;
38520
+ try {
38521
+ await promises.writeFile(tempPath, data, "utf-8");
38522
+ await promises.rename(tempPath, filePath);
38523
+ } catch (error) {
38524
+ try {
38525
+ await promises.unlink(tempPath);
38526
+ } catch {
38527
+ }
38528
+ throw error;
38529
+ }
38530
+ await this.updateIndex(userId, definition);
38531
+ }
38532
+ async load(userId, id) {
38533
+ const sanitized = sanitizeId2(id);
38534
+ const filePath = this.getRoutinePath(userId, sanitized);
38535
+ try {
38536
+ const data = await promises.readFile(filePath, "utf-8");
38537
+ const stored = JSON.parse(data);
38538
+ return stored.definition;
38539
+ } catch (error) {
38540
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
38541
+ return null;
38542
+ }
38543
+ if (error instanceof SyntaxError) {
38544
+ return null;
38545
+ }
38546
+ throw error;
38547
+ }
38548
+ }
38549
+ async delete(userId, id) {
38550
+ const sanitized = sanitizeId2(id);
38551
+ const filePath = this.getRoutinePath(userId, sanitized);
38552
+ try {
38553
+ await promises.unlink(filePath);
38554
+ } catch (error) {
38555
+ if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
38556
+ throw error;
38557
+ }
38558
+ }
38559
+ await this.removeFromIndex(userId, id);
38560
+ }
38561
+ async exists(userId, id) {
38562
+ const sanitized = sanitizeId2(id);
38563
+ const filePath = this.getRoutinePath(userId, sanitized);
38564
+ try {
38565
+ await promises.access(filePath);
38566
+ return true;
38567
+ } catch {
38568
+ return false;
38569
+ }
38570
+ }
38571
+ async list(userId, options) {
38572
+ const index = await this.loadIndex(userId);
38573
+ let entries = [...index.routines];
38574
+ if (options?.tags && options.tags.length > 0) {
38575
+ entries = entries.filter((e) => {
38576
+ const entryTags = e.tags ?? [];
38577
+ return options.tags.some((t) => entryTags.includes(t));
38578
+ });
38579
+ }
38580
+ if (options?.search) {
38581
+ const searchLower = options.search.toLowerCase();
38582
+ entries = entries.filter(
38583
+ (e) => e.name.toLowerCase().includes(searchLower) || e.description.toLowerCase().includes(searchLower)
38584
+ );
38585
+ }
38586
+ entries.sort(
38587
+ (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
38588
+ );
38589
+ if (options?.offset) {
38590
+ entries = entries.slice(options.offset);
38591
+ }
38592
+ if (options?.limit) {
38593
+ entries = entries.slice(0, options.limit);
38594
+ }
38595
+ const results = [];
38596
+ for (const entry of entries) {
38597
+ const def = await this.load(userId, entry.id);
38598
+ if (def) {
38599
+ results.push(def);
38600
+ }
38601
+ }
38602
+ return results;
38603
+ }
38604
+ getPath(userId) {
38605
+ return this.getUserDirectory(userId);
38606
+ }
38607
+ // ==========================================================================
38608
+ // Private Helpers
38609
+ // ==========================================================================
38610
+ async ensureDirectory(dir) {
38611
+ try {
38612
+ await promises.mkdir(dir, { recursive: true });
38613
+ } catch (error) {
38614
+ if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
38615
+ throw error;
38616
+ }
38617
+ }
38618
+ }
38619
+ async loadIndex(userId) {
38620
+ const indexPath = this.getIndexPath(userId);
38621
+ try {
38622
+ const data = await promises.readFile(indexPath, "utf-8");
38623
+ return JSON.parse(data);
38624
+ } catch (error) {
38625
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
38626
+ return await this.rebuildIndex(userId);
38627
+ }
38628
+ throw error;
38629
+ }
38630
+ }
38631
+ async saveIndex(userId, index) {
38632
+ const directory = this.getUserDirectory(userId);
38633
+ const indexPath = this.getIndexPath(userId);
38634
+ await this.ensureDirectory(directory);
38635
+ index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
38636
+ const data = this.prettyPrint ? JSON.stringify(index, null, 2) : JSON.stringify(index);
38637
+ await promises.writeFile(indexPath, data, "utf-8");
38638
+ }
38639
+ async updateIndex(userId, definition) {
38640
+ const index = await this.loadIndex(userId);
38641
+ const entry = this.definitionToIndexEntry(definition);
38642
+ const existingIdx = index.routines.findIndex((e) => e.id === definition.id);
38643
+ if (existingIdx >= 0) {
38644
+ index.routines[existingIdx] = entry;
38645
+ } else {
38646
+ index.routines.push(entry);
38647
+ }
38648
+ await this.saveIndex(userId, index);
38649
+ }
38650
+ async removeFromIndex(userId, id) {
38651
+ const index = await this.loadIndex(userId);
38652
+ index.routines = index.routines.filter((e) => e.id !== id);
38653
+ await this.saveIndex(userId, index);
38654
+ }
38655
+ definitionToIndexEntry(definition) {
38656
+ return {
38657
+ id: definition.id,
38658
+ name: definition.name,
38659
+ description: definition.description,
38660
+ tags: definition.tags,
38661
+ author: definition.author,
38662
+ updatedAt: definition.updatedAt
38663
+ };
38664
+ }
38665
+ /**
38666
+ * Rebuild index by scanning directory for .json files (excluding _index.json).
38667
+ * Returns empty index if directory doesn't exist.
38668
+ */
38669
+ async rebuildIndex(userId) {
38670
+ const directory = this.getUserDirectory(userId);
38671
+ const index = {
38672
+ version: 1,
38673
+ routines: [],
38674
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
38675
+ };
38676
+ let files;
38677
+ try {
38678
+ files = await promises.readdir(directory);
38679
+ } catch {
38680
+ return index;
38681
+ }
38682
+ for (const file of files) {
38683
+ if (!file.endsWith(".json") || file === "_index.json") continue;
38684
+ try {
38685
+ const data = await promises.readFile(join(directory, file), "utf-8");
38686
+ const stored = JSON.parse(data);
38687
+ if (stored.definition) {
38688
+ index.routines.push(this.definitionToIndexEntry(stored.definition));
38689
+ }
38690
+ } catch {
38691
+ }
38692
+ }
38693
+ if (index.routines.length > 0) {
38694
+ await this.saveIndex(userId, index);
38695
+ }
38696
+ return index;
38697
+ }
38698
+ };
38699
+ function createFileRoutineDefinitionStorage(config) {
38700
+ return new FileRoutineDefinitionStorage(config);
38701
+ }
37806
38702
 
37807
38703
  // src/domain/entities/CustomToolDefinition.ts
37808
38704
  var CUSTOM_TOOL_DEFINITION_VERSION = 1;
@@ -38903,8 +39799,8 @@ var FileStorage = class {
38903
39799
  }
38904
39800
  async ensureDirectory() {
38905
39801
  try {
38906
- await fs17.mkdir(this.directory, { recursive: true });
38907
- await fs17.chmod(this.directory, 448);
39802
+ await fs18.mkdir(this.directory, { recursive: true });
39803
+ await fs18.chmod(this.directory, 448);
38908
39804
  } catch (error) {
38909
39805
  }
38910
39806
  }
@@ -38920,13 +39816,13 @@ var FileStorage = class {
38920
39816
  const filePath = this.getFilePath(key);
38921
39817
  const plaintext = JSON.stringify(token);
38922
39818
  const encrypted = encrypt(plaintext, this.encryptionKey);
38923
- await fs17.writeFile(filePath, encrypted, "utf8");
38924
- await fs17.chmod(filePath, 384);
39819
+ await fs18.writeFile(filePath, encrypted, "utf8");
39820
+ await fs18.chmod(filePath, 384);
38925
39821
  }
38926
39822
  async getToken(key) {
38927
39823
  const filePath = this.getFilePath(key);
38928
39824
  try {
38929
- const encrypted = await fs17.readFile(filePath, "utf8");
39825
+ const encrypted = await fs18.readFile(filePath, "utf8");
38930
39826
  const decrypted = decrypt(encrypted, this.encryptionKey);
38931
39827
  return JSON.parse(decrypted);
38932
39828
  } catch (error) {
@@ -38935,7 +39831,7 @@ var FileStorage = class {
38935
39831
  }
38936
39832
  console.error("Failed to read/decrypt token file:", error);
38937
39833
  try {
38938
- await fs17.unlink(filePath);
39834
+ await fs18.unlink(filePath);
38939
39835
  } catch {
38940
39836
  }
38941
39837
  return null;
@@ -38944,7 +39840,7 @@ var FileStorage = class {
38944
39840
  async deleteToken(key) {
38945
39841
  const filePath = this.getFilePath(key);
38946
39842
  try {
38947
- await fs17.unlink(filePath);
39843
+ await fs18.unlink(filePath);
38948
39844
  } catch (error) {
38949
39845
  if (error.code !== "ENOENT") {
38950
39846
  throw error;
@@ -38954,7 +39850,7 @@ var FileStorage = class {
38954
39850
  async hasToken(key) {
38955
39851
  const filePath = this.getFilePath(key);
38956
39852
  try {
38957
- await fs17.access(filePath);
39853
+ await fs18.access(filePath);
38958
39854
  return true;
38959
39855
  } catch {
38960
39856
  return false;
@@ -38965,7 +39861,7 @@ var FileStorage = class {
38965
39861
  */
38966
39862
  async listTokens() {
38967
39863
  try {
38968
- const files = await fs17.readdir(this.directory);
39864
+ const files = await fs18.readdir(this.directory);
38969
39865
  return files.filter((f) => f.endsWith(".token")).map((f) => f.replace(".token", ""));
38970
39866
  } catch {
38971
39867
  return [];
@@ -38976,10 +39872,10 @@ var FileStorage = class {
38976
39872
  */
38977
39873
  async clearAll() {
38978
39874
  try {
38979
- const files = await fs17.readdir(this.directory);
39875
+ const files = await fs18.readdir(this.directory);
38980
39876
  const tokenFiles = files.filter((f) => f.endsWith(".token"));
38981
39877
  await Promise.all(
38982
- tokenFiles.map((f) => fs17.unlink(path2.join(this.directory, f)).catch(() => {
39878
+ tokenFiles.map((f) => fs18.unlink(path2.join(this.directory, f)).catch(() => {
38983
39879
  }))
38984
39880
  );
38985
39881
  } catch {
@@ -39427,14 +40323,14 @@ var FileConnectorStorage = class {
39427
40323
  await this.ensureDirectory();
39428
40324
  const filePath = this.getFilePath(name);
39429
40325
  const json = JSON.stringify(stored, null, 2);
39430
- await fs17.writeFile(filePath, json, "utf8");
39431
- await fs17.chmod(filePath, 384);
40326
+ await fs18.writeFile(filePath, json, "utf8");
40327
+ await fs18.chmod(filePath, 384);
39432
40328
  await this.updateIndex(name, "add");
39433
40329
  }
39434
40330
  async get(name) {
39435
40331
  const filePath = this.getFilePath(name);
39436
40332
  try {
39437
- const json = await fs17.readFile(filePath, "utf8");
40333
+ const json = await fs18.readFile(filePath, "utf8");
39438
40334
  return JSON.parse(json);
39439
40335
  } catch (error) {
39440
40336
  const err = error;
@@ -39447,7 +40343,7 @@ var FileConnectorStorage = class {
39447
40343
  async delete(name) {
39448
40344
  const filePath = this.getFilePath(name);
39449
40345
  try {
39450
- await fs17.unlink(filePath);
40346
+ await fs18.unlink(filePath);
39451
40347
  await this.updateIndex(name, "remove");
39452
40348
  return true;
39453
40349
  } catch (error) {
@@ -39461,7 +40357,7 @@ var FileConnectorStorage = class {
39461
40357
  async has(name) {
39462
40358
  const filePath = this.getFilePath(name);
39463
40359
  try {
39464
- await fs17.access(filePath);
40360
+ await fs18.access(filePath);
39465
40361
  return true;
39466
40362
  } catch {
39467
40363
  return false;
@@ -39487,13 +40383,13 @@ var FileConnectorStorage = class {
39487
40383
  */
39488
40384
  async clear() {
39489
40385
  try {
39490
- const files = await fs17.readdir(this.directory);
40386
+ const files = await fs18.readdir(this.directory);
39491
40387
  const connectorFiles = files.filter(
39492
40388
  (f) => f.endsWith(".connector.json") || f === "_index.json"
39493
40389
  );
39494
40390
  await Promise.all(
39495
40391
  connectorFiles.map(
39496
- (f) => fs17.unlink(path2.join(this.directory, f)).catch(() => {
40392
+ (f) => fs18.unlink(path2.join(this.directory, f)).catch(() => {
39497
40393
  })
39498
40394
  )
39499
40395
  );
@@ -39520,8 +40416,8 @@ var FileConnectorStorage = class {
39520
40416
  async ensureDirectory() {
39521
40417
  if (this.initialized) return;
39522
40418
  try {
39523
- await fs17.mkdir(this.directory, { recursive: true });
39524
- await fs17.chmod(this.directory, 448);
40419
+ await fs18.mkdir(this.directory, { recursive: true });
40420
+ await fs18.chmod(this.directory, 448);
39525
40421
  this.initialized = true;
39526
40422
  } catch {
39527
40423
  this.initialized = true;
@@ -39532,7 +40428,7 @@ var FileConnectorStorage = class {
39532
40428
  */
39533
40429
  async loadIndex() {
39534
40430
  try {
39535
- const json = await fs17.readFile(this.indexPath, "utf8");
40431
+ const json = await fs18.readFile(this.indexPath, "utf8");
39536
40432
  return JSON.parse(json);
39537
40433
  } catch {
39538
40434
  return { connectors: {} };
@@ -39550,8 +40446,8 @@ var FileConnectorStorage = class {
39550
40446
  delete index.connectors[hash];
39551
40447
  }
39552
40448
  const json = JSON.stringify(index, null, 2);
39553
- await fs17.writeFile(this.indexPath, json, "utf8");
39554
- await fs17.chmod(this.indexPath, 384);
40449
+ await fs18.writeFile(this.indexPath, json, "utf8");
40450
+ await fs18.chmod(this.indexPath, 384);
39555
40451
  }
39556
40452
  };
39557
40453
 
@@ -42006,8 +42902,8 @@ function createMessageWithImages(text, imageUrls, role = "user" /* USER */) {
42006
42902
  var execAsync = promisify(exec);
42007
42903
  function cleanupTempFile(filePath) {
42008
42904
  try {
42009
- if (fs18.existsSync(filePath)) {
42010
- fs18.unlinkSync(filePath);
42905
+ if (fs19.existsSync(filePath)) {
42906
+ fs19.unlinkSync(filePath);
42011
42907
  }
42012
42908
  } catch {
42013
42909
  }
@@ -42058,7 +42954,7 @@ async function readClipboardImageMac() {
42058
42954
  end try
42059
42955
  `;
42060
42956
  const { stdout } = await execAsync(`osascript -e '${script}'`);
42061
- if (stdout.includes("success") || fs18.existsSync(tempFile)) {
42957
+ if (stdout.includes("success") || fs19.existsSync(tempFile)) {
42062
42958
  return await convertFileToDataUri(tempFile);
42063
42959
  }
42064
42960
  return {
@@ -42075,14 +42971,14 @@ async function readClipboardImageLinux() {
42075
42971
  try {
42076
42972
  try {
42077
42973
  await execAsync(`xclip -selection clipboard -t image/png -o > "${tempFile}"`);
42078
- if (fs18.existsSync(tempFile) && fs18.statSync(tempFile).size > 0) {
42974
+ if (fs19.existsSync(tempFile) && fs19.statSync(tempFile).size > 0) {
42079
42975
  return await convertFileToDataUri(tempFile);
42080
42976
  }
42081
42977
  } catch {
42082
42978
  }
42083
42979
  try {
42084
42980
  await execAsync(`wl-paste -t image/png > "${tempFile}"`);
42085
- if (fs18.existsSync(tempFile) && fs18.statSync(tempFile).size > 0) {
42981
+ if (fs19.existsSync(tempFile) && fs19.statSync(tempFile).size > 0) {
42086
42982
  return await convertFileToDataUri(tempFile);
42087
42983
  }
42088
42984
  } catch {
@@ -42109,7 +43005,7 @@ async function readClipboardImageWindows() {
42109
43005
  }
42110
43006
  `;
42111
43007
  await execAsync(`powershell -Command "${psScript}"`);
42112
- if (fs18.existsSync(tempFile) && fs18.statSync(tempFile).size > 0) {
43008
+ if (fs19.existsSync(tempFile) && fs19.statSync(tempFile).size > 0) {
42113
43009
  return await convertFileToDataUri(tempFile);
42114
43010
  }
42115
43011
  return {
@@ -42122,7 +43018,7 @@ async function readClipboardImageWindows() {
42122
43018
  }
42123
43019
  async function convertFileToDataUri(filePath) {
42124
43020
  try {
42125
- const imageBuffer = fs18.readFileSync(filePath);
43021
+ const imageBuffer = fs19.readFileSync(filePath);
42126
43022
  const base64Image = imageBuffer.toString("base64");
42127
43023
  const magic = imageBuffer.slice(0, 4).toString("hex");
42128
43024
  let mimeType = "image/png";
@@ -42181,186 +43077,6 @@ async function hasClipboardImage() {
42181
43077
  }
42182
43078
  }
42183
43079
 
42184
- // src/utils/jsonExtractor.ts
42185
- function extractJSON(text) {
42186
- if (!text || typeof text !== "string") {
42187
- return {
42188
- success: false,
42189
- error: "Input is empty or not a string"
42190
- };
42191
- }
42192
- const trimmedText = text.trim();
42193
- const codeBlockResult = extractFromCodeBlock(trimmedText);
42194
- if (codeBlockResult.success) {
42195
- return codeBlockResult;
42196
- }
42197
- const inlineResult = extractInlineJSON(trimmedText);
42198
- if (inlineResult.success) {
42199
- return inlineResult;
42200
- }
42201
- try {
42202
- const data = JSON.parse(trimmedText);
42203
- return {
42204
- success: true,
42205
- data,
42206
- rawJson: trimmedText,
42207
- method: "raw"
42208
- };
42209
- } catch (e) {
42210
- return {
42211
- success: false,
42212
- error: `Could not extract JSON from text: ${e instanceof Error ? e.message : String(e)}`
42213
- };
42214
- }
42215
- }
42216
- function extractFromCodeBlock(text) {
42217
- const codeBlockRegex = /```(?:json)?\s*([\s\S]*?)```/g;
42218
- let match;
42219
- while ((match = codeBlockRegex.exec(text)) !== null) {
42220
- const content = match[1];
42221
- if (content) {
42222
- const trimmed = content.trim();
42223
- try {
42224
- const data = JSON.parse(trimmed);
42225
- return {
42226
- success: true,
42227
- data,
42228
- rawJson: trimmed,
42229
- method: "code_block"
42230
- };
42231
- } catch {
42232
- continue;
42233
- }
42234
- }
42235
- }
42236
- return { success: false };
42237
- }
42238
- function extractInlineJSON(text) {
42239
- const objectMatch = findJSONObject(text);
42240
- if (objectMatch) {
42241
- try {
42242
- const data = JSON.parse(objectMatch);
42243
- return {
42244
- success: true,
42245
- data,
42246
- rawJson: objectMatch,
42247
- method: "inline"
42248
- };
42249
- } catch {
42250
- }
42251
- }
42252
- const arrayMatch = findJSONArray(text);
42253
- if (arrayMatch) {
42254
- try {
42255
- const data = JSON.parse(arrayMatch);
42256
- return {
42257
- success: true,
42258
- data,
42259
- rawJson: arrayMatch,
42260
- method: "inline"
42261
- };
42262
- } catch {
42263
- }
42264
- }
42265
- return { success: false };
42266
- }
42267
- function findJSONObject(text) {
42268
- const startIndex = text.indexOf("{");
42269
- if (startIndex === -1) return null;
42270
- let depth = 0;
42271
- let inString = false;
42272
- let escaped = false;
42273
- for (let i = startIndex; i < text.length; i++) {
42274
- const char = text[i];
42275
- if (escaped) {
42276
- escaped = false;
42277
- continue;
42278
- }
42279
- if (char === "\\" && inString) {
42280
- escaped = true;
42281
- continue;
42282
- }
42283
- if (char === '"') {
42284
- inString = !inString;
42285
- continue;
42286
- }
42287
- if (inString) continue;
42288
- if (char === "{") {
42289
- depth++;
42290
- } else if (char === "}") {
42291
- depth--;
42292
- if (depth === 0) {
42293
- return text.slice(startIndex, i + 1);
42294
- }
42295
- }
42296
- }
42297
- return null;
42298
- }
42299
- function findJSONArray(text) {
42300
- const startIndex = text.indexOf("[");
42301
- if (startIndex === -1) return null;
42302
- let depth = 0;
42303
- let inString = false;
42304
- let escaped = false;
42305
- for (let i = startIndex; i < text.length; i++) {
42306
- const char = text[i];
42307
- if (escaped) {
42308
- escaped = false;
42309
- continue;
42310
- }
42311
- if (char === "\\" && inString) {
42312
- escaped = true;
42313
- continue;
42314
- }
42315
- if (char === '"') {
42316
- inString = !inString;
42317
- continue;
42318
- }
42319
- if (inString) continue;
42320
- if (char === "[") {
42321
- depth++;
42322
- } else if (char === "]") {
42323
- depth--;
42324
- if (depth === 0) {
42325
- return text.slice(startIndex, i + 1);
42326
- }
42327
- }
42328
- }
42329
- return null;
42330
- }
42331
- function extractJSONField(text, field, defaultValue) {
42332
- const result = extractJSON(text);
42333
- if (result.success && result.data && field in result.data) {
42334
- return result.data[field];
42335
- }
42336
- return defaultValue;
42337
- }
42338
- function extractNumber(text, patterns = [
42339
- /(\d{1,3})%?\s*(?:complete|score|percent)/i,
42340
- /(?:score|completion|rating)[:\s]+(\d{1,3})/i,
42341
- /(\d{1,3})\s*(?:out of|\/)\s*100/i
42342
- ], defaultValue = 0) {
42343
- const jsonResult = extractJSON(text);
42344
- if (jsonResult.success && jsonResult.data) {
42345
- const scoreFields = ["score", "completionScore", "completion_score", "rating", "percent", "value"];
42346
- for (const field of scoreFields) {
42347
- if (field in jsonResult.data && typeof jsonResult.data[field] === "number") {
42348
- return jsonResult.data[field];
42349
- }
42350
- }
42351
- }
42352
- for (const pattern of patterns) {
42353
- const match = text.match(pattern);
42354
- if (match && match[1]) {
42355
- const num = parseInt(match[1], 10);
42356
- if (!isNaN(num)) {
42357
- return num;
42358
- }
42359
- }
42360
- }
42361
- return defaultValue;
42362
- }
42363
-
42364
43080
  // src/tools/index.ts
42365
43081
  var tools_exports = {};
42366
43082
  __export(tools_exports, {
@@ -42396,19 +43112,25 @@ __export(tools_exports, {
42396
43112
  createDesktopScreenshotTool: () => createDesktopScreenshotTool,
42397
43113
  createDesktopWindowFocusTool: () => createDesktopWindowFocusTool,
42398
43114
  createDesktopWindowListTool: () => createDesktopWindowListTool,
43115
+ createDraftEmailTool: () => createDraftEmailTool,
42399
43116
  createEditFileTool: () => createEditFileTool,
43117
+ createEditMeetingTool: () => createEditMeetingTool,
42400
43118
  createExecuteJavaScriptTool: () => createExecuteJavaScriptTool,
43119
+ createFindMeetingSlotsTool: () => createFindMeetingSlotsTool,
43120
+ createGetMeetingTranscriptTool: () => createGetMeetingTranscriptTool,
42401
43121
  createGetPRTool: () => createGetPRTool,
42402
43122
  createGitHubReadFileTool: () => createGitHubReadFileTool,
42403
43123
  createGlobTool: () => createGlobTool,
42404
43124
  createGrepTool: () => createGrepTool,
42405
43125
  createImageGenerationTool: () => createImageGenerationTool,
42406
43126
  createListDirectoryTool: () => createListDirectoryTool,
43127
+ createMeetingTool: () => createMeetingTool,
42407
43128
  createPRCommentsTool: () => createPRCommentsTool,
42408
43129
  createPRFilesTool: () => createPRFilesTool,
42409
43130
  createReadFileTool: () => createReadFileTool,
42410
43131
  createSearchCodeTool: () => createSearchCodeTool,
42411
43132
  createSearchFilesTool: () => createSearchFilesTool,
43133
+ createSendEmailTool: () => createSendEmailTool,
42412
43134
  createSpeechToTextTool: () => createSpeechToTextTool,
42413
43135
  createTextToSpeechTool: () => createTextToSpeechTool,
42414
43136
  createVideoTools: () => createVideoTools,
@@ -42438,6 +43160,8 @@ __export(tools_exports, {
42438
43160
  executeInVM: () => executeInVM,
42439
43161
  executeJavaScript: () => executeJavaScript,
42440
43162
  expandTilde: () => expandTilde,
43163
+ formatAttendees: () => formatAttendees,
43164
+ formatRecipients: () => formatRecipients,
42441
43165
  getAllBuiltInTools: () => getAllBuiltInTools,
42442
43166
  getBackgroundOutput: () => getBackgroundOutput,
42443
43167
  getDesktopDriver: () => getDesktopDriver,
@@ -42448,19 +43172,24 @@ __export(tools_exports, {
42448
43172
  getToolRegistry: () => getToolRegistry,
42449
43173
  getToolsByCategory: () => getToolsByCategory,
42450
43174
  getToolsRequiringConnector: () => getToolsRequiringConnector,
43175
+ getUserPathPrefix: () => getUserPathPrefix,
42451
43176
  glob: () => glob,
42452
43177
  grep: () => grep,
42453
43178
  hydrateCustomTool: () => hydrateCustomTool,
42454
43179
  isBlockedCommand: () => isBlockedCommand,
42455
43180
  isExcludedExtension: () => isExcludedExtension,
43181
+ isTeamsMeetingUrl: () => isTeamsMeetingUrl,
42456
43182
  jsonManipulator: () => jsonManipulator,
42457
43183
  killBackgroundProcess: () => killBackgroundProcess,
42458
43184
  listDirectory: () => listDirectory,
42459
43185
  mergeTextPieces: () => mergeTextPieces,
43186
+ microsoftFetch: () => microsoftFetch,
43187
+ normalizeEmails: () => normalizeEmails,
42460
43188
  parseKeyCombo: () => parseKeyCombo,
42461
43189
  parseRepository: () => parseRepository,
42462
43190
  readFile: () => readFile5,
42463
43191
  resetDefaultDriver: () => resetDefaultDriver,
43192
+ resolveMeetingId: () => resolveMeetingId,
42464
43193
  resolveRepository: () => resolveRepository,
42465
43194
  setMediaOutputHandler: () => setMediaOutputHandler,
42466
43195
  setMediaStorage: () => setMediaStorage,
@@ -46542,6 +47271,840 @@ function registerGitHubTools() {
46542
47271
  // src/tools/github/index.ts
46543
47272
  registerGitHubTools();
46544
47273
 
47274
+ // src/tools/microsoft/types.ts
47275
+ function getUserPathPrefix(connector, targetUser) {
47276
+ const auth2 = connector.config.auth;
47277
+ if (auth2.type === "oauth" && auth2.flow === "client_credentials") {
47278
+ if (!targetUser) {
47279
+ throw new Error(
47280
+ 'targetUser is required when using client_credentials (application) flow. Provide a user ID or UPN (e.g., "user@domain.com").'
47281
+ );
47282
+ }
47283
+ return `/users/${targetUser}`;
47284
+ }
47285
+ return "/me";
47286
+ }
47287
+ var MicrosoftAPIError = class extends Error {
47288
+ constructor(status, statusText, body) {
47289
+ const msg = typeof body === "object" && body !== null && "error" in body ? body.error?.message ?? statusText : statusText;
47290
+ super(`Microsoft Graph API error ${status}: ${msg}`);
47291
+ this.status = status;
47292
+ this.statusText = statusText;
47293
+ this.body = body;
47294
+ this.name = "MicrosoftAPIError";
47295
+ }
47296
+ };
47297
+ async function microsoftFetch(connector, endpoint, options) {
47298
+ let url2 = endpoint;
47299
+ if (options?.queryParams && Object.keys(options.queryParams).length > 0) {
47300
+ const params = new URLSearchParams();
47301
+ for (const [key, value] of Object.entries(options.queryParams)) {
47302
+ params.append(key, String(value));
47303
+ }
47304
+ url2 += (url2.includes("?") ? "&" : "?") + params.toString();
47305
+ }
47306
+ const headers = {
47307
+ "Accept": options?.accept ?? "application/json"
47308
+ };
47309
+ if (options?.body) {
47310
+ headers["Content-Type"] = "application/json";
47311
+ }
47312
+ const response = await connector.fetch(
47313
+ url2,
47314
+ {
47315
+ method: options?.method ?? "GET",
47316
+ headers,
47317
+ body: options?.body ? JSON.stringify(options.body) : void 0
47318
+ },
47319
+ options?.userId
47320
+ );
47321
+ const text = await response.text();
47322
+ if (!response.ok) {
47323
+ let data;
47324
+ try {
47325
+ data = JSON.parse(text);
47326
+ } catch {
47327
+ data = text;
47328
+ }
47329
+ throw new MicrosoftAPIError(response.status, response.statusText, data);
47330
+ }
47331
+ if (!text || text.trim().length === 0) {
47332
+ return void 0;
47333
+ }
47334
+ try {
47335
+ return JSON.parse(text);
47336
+ } catch {
47337
+ return text;
47338
+ }
47339
+ }
47340
+ function normalizeEmails(input) {
47341
+ return input.map((item) => {
47342
+ if (typeof item === "string") return item;
47343
+ if (typeof item === "object" && item !== null) {
47344
+ const obj = item;
47345
+ if (obj.emailAddress && typeof obj.emailAddress === "object") {
47346
+ const ea = obj.emailAddress;
47347
+ if (typeof ea.address === "string") return ea.address;
47348
+ }
47349
+ if (typeof obj.address === "string") return obj.address;
47350
+ if (typeof obj.email === "string") return obj.email;
47351
+ }
47352
+ return String(item);
47353
+ });
47354
+ }
47355
+ function formatRecipients(emails) {
47356
+ return normalizeEmails(emails).map((address) => ({ emailAddress: { address } }));
47357
+ }
47358
+ function formatAttendees(emails) {
47359
+ return normalizeEmails(emails).map((address) => ({
47360
+ emailAddress: { address },
47361
+ type: "required"
47362
+ }));
47363
+ }
47364
+ function isTeamsMeetingUrl(input) {
47365
+ try {
47366
+ const url2 = new URL(input.trim());
47367
+ return (url2.hostname === "teams.microsoft.com" || url2.hostname === "teams.live.com") && url2.pathname.includes("meetup-join");
47368
+ } catch {
47369
+ return false;
47370
+ }
47371
+ }
47372
+ async function resolveMeetingId(connector, input, prefix, effectiveUserId) {
47373
+ if (!input || input.trim().length === 0) {
47374
+ throw new Error("Meeting ID cannot be empty");
47375
+ }
47376
+ const trimmed = input.trim();
47377
+ if (!isTeamsMeetingUrl(trimmed)) {
47378
+ return { meetingId: trimmed };
47379
+ }
47380
+ const meetings = await microsoftFetch(
47381
+ connector,
47382
+ `${prefix}/onlineMeetings`,
47383
+ {
47384
+ userId: effectiveUserId,
47385
+ queryParams: { "$filter": `JoinWebUrl eq '${trimmed}'` }
47386
+ }
47387
+ );
47388
+ if (!meetings.value || meetings.value.length === 0) {
47389
+ throw new Error(
47390
+ `Could not find an online meeting matching the provided Teams URL. Make sure the URL is correct and you have access to this meeting.`
47391
+ );
47392
+ }
47393
+ return {
47394
+ meetingId: meetings.value[0].id,
47395
+ subject: meetings.value[0].subject
47396
+ };
47397
+ }
47398
+
47399
+ // src/tools/microsoft/createDraftEmail.ts
47400
+ function createDraftEmailTool(connector, userId) {
47401
+ return {
47402
+ definition: {
47403
+ type: "function",
47404
+ function: {
47405
+ name: "create_draft_email",
47406
+ description: `Create a draft email or draft reply in the user's Outlook mailbox via Microsoft Graph. The draft is saved but NOT sent \u2014 use send_email to send immediately instead.
47407
+
47408
+ PARAMETER FORMATS:
47409
+ - to/cc: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects.
47410
+ - subject: plain string. Example: "Project update" or "Re: Project update" for replies.
47411
+ - body: HTML string. Example: "<p>Hi Alice,</p><p>Here is the update.</p>". Use <p>, <br>, <b>, <ul> tags for formatting.
47412
+ - replyToMessageId: Graph message ID string (starts with "AAMk..."). Only set when replying to an existing email.
47413
+
47414
+ EXAMPLES:
47415
+ - New draft: { "to": ["alice@contoso.com"], "subject": "Project update", "body": "<p>Hi Alice,</p><p>Here is the update.</p>" }
47416
+ - Reply draft: { "to": ["alice@contoso.com"], "subject": "Re: Project update", "body": "<p>Thanks!</p>", "replyToMessageId": "AAMkADI1..." }
47417
+ - With CC: { "to": ["alice@contoso.com"], "subject": "Notes", "body": "<p>See attached.</p>", "cc": ["bob@contoso.com"] }`,
47418
+ parameters: {
47419
+ type: "object",
47420
+ properties: {
47421
+ to: {
47422
+ type: "array",
47423
+ items: { type: "string" },
47424
+ description: 'Recipient email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]'
47425
+ },
47426
+ subject: {
47427
+ type: "string",
47428
+ description: 'Email subject as plain string. Example: "Project update" or "Re: Original subject" for replies.'
47429
+ },
47430
+ body: {
47431
+ type: "string",
47432
+ description: 'Email body as an HTML string. Example: "<p>Hello!</p><p>See you tomorrow.</p>"'
47433
+ },
47434
+ cc: {
47435
+ type: "array",
47436
+ items: { type: "string" },
47437
+ description: 'CC email addresses as plain strings. Example: ["bob@contoso.com"]. Optional.'
47438
+ },
47439
+ replyToMessageId: {
47440
+ type: "string",
47441
+ description: 'Graph message ID of the email to reply to. Example: "AAMkADI1M2I3YzgtODg...". When set, creates a threaded reply draft.'
47442
+ },
47443
+ targetUser: {
47444
+ type: "string",
47445
+ description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
47446
+ }
47447
+ },
47448
+ required: ["to", "subject", "body"]
47449
+ }
47450
+ }
47451
+ },
47452
+ describeCall: (args) => {
47453
+ const action = args.replyToMessageId ? "Reply draft" : "Draft";
47454
+ return `${action} to ${args.to.join(", ")}: ${args.subject}`;
47455
+ },
47456
+ permission: {
47457
+ scope: "session",
47458
+ riskLevel: "medium",
47459
+ approvalMessage: `Create a draft email via ${connector.displayName}`
47460
+ },
47461
+ execute: async (args, context) => {
47462
+ const effectiveUserId = context?.userId ?? userId;
47463
+ try {
47464
+ const prefix = getUserPathPrefix(connector, args.targetUser);
47465
+ if (args.replyToMessageId) {
47466
+ const replyDraft = await microsoftFetch(
47467
+ connector,
47468
+ `${prefix}/messages/${args.replyToMessageId}/createReply`,
47469
+ { method: "POST", userId: effectiveUserId, body: {} }
47470
+ );
47471
+ const updated = await microsoftFetch(
47472
+ connector,
47473
+ `${prefix}/messages/${replyDraft.id}`,
47474
+ {
47475
+ method: "PATCH",
47476
+ userId: effectiveUserId,
47477
+ body: {
47478
+ subject: args.subject,
47479
+ body: { contentType: "HTML", content: args.body },
47480
+ toRecipients: formatRecipients(args.to),
47481
+ ...args.cc && { ccRecipients: formatRecipients(args.cc) }
47482
+ }
47483
+ }
47484
+ );
47485
+ return {
47486
+ success: true,
47487
+ draftId: updated.id,
47488
+ webLink: updated.webLink
47489
+ };
47490
+ }
47491
+ const draft = await microsoftFetch(
47492
+ connector,
47493
+ `${prefix}/messages`,
47494
+ {
47495
+ method: "POST",
47496
+ userId: effectiveUserId,
47497
+ body: {
47498
+ isDraft: true,
47499
+ subject: args.subject,
47500
+ body: { contentType: "HTML", content: args.body },
47501
+ toRecipients: formatRecipients(args.to),
47502
+ ...args.cc && { ccRecipients: formatRecipients(args.cc) }
47503
+ }
47504
+ }
47505
+ );
47506
+ return {
47507
+ success: true,
47508
+ draftId: draft.id,
47509
+ webLink: draft.webLink
47510
+ };
47511
+ } catch (error) {
47512
+ return {
47513
+ success: false,
47514
+ error: `Failed to create draft email: ${error instanceof Error ? error.message : String(error)}`
47515
+ };
47516
+ }
47517
+ }
47518
+ };
47519
+ }
47520
+
47521
+ // src/tools/microsoft/sendEmail.ts
47522
+ function createSendEmailTool(connector, userId) {
47523
+ return {
47524
+ definition: {
47525
+ type: "function",
47526
+ function: {
47527
+ name: "send_email",
47528
+ description: `Send an email immediately or reply to an existing message via Microsoft Graph (Outlook). The email is sent right away \u2014 use create_draft_email to save a draft instead.
47529
+
47530
+ PARAMETER FORMATS:
47531
+ - to/cc: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects.
47532
+ - subject: plain string. Example: "Meeting tomorrow" or "Re: Meeting tomorrow" for replies.
47533
+ - body: HTML string. Example: "<p>Hi Alice,</p><p>Can we meet at 2pm?</p>". Use <p>, <br>, <b>, <ul> tags.
47534
+ - replyToMessageId: Graph message ID string (starts with "AAMk..."). Only set when replying to an existing email.
47535
+
47536
+ EXAMPLES:
47537
+ - Send email: { "to": ["alice@contoso.com"], "subject": "Meeting tomorrow", "body": "<p>Can we meet at 2pm?</p>" }
47538
+ - Reply: { "to": ["alice@contoso.com"], "subject": "Re: Meeting", "body": "<p>Confirmed!</p>", "replyToMessageId": "AAMkADI1..." }
47539
+ - With CC: { "to": ["alice@contoso.com"], "subject": "Update", "body": "<p>FYI</p>", "cc": ["bob@contoso.com"] }`,
47540
+ parameters: {
47541
+ type: "object",
47542
+ properties: {
47543
+ to: {
47544
+ type: "array",
47545
+ items: { type: "string" },
47546
+ description: 'Recipient email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]'
47547
+ },
47548
+ subject: {
47549
+ type: "string",
47550
+ description: 'Email subject as plain string. Example: "Meeting tomorrow" or "Re: Original subject" for replies.'
47551
+ },
47552
+ body: {
47553
+ type: "string",
47554
+ description: 'Email body as an HTML string. Example: "<p>Hi!</p><p>Can we meet at 2pm?</p>"'
47555
+ },
47556
+ cc: {
47557
+ type: "array",
47558
+ items: { type: "string" },
47559
+ description: 'CC email addresses as plain strings. Example: ["bob@contoso.com"]. Optional.'
47560
+ },
47561
+ replyToMessageId: {
47562
+ type: "string",
47563
+ description: 'Graph message ID of the email to reply to. Example: "AAMkADI1M2I3YzgtODg...". When set, sends a threaded reply.'
47564
+ },
47565
+ targetUser: {
47566
+ type: "string",
47567
+ description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
47568
+ }
47569
+ },
47570
+ required: ["to", "subject", "body"]
47571
+ }
47572
+ }
47573
+ },
47574
+ describeCall: (args) => {
47575
+ const action = args.replyToMessageId ? "Reply" : "Send";
47576
+ return `${action} to ${args.to.join(", ")}: ${args.subject}`;
47577
+ },
47578
+ permission: {
47579
+ scope: "session",
47580
+ riskLevel: "medium",
47581
+ approvalMessage: `Send an email via ${connector.displayName}`
47582
+ },
47583
+ execute: async (args, context) => {
47584
+ const effectiveUserId = context?.userId ?? userId;
47585
+ try {
47586
+ const prefix = getUserPathPrefix(connector, args.targetUser);
47587
+ if (args.replyToMessageId) {
47588
+ await microsoftFetch(
47589
+ connector,
47590
+ `${prefix}/messages/${args.replyToMessageId}/reply`,
47591
+ {
47592
+ method: "POST",
47593
+ userId: effectiveUserId,
47594
+ body: {
47595
+ message: {
47596
+ toRecipients: formatRecipients(args.to),
47597
+ ...args.cc && { ccRecipients: formatRecipients(args.cc) }
47598
+ },
47599
+ comment: args.body
47600
+ }
47601
+ }
47602
+ );
47603
+ } else {
47604
+ await microsoftFetch(
47605
+ connector,
47606
+ `${prefix}/sendMail`,
47607
+ {
47608
+ method: "POST",
47609
+ userId: effectiveUserId,
47610
+ body: {
47611
+ message: {
47612
+ subject: args.subject,
47613
+ body: { contentType: "HTML", content: args.body },
47614
+ toRecipients: formatRecipients(args.to),
47615
+ ...args.cc && { ccRecipients: formatRecipients(args.cc) }
47616
+ },
47617
+ saveToSentItems: true
47618
+ }
47619
+ }
47620
+ );
47621
+ }
47622
+ return { success: true };
47623
+ } catch (error) {
47624
+ return {
47625
+ success: false,
47626
+ error: `Failed to send email: ${error instanceof Error ? error.message : String(error)}`
47627
+ };
47628
+ }
47629
+ }
47630
+ };
47631
+ }
47632
+
47633
+ // src/tools/microsoft/createMeeting.ts
47634
+ function createMeetingTool(connector, userId) {
47635
+ return {
47636
+ definition: {
47637
+ type: "function",
47638
+ function: {
47639
+ name: "create_meeting",
47640
+ description: `Create a calendar event on the user's Outlook calendar via Microsoft Graph, optionally with a Teams online meeting link.
47641
+
47642
+ PARAMETER FORMATS:
47643
+ - subject: plain string. Example: "Sprint Review"
47644
+ - startDateTime/endDateTime: ISO 8601 string WITHOUT timezone suffix (timezone is a separate param). Example: "2025-01-15T09:00:00"
47645
+ - attendees: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects.
47646
+ - body: HTML string for the invitation body. Example: "<p>Agenda: discuss Q1 goals</p>". Optional.
47647
+ - timeZone: IANA timezone string. Example: "America/New_York", "Europe/Zurich". Default: "UTC".
47648
+ - isOnlineMeeting: boolean. Set true to auto-generate a Teams meeting link.
47649
+ - location: plain string. Example: "Conference Room A". Optional.
47650
+
47651
+ EXAMPLES:
47652
+ - Simple: { "subject": "Standup", "startDateTime": "2025-01-15T09:00:00", "endDateTime": "2025-01-15T09:30:00", "attendees": ["alice@contoso.com"], "timeZone": "America/New_York" }
47653
+ - Teams: { "subject": "Sprint Review", "startDateTime": "2025-01-15T14:00:00", "endDateTime": "2025-01-15T15:00:00", "attendees": ["alice@contoso.com", "bob@contoso.com"], "isOnlineMeeting": true }`,
47654
+ parameters: {
47655
+ type: "object",
47656
+ properties: {
47657
+ subject: {
47658
+ type: "string",
47659
+ description: 'Meeting title as plain string. Example: "Sprint Review"'
47660
+ },
47661
+ startDateTime: {
47662
+ type: "string",
47663
+ description: 'Start date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T09:00:00"'
47664
+ },
47665
+ endDateTime: {
47666
+ type: "string",
47667
+ description: 'End date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T09:30:00"'
47668
+ },
47669
+ attendees: {
47670
+ type: "array",
47671
+ items: { type: "string" },
47672
+ description: 'Attendee email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]'
47673
+ },
47674
+ body: {
47675
+ type: "string",
47676
+ description: 'Meeting description as HTML string. Example: "<p>Agenda: discuss Q1 goals</p>". Optional.'
47677
+ },
47678
+ isOnlineMeeting: {
47679
+ type: "boolean",
47680
+ description: "Set to true to generate a Teams online meeting link. Default: false."
47681
+ },
47682
+ location: {
47683
+ type: "string",
47684
+ description: 'Physical location as plain string. Example: "Conference Room A". Optional.'
47685
+ },
47686
+ timeZone: {
47687
+ type: "string",
47688
+ description: 'IANA timezone string for start/end times. Example: "America/New_York", "Europe/Zurich". Default: "UTC".'
47689
+ },
47690
+ targetUser: {
47691
+ type: "string",
47692
+ description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
47693
+ }
47694
+ },
47695
+ required: ["subject", "startDateTime", "endDateTime", "attendees"]
47696
+ }
47697
+ }
47698
+ },
47699
+ describeCall: (args) => {
47700
+ return `Create meeting: ${args.subject} (${args.attendees.length} attendees)`;
47701
+ },
47702
+ permission: {
47703
+ scope: "session",
47704
+ riskLevel: "medium",
47705
+ approvalMessage: `Create a calendar event via ${connector.displayName}`
47706
+ },
47707
+ execute: async (args, context) => {
47708
+ const effectiveUserId = context?.userId ?? userId;
47709
+ try {
47710
+ const prefix = getUserPathPrefix(connector, args.targetUser);
47711
+ const tz = args.timeZone ?? "UTC";
47712
+ const eventBody = {
47713
+ subject: args.subject,
47714
+ start: { dateTime: args.startDateTime, timeZone: tz },
47715
+ end: { dateTime: args.endDateTime, timeZone: tz },
47716
+ attendees: formatAttendees(args.attendees)
47717
+ };
47718
+ if (args.body) {
47719
+ eventBody.body = { contentType: "HTML", content: args.body };
47720
+ }
47721
+ if (args.isOnlineMeeting) {
47722
+ eventBody.isOnlineMeeting = true;
47723
+ eventBody.onlineMeetingProvider = "teamsForBusiness";
47724
+ }
47725
+ if (args.location) {
47726
+ eventBody.location = { displayName: args.location };
47727
+ }
47728
+ const event = await microsoftFetch(
47729
+ connector,
47730
+ `${prefix}/events`,
47731
+ { method: "POST", userId: effectiveUserId, body: eventBody }
47732
+ );
47733
+ return {
47734
+ success: true,
47735
+ eventId: event.id,
47736
+ webLink: event.webLink,
47737
+ onlineMeetingUrl: event.onlineMeeting?.joinUrl
47738
+ };
47739
+ } catch (error) {
47740
+ return {
47741
+ success: false,
47742
+ error: `Failed to create meeting: ${error instanceof Error ? error.message : String(error)}`
47743
+ };
47744
+ }
47745
+ }
47746
+ };
47747
+ }
47748
+
47749
+ // src/tools/microsoft/editMeeting.ts
47750
+ function createEditMeetingTool(connector, userId) {
47751
+ return {
47752
+ definition: {
47753
+ type: "function",
47754
+ function: {
47755
+ name: "edit_meeting",
47756
+ description: `Update an existing Outlook calendar event via Microsoft Graph. Only the fields you provide will be changed \u2014 omitted fields keep their current values.
47757
+
47758
+ IMPORTANT: The "attendees" field REPLACES the entire attendee list. Include ALL desired attendees (both new and existing), not just the ones you want to add.
47759
+
47760
+ PARAMETER FORMATS:
47761
+ - eventId: Graph event ID string (starts with "AAMk..."). Get this from a previous create_meeting result.
47762
+ - subject: plain string. Example: "Updated: Sprint Review"
47763
+ - startDateTime/endDateTime: ISO 8601 string without timezone suffix. Example: "2025-01-15T10:00:00"
47764
+ - attendees: plain string array of email addresses. Example: ["alice@contoso.com", "charlie@contoso.com"]. Do NOT use objects. REPLACES all attendees.
47765
+ - body: HTML string. Example: "<p>Updated agenda</p>"
47766
+ - timeZone: IANA timezone string. Example: "Europe/Zurich". Default: "UTC".
47767
+ - isOnlineMeeting: boolean. true = add Teams link, false = remove it.
47768
+ - location: plain string. Example: "Room 201"
47769
+
47770
+ EXAMPLES:
47771
+ - Reschedule: { "eventId": "AAMkADI1...", "startDateTime": "2025-01-15T10:00:00", "endDateTime": "2025-01-15T10:30:00", "timeZone": "America/New_York" }
47772
+ - Change attendees: { "eventId": "AAMkADI1...", "attendees": ["alice@contoso.com", "charlie@contoso.com"] }
47773
+ - Add Teams link: { "eventId": "AAMkADI1...", "isOnlineMeeting": true }`,
47774
+ parameters: {
47775
+ type: "object",
47776
+ properties: {
47777
+ eventId: {
47778
+ type: "string",
47779
+ description: 'Calendar event ID string from create_meeting result. Example: "AAMkADI1M2I3YzgtODg..."'
47780
+ },
47781
+ subject: {
47782
+ type: "string",
47783
+ description: 'New meeting title as plain string. Example: "Updated: Sprint Review"'
47784
+ },
47785
+ startDateTime: {
47786
+ type: "string",
47787
+ description: 'New start date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T10:00:00"'
47788
+ },
47789
+ endDateTime: {
47790
+ type: "string",
47791
+ description: 'New end date/time as ISO 8601 string without timezone suffix. Example: "2025-01-15T10:30:00"'
47792
+ },
47793
+ attendees: {
47794
+ type: "array",
47795
+ items: { type: "string" },
47796
+ description: 'FULL replacement attendee list as plain email strings. Example: ["alice@contoso.com", "charlie@contoso.com"]. Include ALL attendees.'
47797
+ },
47798
+ body: {
47799
+ type: "string",
47800
+ description: 'New meeting description as HTML string. Example: "<p>Updated agenda</p>"'
47801
+ },
47802
+ isOnlineMeeting: {
47803
+ type: "boolean",
47804
+ description: "true to add Teams meeting link, false to remove it."
47805
+ },
47806
+ location: {
47807
+ type: "string",
47808
+ description: 'New location as plain string. Example: "Conference Room A"'
47809
+ },
47810
+ timeZone: {
47811
+ type: "string",
47812
+ description: 'IANA timezone string for start/end times. Example: "Europe/Zurich". Default: "UTC".'
47813
+ },
47814
+ targetUser: {
47815
+ type: "string",
47816
+ description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
47817
+ }
47818
+ },
47819
+ required: ["eventId"]
47820
+ }
47821
+ }
47822
+ },
47823
+ describeCall: (args) => {
47824
+ const fields = ["subject", "startDateTime", "endDateTime", "attendees", "body", "location"];
47825
+ const changed = fields.filter((f) => args[f] !== void 0);
47826
+ return `Edit meeting ${args.eventId.slice(0, 12)}... (${changed.join(", ") || "no changes"})`;
47827
+ },
47828
+ permission: {
47829
+ scope: "session",
47830
+ riskLevel: "medium",
47831
+ approvalMessage: `Update a calendar event via ${connector.displayName}`
47832
+ },
47833
+ execute: async (args, context) => {
47834
+ const effectiveUserId = context?.userId ?? userId;
47835
+ try {
47836
+ const prefix = getUserPathPrefix(connector, args.targetUser);
47837
+ const tz = args.timeZone ?? "UTC";
47838
+ const patchBody = {};
47839
+ if (args.subject !== void 0) patchBody.subject = args.subject;
47840
+ if (args.body !== void 0) patchBody.body = { contentType: "HTML", content: args.body };
47841
+ if (args.startDateTime !== void 0) patchBody.start = { dateTime: args.startDateTime, timeZone: tz };
47842
+ if (args.endDateTime !== void 0) patchBody.end = { dateTime: args.endDateTime, timeZone: tz };
47843
+ if (args.attendees !== void 0) {
47844
+ patchBody.attendees = formatAttendees(args.attendees);
47845
+ }
47846
+ if (args.isOnlineMeeting !== void 0) {
47847
+ patchBody.isOnlineMeeting = args.isOnlineMeeting;
47848
+ if (args.isOnlineMeeting) {
47849
+ patchBody.onlineMeetingProvider = "teamsForBusiness";
47850
+ }
47851
+ }
47852
+ if (args.location !== void 0) {
47853
+ patchBody.location = { displayName: args.location };
47854
+ }
47855
+ const event = await microsoftFetch(
47856
+ connector,
47857
+ `${prefix}/events/${args.eventId}`,
47858
+ { method: "PATCH", userId: effectiveUserId, body: patchBody }
47859
+ );
47860
+ return {
47861
+ success: true,
47862
+ eventId: event.id,
47863
+ webLink: event.webLink
47864
+ };
47865
+ } catch (error) {
47866
+ return {
47867
+ success: false,
47868
+ error: `Failed to edit meeting: ${error instanceof Error ? error.message : String(error)}`
47869
+ };
47870
+ }
47871
+ }
47872
+ };
47873
+ }
47874
+
47875
+ // src/tools/microsoft/getMeetingTranscript.ts
47876
+ function parseVttToText(vtt) {
47877
+ const lines = vtt.split("\n");
47878
+ const textLines = [];
47879
+ for (const line of lines) {
47880
+ const trimmed = line.trim();
47881
+ if (trimmed === "" || trimmed === "WEBVTT" || trimmed.startsWith("NOTE") || /^\d+$/.test(trimmed) || /^\d{2}:\d{2}/.test(trimmed)) {
47882
+ continue;
47883
+ }
47884
+ textLines.push(trimmed);
47885
+ }
47886
+ return textLines.join("\n");
47887
+ }
47888
+ function createGetMeetingTranscriptTool(connector, userId) {
47889
+ return {
47890
+ definition: {
47891
+ type: "function",
47892
+ function: {
47893
+ name: "get_meeting_transcript",
47894
+ description: `Retrieve the transcript from a Teams online meeting via Microsoft Graph. Returns plain text with speaker labels (VTT timestamps are stripped).
47895
+
47896
+ NOTE: Requires the OnlineMeetingTranscript.Read.All permission. Transcription must have been enabled during the meeting.
47897
+
47898
+ USAGE:
47899
+ - Provide the Teams online meeting ID (NOT the calendar event ID \u2014 this is different) or a Teams meeting join URL
47900
+ - The meetingId can be found in the Teams meeting details or extracted from the join URL
47901
+
47902
+ EXAMPLES:
47903
+ - By meeting ID: { "meetingId": "MSo1N2Y5ZGFjYy03MWJmLTQ3NDMtYjQxMy01M2EdFGkdRWHJlQ" }
47904
+ - By Teams join URL: { "meetingId": "https://teams.microsoft.com/l/meetup-join/19%3ameeting_MjA5YjFi..." }`,
47905
+ parameters: {
47906
+ type: "object",
47907
+ properties: {
47908
+ meetingId: {
47909
+ type: "string",
47910
+ description: 'Teams online meeting ID (e.g. "MSo1N2Y5...") or Teams meeting join URL. This is NOT the calendar event ID.'
47911
+ },
47912
+ targetUser: {
47913
+ type: "string",
47914
+ description: "User ID or email (UPN) to act on behalf of. Only needed for app-only (client_credentials) auth. Ignored in delegated auth."
47915
+ }
47916
+ },
47917
+ required: ["meetingId"]
47918
+ }
47919
+ }
47920
+ },
47921
+ describeCall: (args) => {
47922
+ return `Get transcript for meeting ${args.meetingId.slice(0, 20)}...`;
47923
+ },
47924
+ permission: {
47925
+ scope: "session",
47926
+ riskLevel: "low",
47927
+ approvalMessage: `Get a meeting transcript via ${connector.displayName}`
47928
+ },
47929
+ execute: async (args, context) => {
47930
+ const effectiveUserId = context?.userId ?? userId;
47931
+ try {
47932
+ const prefix = getUserPathPrefix(connector, args.targetUser);
47933
+ const resolved = await resolveMeetingId(connector, args.meetingId, prefix, effectiveUserId);
47934
+ const meetingId = resolved.meetingId;
47935
+ const transcriptList = await microsoftFetch(
47936
+ connector,
47937
+ `${prefix}/onlineMeetings/${meetingId}/transcripts`,
47938
+ { userId: effectiveUserId }
47939
+ );
47940
+ if (!transcriptList.value || transcriptList.value.length === 0) {
47941
+ return {
47942
+ success: false,
47943
+ error: "No transcripts found for this meeting. The meeting may not have had transcription enabled."
47944
+ };
47945
+ }
47946
+ const transcriptId = transcriptList.value[0].id;
47947
+ const contentUrl = `${prefix}/onlineMeetings/${meetingId}/transcripts/${transcriptId}/content`;
47948
+ const response = await connector.fetch(
47949
+ contentUrl + "?$format=text/vtt",
47950
+ { method: "GET", headers: { "Accept": "text/vtt" } },
47951
+ effectiveUserId
47952
+ );
47953
+ if (!response.ok) {
47954
+ const errorText = await response.text();
47955
+ return {
47956
+ success: false,
47957
+ error: `Failed to fetch transcript content: ${response.status} ${errorText}`
47958
+ };
47959
+ }
47960
+ const vttContent = await response.text();
47961
+ const transcript = parseVttToText(vttContent);
47962
+ return {
47963
+ success: true,
47964
+ transcript,
47965
+ meetingSubject: resolved.subject
47966
+ };
47967
+ } catch (error) {
47968
+ return {
47969
+ success: false,
47970
+ error: `Failed to get meeting transcript: ${error instanceof Error ? error.message : String(error)}`
47971
+ };
47972
+ }
47973
+ }
47974
+ };
47975
+ }
47976
+
47977
+ // src/tools/microsoft/findMeetingSlots.ts
47978
+ function createFindMeetingSlotsTool(connector, userId) {
47979
+ return {
47980
+ definition: {
47981
+ type: "function",
47982
+ function: {
47983
+ name: "find_meeting_slots",
47984
+ description: `Find available meeting time slots when all attendees are free, via Microsoft Graph. Checks each attendee's Outlook calendar and suggests times when everyone is available.
47985
+
47986
+ PARAMETER FORMATS:
47987
+ - attendees: plain string array of email addresses. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT use objects \u2014 just plain email strings.
47988
+ - startDateTime/endDateTime: ISO 8601 string without timezone suffix. Example: "2025-01-15T08:00:00". Can span multiple days.
47989
+ - duration: number of minutes as integer. Example: 30 or 60.
47990
+ - timeZone: IANA timezone string. Example: "America/New_York", "Europe/Zurich". Default: "UTC".
47991
+ - maxResults: integer. Default: 5.
47992
+
47993
+ EXAMPLES:
47994
+ - Find 30min slot: { "attendees": ["alice@contoso.com", "bob@contoso.com"], "startDateTime": "2025-01-15T08:00:00", "endDateTime": "2025-01-15T18:00:00", "duration": 30, "timeZone": "America/New_York" }
47995
+ - Find 1hr slot across days: { "attendees": ["alice@contoso.com"], "startDateTime": "2025-01-15T08:00:00", "endDateTime": "2025-01-17T18:00:00", "duration": 60, "maxResults": 10 }`,
47996
+ parameters: {
47997
+ type: "object",
47998
+ properties: {
47999
+ attendees: {
48000
+ type: "array",
48001
+ items: { type: "string" },
48002
+ description: 'Attendee email addresses as plain strings. Example: ["alice@contoso.com", "bob@contoso.com"]. Do NOT pass objects.'
48003
+ },
48004
+ startDateTime: {
48005
+ type: "string",
48006
+ description: 'Search window start as ISO 8601 string without timezone suffix. Example: "2025-01-15T08:00:00"'
48007
+ },
48008
+ endDateTime: {
48009
+ type: "string",
48010
+ description: 'Search window end as ISO 8601 string without timezone suffix. Example: "2025-01-15T18:00:00". Can span multiple days.'
48011
+ },
48012
+ duration: {
48013
+ type: "number",
48014
+ description: "Meeting duration in minutes as integer. Example: 30 or 60."
48015
+ },
48016
+ timeZone: {
48017
+ type: "string",
48018
+ description: 'IANA timezone string for start/end times. Example: "America/New_York", "Europe/Zurich". Default: "UTC".'
48019
+ },
48020
+ maxResults: {
48021
+ type: "number",
48022
+ description: "Maximum number of time slot suggestions as integer. Default: 5."
48023
+ },
48024
+ targetUser: {
48025
+ type: "string",
48026
+ description: 'User ID or email (UPN) for app-only auth. Example: "alice@contoso.com". Ignored in delegated auth.'
48027
+ }
48028
+ },
48029
+ required: ["attendees", "startDateTime", "endDateTime", "duration"]
48030
+ }
48031
+ }
48032
+ },
48033
+ describeCall: (args) => {
48034
+ return `Find ${args.duration}min slots for ${args.attendees.length} attendees`;
48035
+ },
48036
+ permission: {
48037
+ scope: "session",
48038
+ riskLevel: "low",
48039
+ approvalMessage: `Find meeting time slots via ${connector.displayName}`
48040
+ },
48041
+ execute: async (args, context) => {
48042
+ const effectiveUserId = context?.userId ?? userId;
48043
+ try {
48044
+ const prefix = getUserPathPrefix(connector, args.targetUser);
48045
+ const tz = args.timeZone ?? "UTC";
48046
+ const result = await microsoftFetch(
48047
+ connector,
48048
+ `${prefix}/findMeetingTimes`,
48049
+ {
48050
+ method: "POST",
48051
+ userId: effectiveUserId,
48052
+ body: {
48053
+ attendees: formatAttendees(args.attendees),
48054
+ timeConstraint: {
48055
+ timeslots: [
48056
+ {
48057
+ start: { dateTime: args.startDateTime, timeZone: tz },
48058
+ end: { dateTime: args.endDateTime, timeZone: tz }
48059
+ }
48060
+ ]
48061
+ },
48062
+ meetingDuration: `PT${args.duration}M`,
48063
+ maxCandidates: args.maxResults ?? 5
48064
+ }
48065
+ }
48066
+ );
48067
+ const slots = (result.meetingTimeSuggestions ?? []).map((s) => ({
48068
+ start: s.meetingTimeSlot.start.dateTime,
48069
+ end: s.meetingTimeSlot.end.dateTime,
48070
+ confidence: String(s.confidence),
48071
+ attendeeAvailability: (s.attendeeAvailability ?? []).map((a) => ({
48072
+ attendee: a.attendee.emailAddress.address,
48073
+ availability: a.availability
48074
+ }))
48075
+ }));
48076
+ return {
48077
+ success: true,
48078
+ slots,
48079
+ emptySuggestionsReason: result.emptySuggestionsReason
48080
+ };
48081
+ } catch (error) {
48082
+ return {
48083
+ success: false,
48084
+ error: `Failed to find meeting slots: ${error instanceof Error ? error.message : String(error)}`
48085
+ };
48086
+ }
48087
+ }
48088
+ };
48089
+ }
48090
+
48091
+ // src/tools/microsoft/register.ts
48092
+ function registerMicrosoftTools() {
48093
+ ConnectorTools.registerService("microsoft", (connector, userId) => {
48094
+ return [
48095
+ createDraftEmailTool(connector, userId),
48096
+ createSendEmailTool(connector, userId),
48097
+ createMeetingTool(connector, userId),
48098
+ createEditMeetingTool(connector, userId),
48099
+ createGetMeetingTranscriptTool(connector, userId),
48100
+ createFindMeetingSlotsTool(connector, userId)
48101
+ ];
48102
+ });
48103
+ }
48104
+
48105
+ // src/tools/microsoft/index.ts
48106
+ registerMicrosoftTools();
48107
+
46545
48108
  // src/tools/desktop/types.ts
46546
48109
  var DEFAULT_DESKTOP_CONFIG = {
46547
48110
  driver: null,
@@ -48528,6 +50091,6 @@ REMEMBER: Keep it conversational, ask one question at a time, and only output th
48528
50091
  }
48529
50092
  };
48530
50093
 
48531
- export { AGENT_DEFINITION_FORMAT_VERSION, AIError, APPROVAL_STATE_VERSION, Agent, AgentContextNextGen, ApproximateTokenEstimator, BaseMediaProvider, BasePluginNextGen, BaseProvider, BaseTextProvider, BraveProvider, CONNECTOR_CONFIG_VERSION, CONTEXT_SESSION_FORMAT_VERSION, CUSTOM_TOOL_DEFINITION_VERSION, CheckpointManager, CircuitBreaker, CircuitOpenError, Connector, ConnectorConfigStore, ConnectorTools, ConsoleMetrics, ContentType, ContextOverflowError, DEFAULT_ALLOWLIST, DEFAULT_BACKOFF_CONFIG, DEFAULT_BASE_DELAY_MS, DEFAULT_CHECKPOINT_STRATEGY, DEFAULT_CIRCUIT_BREAKER_CONFIG, DEFAULT_CONFIG2 as DEFAULT_CONFIG, DEFAULT_CONNECTOR_TIMEOUT, DEFAULT_CONTEXT_CONFIG, DEFAULT_DESKTOP_CONFIG, DEFAULT_FEATURES, DEFAULT_FILESYSTEM_CONFIG, DEFAULT_HISTORY_MANAGER_CONFIG, DEFAULT_MAX_DELAY_MS, DEFAULT_MAX_RETRIES, DEFAULT_MEMORY_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_RATE_LIMITER_CONFIG, DEFAULT_RETRYABLE_STATUSES, DEFAULT_SHELL_CONFIG, DESKTOP_TOOL_NAMES, DefaultCompactionStrategy, DependencyCycleError, DocumentReader, ErrorHandler, ExecutionContext, ExternalDependencyHandler, FileAgentDefinitionStorage, FileConnectorStorage, FileContextStorage, FileCustomToolStorage, FileMediaStorage as FileMediaOutputHandler, FileMediaStorage, FilePersistentInstructionsStorage, FileStorage, FileUserInfoStorage, FormatDetector, FrameworkLogger, HookManager, IMAGE_MODELS, IMAGE_MODEL_REGISTRY, ImageGeneration, InContextMemoryPluginNextGen, InMemoryAgentStateStorage, InMemoryHistoryStorage, InMemoryMetrics, InMemoryPlanStorage, InMemoryStorage, InvalidConfigError, InvalidToolArgumentsError, LLM_MODELS, LoggingPlugin, MCPClient, MCPConnectionError, MCPError, MCPProtocolError, MCPRegistry, MCPResourceError, MCPTimeoutError, MCPToolError, MEMORY_PRIORITY_VALUES, MODEL_REGISTRY, MemoryConnectorStorage, MemoryEvictionCompactor, MemoryStorage, MessageBuilder, MessageRole, ModelNotSupportedError, NoOpMetrics, NutTreeDriver, OAuthManager, ParallelTasksError, PersistentInstructionsPluginNextGen, PlanningAgent, ProviderAuthError, ProviderConfigAgent, ProviderContextLengthError, ProviderError, ProviderErrorMapper, ProviderNotFoundError, ProviderRateLimitError, RapidAPIProvider, RateLimitError, SERVICE_DEFINITIONS, SERVICE_INFO, SERVICE_URL_PATTERNS, SIMPLE_ICONS_CDN, STT_MODELS, STT_MODEL_REGISTRY, ScopedConnectorRegistry, ScrapeProvider, SearchProvider, SerperProvider, Services, SpeechToText, StorageRegistry, StrategyRegistry, StreamEventType, StreamHelpers, StreamState, SummarizeCompactor, TERMINAL_TASK_STATUSES, TTS_MODELS, TTS_MODEL_REGISTRY, TaskTimeoutError, TaskValidationError, TavilyProvider, TextToSpeech, TokenBucketRateLimiter, ToolCallState, ToolExecutionError, ToolExecutionPipeline, ToolManager, ToolNotFoundError, ToolPermissionManager, ToolRegistry, ToolTimeoutError, TruncateCompactor, UserInfoPluginNextGen, VENDORS, VENDOR_ICON_MAP, VIDEO_MODELS, VIDEO_MODEL_REGISTRY, Vendor, VideoGeneration, WorkingMemory, WorkingMemoryPluginNextGen, addJitter, allVendorTemplates, assertNotDestroyed, authenticatedFetch, backoffSequence, backoffWait, bash, buildAuthConfig, buildEndpointWithQuery, buildQueryString, calculateBackoff, calculateCost, calculateEntrySize, calculateImageCost, calculateSTTCost, calculateTTSCost, calculateVideoCost, canTaskExecute, createAgentStorage, createAuthenticatedFetch, createBashTool, createConnectorFromTemplate, createCreatePRTool, createCustomToolDelete, createCustomToolDraft, createCustomToolList, createCustomToolLoad, createCustomToolMetaTools, createCustomToolSave, createCustomToolTest, createDesktopGetCursorTool, createDesktopGetScreenSizeTool, createDesktopKeyboardKeyTool, createDesktopKeyboardTypeTool, createDesktopMouseClickTool, createDesktopMouseDragTool, createDesktopMouseMoveTool, createDesktopMouseScrollTool, createDesktopScreenshotTool, createDesktopWindowFocusTool, createDesktopWindowListTool, createEditFileTool, createEstimator, createExecuteJavaScriptTool, createFileAgentDefinitionStorage, createFileContextStorage, createFileCustomToolStorage, createFileMediaStorage, createGetPRTool, createGitHubReadFileTool, createGlobTool, createGrepTool, createImageGenerationTool, createImageProvider, createListDirectoryTool, createMessageWithImages, createMetricsCollector, createPRCommentsTool, createPRFilesTool, createPlan, createProvider, createReadFileTool, createSearchCodeTool, createSearchFilesTool, createSpeechToTextTool, createTask, createTextMessage, createTextToSpeechTool, createVideoProvider, createVideoTools, createWriteFileTool, customToolDelete, customToolDraft, customToolList, customToolLoad, customToolSave, customToolTest, defaultDescribeCall, desktopGetCursor, desktopGetScreenSize, desktopKeyboardKey, desktopKeyboardType, desktopMouseClick, desktopMouseDrag, desktopMouseMove, desktopMouseScroll, desktopScreenshot, desktopTools, desktopWindowFocus, desktopWindowList, detectDependencyCycle, detectServiceFromURL, developerTools, documentToContent, editFile, evaluateCondition, extractJSON, extractJSONField, extractNumber, findConnectorByServiceTypes, forPlan, forTasks, generateEncryptionKey, generateSimplePlan, generateWebAPITool, getActiveImageModels, getActiveModels, getActiveSTTModels, getActiveTTSModels, getActiveVideoModels, getAllBuiltInTools, getAllServiceIds, getAllVendorLogos, getAllVendorTemplates, getBackgroundOutput, getConnectorTools, getCredentialsSetupURL, getDesktopDriver, getDocsURL, getImageModelInfo, getImageModelsByVendor, getImageModelsWithFeature, getMediaOutputHandler, getMediaStorage, getModelInfo, getModelsByVendor, getNextExecutableTasks, getRegisteredScrapeProviders, getSTTModelInfo, getSTTModelsByVendor, getSTTModelsWithFeature, getServiceDefinition, getServiceInfo, getServicesByCategory, getTTSModelInfo, getTTSModelsByVendor, getTTSModelsWithFeature, getTaskDependencies, getToolByName, getToolCallDescription, getToolCategories, getToolRegistry, getToolsByCategory, getToolsRequiringConnector, getVendorAuthTemplate, getVendorColor, getVendorDefaultBaseURL, getVendorInfo, getVendorLogo, getVendorLogoCdnUrl, getVendorLogoSvg, getVendorTemplate, getVideoModelInfo, getVideoModelsByVendor, getVideoModelsWithAudio, getVideoModelsWithFeature, glob, globalErrorHandler, grep, hasClipboardImage, hasVendorLogo, hydrateCustomTool, isBlockedCommand, isErrorEvent, isExcludedExtension, isKnownService, isOutputTextDelta, isResponseComplete, isSimpleScope, isStreamEvent, isTaskAwareScope, isTaskBlocked, isTerminalMemoryStatus, isTerminalStatus, isToolCallArgumentsDelta, isToolCallArgumentsDone, isToolCallStart, isVendor, killBackgroundProcess, listConnectorsByServiceTypes, listDirectory, listVendorIds, listVendors, listVendorsByAuthType, listVendorsByCategory, listVendorsWithLogos, logger, mergeTextPieces, metrics, parseKeyCombo, parseRepository, readClipboardImage, readDocumentAsContent, readFile5 as readFile, registerScrapeProvider, resetDefaultDriver, resolveConnector, resolveDependencies, resolveMaxContextTokens, resolveModelCapabilities, resolveRepository, retryWithBackoff, sanitizeToolName, scopeEquals, scopeMatches, setMediaOutputHandler, setMediaStorage, setMetricsCollector, simpleTokenEstimator, toConnectorOptions, toolRegistry, tools_exports as tools, updateTaskStatus, validatePath, writeFile5 as writeFile };
50094
+ export { AGENT_DEFINITION_FORMAT_VERSION, AIError, APPROVAL_STATE_VERSION, Agent, AgentContextNextGen, ApproximateTokenEstimator, BaseMediaProvider, BasePluginNextGen, BaseProvider, BaseTextProvider, BraveProvider, CONNECTOR_CONFIG_VERSION, CONTEXT_SESSION_FORMAT_VERSION, CUSTOM_TOOL_DEFINITION_VERSION, CheckpointManager, CircuitBreaker, CircuitOpenError, Connector, ConnectorConfigStore, ConnectorTools, ConsoleMetrics, ContentType, ContextOverflowError, DEFAULT_ALLOWLIST, DEFAULT_BACKOFF_CONFIG, DEFAULT_BASE_DELAY_MS, DEFAULT_CHECKPOINT_STRATEGY, DEFAULT_CIRCUIT_BREAKER_CONFIG, DEFAULT_CONFIG2 as DEFAULT_CONFIG, DEFAULT_CONNECTOR_TIMEOUT, DEFAULT_CONTEXT_CONFIG, DEFAULT_DESKTOP_CONFIG, DEFAULT_FEATURES, DEFAULT_FILESYSTEM_CONFIG, DEFAULT_HISTORY_MANAGER_CONFIG, DEFAULT_MAX_DELAY_MS, DEFAULT_MAX_RETRIES, DEFAULT_MEMORY_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_RATE_LIMITER_CONFIG, DEFAULT_RETRYABLE_STATUSES, DEFAULT_SHELL_CONFIG, DESKTOP_TOOL_NAMES, DefaultCompactionStrategy, DependencyCycleError, DocumentReader, ErrorHandler, ExecutionContext, ExternalDependencyHandler, FileAgentDefinitionStorage, FileConnectorStorage, FileContextStorage, FileCustomToolStorage, FileMediaStorage as FileMediaOutputHandler, FileMediaStorage, FilePersistentInstructionsStorage, FileRoutineDefinitionStorage, FileStorage, FileUserInfoStorage, FormatDetector, FrameworkLogger, HookManager, IMAGE_MODELS, IMAGE_MODEL_REGISTRY, ImageGeneration, InContextMemoryPluginNextGen, InMemoryAgentStateStorage, InMemoryHistoryStorage, InMemoryMetrics, InMemoryPlanStorage, InMemoryStorage, InvalidConfigError, InvalidToolArgumentsError, LLM_MODELS, LoggingPlugin, MCPClient, MCPConnectionError, MCPError, MCPProtocolError, MCPRegistry, MCPResourceError, MCPTimeoutError, MCPToolError, MEMORY_PRIORITY_VALUES, MODEL_REGISTRY, MemoryConnectorStorage, MemoryEvictionCompactor, MemoryStorage, MessageBuilder, MessageRole, ModelNotSupportedError, NoOpMetrics, NutTreeDriver, OAuthManager, ParallelTasksError, PersistentInstructionsPluginNextGen, PlanningAgent, ProviderAuthError, ProviderConfigAgent, ProviderContextLengthError, ProviderError, ProviderErrorMapper, ProviderNotFoundError, ProviderRateLimitError, RapidAPIProvider, RateLimitError, SERVICE_DEFINITIONS, SERVICE_INFO, SERVICE_URL_PATTERNS, SIMPLE_ICONS_CDN, STT_MODELS, STT_MODEL_REGISTRY, ScopedConnectorRegistry, ScrapeProvider, SearchProvider, SerperProvider, Services, SpeechToText, StorageRegistry, StrategyRegistry, StreamEventType, StreamHelpers, StreamState, SummarizeCompactor, TERMINAL_TASK_STATUSES, TTS_MODELS, TTS_MODEL_REGISTRY, TaskTimeoutError, TaskValidationError, TavilyProvider, TextToSpeech, TokenBucketRateLimiter, ToolCallState, ToolExecutionError, ToolExecutionPipeline, ToolManager, ToolNotFoundError, ToolPermissionManager, ToolRegistry, ToolTimeoutError, TruncateCompactor, UserInfoPluginNextGen, VENDORS, VENDOR_ICON_MAP, VIDEO_MODELS, VIDEO_MODEL_REGISTRY, Vendor, VideoGeneration, WorkingMemory, WorkingMemoryPluginNextGen, addJitter, allVendorTemplates, assertNotDestroyed, authenticatedFetch, backoffSequence, backoffWait, bash, buildAuthConfig, buildEndpointWithQuery, buildQueryString, calculateBackoff, calculateCost, calculateEntrySize, calculateImageCost, calculateSTTCost, calculateTTSCost, calculateVideoCost, canTaskExecute, createAgentStorage, createAuthenticatedFetch, createBashTool, createConnectorFromTemplate, createCreatePRTool, createCustomToolDelete, createCustomToolDraft, createCustomToolList, createCustomToolLoad, createCustomToolMetaTools, createCustomToolSave, createCustomToolTest, createDesktopGetCursorTool, createDesktopGetScreenSizeTool, createDesktopKeyboardKeyTool, createDesktopKeyboardTypeTool, createDesktopMouseClickTool, createDesktopMouseDragTool, createDesktopMouseMoveTool, createDesktopMouseScrollTool, createDesktopScreenshotTool, createDesktopWindowFocusTool, createDesktopWindowListTool, createDraftEmailTool, createEditFileTool, createEditMeetingTool, createEstimator, createExecuteJavaScriptTool, createFileAgentDefinitionStorage, createFileContextStorage, createFileCustomToolStorage, createFileMediaStorage, createFileRoutineDefinitionStorage, createFindMeetingSlotsTool, createGetMeetingTranscriptTool, createGetPRTool, createGitHubReadFileTool, createGlobTool, createGrepTool, createImageGenerationTool, createImageProvider, createListDirectoryTool, createMeetingTool, createMessageWithImages, createMetricsCollector, createPRCommentsTool, createPRFilesTool, createPlan, createProvider, createReadFileTool, createRoutineDefinition, createRoutineExecution, createSearchCodeTool, createSearchFilesTool, createSendEmailTool, createSpeechToTextTool, createTask, createTextMessage, createTextToSpeechTool, createVideoProvider, createVideoTools, createWriteFileTool, customToolDelete, customToolDraft, customToolList, customToolLoad, customToolSave, customToolTest, defaultDescribeCall, desktopGetCursor, desktopGetScreenSize, desktopKeyboardKey, desktopKeyboardType, desktopMouseClick, desktopMouseDrag, desktopMouseMove, desktopMouseScroll, desktopScreenshot, desktopTools, desktopWindowFocus, desktopWindowList, detectDependencyCycle, detectServiceFromURL, developerTools, documentToContent, editFile, evaluateCondition, executeRoutine, extractJSON, extractJSONField, extractNumber, findConnectorByServiceTypes, forPlan, forTasks, formatAttendees, formatRecipients, generateEncryptionKey, generateSimplePlan, generateWebAPITool, getActiveImageModels, getActiveModels, getActiveSTTModels, getActiveTTSModels, getActiveVideoModels, getAllBuiltInTools, getAllServiceIds, getAllVendorLogos, getAllVendorTemplates, getBackgroundOutput, getConnectorTools, getCredentialsSetupURL, getDesktopDriver, getDocsURL, getImageModelInfo, getImageModelsByVendor, getImageModelsWithFeature, getMediaOutputHandler, getMediaStorage, getModelInfo, getModelsByVendor, getNextExecutableTasks, getRegisteredScrapeProviders, getRoutineProgress, getSTTModelInfo, getSTTModelsByVendor, getSTTModelsWithFeature, getServiceDefinition, getServiceInfo, getServicesByCategory, getTTSModelInfo, getTTSModelsByVendor, getTTSModelsWithFeature, getTaskDependencies, getToolByName, getToolCallDescription, getToolCategories, getToolRegistry, getToolsByCategory, getToolsRequiringConnector, getUserPathPrefix, getVendorAuthTemplate, getVendorColor, getVendorDefaultBaseURL, getVendorInfo, getVendorLogo, getVendorLogoCdnUrl, getVendorLogoSvg, getVendorTemplate, getVideoModelInfo, getVideoModelsByVendor, getVideoModelsWithAudio, getVideoModelsWithFeature, glob, globalErrorHandler, grep, hasClipboardImage, hasVendorLogo, hydrateCustomTool, isBlockedCommand, isErrorEvent, isExcludedExtension, isKnownService, isOutputTextDelta, isResponseComplete, isSimpleScope, isStreamEvent, isTaskAwareScope, isTaskBlocked, isTeamsMeetingUrl, isTerminalMemoryStatus, isTerminalStatus, isToolCallArgumentsDelta, isToolCallArgumentsDone, isToolCallStart, isVendor, killBackgroundProcess, listConnectorsByServiceTypes, listDirectory, listVendorIds, listVendors, listVendorsByAuthType, listVendorsByCategory, listVendorsWithLogos, logger, mergeTextPieces, metrics, microsoftFetch, normalizeEmails, parseKeyCombo, parseRepository, readClipboardImage, readDocumentAsContent, readFile5 as readFile, registerScrapeProvider, resetDefaultDriver, resolveConnector, resolveDependencies, resolveMaxContextTokens, resolveMeetingId, resolveModelCapabilities, resolveRepository, retryWithBackoff, sanitizeToolName, scopeEquals, scopeMatches, setMediaOutputHandler, setMediaStorage, setMetricsCollector, simpleTokenEstimator, toConnectorOptions, toolRegistry, tools_exports as tools, updateTaskStatus, validatePath, writeFile5 as writeFile };
48532
50095
  //# sourceMappingURL=index.js.map
48533
50096
  //# sourceMappingURL=index.js.map