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