@eko-ai/eko 1.0.6 → 1.0.8

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.
@@ -40,6 +40,11 @@ chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
40
40
  sendResponse(result);
41
41
  break;
42
42
  }
43
+ case 'request_user_help': {
44
+ request_user_help(request.task_id, request.failure_type, request.failure_message);
45
+ sendResponse(true);
46
+ break;
47
+ }
43
48
  case 'computer:type': {
44
49
  sendResponse(type(request));
45
50
  break;
@@ -204,7 +209,7 @@ function scroll_to(request) {
204
209
  return false;
205
210
  }
206
211
  element.scrollIntoView({
207
- behavior: 'smooth'
212
+ behavior: 'smooth',
208
213
  });
209
214
  }
210
215
  else if (request.xpath) {
@@ -215,7 +220,7 @@ function scroll_to(request) {
215
220
  return false;
216
221
  }
217
222
  element.scrollIntoView({
218
- behavior: 'smooth'
223
+ behavior: 'smooth',
219
224
  });
220
225
  }
221
226
  else {
@@ -277,3 +282,125 @@ function select_dropdown_option(request) {
277
282
  selectedText: option.text.trim(),
278
283
  };
279
284
  }
285
+ function request_user_help(task_id, failure_type, failure_message) {
286
+ const domId = 'eko-request-user-help';
287
+ if (document.getElementById(domId)) {
288
+ return;
289
+ }
290
+ const failureTitleMap = {
291
+ login_required: 'Login Required',
292
+ captcha: 'Captcha Detected',
293
+ blocked: 'Blocked',
294
+ other: 'Error',
295
+ rate_limited: 'Rate Limited',
296
+ };
297
+ const notification = document.createElement('div');
298
+ notification.id = domId;
299
+ notification.style.cssText = `
300
+ position: fixed;
301
+ top: 5px;
302
+ left: 18px;
303
+ z-index: 9999;
304
+ background-color: #FEF0ED;
305
+ color: white;
306
+ padding: 16px;
307
+ border-radius: 12px;
308
+ border: 1px solid #FBB8A5;
309
+ font-family: Arial, sans-serif;
310
+ width: 350px;
311
+ display: flex;
312
+ flex-direction: row;
313
+ gap: 10px;
314
+ cursor: move;
315
+ user-select: none;
316
+ `;
317
+ let isDragging = false;
318
+ let xOffset = 0;
319
+ let yOffset = 0;
320
+ let initialX = 0;
321
+ let initialY = 0;
322
+ notification.addEventListener('mousedown', (e) => {
323
+ isDragging = true;
324
+ initialX = e.clientX - xOffset;
325
+ initialY = e.clientY - yOffset;
326
+ e.preventDefault();
327
+ });
328
+ document.addEventListener('mousemove', (e) => {
329
+ if (!isDragging)
330
+ return;
331
+ const currentX = e.clientX - initialX;
332
+ const currentY = e.clientY - initialY;
333
+ xOffset = currentX;
334
+ yOffset = currentY;
335
+ notification.style.transform = `translate(${xOffset}px, ${yOffset}px)`;
336
+ });
337
+ document.addEventListener('mouseup', () => {
338
+ isDragging = false;
339
+ });
340
+ const leftContainer = document.createElement('div');
341
+ leftContainer.style.cssText = `
342
+ width: 28px;
343
+ height: 28px;
344
+ display: flex;
345
+ flex-direction: column;
346
+ align-items: center;
347
+ border-radius: 99px;
348
+ background: #FDCCCC;
349
+ justify-content: center;
350
+ `;
351
+ leftContainer.innerHTML = ``;
352
+ const rightContainer = document.createElement('div');
353
+ rightContainer.style.cssText = `
354
+ flex: 1;
355
+ display: flex;
356
+ flex-direction: column;
357
+ `;
358
+ const title = document.createElement('div');
359
+ title.style.cssText = `
360
+ font-size: 16px;
361
+ font-weight: 700;
362
+ line-height: 22px;
363
+ color: #DD342D;
364
+ text-align: left;
365
+ `;
366
+ title.innerText = failureTitleMap[failure_type] || failure_type;
367
+ const message2 = document.createElement('div');
368
+ message2.style.cssText = `
369
+ font-size: 16px;
370
+ font-weight: 400;
371
+ line-height: 22px;
372
+ color: #DD342D;
373
+ text-align: left;
374
+ `;
375
+ message2.innerText = failure_message + '\nWhen you resolve the issue, click the button below.';
376
+ const buttonDiv = document.createElement('div');
377
+ buttonDiv.style.cssText = `
378
+ margin-top: 16px;
379
+ display: flex;
380
+ flex-direction: row-reverse;
381
+ justify-content: flex-start;
382
+ align-items: center;
383
+ `;
384
+ const resolvedBut = document.createElement('div');
385
+ resolvedBut.innerText = 'Resolved';
386
+ resolvedBut.style.cssText = `
387
+ border-radius: 8px;
388
+ background: #DD342D;
389
+ color: white;
390
+ padding: 10px;
391
+ border: none;
392
+ cursor: pointer;
393
+ `;
394
+ resolvedBut.onclick = () => {
395
+ chrome.runtime.sendMessage({ type: 'issue_resolved', task_id, failure_type }, () => {
396
+ notification.remove();
397
+ });
398
+ };
399
+ buttonDiv.appendChild(resolvedBut);
400
+ rightContainer.appendChild(title);
401
+ rightContainer.appendChild(message2);
402
+ rightContainer.appendChild(buttonDiv);
403
+ notification.appendChild(leftContainer);
404
+ notification.appendChild(rightContainer);
405
+ document.body.appendChild(notification);
406
+ }
package/dist/index.cjs.js CHANGED
@@ -243,6 +243,16 @@ class ActionImpl {
243
243
  }
244
244
  }
245
245
  if (context.__skip || context.__abort) {
246
+ toolResultMessage = {
247
+ role: 'user',
248
+ content: [
249
+ {
250
+ type: 'tool_result',
251
+ tool_use_id: toolCall.id,
252
+ content: 'skip',
253
+ },
254
+ ],
255
+ };
246
256
  return;
247
257
  }
248
258
  // Execute the tool
@@ -303,6 +313,7 @@ class ActionImpl {
303
313
  console.error('Stream Error:', error);
304
314
  },
305
315
  };
316
+ this.handleHistoryImageMessages(messages);
306
317
  // Wait for stream to complete
307
318
  await this.llmProvider.generateStream(messages, params, handler);
308
319
  // Wait for tool execution to complete if it was started
@@ -310,7 +321,7 @@ class ActionImpl {
310
321
  await toolExecutionPromise;
311
322
  }
312
323
  if (context.__abort) {
313
- throw new Error("Abort");
324
+ throw new Error('Abort');
314
325
  }
315
326
  // Add messages in the correct order after everything is complete
316
327
  if (assistantTextMessage) {
@@ -324,6 +335,37 @@ class ActionImpl {
324
335
  }
325
336
  return { response, hasToolUse, roundMessages };
326
337
  }
338
+ handleHistoryImageMessages(messages) {
339
+ // Remove all images of the historical tool call results, except for the last one.
340
+ let last_user = true;
341
+ for (let i = messages.length - 1; i >= 0; i--) {
342
+ const message = messages[i];
343
+ if (message.role === 'user') {
344
+ if (last_user) {
345
+ last_user = false;
346
+ continue;
347
+ }
348
+ if (message.content instanceof Array) {
349
+ let content = message.content;
350
+ for (let j = 0; j < content.length; j++) {
351
+ if (content[j].type === 'tool_result' && content[j].content instanceof Array) {
352
+ let tool_content = content[j].content;
353
+ if (tool_content.length > 0) {
354
+ for (let k = tool_content.length - 1; k >= 0; k--) {
355
+ if (tool_content[k].type === 'image') {
356
+ tool_content.splice(k, 1);
357
+ }
358
+ }
359
+ }
360
+ else if (tool_content[0].type === 'image') {
361
+ tool_content = [{ type: 'text', text: 'ok' }];
362
+ }
363
+ }
364
+ }
365
+ }
366
+ }
367
+ }
368
+ }
327
369
  async execute(input, context, outputSchema) {
328
370
  var _a;
329
371
  // Create return tool with output schema
@@ -466,6 +508,7 @@ Generate a complete workflow that:
466
508
  5. Includes detailed descriptions for each action, ensuring that the actions, when combined, is a complete solution to the user's problem`;
467
509
  },
468
510
  formatUserPrompt: (requirement) => `Create a workflow for the following requirement: ${requirement}`,
511
+ modifyUserPrompt: (prompt) => `Modify workflow: ${prompt}`,
469
512
  };
470
513
  }
471
514
  function createWorkflowGenerationTool(registry) {
@@ -540,30 +583,68 @@ class WorkflowGenerator {
540
583
  constructor(llmProvider, toolRegistry) {
541
584
  this.llmProvider = llmProvider;
542
585
  this.toolRegistry = toolRegistry;
586
+ this.message_history = [];
543
587
  }
544
588
  async generateWorkflow(prompt) {
589
+ return this.doGenerateWorkflow(prompt, false);
590
+ }
591
+ async modifyWorkflow(prompt) {
592
+ return this.doGenerateWorkflow(prompt, true);
593
+ }
594
+ async doGenerateWorkflow(prompt, modify) {
545
595
  // Create prompts with current set of tools
546
596
  const prompts = createWorkflowPrompts(this.toolRegistry.getToolDefinitions());
547
- const messages = [
548
- {
549
- role: 'system',
550
- content: prompts.formatSystemPrompt()
551
- },
552
- {
597
+ let messages = [];
598
+ if (modify) {
599
+ messages = this.message_history;
600
+ messages.push({
553
601
  role: 'user',
554
- content: prompts.formatUserPrompt(prompt)
555
- }
556
- ];
602
+ content: prompts.modifyUserPrompt(prompt),
603
+ });
604
+ }
605
+ else {
606
+ messages = this.message_history = [
607
+ {
608
+ role: 'system',
609
+ content: prompts.formatSystemPrompt(),
610
+ },
611
+ {
612
+ role: 'user',
613
+ content: prompts.formatUserPrompt(prompt),
614
+ },
615
+ ];
616
+ }
557
617
  const params = {
558
618
  temperature: 0.7,
559
619
  maxTokens: 8192,
560
620
  tools: [createWorkflowGenerationTool(this.toolRegistry)],
561
- toolChoice: { type: 'tool', name: 'generate_workflow' }
621
+ toolChoice: { type: 'tool', name: 'generate_workflow' },
562
622
  };
563
623
  const response = await this.llmProvider.generateText(messages, params);
564
624
  if (!response.toolCalls.length || !response.toolCalls[0].input.workflow) {
625
+ messages.pop();
565
626
  throw new Error('Failed to generate workflow: Invalid response from LLM');
566
627
  }
628
+ messages.push({
629
+ role: 'assistant',
630
+ content: [
631
+ {
632
+ type: 'tool_use',
633
+ id: response.toolCalls[0].id,
634
+ name: response.toolCalls[0].name,
635
+ input: response.toolCalls[0].input,
636
+ },
637
+ ],
638
+ }, {
639
+ role: 'user',
640
+ content: [
641
+ {
642
+ type: 'tool_result',
643
+ tool_use_id: response.toolCalls[0].id,
644
+ content: 'ok',
645
+ },
646
+ ],
647
+ });
567
648
  const workflowData = response.toolCalls[0].input.workflow;
568
649
  // Validate all tools exist
569
650
  for (const node of workflowData.nodes) {
@@ -590,16 +671,13 @@ class WorkflowGenerator {
590
671
  input: nodeData.input || { type: 'any', schema: {}, value: undefined },
591
672
  output: nodeData.output || { type: 'any', schema: {}, value: undefined },
592
673
  action: action,
593
- dependencies: nodeData.dependencies || []
674
+ dependencies: nodeData.dependencies || [],
594
675
  };
595
676
  workflow.addNode(node);
596
677
  });
597
678
  }
598
679
  return workflow;
599
680
  }
600
- async modifyWorkflow(workflow, prompt) {
601
- throw new Error('Not implemented');
602
- }
603
681
  }
604
682
 
605
683
  const VERSION$1 = '0.33.1'; // x-release-please-version
@@ -8830,13 +8908,61 @@ class OpenaiProvider {
8830
8908
  content: content.text,
8831
8909
  });
8832
8910
  }
8833
- else if (content.type == 'tool_result') {
8911
+ else if (content.type == 'image') {
8834
8912
  _messages.push({
8835
- role: 'tool',
8836
- content: content.content,
8837
- tool_call_id: content.tool_call_id || content.tool_use_id,
8913
+ role: 'user',
8914
+ content: [
8915
+ {
8916
+ type: 'image_url',
8917
+ image_url: {
8918
+ url: `data:${content.source.media_type};base64,${content.source.data}`,
8919
+ },
8920
+ },
8921
+ ],
8838
8922
  });
8839
8923
  }
8924
+ else if (content.type == 'tool_result') {
8925
+ let _content = [];
8926
+ if (content.content == 'string') {
8927
+ _content.push({ type: 'text', text: content.content });
8928
+ }
8929
+ else {
8930
+ for (let k = 0; k < content.content.length; k++) {
8931
+ let item = content.content[k];
8932
+ if (item.type == 'text') {
8933
+ _content.push({ ...item });
8934
+ }
8935
+ else if (item.type == 'image') {
8936
+ _content.push({
8937
+ type: 'image_url',
8938
+ image_url: {
8939
+ url: `data:${item.source.media_type};base64,${item.source.data}`,
8940
+ },
8941
+ });
8942
+ }
8943
+ }
8944
+ }
8945
+ let hasImage = _content.filter((s) => s.type == 'image_url').length > 0;
8946
+ if (hasImage) {
8947
+ // OpenAI does not support images returned by the tool.
8948
+ _messages.push({
8949
+ role: 'tool',
8950
+ content: 'ok',
8951
+ tool_call_id: content.tool_call_id || content.tool_use_id,
8952
+ });
8953
+ _messages.push({
8954
+ role: 'user',
8955
+ content: _content,
8956
+ });
8957
+ }
8958
+ else {
8959
+ _messages.push({
8960
+ role: 'tool',
8961
+ content: _content,
8962
+ tool_call_id: content.tool_call_id || content.tool_use_id,
8963
+ });
8964
+ }
8965
+ }
8840
8966
  }
8841
8967
  }
8842
8968
  else {
@@ -9112,6 +9238,7 @@ class ToolRegistry {
9112
9238
  class Eko {
9113
9239
  constructor(config) {
9114
9240
  this.toolRegistry = new ToolRegistry();
9241
+ this.workflowGeneratorMap = new Map();
9115
9242
  if (typeof config == 'string') {
9116
9243
  this.llmProvider = new ClaudeProvider(config);
9117
9244
  }
@@ -9148,11 +9275,19 @@ class Eko {
9148
9275
  }
9149
9276
  }
9150
9277
  const generator = new WorkflowGenerator(this.llmProvider, toolRegistry);
9151
- return await generator.generateWorkflow(prompt);
9278
+ const workflow = await generator.generateWorkflow(prompt);
9279
+ this.workflowGeneratorMap.set(workflow, generator);
9280
+ return workflow;
9152
9281
  }
9153
9282
  async execute(workflow, callback) {
9154
9283
  return await workflow.execute(callback);
9155
9284
  }
9285
+ async modify(workflow, prompt) {
9286
+ const generator = this.workflowGeneratorMap.get(workflow);
9287
+ workflow = await generator.modifyWorkflow(prompt);
9288
+ this.workflowGeneratorMap.set(workflow, generator);
9289
+ return workflow;
9290
+ }
9156
9291
  getTool(toolName) {
9157
9292
  let tool;
9158
9293
  if (this.toolRegistry.hasTools([toolName])) {
package/dist/index.esm.js CHANGED
@@ -239,6 +239,16 @@ class ActionImpl {
239
239
  }
240
240
  }
241
241
  if (context.__skip || context.__abort) {
242
+ toolResultMessage = {
243
+ role: 'user',
244
+ content: [
245
+ {
246
+ type: 'tool_result',
247
+ tool_use_id: toolCall.id,
248
+ content: 'skip',
249
+ },
250
+ ],
251
+ };
242
252
  return;
243
253
  }
244
254
  // Execute the tool
@@ -299,6 +309,7 @@ class ActionImpl {
299
309
  console.error('Stream Error:', error);
300
310
  },
301
311
  };
312
+ this.handleHistoryImageMessages(messages);
302
313
  // Wait for stream to complete
303
314
  await this.llmProvider.generateStream(messages, params, handler);
304
315
  // Wait for tool execution to complete if it was started
@@ -306,7 +317,7 @@ class ActionImpl {
306
317
  await toolExecutionPromise;
307
318
  }
308
319
  if (context.__abort) {
309
- throw new Error("Abort");
320
+ throw new Error('Abort');
310
321
  }
311
322
  // Add messages in the correct order after everything is complete
312
323
  if (assistantTextMessage) {
@@ -320,6 +331,37 @@ class ActionImpl {
320
331
  }
321
332
  return { response, hasToolUse, roundMessages };
322
333
  }
334
+ handleHistoryImageMessages(messages) {
335
+ // Remove all images of the historical tool call results, except for the last one.
336
+ let last_user = true;
337
+ for (let i = messages.length - 1; i >= 0; i--) {
338
+ const message = messages[i];
339
+ if (message.role === 'user') {
340
+ if (last_user) {
341
+ last_user = false;
342
+ continue;
343
+ }
344
+ if (message.content instanceof Array) {
345
+ let content = message.content;
346
+ for (let j = 0; j < content.length; j++) {
347
+ if (content[j].type === 'tool_result' && content[j].content instanceof Array) {
348
+ let tool_content = content[j].content;
349
+ if (tool_content.length > 0) {
350
+ for (let k = tool_content.length - 1; k >= 0; k--) {
351
+ if (tool_content[k].type === 'image') {
352
+ tool_content.splice(k, 1);
353
+ }
354
+ }
355
+ }
356
+ else if (tool_content[0].type === 'image') {
357
+ tool_content = [{ type: 'text', text: 'ok' }];
358
+ }
359
+ }
360
+ }
361
+ }
362
+ }
363
+ }
364
+ }
323
365
  async execute(input, context, outputSchema) {
324
366
  var _a;
325
367
  // Create return tool with output schema
@@ -462,6 +504,7 @@ Generate a complete workflow that:
462
504
  5. Includes detailed descriptions for each action, ensuring that the actions, when combined, is a complete solution to the user's problem`;
463
505
  },
464
506
  formatUserPrompt: (requirement) => `Create a workflow for the following requirement: ${requirement}`,
507
+ modifyUserPrompt: (prompt) => `Modify workflow: ${prompt}`,
465
508
  };
466
509
  }
467
510
  function createWorkflowGenerationTool(registry) {
@@ -536,30 +579,68 @@ class WorkflowGenerator {
536
579
  constructor(llmProvider, toolRegistry) {
537
580
  this.llmProvider = llmProvider;
538
581
  this.toolRegistry = toolRegistry;
582
+ this.message_history = [];
539
583
  }
540
584
  async generateWorkflow(prompt) {
585
+ return this.doGenerateWorkflow(prompt, false);
586
+ }
587
+ async modifyWorkflow(prompt) {
588
+ return this.doGenerateWorkflow(prompt, true);
589
+ }
590
+ async doGenerateWorkflow(prompt, modify) {
541
591
  // Create prompts with current set of tools
542
592
  const prompts = createWorkflowPrompts(this.toolRegistry.getToolDefinitions());
543
- const messages = [
544
- {
545
- role: 'system',
546
- content: prompts.formatSystemPrompt()
547
- },
548
- {
593
+ let messages = [];
594
+ if (modify) {
595
+ messages = this.message_history;
596
+ messages.push({
549
597
  role: 'user',
550
- content: prompts.formatUserPrompt(prompt)
551
- }
552
- ];
598
+ content: prompts.modifyUserPrompt(prompt),
599
+ });
600
+ }
601
+ else {
602
+ messages = this.message_history = [
603
+ {
604
+ role: 'system',
605
+ content: prompts.formatSystemPrompt(),
606
+ },
607
+ {
608
+ role: 'user',
609
+ content: prompts.formatUserPrompt(prompt),
610
+ },
611
+ ];
612
+ }
553
613
  const params = {
554
614
  temperature: 0.7,
555
615
  maxTokens: 8192,
556
616
  tools: [createWorkflowGenerationTool(this.toolRegistry)],
557
- toolChoice: { type: 'tool', name: 'generate_workflow' }
617
+ toolChoice: { type: 'tool', name: 'generate_workflow' },
558
618
  };
559
619
  const response = await this.llmProvider.generateText(messages, params);
560
620
  if (!response.toolCalls.length || !response.toolCalls[0].input.workflow) {
621
+ messages.pop();
561
622
  throw new Error('Failed to generate workflow: Invalid response from LLM');
562
623
  }
624
+ messages.push({
625
+ role: 'assistant',
626
+ content: [
627
+ {
628
+ type: 'tool_use',
629
+ id: response.toolCalls[0].id,
630
+ name: response.toolCalls[0].name,
631
+ input: response.toolCalls[0].input,
632
+ },
633
+ ],
634
+ }, {
635
+ role: 'user',
636
+ content: [
637
+ {
638
+ type: 'tool_result',
639
+ tool_use_id: response.toolCalls[0].id,
640
+ content: 'ok',
641
+ },
642
+ ],
643
+ });
563
644
  const workflowData = response.toolCalls[0].input.workflow;
564
645
  // Validate all tools exist
565
646
  for (const node of workflowData.nodes) {
@@ -586,16 +667,13 @@ class WorkflowGenerator {
586
667
  input: nodeData.input || { type: 'any', schema: {}, value: undefined },
587
668
  output: nodeData.output || { type: 'any', schema: {}, value: undefined },
588
669
  action: action,
589
- dependencies: nodeData.dependencies || []
670
+ dependencies: nodeData.dependencies || [],
590
671
  };
591
672
  workflow.addNode(node);
592
673
  });
593
674
  }
594
675
  return workflow;
595
676
  }
596
- async modifyWorkflow(workflow, prompt) {
597
- throw new Error('Not implemented');
598
- }
599
677
  }
600
678
 
601
679
  const VERSION$1 = '0.33.1'; // x-release-please-version
@@ -8826,13 +8904,61 @@ class OpenaiProvider {
8826
8904
  content: content.text,
8827
8905
  });
8828
8906
  }
8829
- else if (content.type == 'tool_result') {
8907
+ else if (content.type == 'image') {
8830
8908
  _messages.push({
8831
- role: 'tool',
8832
- content: content.content,
8833
- tool_call_id: content.tool_call_id || content.tool_use_id,
8909
+ role: 'user',
8910
+ content: [
8911
+ {
8912
+ type: 'image_url',
8913
+ image_url: {
8914
+ url: `data:${content.source.media_type};base64,${content.source.data}`,
8915
+ },
8916
+ },
8917
+ ],
8834
8918
  });
8835
8919
  }
8920
+ else if (content.type == 'tool_result') {
8921
+ let _content = [];
8922
+ if (content.content == 'string') {
8923
+ _content.push({ type: 'text', text: content.content });
8924
+ }
8925
+ else {
8926
+ for (let k = 0; k < content.content.length; k++) {
8927
+ let item = content.content[k];
8928
+ if (item.type == 'text') {
8929
+ _content.push({ ...item });
8930
+ }
8931
+ else if (item.type == 'image') {
8932
+ _content.push({
8933
+ type: 'image_url',
8934
+ image_url: {
8935
+ url: `data:${item.source.media_type};base64,${item.source.data}`,
8936
+ },
8937
+ });
8938
+ }
8939
+ }
8940
+ }
8941
+ let hasImage = _content.filter((s) => s.type == 'image_url').length > 0;
8942
+ if (hasImage) {
8943
+ // OpenAI does not support images returned by the tool.
8944
+ _messages.push({
8945
+ role: 'tool',
8946
+ content: 'ok',
8947
+ tool_call_id: content.tool_call_id || content.tool_use_id,
8948
+ });
8949
+ _messages.push({
8950
+ role: 'user',
8951
+ content: _content,
8952
+ });
8953
+ }
8954
+ else {
8955
+ _messages.push({
8956
+ role: 'tool',
8957
+ content: _content,
8958
+ tool_call_id: content.tool_call_id || content.tool_use_id,
8959
+ });
8960
+ }
8961
+ }
8836
8962
  }
8837
8963
  }
8838
8964
  else {
@@ -9108,6 +9234,7 @@ class ToolRegistry {
9108
9234
  class Eko {
9109
9235
  constructor(config) {
9110
9236
  this.toolRegistry = new ToolRegistry();
9237
+ this.workflowGeneratorMap = new Map();
9111
9238
  if (typeof config == 'string') {
9112
9239
  this.llmProvider = new ClaudeProvider(config);
9113
9240
  }
@@ -9144,11 +9271,19 @@ class Eko {
9144
9271
  }
9145
9272
  }
9146
9273
  const generator = new WorkflowGenerator(this.llmProvider, toolRegistry);
9147
- return await generator.generateWorkflow(prompt);
9274
+ const workflow = await generator.generateWorkflow(prompt);
9275
+ this.workflowGeneratorMap.set(workflow, generator);
9276
+ return workflow;
9148
9277
  }
9149
9278
  async execute(workflow, callback) {
9150
9279
  return await workflow.execute(callback);
9151
9280
  }
9281
+ async modify(workflow, prompt) {
9282
+ const generator = this.workflowGeneratorMap.get(workflow);
9283
+ workflow = await generator.modifyWorkflow(prompt);
9284
+ this.workflowGeneratorMap.set(workflow, generator);
9285
+ return workflow;
9286
+ }
9152
9287
  getTool(toolName) {
9153
9288
  let tool;
9154
9289
  if (this.toolRegistry.hasTools([toolName])) {