@eko-ai/eko 1.0.7 → 1.0.9
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 +72 -21
- package/dist/core/eko.d.ts +3 -2
- package/dist/extension/content/index.d.ts +1 -0
- package/dist/extension/tools/browser.d.ts +2 -1
- package/dist/extension/tools/get_all_tabs.d.ts +9 -0
- package/dist/extension/tools/index.d.ts +4 -1
- package/dist/extension/tools/request_login.d.ts +10 -0
- package/dist/extension/tools/tab_management.d.ts +1 -1
- package/dist/extension/utils.d.ts +2 -1
- package/dist/extension.cjs.js +797 -209
- package/dist/extension.esm.js +797 -209
- package/dist/extension_content_script.js +129 -2
- package/dist/index.cjs.js +518 -114
- package/dist/index.d.ts +2 -1
- package/dist/index.esm.js +518 -115
- package/dist/models/action.d.ts +9 -4
- package/dist/models/workflow.d.ts +8 -3
- package/dist/nodejs/script/build_dom_tree.d.ts +1 -0
- package/dist/nodejs/tools/browser_use.d.ts +28 -0
- package/dist/nodejs/tools/index.d.ts +2 -0
- package/dist/nodejs.cjs.js +71638 -12
- package/dist/nodejs.esm.js +71632 -6
- package/dist/schemas/workflow.schema.d.ts +2 -13
- package/dist/services/llm/claude-provider.d.ts +2 -1
- package/dist/services/llm/openai-provider.d.ts +2 -1
- package/dist/services/parser/workflow-parser.d.ts +0 -7
- package/dist/types/action.types.d.ts +8 -3
- package/dist/types/tools.types.d.ts +44 -1
- package/dist/types/workflow.types.d.ts +22 -9
- package/dist/universal_tools/cancel_workflow.d.ts +9 -0
- package/dist/universal_tools/human.d.ts +30 -0
- package/dist/universal_tools/index.d.ts +4 -0
- package/dist/universal_tools/summary_workflow.d.ts +9 -0
- package/dist/utils/execution-logger.d.ts +69 -0
- package/dist/web/tools/browser.d.ts +2 -1
- package/dist/web.cjs.js +29 -17
- package/dist/web.esm.js +29 -17
- package/package.json +6 -9
package/dist/index.cjs.js
CHANGED
|
@@ -2,14 +2,219 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Manages logging for action execution, providing a cleaner view of the execution
|
|
7
|
+
* flow while maintaining important context and history.
|
|
8
|
+
*/
|
|
9
|
+
class ExecutionLogger {
|
|
10
|
+
constructor(options = {}) {
|
|
11
|
+
var _a;
|
|
12
|
+
this.history = [];
|
|
13
|
+
this.maxHistoryLength = options.maxHistoryLength || 10;
|
|
14
|
+
this.logLevel = options.logLevel || 'info';
|
|
15
|
+
this.includeTimestamp = (_a = options.includeTimestamp) !== null && _a !== void 0 ? _a : true;
|
|
16
|
+
this.debugImagePath = options.debugImagePath;
|
|
17
|
+
this.imageSaver = options.imageSaver;
|
|
18
|
+
// Check if running in Node.js environment
|
|
19
|
+
this.isNode =
|
|
20
|
+
typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Logs a message with execution context
|
|
24
|
+
*/
|
|
25
|
+
log(level, message, context) {
|
|
26
|
+
if (this.shouldLog(level)) {
|
|
27
|
+
const timestamp = this.includeTimestamp ? new Date().toISOString() : '';
|
|
28
|
+
const contextSummary = this.summarizeContext(context);
|
|
29
|
+
console.log(`${timestamp} [${level.toUpperCase()}] ${message}${contextSummary}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Updates conversation history while maintaining size limit
|
|
34
|
+
*/
|
|
35
|
+
updateHistory(messages) {
|
|
36
|
+
// Keep system messages and last N messages
|
|
37
|
+
const systemMessages = messages.filter((m) => m.role === 'system');
|
|
38
|
+
const nonSystemMessages = messages.filter((m) => m.role !== 'system');
|
|
39
|
+
const recentMessages = nonSystemMessages.slice(-this.maxHistoryLength);
|
|
40
|
+
this.history = [...systemMessages, ...recentMessages];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Gets current conversation history
|
|
44
|
+
*/
|
|
45
|
+
getHistory() {
|
|
46
|
+
return this.history;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Summarizes the execution context for logging
|
|
50
|
+
*/
|
|
51
|
+
summarizeContext(context) {
|
|
52
|
+
if (!context)
|
|
53
|
+
return '';
|
|
54
|
+
const summary = {
|
|
55
|
+
variables: Object.fromEntries(context.variables),
|
|
56
|
+
tools: context.tools ? Array.from(context.tools.keys()) : [],
|
|
57
|
+
};
|
|
58
|
+
return `\nContext: ${JSON.stringify(summary, null, 2)}`;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Checks if message should be logged based on log level
|
|
62
|
+
*/
|
|
63
|
+
shouldLog(level) {
|
|
64
|
+
const levels = {
|
|
65
|
+
error: 0,
|
|
66
|
+
warn: 1,
|
|
67
|
+
info: 2,
|
|
68
|
+
debug: 3,
|
|
69
|
+
};
|
|
70
|
+
return levels[level] <= levels[this.logLevel];
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Logs the start of an action execution
|
|
74
|
+
*/
|
|
75
|
+
logActionStart(actionName, input, context) {
|
|
76
|
+
this.log('info', `Starting action: ${actionName}`, context);
|
|
77
|
+
this.log('info', `Input: ${JSON.stringify(input, null, 2)}`);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Logs the completion of an action execution
|
|
81
|
+
*/
|
|
82
|
+
logActionComplete(actionName, result, context) {
|
|
83
|
+
this.log('info', `Completed action: ${actionName}`, context);
|
|
84
|
+
this.log('info', `Result: ${JSON.stringify(result, null, 2)}`);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Logs a tool execution
|
|
88
|
+
*/
|
|
89
|
+
logToolExecution(toolName, input, context) {
|
|
90
|
+
this.log('info', `Executing tool: ${toolName}`);
|
|
91
|
+
this.log('info', `Tool input: ${JSON.stringify(input, null, 2)}`);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Logs an error that occurred during execution
|
|
95
|
+
*/
|
|
96
|
+
logError(error, context) {
|
|
97
|
+
this.log('error', `Error occurred: ${error.message}`, context);
|
|
98
|
+
if (error.stack) {
|
|
99
|
+
this.log('debug', `Stack trace: ${error.stack}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
extractFromDataUrl(dataUrl) {
|
|
103
|
+
const matches = dataUrl.match(/^data:image\/([a-zA-Z0-9]+);base64,(.+)$/);
|
|
104
|
+
if (!matches) {
|
|
105
|
+
throw new Error('Invalid data URL format');
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
extension: matches[1],
|
|
109
|
+
base64Data: matches[2],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
async saveDebugImage(imageData, toolName) {
|
|
113
|
+
try {
|
|
114
|
+
let extension;
|
|
115
|
+
let base64Data;
|
|
116
|
+
// Handle both data URL strings and ImageData objects
|
|
117
|
+
if (typeof imageData === 'string' && imageData.startsWith('data:')) {
|
|
118
|
+
const extracted = this.extractFromDataUrl(imageData);
|
|
119
|
+
extension = extracted.extension;
|
|
120
|
+
base64Data = extracted.base64Data;
|
|
121
|
+
}
|
|
122
|
+
else if (typeof imageData === 'object' && 'type' in imageData) {
|
|
123
|
+
extension = imageData.media_type.split('/')[1] || 'png';
|
|
124
|
+
base64Data = imageData.data;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
return '[image]';
|
|
128
|
+
}
|
|
129
|
+
// If custom image saver is provided, use it
|
|
130
|
+
if (this.imageSaver) {
|
|
131
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
132
|
+
const filename = `${toolName}_${timestamp}.${extension}`;
|
|
133
|
+
return await this.imageSaver({ type: 'base64', media_type: `image/${extension}`, data: base64Data }, filename);
|
|
134
|
+
}
|
|
135
|
+
// If in Node.js environment and debugImagePath is set
|
|
136
|
+
if (this.isNode && this.debugImagePath) {
|
|
137
|
+
// Dynamically import Node.js modules only when needed
|
|
138
|
+
const { promises: fs } = await import('fs');
|
|
139
|
+
const { join } = await import('path');
|
|
140
|
+
await fs.mkdir(this.debugImagePath, { recursive: true });
|
|
141
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
142
|
+
const filename = `${toolName}_${timestamp}.${extension}`;
|
|
143
|
+
const filepath = join(this.debugImagePath, filename);
|
|
144
|
+
const buffer = Buffer.from(base64Data, 'base64');
|
|
145
|
+
await fs.writeFile(filepath, buffer);
|
|
146
|
+
return `[image saved to: ${filepath}]`;
|
|
147
|
+
}
|
|
148
|
+
// Default case - just return placeholder
|
|
149
|
+
return '[image]';
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
console.warn('Failed to save debug image:', error);
|
|
153
|
+
return '[image]';
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async formatToolResult(result) {
|
|
157
|
+
// Handle null/undefined
|
|
158
|
+
if (result == null) {
|
|
159
|
+
return 'null';
|
|
160
|
+
}
|
|
161
|
+
// Handle direct image result
|
|
162
|
+
if (result.image) {
|
|
163
|
+
const imagePlaceholder = await this.saveDebugImage(result.image, 'tool');
|
|
164
|
+
const modifiedResult = { ...result, image: imagePlaceholder };
|
|
165
|
+
return JSON.stringify(modifiedResult);
|
|
166
|
+
}
|
|
167
|
+
// Handle nested images in result object
|
|
168
|
+
if (typeof result === 'object') {
|
|
169
|
+
const formatted = { ...result };
|
|
170
|
+
for (const [key, value] of Object.entries(formatted)) {
|
|
171
|
+
if (value && typeof value === 'string' && value.startsWith('data:image/')) {
|
|
172
|
+
formatted[key] = await this.saveDebugImage(value, key);
|
|
173
|
+
}
|
|
174
|
+
else if (value &&
|
|
175
|
+
typeof value === 'object' &&
|
|
176
|
+
'type' in value &&
|
|
177
|
+
value.type === 'base64') {
|
|
178
|
+
formatted[key] = await this.saveDebugImage(value, key);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return JSON.stringify(formatted);
|
|
182
|
+
}
|
|
183
|
+
// Handle primitive values
|
|
184
|
+
return String(result);
|
|
185
|
+
}
|
|
186
|
+
async logToolResult(toolName, result, context) {
|
|
187
|
+
if (this.shouldLog('info')) {
|
|
188
|
+
const timestamp = this.includeTimestamp ? new Date().toISOString() : '';
|
|
189
|
+
const contextSummary = this.summarizeContext(context);
|
|
190
|
+
const formattedResult = await this.formatToolResult(result);
|
|
191
|
+
console.log(`${timestamp} [INFO] Tool executed: ${toolName}\n` +
|
|
192
|
+
`${timestamp} [INFO] Tool result: ${formattedResult}${contextSummary}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
5
197
|
class WorkflowImpl {
|
|
6
|
-
constructor(id, name, description, nodes = [], variables = new Map(), llmProvider) {
|
|
198
|
+
constructor(id, name, description, nodes = [], variables = new Map(), llmProvider, loggerOptions) {
|
|
7
199
|
this.id = id;
|
|
8
200
|
this.name = name;
|
|
9
201
|
this.description = description;
|
|
10
202
|
this.nodes = nodes;
|
|
11
203
|
this.variables = variables;
|
|
12
204
|
this.llmProvider = llmProvider;
|
|
205
|
+
this.abortControllers = new Map();
|
|
206
|
+
if (loggerOptions) {
|
|
207
|
+
this.logger = new ExecutionLogger(loggerOptions);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
setLogger(logger) {
|
|
211
|
+
this.logger = logger;
|
|
212
|
+
}
|
|
213
|
+
async cancel() {
|
|
214
|
+
this.abort = true;
|
|
215
|
+
for (const controller of this.abortControllers.values()) {
|
|
216
|
+
controller.abort("Workflow cancelled");
|
|
217
|
+
}
|
|
13
218
|
}
|
|
14
219
|
async execute(callback) {
|
|
15
220
|
var _a, _b, _c, _d;
|
|
@@ -32,37 +237,49 @@ class WorkflowImpl {
|
|
|
32
237
|
throw new Error(`Circular dependency detected at node: ${nodeId}`);
|
|
33
238
|
}
|
|
34
239
|
const node = this.getNode(nodeId);
|
|
240
|
+
const abortController = new AbortController();
|
|
241
|
+
this.abortControllers.set(nodeId, abortController);
|
|
35
242
|
// Execute the node's action
|
|
36
243
|
const context = {
|
|
37
244
|
__skip: false,
|
|
38
245
|
__abort: false,
|
|
246
|
+
workflow: this,
|
|
39
247
|
variables: this.variables,
|
|
40
248
|
llmProvider: this.llmProvider,
|
|
41
249
|
tools: new Map(node.action.tools.map(tool => [tool.name, tool])),
|
|
42
250
|
callback,
|
|
251
|
+
logger: this.logger,
|
|
43
252
|
next: () => context.__skip = true,
|
|
44
|
-
abortAll: () =>
|
|
253
|
+
abortAll: () => {
|
|
254
|
+
this.abort = context.__abort = true;
|
|
255
|
+
// Abort all running tasks
|
|
256
|
+
for (const controller of this.abortControllers.values()) {
|
|
257
|
+
controller.abort("Workflow cancelled");
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
signal: abortController.signal
|
|
45
261
|
};
|
|
46
|
-
callback && await ((_b = (_a = callback.hooks).beforeSubtask) === null || _b === void 0 ? void 0 : _b.call(_a, node, context));
|
|
47
|
-
if (context.__abort) {
|
|
48
|
-
throw new Error("Abort");
|
|
49
|
-
}
|
|
50
|
-
else if (context.__skip) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
262
|
executing.add(nodeId);
|
|
54
263
|
// Execute dependencies first
|
|
55
264
|
for (const depId of node.dependencies) {
|
|
56
265
|
await executeNode(depId);
|
|
57
266
|
}
|
|
58
267
|
// Prepare input by gathering outputs from dependencies
|
|
59
|
-
const input = {};
|
|
268
|
+
const input = { items: [] };
|
|
60
269
|
for (const depId of node.dependencies) {
|
|
61
270
|
const depNode = this.getNode(depId);
|
|
62
|
-
input
|
|
271
|
+
input.items.push(depNode.output);
|
|
272
|
+
}
|
|
273
|
+
node.input = input;
|
|
274
|
+
// Run pre-execution hooks and execute action
|
|
275
|
+
callback && await ((_b = (_a = callback.hooks).beforeSubtask) === null || _b === void 0 ? void 0 : _b.call(_a, node, context));
|
|
276
|
+
if (context.__abort) {
|
|
277
|
+
throw new Error("Abort");
|
|
63
278
|
}
|
|
64
|
-
|
|
65
|
-
|
|
279
|
+
else if (context.__skip) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
node.output.value = await node.action.execute(node.input, node.output, context);
|
|
66
283
|
executing.delete(nodeId);
|
|
67
284
|
executed.add(nodeId);
|
|
68
285
|
callback && await ((_d = (_c = callback.hooks).afterSubtask) === null || _d === void 0 ? void 0 : _d.call(_c, node, context, (_e = node.output) === null || _e === void 0 ? void 0 : _e.value));
|
|
@@ -71,6 +288,7 @@ class WorkflowImpl {
|
|
|
71
288
|
const terminalNodes = this.nodes.filter(node => !this.nodes.some(n => n.dependencies.includes(node.id)));
|
|
72
289
|
await Promise.all(terminalNodes.map(node => executeNode(node.id)));
|
|
73
290
|
callback && await ((_d = (_c = callback.hooks).afterWorkflow) === null || _d === void 0 ? void 0 : _d.call(_c, this, this.variables));
|
|
291
|
+
return terminalNodes.map(node => node.output);
|
|
74
292
|
}
|
|
75
293
|
addNode(node) {
|
|
76
294
|
if (this.nodes.some(n => n.id === node.id)) {
|
|
@@ -129,7 +347,7 @@ class WorkflowImpl {
|
|
|
129
347
|
class WriteContextTool {
|
|
130
348
|
constructor() {
|
|
131
349
|
this.name = 'write_context';
|
|
132
|
-
this.description = 'Write a value to the workflow context. Use this to store intermediate results
|
|
350
|
+
this.description = 'Write a value to the global workflow context. Use this to store important intermediate results, but only when a piece of information is essential for future reference but missing from the final output specification of the current action.';
|
|
133
351
|
this.input_schema = {
|
|
134
352
|
type: 'object',
|
|
135
353
|
properties: {
|
|
@@ -159,25 +377,32 @@ class WriteContextTool {
|
|
|
159
377
|
return { success: true, key, value };
|
|
160
378
|
}
|
|
161
379
|
}
|
|
162
|
-
function createReturnTool(outputSchema) {
|
|
380
|
+
function createReturnTool(actionName, outputDescription, outputSchema) {
|
|
163
381
|
return {
|
|
164
382
|
name: 'return_output',
|
|
165
|
-
description:
|
|
383
|
+
description: `Return the final output of this action. Use this to return a value matching the required output schema (if specified) and the following description:
|
|
384
|
+
${outputDescription}
|
|
385
|
+
|
|
386
|
+
You can either set 'use_tool_result=true' to return the result of a previous tool call, or explicitly specify 'value' with 'use_tool_result=false' to return a value according to your own understanding. Whenever possible, reuse tool results to avoid redundancy.
|
|
387
|
+
`,
|
|
166
388
|
input_schema: {
|
|
167
389
|
type: 'object',
|
|
168
390
|
properties: {
|
|
391
|
+
use_tool_result: {
|
|
392
|
+
type: ['boolean'],
|
|
393
|
+
description: `Whether to use the latest tool result as output. When set to true, the 'value' parameter is ignored.`,
|
|
394
|
+
},
|
|
169
395
|
value: outputSchema || {
|
|
170
396
|
// Default to accepting any JSON value
|
|
171
397
|
type: ['string', 'number', 'boolean', 'object', 'null'],
|
|
172
|
-
description: 'The output value',
|
|
398
|
+
description: 'The output value. Only provide a value if the previous tool result is not suitable for the output description. Otherwise, leave this as null.',
|
|
173
399
|
},
|
|
174
400
|
},
|
|
175
|
-
required: ['value'],
|
|
401
|
+
required: ['use_tool_result', 'value'],
|
|
176
402
|
},
|
|
177
403
|
async execute(context, params) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
return { returned: value };
|
|
404
|
+
context.variables.set(`__action_${actionName}_output`, params);
|
|
405
|
+
return { success: true };
|
|
181
406
|
},
|
|
182
407
|
};
|
|
183
408
|
}
|
|
@@ -191,6 +416,8 @@ class ActionImpl {
|
|
|
191
416
|
this.llmProvider = llmProvider;
|
|
192
417
|
this.llmConfig = llmConfig;
|
|
193
418
|
this.maxRounds = 10; // Default max rounds
|
|
419
|
+
this.toolResults = new Map();
|
|
420
|
+
this.logger = new ExecutionLogger();
|
|
194
421
|
this.writeContextTool = new WriteContextTool();
|
|
195
422
|
this.tools = [...tools, this.writeContextTool];
|
|
196
423
|
if (config === null || config === void 0 ? void 0 : config.maxRounds) {
|
|
@@ -198,6 +425,7 @@ class ActionImpl {
|
|
|
198
425
|
}
|
|
199
426
|
}
|
|
200
427
|
async executeSingleRound(messages, params, toolMap, context) {
|
|
428
|
+
this.logger = context.logger;
|
|
201
429
|
const roundMessages = [];
|
|
202
430
|
let hasToolUse = false;
|
|
203
431
|
let response = null;
|
|
@@ -207,6 +435,12 @@ class ActionImpl {
|
|
|
207
435
|
let toolResultMessage = null;
|
|
208
436
|
// Track tool execution promise
|
|
209
437
|
let toolExecutionPromise = null;
|
|
438
|
+
// Listen for abort signal
|
|
439
|
+
if (context.signal) {
|
|
440
|
+
context.signal.addEventListener('abort', () => {
|
|
441
|
+
context.__abort = true;
|
|
442
|
+
});
|
|
443
|
+
}
|
|
210
444
|
const handler = {
|
|
211
445
|
onContent: (content) => {
|
|
212
446
|
if (content.trim()) {
|
|
@@ -214,7 +448,8 @@ class ActionImpl {
|
|
|
214
448
|
}
|
|
215
449
|
},
|
|
216
450
|
onToolUse: async (toolCall) => {
|
|
217
|
-
|
|
451
|
+
this.logger.log('info', `Assistant: ${assistantTextMessage}`);
|
|
452
|
+
this.logger.logToolExecution(toolCall.name, toolCall.input, context);
|
|
218
453
|
hasToolUse = true;
|
|
219
454
|
const tool = toolMap.get(toolCall.name);
|
|
220
455
|
if (!tool) {
|
|
@@ -233,6 +468,7 @@ class ActionImpl {
|
|
|
233
468
|
};
|
|
234
469
|
// Store the promise of tool execution
|
|
235
470
|
toolExecutionPromise = (async () => {
|
|
471
|
+
var _a;
|
|
236
472
|
try {
|
|
237
473
|
// beforeToolUse
|
|
238
474
|
context.__skip = false;
|
|
@@ -242,7 +478,7 @@ class ActionImpl {
|
|
|
242
478
|
toolCall.input = modified_input;
|
|
243
479
|
}
|
|
244
480
|
}
|
|
245
|
-
if (context.__skip || context.__abort) {
|
|
481
|
+
if (context.__skip || context.__abort || ((_a = context.signal) === null || _a === void 0 ? void 0 : _a.aborted)) {
|
|
246
482
|
toolResultMessage = {
|
|
247
483
|
role: 'user',
|
|
248
484
|
content: [
|
|
@@ -264,31 +500,42 @@ class ActionImpl {
|
|
|
264
500
|
result = modified_result;
|
|
265
501
|
}
|
|
266
502
|
}
|
|
503
|
+
const result_has_image = result && "image" in result;
|
|
504
|
+
const resultContent = result_has_image
|
|
505
|
+
? {
|
|
506
|
+
type: 'tool_result',
|
|
507
|
+
tool_use_id: toolCall.id,
|
|
508
|
+
content: result.text
|
|
509
|
+
? [
|
|
510
|
+
{ type: 'image', source: result.image },
|
|
511
|
+
{ type: 'text', text: result.text },
|
|
512
|
+
]
|
|
513
|
+
: [{ type: 'image', source: result.image }],
|
|
514
|
+
}
|
|
515
|
+
: {
|
|
516
|
+
type: 'tool_result',
|
|
517
|
+
tool_use_id: toolCall.id,
|
|
518
|
+
content: [{ type: 'text', text: JSON.stringify(result) }],
|
|
519
|
+
};
|
|
520
|
+
const resultContentText = result_has_image
|
|
521
|
+
? result.text
|
|
522
|
+
? result.text + ' [Image]'
|
|
523
|
+
: '[Image]'
|
|
524
|
+
: JSON.stringify(result);
|
|
267
525
|
const resultMessage = {
|
|
268
526
|
role: 'user',
|
|
269
|
-
content: [
|
|
270
|
-
result.image && result.image.type
|
|
271
|
-
? {
|
|
272
|
-
type: 'tool_result',
|
|
273
|
-
tool_use_id: toolCall.id,
|
|
274
|
-
content: result.text
|
|
275
|
-
? [
|
|
276
|
-
{ type: 'image', source: result.image },
|
|
277
|
-
{ type: 'text', text: result.text },
|
|
278
|
-
]
|
|
279
|
-
: [{ type: 'image', source: result.image }],
|
|
280
|
-
}
|
|
281
|
-
: {
|
|
282
|
-
type: 'tool_result',
|
|
283
|
-
tool_use_id: toolCall.id,
|
|
284
|
-
content: [{ type: 'text', text: JSON.stringify(result) }],
|
|
285
|
-
},
|
|
286
|
-
],
|
|
527
|
+
content: [resultContent],
|
|
287
528
|
};
|
|
288
529
|
toolResultMessage = resultMessage;
|
|
289
|
-
|
|
530
|
+
this.logger.logToolResult(tool.name, result, context);
|
|
531
|
+
// Store tool results except for the return_output tool
|
|
532
|
+
if (tool.name !== 'return_output') {
|
|
533
|
+
this.toolResults.set(toolCall.id, resultContentText);
|
|
534
|
+
}
|
|
290
535
|
}
|
|
291
536
|
catch (err) {
|
|
537
|
+
console.log("An error occurred when calling tool:");
|
|
538
|
+
console.log(err);
|
|
292
539
|
const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
|
|
293
540
|
const errorResult = {
|
|
294
541
|
role: 'user',
|
|
@@ -302,7 +549,7 @@ class ActionImpl {
|
|
|
302
549
|
],
|
|
303
550
|
};
|
|
304
551
|
toolResultMessage = errorResult;
|
|
305
|
-
|
|
552
|
+
this.logger.logError(err, context);
|
|
306
553
|
}
|
|
307
554
|
})();
|
|
308
555
|
},
|
|
@@ -311,16 +558,21 @@ class ActionImpl {
|
|
|
311
558
|
},
|
|
312
559
|
onError: (error) => {
|
|
313
560
|
console.error('Stream Error:', error);
|
|
561
|
+
console.log('Last message array sent to LLM:', JSON.stringify(messages, null, 2));
|
|
314
562
|
},
|
|
315
563
|
};
|
|
564
|
+
this.handleHistoryImageMessages(messages);
|
|
316
565
|
// Wait for stream to complete
|
|
566
|
+
if (!this.llmProvider) {
|
|
567
|
+
throw new Error('LLM provider not set');
|
|
568
|
+
}
|
|
317
569
|
await this.llmProvider.generateStream(messages, params, handler);
|
|
318
570
|
// Wait for tool execution to complete if it was started
|
|
319
571
|
if (toolExecutionPromise) {
|
|
320
572
|
await toolExecutionPromise;
|
|
321
573
|
}
|
|
322
574
|
if (context.__abort) {
|
|
323
|
-
throw new Error(
|
|
575
|
+
throw new Error('Abort');
|
|
324
576
|
}
|
|
325
577
|
// Add messages in the correct order after everything is complete
|
|
326
578
|
if (assistantTextMessage) {
|
|
@@ -334,10 +586,59 @@ class ActionImpl {
|
|
|
334
586
|
}
|
|
335
587
|
return { response, hasToolUse, roundMessages };
|
|
336
588
|
}
|
|
337
|
-
|
|
338
|
-
|
|
589
|
+
handleHistoryImageMessages(messages) {
|
|
590
|
+
// Remove all images from historical tool results except the most recent user message
|
|
591
|
+
const initialImageCount = this.countImages(messages);
|
|
592
|
+
let foundFirstUser = false;
|
|
593
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
594
|
+
const message = messages[i];
|
|
595
|
+
if (message.role === 'user') {
|
|
596
|
+
if (!foundFirstUser) {
|
|
597
|
+
foundFirstUser = true;
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
600
|
+
if (Array.isArray(message.content)) {
|
|
601
|
+
// Directly modify the message content array
|
|
602
|
+
message.content = message.content.map((item) => {
|
|
603
|
+
if (item.type === 'tool_result' && Array.isArray(item.content)) {
|
|
604
|
+
// Create a new content array without images
|
|
605
|
+
if (item.content.length > 0) {
|
|
606
|
+
item.content = item.content.filter((c) => c.type !== 'image');
|
|
607
|
+
// If all content was images and got filtered out, replace with ok message
|
|
608
|
+
if (item.content.length === 0) {
|
|
609
|
+
item.content = [{ type: 'text', text: 'ok' }];
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return item;
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
const finalImageCount = this.countImages(messages);
|
|
619
|
+
if (initialImageCount !== finalImageCount) {
|
|
620
|
+
this.logger.log("info", `Removed ${initialImageCount - finalImageCount} images from history`);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
countImages(messages) {
|
|
624
|
+
let count = 0;
|
|
625
|
+
messages.forEach(msg => {
|
|
626
|
+
if (Array.isArray(msg.content)) {
|
|
627
|
+
msg.content.forEach((item) => {
|
|
628
|
+
if (item.type === 'tool_result' && Array.isArray(item.content)) {
|
|
629
|
+
count += item.content.filter((c) => c.type === 'image').length;
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
return count;
|
|
635
|
+
}
|
|
636
|
+
async execute(input, output, context, outputSchema) {
|
|
637
|
+
var _a, _b, _c, _d, _e;
|
|
638
|
+
this.logger = context.logger;
|
|
639
|
+
console.log(`Executing action started: ${this.name}`);
|
|
339
640
|
// Create return tool with output schema
|
|
340
|
-
const returnTool = createReturnTool(outputSchema);
|
|
641
|
+
const returnTool = createReturnTool(this.name, output.description, outputSchema);
|
|
341
642
|
// Create tool map combining context tools, action tools, and return tool
|
|
342
643
|
const toolMap = new Map();
|
|
343
644
|
this.tools.forEach((tool) => toolMap.set(tool.name, tool));
|
|
@@ -348,9 +649,7 @@ class ActionImpl {
|
|
|
348
649
|
{ role: 'system', content: this.formatSystemPrompt() },
|
|
349
650
|
{ role: 'user', content: this.formatUserPrompt(context, input) },
|
|
350
651
|
];
|
|
351
|
-
|
|
352
|
-
console.log('Initial messages:', messages);
|
|
353
|
-
console.log('Output schema:', outputSchema);
|
|
652
|
+
this.logger.logActionStart(this.name, input, context);
|
|
354
653
|
// Configure tool parameters
|
|
355
654
|
const params = {
|
|
356
655
|
...this.llmConfig,
|
|
@@ -362,17 +661,24 @@ class ActionImpl {
|
|
|
362
661
|
};
|
|
363
662
|
let roundCount = 0;
|
|
364
663
|
while (roundCount < this.maxRounds) {
|
|
664
|
+
// Check for abort signal
|
|
665
|
+
if ((_b = context.signal) === null || _b === void 0 ? void 0 : _b.aborted) {
|
|
666
|
+
throw new Error('Workflow cancelled');
|
|
667
|
+
}
|
|
365
668
|
roundCount++;
|
|
366
|
-
|
|
367
|
-
console.log('Current conversation status:', JSON.stringify(messages, null, 2));
|
|
669
|
+
this.logger.log('info', `Starting round ${roundCount} of ${this.maxRounds}`, context);
|
|
368
670
|
const { response, hasToolUse, roundMessages } = await this.executeSingleRound(messages, params, toolMap, context);
|
|
671
|
+
if (response === null || response === void 0 ? void 0 : response.textContent) {
|
|
672
|
+
(_e = (_d = (_c = context.callback) === null || _c === void 0 ? void 0 : _c.hooks) === null || _d === void 0 ? void 0 : _d.onLlmMessage) === null || _e === void 0 ? void 0 : _e.call(_d, response.textContent);
|
|
673
|
+
}
|
|
369
674
|
// Add round messages to conversation history
|
|
370
675
|
messages.push(...roundMessages);
|
|
676
|
+
this.logger.log('debug', `Round ${roundCount} messages: ${JSON.stringify(roundMessages)}`, context);
|
|
371
677
|
// Check termination conditions
|
|
372
678
|
if (!hasToolUse && response) {
|
|
373
679
|
// LLM sent a message without using tools - request explicit return
|
|
374
|
-
|
|
375
|
-
|
|
680
|
+
this.logger.log('info', `Assistant: ${response.textContent}`);
|
|
681
|
+
this.logger.log('warn', 'LLM sent a message without using tools; requesting explicit return');
|
|
376
682
|
const returnOnlyParams = {
|
|
377
683
|
...params,
|
|
378
684
|
tools: [
|
|
@@ -392,12 +698,11 @@ class ActionImpl {
|
|
|
392
698
|
break;
|
|
393
699
|
}
|
|
394
700
|
if (response === null || response === void 0 ? void 0 : response.toolCalls.some((call) => call.name === 'return_output')) {
|
|
395
|
-
console.log('Task completed with return_output tool');
|
|
396
701
|
break;
|
|
397
702
|
}
|
|
398
703
|
// If this is the last round, force an explicit return
|
|
399
704
|
if (roundCount === this.maxRounds) {
|
|
400
|
-
|
|
705
|
+
this.logger.log('warn', 'Max rounds reached, requesting explicit return');
|
|
401
706
|
const returnOnlyParams = {
|
|
402
707
|
...params,
|
|
403
708
|
tools: [
|
|
@@ -417,33 +722,50 @@ class ActionImpl {
|
|
|
417
722
|
}
|
|
418
723
|
}
|
|
419
724
|
// Get and clean up output value
|
|
420
|
-
const
|
|
421
|
-
context.variables.
|
|
422
|
-
|
|
725
|
+
const outputKey = `__action_${this.name}_output`;
|
|
726
|
+
const outputParams = context.variables.get(outputKey);
|
|
727
|
+
context.variables.delete(outputKey);
|
|
728
|
+
// Get output value, first checking for use_tool_result
|
|
729
|
+
const outputValue = outputParams.use_tool_result
|
|
730
|
+
? Array.from(this.toolResults.values()).pop()
|
|
731
|
+
: outputParams === null || outputParams === void 0 ? void 0 : outputParams.value;
|
|
732
|
+
if (outputValue === undefined) {
|
|
423
733
|
console.warn('Action completed without returning a value');
|
|
424
734
|
return {};
|
|
425
735
|
}
|
|
426
|
-
return
|
|
736
|
+
return outputValue;
|
|
427
737
|
}
|
|
428
738
|
formatSystemPrompt() {
|
|
429
|
-
return `You are a
|
|
739
|
+
return `You are a subtask executor. You need to complete the subtask specified by the user, which is a consisting part of the overall task. Help the user by calling the tools provided.
|
|
430
740
|
|
|
431
741
|
Remember to:
|
|
432
742
|
1. Use tools when needed to accomplish the task
|
|
433
|
-
2.
|
|
434
|
-
3.
|
|
743
|
+
2. Think step by step about what needs to be done
|
|
744
|
+
3. Return the output of the subtask using the 'return_output' tool when you are done; prefer using the 'tool_use_id' parameter to refer to the output of a tool call over providing a long text as the value
|
|
745
|
+
4. Use the context to store important information for later reference, but use it sparingly: most of the time, the output of the subtask should be sufficient for the next steps
|
|
746
|
+
5. If there are any unclear points during the task execution, please use the human-related tool to inquire with the user
|
|
747
|
+
6. If user intervention is required during the task execution, please use the human-related tool to transfer the operation rights to the user
|
|
748
|
+
`;
|
|
435
749
|
}
|
|
436
750
|
formatUserPrompt(context, input) {
|
|
437
|
-
|
|
438
|
-
const
|
|
751
|
+
var _a;
|
|
752
|
+
const workflowDescription = ((_a = context.workflow) === null || _a === void 0 ? void 0 : _a.description) || null;
|
|
753
|
+
const actionDescription = `${this.name} -- ${this.description}`;
|
|
754
|
+
const inputDescription = JSON.stringify(input, null, 2) || null;
|
|
755
|
+
const contextVariables = Array.from(context.variables.entries())
|
|
439
756
|
.map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
|
|
440
757
|
.join('\n');
|
|
441
|
-
return `You are executing the
|
|
758
|
+
return `You are executing a subtask in the workflow. The workflow description is as follows:
|
|
759
|
+
${workflowDescription}
|
|
442
760
|
|
|
443
|
-
|
|
761
|
+
The subtask description is as follows:
|
|
762
|
+
${actionDescription}
|
|
444
763
|
|
|
445
|
-
|
|
446
|
-
${
|
|
764
|
+
The input to the subtask is as follows:
|
|
765
|
+
${inputDescription}
|
|
766
|
+
|
|
767
|
+
There are some variables stored in the context that you can use for reference:
|
|
768
|
+
${contextVariables}
|
|
447
769
|
`;
|
|
448
770
|
}
|
|
449
771
|
// Static factory method
|
|
@@ -473,7 +795,8 @@ Generate a complete workflow that:
|
|
|
473
795
|
2. Properly sequences tool usage based on dependencies
|
|
474
796
|
3. Ensures each action has appropriate input/output schemas, and that the "tools" field in each action is populated with the sufficient subset of all available tools needed to complete the action
|
|
475
797
|
4. Creates a clear, logical flow to accomplish the user's goal
|
|
476
|
-
5. Includes detailed descriptions for each action, ensuring that the actions, when combined, is a complete solution to the user's problem
|
|
798
|
+
5. Includes detailed descriptions for each action, ensuring that the actions, when combined, is a complete solution to the user's problem
|
|
799
|
+
6. You should always add a SubTask at the end of the workflow to summarize it, and this SubTask should always call the "summary_workflow" tool. It's dependencies should be all of the SubTasks`;
|
|
477
800
|
},
|
|
478
801
|
formatUserPrompt: (requirement) => `Create a workflow for the following requirement: ${requirement}`,
|
|
479
802
|
modifyUserPrompt: (prompt) => `Modify workflow: ${prompt}`,
|
|
@@ -614,6 +937,19 @@ class WorkflowGenerator {
|
|
|
614
937
|
],
|
|
615
938
|
});
|
|
616
939
|
const workflowData = response.toolCalls[0].input.workflow;
|
|
940
|
+
// Forcibly add special tools
|
|
941
|
+
const specialTools = [
|
|
942
|
+
"cancel_workflow",
|
|
943
|
+
"human_input_text",
|
|
944
|
+
"human_operate",
|
|
945
|
+
];
|
|
946
|
+
for (const node of workflowData.nodes) {
|
|
947
|
+
for (const tool of specialTools) {
|
|
948
|
+
if (!node.action.tools.includes(tool)) {
|
|
949
|
+
node.action.tools.push(tool);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
617
953
|
// Validate all tools exist
|
|
618
954
|
for (const node of workflowData.nodes) {
|
|
619
955
|
if (!this.toolRegistry.hasTools(node.action.tools)) {
|
|
@@ -624,15 +960,22 @@ class WorkflowGenerator {
|
|
|
624
960
|
if (!workflowData.id) {
|
|
625
961
|
workflowData.id = v4();
|
|
626
962
|
}
|
|
963
|
+
// debug
|
|
964
|
+
console.log("Debug the workflow...");
|
|
965
|
+
console.log(workflowData);
|
|
966
|
+
console.log("Debug the workflow...Done");
|
|
627
967
|
return this.createWorkflowFromData(workflowData);
|
|
628
968
|
}
|
|
629
969
|
createWorkflowFromData(data) {
|
|
630
|
-
const workflow = new WorkflowImpl(data.id, data.name, data.description || '', [], new Map(Object.entries(data.variables || {})), this.llmProvider
|
|
970
|
+
const workflow = new WorkflowImpl(data.id, data.name, data.description || '', [], new Map(Object.entries(data.variables || {})), this.llmProvider, {
|
|
971
|
+
logLevel: 'info',
|
|
972
|
+
includeTimestamp: true,
|
|
973
|
+
});
|
|
631
974
|
// Add nodes to workflow
|
|
632
975
|
if (Array.isArray(data.nodes)) {
|
|
633
976
|
data.nodes.forEach((nodeData) => {
|
|
634
977
|
const tools = nodeData.action.tools.map((toolName) => this.toolRegistry.getTool(toolName));
|
|
635
|
-
const action = ActionImpl.createPromptAction(nodeData.action.name, nodeData.action.description, tools, this.llmProvider, { maxTokens:
|
|
978
|
+
const action = ActionImpl.createPromptAction(nodeData.action.name, nodeData.action.description, tools, this.llmProvider, { maxTokens: 8192 });
|
|
636
979
|
const node = {
|
|
637
980
|
id: nodeData.id,
|
|
638
981
|
name: nodeData.name || nodeData.id,
|
|
@@ -3376,8 +3719,13 @@ class ClaudeProvider {
|
|
|
3376
3719
|
...options,
|
|
3377
3720
|
});
|
|
3378
3721
|
}
|
|
3722
|
+
else if (param.messages && param.completions) {
|
|
3723
|
+
this.client = param;
|
|
3724
|
+
}
|
|
3379
3725
|
else {
|
|
3380
|
-
|
|
3726
|
+
let options = param;
|
|
3727
|
+
options.dangerouslyAllowBrowser = true;
|
|
3728
|
+
this.client = new Anthropic(options);
|
|
3381
3729
|
}
|
|
3382
3730
|
}
|
|
3383
3731
|
processResponse(response) {
|
|
@@ -8796,8 +9144,13 @@ class OpenaiProvider {
|
|
|
8796
9144
|
...options,
|
|
8797
9145
|
});
|
|
8798
9146
|
}
|
|
9147
|
+
else if (param.chat && param.chat.completions) {
|
|
9148
|
+
this.client = param;
|
|
9149
|
+
}
|
|
8799
9150
|
else {
|
|
8800
|
-
|
|
9151
|
+
let options = param;
|
|
9152
|
+
options.dangerouslyAllowBrowser = true;
|
|
9153
|
+
this.client = new OpenAI(options);
|
|
8801
9154
|
}
|
|
8802
9155
|
}
|
|
8803
9156
|
buildParams(messages, params, stream) {
|
|
@@ -8876,13 +9229,61 @@ class OpenaiProvider {
|
|
|
8876
9229
|
content: content.text,
|
|
8877
9230
|
});
|
|
8878
9231
|
}
|
|
8879
|
-
else if (content.type == '
|
|
9232
|
+
else if (content.type == 'image') {
|
|
8880
9233
|
_messages.push({
|
|
8881
|
-
role: '
|
|
8882
|
-
content:
|
|
8883
|
-
|
|
9234
|
+
role: 'user',
|
|
9235
|
+
content: [
|
|
9236
|
+
{
|
|
9237
|
+
type: 'image_url',
|
|
9238
|
+
image_url: {
|
|
9239
|
+
url: `data:${content.source.media_type};base64,${content.source.data}`,
|
|
9240
|
+
},
|
|
9241
|
+
},
|
|
9242
|
+
],
|
|
8884
9243
|
});
|
|
8885
9244
|
}
|
|
9245
|
+
else if (content.type == 'tool_result') {
|
|
9246
|
+
let _content = [];
|
|
9247
|
+
if (content.content == 'string') {
|
|
9248
|
+
_content.push({ type: 'text', text: content.content });
|
|
9249
|
+
}
|
|
9250
|
+
else {
|
|
9251
|
+
for (let k = 0; k < content.content.length; k++) {
|
|
9252
|
+
let item = content.content[k];
|
|
9253
|
+
if (item.type == 'text') {
|
|
9254
|
+
_content.push({ ...item });
|
|
9255
|
+
}
|
|
9256
|
+
else if (item.type == 'image') {
|
|
9257
|
+
_content.push({
|
|
9258
|
+
type: 'image_url',
|
|
9259
|
+
image_url: {
|
|
9260
|
+
url: `data:${item.source.media_type};base64,${item.source.data}`,
|
|
9261
|
+
},
|
|
9262
|
+
});
|
|
9263
|
+
}
|
|
9264
|
+
}
|
|
9265
|
+
}
|
|
9266
|
+
let hasImage = _content.filter((s) => s.type == 'image_url').length > 0;
|
|
9267
|
+
if (hasImage) {
|
|
9268
|
+
// OpenAI does not support images returned by the tool.
|
|
9269
|
+
_messages.push({
|
|
9270
|
+
role: 'tool',
|
|
9271
|
+
content: 'ok',
|
|
9272
|
+
tool_call_id: content.tool_call_id || content.tool_use_id,
|
|
9273
|
+
});
|
|
9274
|
+
_messages.push({
|
|
9275
|
+
role: 'user',
|
|
9276
|
+
content: _content,
|
|
9277
|
+
});
|
|
9278
|
+
}
|
|
9279
|
+
else {
|
|
9280
|
+
_messages.push({
|
|
9281
|
+
role: 'tool',
|
|
9282
|
+
content: _content,
|
|
9283
|
+
tool_call_id: content.tool_call_id || content.tool_use_id,
|
|
9284
|
+
});
|
|
9285
|
+
}
|
|
9286
|
+
}
|
|
8886
9287
|
}
|
|
8887
9288
|
}
|
|
8888
9289
|
else {
|
|
@@ -9060,18 +9461,11 @@ const workflowSchema = {
|
|
|
9060
9461
|
type: "array",
|
|
9061
9462
|
items: { type: "string" },
|
|
9062
9463
|
},
|
|
9063
|
-
input: {
|
|
9064
|
-
type: "object",
|
|
9065
|
-
properties: {
|
|
9066
|
-
type: { type: "string" },
|
|
9067
|
-
schema: { type: "object" },
|
|
9068
|
-
},
|
|
9069
|
-
},
|
|
9070
9464
|
output: {
|
|
9071
9465
|
type: "object",
|
|
9072
9466
|
properties: {
|
|
9073
|
-
|
|
9074
|
-
|
|
9467
|
+
name: { type: "string" },
|
|
9468
|
+
description: { type: "string" },
|
|
9075
9469
|
},
|
|
9076
9470
|
},
|
|
9077
9471
|
action: {
|
|
@@ -9200,8 +9594,27 @@ class Eko {
|
|
|
9200
9594
|
return workflow;
|
|
9201
9595
|
}
|
|
9202
9596
|
async execute(workflow, callback) {
|
|
9597
|
+
// Inject LLM provider at workflow level
|
|
9598
|
+
workflow.llmProvider = this.llmProvider;
|
|
9599
|
+
// Process each node's action
|
|
9600
|
+
for (const node of workflow.nodes) {
|
|
9601
|
+
if (node.action.type === 'prompt') {
|
|
9602
|
+
// Inject LLM provider
|
|
9603
|
+
node.action.llmProvider = this.llmProvider;
|
|
9604
|
+
// Resolve tools
|
|
9605
|
+
node.action.tools = node.action.tools.map(tool => {
|
|
9606
|
+
if (typeof tool === 'string') {
|
|
9607
|
+
return this.toolRegistry.getTool(tool);
|
|
9608
|
+
}
|
|
9609
|
+
return tool;
|
|
9610
|
+
});
|
|
9611
|
+
}
|
|
9612
|
+
}
|
|
9203
9613
|
return await workflow.execute(callback);
|
|
9204
9614
|
}
|
|
9615
|
+
async cancel(workflow) {
|
|
9616
|
+
return await workflow.cancel();
|
|
9617
|
+
}
|
|
9205
9618
|
async modify(workflow, prompt) {
|
|
9206
9619
|
const generator = this.workflowGeneratorMap.get(workflow);
|
|
9207
9620
|
workflow = await generator.modifyWorkflow(prompt);
|
|
@@ -9385,31 +9798,30 @@ class WorkflowParser {
|
|
|
9385
9798
|
errors,
|
|
9386
9799
|
};
|
|
9387
9800
|
}
|
|
9388
|
-
/**
|
|
9389
|
-
* Convert parsed JSON to runtime Workflow object
|
|
9390
|
-
*/
|
|
9391
9801
|
static toRuntime(json) {
|
|
9392
9802
|
const variables = new Map(Object.entries(json.variables || {}));
|
|
9393
|
-
const workflow = new WorkflowImpl(json.id, json.name, json.description, [], variables
|
|
9803
|
+
const workflow = new WorkflowImpl(json.id, json.name, json.description, [], variables, undefined, {
|
|
9804
|
+
logLevel: 'info',
|
|
9805
|
+
includeTimestamp: true,
|
|
9806
|
+
});
|
|
9394
9807
|
// Convert nodes
|
|
9395
9808
|
json.nodes.forEach((nodeJson) => {
|
|
9809
|
+
const action = ActionImpl.createPromptAction(nodeJson.action.name, nodeJson.action.description,
|
|
9810
|
+
// Pass tool names as strings, they'll be resolved at execution time
|
|
9811
|
+
nodeJson.action.tools || [], undefined, // LLM provider will be injected at execution time
|
|
9812
|
+
{ maxTokens: 1000 });
|
|
9396
9813
|
const node = {
|
|
9397
9814
|
id: nodeJson.id,
|
|
9398
9815
|
name: nodeJson.name || nodeJson.id,
|
|
9399
9816
|
description: nodeJson.description,
|
|
9400
9817
|
dependencies: nodeJson.dependencies || [],
|
|
9401
|
-
input:
|
|
9402
|
-
output:
|
|
9403
|
-
|
|
9404
|
-
|
|
9405
|
-
|
|
9406
|
-
description: nodeJson.action.description,
|
|
9407
|
-
tools: nodeJson.action.tools || [],
|
|
9408
|
-
execute: async (input, context) => {
|
|
9409
|
-
// Default implementation - should be overridden by specific action types
|
|
9410
|
-
return input;
|
|
9411
|
-
},
|
|
9818
|
+
input: { items: [] },
|
|
9819
|
+
output: nodeJson.output || {
|
|
9820
|
+
name: `${nodeJson.name || nodeJson.id}_output`,
|
|
9821
|
+
description: `Output of node ${nodeJson.name || nodeJson.id}`,
|
|
9822
|
+
value: null,
|
|
9412
9823
|
},
|
|
9824
|
+
action: action,
|
|
9413
9825
|
};
|
|
9414
9826
|
workflow.addNode(node);
|
|
9415
9827
|
});
|
|
@@ -9429,32 +9841,24 @@ class WorkflowParser {
|
|
|
9429
9841
|
name: node.name,
|
|
9430
9842
|
description: node.description,
|
|
9431
9843
|
dependencies: node.dependencies,
|
|
9432
|
-
input: node.input,
|
|
9433
9844
|
output: node.output,
|
|
9434
9845
|
action: {
|
|
9435
9846
|
type: node.action.type,
|
|
9436
9847
|
name: node.action.name,
|
|
9437
9848
|
description: node.action.description,
|
|
9438
|
-
tools: node.action.tools
|
|
9849
|
+
tools: node.action.tools
|
|
9850
|
+
.map((tool) => (typeof tool === 'string' ? tool : tool.name))
|
|
9851
|
+
.filter((tool) => tool !== 'write_context'),
|
|
9439
9852
|
},
|
|
9440
9853
|
})),
|
|
9441
9854
|
variables: Object.fromEntries(workflow.variables),
|
|
9442
9855
|
};
|
|
9443
9856
|
}
|
|
9444
|
-
/**
|
|
9445
|
-
* Helper to convert IO definitions
|
|
9446
|
-
*/
|
|
9447
|
-
static convertIO(io) {
|
|
9448
|
-
return {
|
|
9449
|
-
type: (io === null || io === void 0 ? void 0 : io.type) || 'object',
|
|
9450
|
-
schema: (io === null || io === void 0 ? void 0 : io.schema) || {},
|
|
9451
|
-
value: null,
|
|
9452
|
-
};
|
|
9453
|
-
}
|
|
9454
9857
|
}
|
|
9455
9858
|
|
|
9456
9859
|
exports.ClaudeProvider = ClaudeProvider;
|
|
9457
9860
|
exports.Eko = Eko;
|
|
9861
|
+
exports.ExecutionLogger = ExecutionLogger;
|
|
9458
9862
|
exports.OpenaiProvider = OpenaiProvider;
|
|
9459
9863
|
exports.ToolRegistry = ToolRegistry;
|
|
9460
9864
|
exports.WorkflowGenerator = WorkflowGenerator;
|