@elizaos/plugin-workflow 2.0.0-beta.1 → 2.0.3-beta.5

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.
Files changed (170) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +28 -26
  3. package/dist/actions/eval-code.d.ts +12 -0
  4. package/dist/actions/eval-code.d.ts.map +1 -0
  5. package/dist/actions/eval-code.js +59 -0
  6. package/dist/actions/eval-code.js.map +1 -0
  7. package/dist/actions/index.d.ts +1 -0
  8. package/dist/actions/index.d.ts.map +1 -1
  9. package/dist/actions/index.js +1 -0
  10. package/dist/actions/index.js.map +1 -1
  11. package/dist/actions/workflow.d.ts +7 -0
  12. package/dist/actions/workflow.d.ts.map +1 -1
  13. package/dist/actions/workflow.js +462 -10
  14. package/dist/actions/workflow.js.map +1 -1
  15. package/dist/db/schema.d.ts +196 -0
  16. package/dist/db/schema.d.ts.map +1 -1
  17. package/dist/db/schema.js +23 -0
  18. package/dist/db/schema.js.map +1 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +9 -64
  21. package/dist/index.js.map +1 -1
  22. package/dist/lib/automations-builder.d.ts.map +1 -1
  23. package/dist/lib/automations-builder.js +10 -35
  24. package/dist/lib/automations-builder.js.map +1 -1
  25. package/dist/lib/automations-types.d.ts +2 -2
  26. package/dist/lib/automations-types.d.ts.map +1 -1
  27. package/dist/lib/automations-types.js.map +1 -1
  28. package/dist/lib/index.d.ts +0 -2
  29. package/dist/lib/index.d.ts.map +1 -1
  30. package/dist/lib/index.js +1 -2
  31. package/dist/lib/index.js.map +1 -1
  32. package/dist/lib/workflow-clarification.d.ts +2 -2
  33. package/dist/lib/workflow-clarification.d.ts.map +1 -1
  34. package/dist/lib/workflow-clarification.js +15 -11
  35. package/dist/lib/workflow-clarification.js.map +1 -1
  36. package/dist/plugin-routes.d.ts.map +1 -1
  37. package/dist/plugin-routes.js +6 -0
  38. package/dist/plugin-routes.js.map +1 -1
  39. package/dist/providers/activeWorkflows.js +2 -2
  40. package/dist/providers/activeWorkflows.js.map +1 -1
  41. package/dist/providers/workflowStatus.js +1 -1
  42. package/dist/providers/workflowStatus.js.map +1 -1
  43. package/dist/routes/workflow-routes.d.ts.map +1 -1
  44. package/dist/routes/workflow-routes.js +68 -2
  45. package/dist/routes/workflow-routes.js.map +1 -1
  46. package/dist/routes/workflows.d.ts.map +1 -1
  47. package/dist/routes/workflows.js +5 -1
  48. package/dist/routes/workflows.js.map +1 -1
  49. package/dist/services/embedded-workflow-service.d.ts +74 -17
  50. package/dist/services/embedded-workflow-service.d.ts.map +1 -1
  51. package/dist/services/embedded-workflow-service.js +343 -149
  52. package/dist/services/embedded-workflow-service.js.map +1 -1
  53. package/dist/services/smithers-runtime.d.ts +47 -0
  54. package/dist/services/smithers-runtime.d.ts.map +1 -0
  55. package/dist/services/smithers-runtime.js +444 -0
  56. package/dist/services/smithers-runtime.js.map +1 -0
  57. package/dist/services/workflow-credential-store.js +1 -1
  58. package/dist/services/workflow-credential-store.js.map +1 -1
  59. package/dist/services/workflow-dispatch.d.ts +31 -1
  60. package/dist/services/workflow-dispatch.d.ts.map +1 -1
  61. package/dist/services/workflow-dispatch.js +75 -10
  62. package/dist/services/workflow-dispatch.js.map +1 -1
  63. package/dist/services/workflow-service.d.ts +27 -1
  64. package/dist/services/workflow-service.d.ts.map +1 -1
  65. package/dist/services/workflow-service.js +133 -11
  66. package/dist/services/workflow-service.js.map +1 -1
  67. package/dist/trigger-routes.d.ts +2 -18
  68. package/dist/trigger-routes.d.ts.map +1 -1
  69. package/dist/trigger-routes.js +11 -39
  70. package/dist/trigger-routes.js.map +1 -1
  71. package/dist/types/index.d.ts +82 -2
  72. package/dist/types/index.d.ts.map +1 -1
  73. package/dist/types/index.js.map +1 -1
  74. package/dist/types/workflow-contracts.d.ts +118 -0
  75. package/dist/types/workflow-contracts.d.ts.map +1 -0
  76. package/dist/types/workflow-contracts.js +2 -0
  77. package/dist/types/workflow-contracts.js.map +1 -0
  78. package/dist/utils/catalog.js +2 -2
  79. package/dist/utils/catalog.js.map +1 -1
  80. package/dist/utils/clarification.d.ts +1 -1
  81. package/dist/utils/clarification.d.ts.map +1 -1
  82. package/dist/utils/clarification.js +15 -4
  83. package/dist/utils/clarification.js.map +1 -1
  84. package/dist/utils/context.js +1 -1
  85. package/dist/utils/context.js.map +1 -1
  86. package/dist/utils/evaluation-samples.d.ts +6 -0
  87. package/dist/utils/evaluation-samples.d.ts.map +1 -0
  88. package/dist/utils/evaluation-samples.js +216 -0
  89. package/dist/utils/evaluation-samples.js.map +1 -0
  90. package/dist/utils/execution-diagnostics.d.ts +26 -0
  91. package/dist/utils/execution-diagnostics.d.ts.map +1 -0
  92. package/dist/utils/execution-diagnostics.js +159 -0
  93. package/dist/utils/execution-diagnostics.js.map +1 -0
  94. package/dist/utils/generation.d.ts.map +1 -1
  95. package/dist/utils/generation.js +134 -19
  96. package/dist/utils/generation.js.map +1 -1
  97. package/dist/utils/host-capabilities.d.ts.map +1 -1
  98. package/dist/utils/host-capabilities.js +20 -5
  99. package/dist/utils/host-capabilities.js.map +1 -1
  100. package/dist/utils/inferSyntheticOutputSchema.js +3 -3
  101. package/dist/utils/inferSyntheticOutputSchema.js.map +1 -1
  102. package/dist/utils/outputSchema.js +1 -1
  103. package/dist/utils/outputSchema.js.map +1 -1
  104. package/dist/utils/validateAndRepair.js +10 -10
  105. package/dist/utils/validateAndRepair.js.map +1 -1
  106. package/dist/utils/workflow-prompts/draftIntent.d.ts +1 -1
  107. package/dist/utils/workflow-prompts/draftIntent.d.ts.map +1 -1
  108. package/dist/utils/workflow-prompts/draftIntent.js +1 -1
  109. package/dist/utils/workflow-prompts/keywordExtraction.d.ts +1 -1
  110. package/dist/utils/workflow-prompts/keywordExtraction.d.ts.map +1 -1
  111. package/dist/utils/workflow-prompts/keywordExtraction.js +1 -1
  112. package/dist/utils/workflow-prompts/workflowGeneration.d.ts +1 -1
  113. package/dist/utils/workflow-prompts/workflowGeneration.d.ts.map +1 -1
  114. package/dist/utils/workflow-prompts/workflowGeneration.js +4 -4
  115. package/dist/utils/workflow-prompts/workflowMatching.d.ts +1 -1
  116. package/dist/utils/workflow-prompts/workflowMatching.d.ts.map +1 -1
  117. package/dist/utils/workflow-prompts/workflowMatching.js +1 -1
  118. package/dist/utils/workflow.d.ts +1 -0
  119. package/dist/utils/workflow.d.ts.map +1 -1
  120. package/dist/utils/workflow.js +44 -8
  121. package/dist/utils/workflow.js.map +1 -1
  122. package/package.json +27 -8
  123. package/registry-entry.json +25 -0
  124. package/src/actions/eval-code.ts +81 -0
  125. package/src/actions/index.ts +1 -0
  126. package/src/actions/workflow.ts +518 -10
  127. package/src/db/schema.ts +31 -0
  128. package/src/index.ts +9 -82
  129. package/src/lib/automations-builder.ts +11 -35
  130. package/src/lib/automations-types.ts +1 -2
  131. package/src/lib/index.ts +0 -8
  132. package/src/lib/workflow-clarification.ts +18 -13
  133. package/src/plugin-routes.ts +6 -0
  134. package/src/providers/activeWorkflows.ts +2 -2
  135. package/src/providers/workflowStatus.ts +1 -1
  136. package/src/routes/workflow-routes.ts +100 -2
  137. package/src/routes/workflows.ts +5 -1
  138. package/src/services/embedded-workflow-service.ts +447 -172
  139. package/src/services/smithers-runtime.ts +526 -0
  140. package/src/services/workflow-credential-store.ts +1 -1
  141. package/src/services/workflow-dispatch.ts +116 -13
  142. package/src/services/workflow-service.ts +186 -10
  143. package/src/trigger-routes.ts +12 -70
  144. package/src/types/index.ts +94 -2
  145. package/src/types/workflow-contracts.ts +166 -0
  146. package/src/utils/catalog.ts +2 -2
  147. package/src/utils/clarification.ts +19 -5
  148. package/src/utils/context.ts +1 -1
  149. package/src/utils/evaluation-samples.ts +239 -0
  150. package/src/utils/execution-diagnostics.ts +192 -0
  151. package/src/utils/generation.ts +224 -32
  152. package/src/utils/host-capabilities.ts +21 -5
  153. package/src/utils/inferSyntheticOutputSchema.ts +3 -3
  154. package/src/utils/outputSchema.ts +1 -1
  155. package/src/utils/validateAndRepair.ts +10 -10
  156. package/src/utils/workflow-prompts/draftIntent.ts +1 -1
  157. package/src/utils/workflow-prompts/keywordExtraction.ts +1 -1
  158. package/src/utils/workflow-prompts/workflowGeneration.ts +4 -4
  159. package/src/utils/workflow-prompts/workflowMatching.ts +1 -1
  160. package/src/utils/workflow.ts +56 -8
  161. package/dist/lib/legacy-task-migration.d.ts +0 -20
  162. package/dist/lib/legacy-task-migration.d.ts.map +0 -1
  163. package/dist/lib/legacy-task-migration.js +0 -110
  164. package/dist/lib/legacy-task-migration.js.map +0 -1
  165. package/dist/lib/legacy-text-trigger-migration.d.ts +0 -18
  166. package/dist/lib/legacy-text-trigger-migration.d.ts.map +0 -1
  167. package/dist/lib/legacy-text-trigger-migration.js +0 -131
  168. package/dist/lib/legacy-text-trigger-migration.js.map +0 -1
  169. package/src/lib/legacy-task-migration.ts +0 -143
  170. package/src/lib/legacy-text-trigger-migration.ts +0 -178
@@ -2,13 +2,20 @@
2
2
  * WORKFLOW — single umbrella action for workflow lifecycle ops.
3
3
  *
4
4
  * Action-based dispatch (provide `action` parameter):
5
+ * list — list deployed workflows for the current user
6
+ * get — fetch one deployed workflow definition by id
5
7
  * create — generate + deploy a new workflow from a seed prompt
6
8
  * modify — load a deployed workflow into the draft editor by id
7
9
  * activate — activate a workflow by id
8
10
  * deactivate — deactivate a workflow by id
9
11
  * toggle_active — explicit active=true|false (preferred when scripting)
10
12
  * delete — permanently delete a workflow by id
13
+ * run — run a workflow immediately
11
14
  * executions — fetch recent executions for a workflow id
15
+ * revisions — fetch restorable workflow versions
16
+ * restore — restore a workflow by version id
17
+ * diagnose — inspect a failed/recent workflow execution
18
+ * eval_samples — generate JSONL evaluation samples from recent executions
12
19
  *
13
20
  * All actions talk to the in-process `WorkflowService` via
14
21
  * `runtime.getService(WORKFLOW_SERVICE_TYPE)`. There is no HTTP boundary.
@@ -34,22 +41,41 @@ import type {
34
41
  WorkflowCreationResult,
35
42
  WorkflowDefinition,
36
43
  WorkflowDefinitionResponse,
44
+ WorkflowExecution,
37
45
  } from '../types/index';
46
+ import {
47
+ buildWorkflowExecutionDiagnostics,
48
+ getWorkflowExecutionError,
49
+ summarizeWorkflowExecution,
50
+ } from '../utils/execution-diagnostics';
38
51
 
39
52
  const WORKFLOW_ACTION = 'WORKFLOW';
40
53
 
41
54
  const WORKFLOW_OPS = [
55
+ 'list',
56
+ 'search',
57
+ 'get',
42
58
  'create',
43
59
  'modify',
44
60
  'activate',
45
61
  'deactivate',
46
62
  'toggle_active',
47
63
  'delete',
64
+ 'run',
48
65
  'executions',
66
+ 'revisions',
67
+ 'restore',
68
+ 'diagnose',
69
+ 'eval_samples',
49
70
  ] as const;
50
71
  type WorkflowOp = (typeof WORKFLOW_OPS)[number];
51
72
 
52
- const WORKFLOW_CONTEXTS = ['automation', 'tasks', 'agent_internal'] as const;
73
+ // `general` (the active context a plain chat/Telegram turn actually seeds) is
74
+ // included so a message like "find my Slack workflow" routes to WORKFLOW search,
75
+ // not just automation/agent-internal turns (#8913). The gate matches active
76
+ // contexts literally; `chat` is only an alias of the `general` *definition* and is
77
+ // NOT expanded by normalizeContextList, so listing `chat` here would be inert.
78
+ const WORKFLOW_CONTEXTS = ['general', 'automation', 'tasks', 'agent_internal'] as const;
53
79
 
54
80
  interface WorkflowActionParameters {
55
81
  action?: unknown;
@@ -58,8 +84,12 @@ interface WorkflowActionParameters {
58
84
  name?: unknown;
59
85
  workflowId?: unknown;
60
86
  workflowName?: unknown;
87
+ executionId?: unknown;
61
88
  active?: unknown;
62
89
  limit?: unknown;
90
+ versionId?: unknown;
91
+ query?: unknown;
92
+ q?: unknown;
63
93
  }
64
94
 
65
95
  function readString(value: unknown): string | undefined {
@@ -97,7 +127,7 @@ function getWorkflowService(runtime: IAgentRuntime): WorkflowService | null {
97
127
  }
98
128
 
99
129
  function resolveAgentId(runtime: IAgentRuntime): string {
100
- return runtime.agentId ?? runtime.character?.id ?? '00000000-0000-0000-0000-000000000000';
130
+ return runtime.agentId;
101
131
  }
102
132
 
103
133
  function summarizeWorkflow(
@@ -106,14 +136,135 @@ function summarizeWorkflow(
106
136
  id: string;
107
137
  name: string;
108
138
  active: boolean;
139
+ nodeCount?: number;
109
140
  } {
141
+ const nodes = (workflow as { nodes?: unknown[]; nodeCount?: number }).nodes;
142
+ const nodeCount =
143
+ typeof (workflow as { nodeCount?: unknown }).nodeCount === 'number'
144
+ ? (workflow as { nodeCount: number }).nodeCount
145
+ : Array.isArray(nodes)
146
+ ? nodes.length
147
+ : undefined;
110
148
  return {
111
149
  id: String((workflow as { id?: string }).id ?? ''),
112
- name: String(workflow.name ?? ''),
150
+ name: String(workflow.name),
113
151
  active: Boolean((workflow as { active?: boolean }).active),
152
+ ...(typeof nodeCount === 'number' ? { nodeCount } : {}),
114
153
  };
115
154
  }
116
155
 
156
+ async function handleListWorkflows(
157
+ service: WorkflowService,
158
+ params: WorkflowActionParameters,
159
+ message: Memory,
160
+ callback: HandlerCallback | undefined
161
+ ): Promise<ActionResult> {
162
+ const limit = Math.min(Math.max(1, readNumber(params.limit) ?? 20), 50);
163
+ try {
164
+ const workflows = await service.listWorkflows(String(message.entityId));
165
+ const summaries = workflows.slice(0, limit).map(summarizeWorkflow);
166
+ const text =
167
+ summaries.length === 0
168
+ ? 'No workflows found.'
169
+ : `Found ${summaries.length} workflow${summaries.length === 1 ? '' : 's'}.`;
170
+ if (callback) {
171
+ await callback({
172
+ text,
173
+ action: WORKFLOW_ACTION,
174
+ metadata: { count: summaries.length },
175
+ });
176
+ }
177
+ return {
178
+ success: true,
179
+ text,
180
+ values: { count: summaries.length },
181
+ data: { workflows: summaries, total: workflows.length },
182
+ };
183
+ } catch (err) {
184
+ const message = err instanceof Error ? err.message : String(err);
185
+ logger.warn({ src: 'plugin:workflow:action:list' }, message);
186
+ return { success: false, text: message };
187
+ }
188
+ }
189
+
190
+ async function handleSearchWorkflows(
191
+ service: WorkflowService,
192
+ params: WorkflowActionParameters,
193
+ message: Memory,
194
+ callback: HandlerCallback | undefined
195
+ ): Promise<ActionResult> {
196
+ const query = readString(params.query) ?? readString(params.q);
197
+ if (!query) {
198
+ return {
199
+ success: false,
200
+ text: 'A search `query` is required (free text to match workflow name / node type / description).',
201
+ };
202
+ }
203
+ const limit = Math.min(Math.max(1, readNumber(params.limit) ?? 20), 50);
204
+ try {
205
+ const matches = await service.searchWorkflows(query, String(message.entityId));
206
+ const summaries = matches.slice(0, limit).map(summarizeWorkflow);
207
+ const text =
208
+ summaries.length === 0
209
+ ? `No workflows match "${query}".`
210
+ : `Found ${summaries.length} workflow${summaries.length === 1 ? '' : 's'} matching "${query}".`;
211
+ if (callback) {
212
+ await callback({
213
+ text,
214
+ action: WORKFLOW_ACTION,
215
+ metadata: { count: summaries.length, query },
216
+ });
217
+ }
218
+ return {
219
+ success: true,
220
+ text,
221
+ values: { count: summaries.length },
222
+ data: { workflows: summaries, total: matches.length, query },
223
+ };
224
+ } catch (err) {
225
+ const errMessage = err instanceof Error ? err.message : String(err);
226
+ logger.warn({ src: 'plugin:workflow:action:search' }, errMessage);
227
+ return { success: false, text: errMessage };
228
+ }
229
+ }
230
+
231
+ async function handleGetWorkflow(
232
+ service: WorkflowService,
233
+ params: WorkflowActionParameters,
234
+ callback: HandlerCallback | undefined
235
+ ): Promise<ActionResult> {
236
+ const workflowId = readString(params.workflowId);
237
+ if (!workflowId) {
238
+ return { success: false, text: 'workflowId is required to review a workflow.' };
239
+ }
240
+ try {
241
+ const workflow = await service.getWorkflow(workflowId);
242
+ const text = `Fetched workflow "${workflow.name}" for review.`;
243
+ if (callback) {
244
+ await callback({
245
+ text,
246
+ action: WORKFLOW_ACTION,
247
+ metadata: { workflowId, workflowName: workflow.name },
248
+ });
249
+ }
250
+ return {
251
+ success: true,
252
+ text,
253
+ values: {
254
+ workflowId,
255
+ workflowName: workflow.name,
256
+ active: Boolean(workflow.active),
257
+ nodeCount: workflow.nodes.length,
258
+ },
259
+ data: { workflow },
260
+ };
261
+ } catch (err) {
262
+ const message = err instanceof Error ? err.message : String(err);
263
+ logger.warn({ src: 'plugin:workflow:action:get' }, message);
264
+ return { success: false, text: message };
265
+ }
266
+ }
267
+
117
268
  async function handleCreate(
118
269
  runtime: IAgentRuntime,
119
270
  service: WorkflowService,
@@ -131,14 +282,14 @@ async function handleCreate(
131
282
  }
132
283
  try {
133
284
  const draft = await service.generateWorkflowDraft(seedPrompt, {
134
- userId: String(message.entityId ?? resolveAgentId(runtime)),
285
+ userId: String(message.entityId),
135
286
  });
136
287
  if (name) {
137
288
  draft.name = name;
138
289
  }
139
290
  const deployed = await service.deployWorkflow(draft, resolveAgentId(runtime));
140
291
  if (!deployed.id) {
141
- const missing = (deployed.missingCredentials ?? []).map((c) => c.credType).join(', ');
292
+ const missing = deployed.missingCredentials.map((c) => c.credType).join(', ');
142
293
  const text = missing
143
294
  ? `Workflow generated but missing credentials: ${missing}.`
144
295
  : 'Workflow generation produced no deployable result.';
@@ -297,7 +448,7 @@ async function handleExecutions(
297
448
  const limit = readNumber(params.limit) ?? 10;
298
449
  try {
299
450
  const response = await service.listExecutions({ workflowId, limit });
300
- const executions = response.data ?? [];
451
+ const executions = response.data;
301
452
  const text =
302
453
  executions.length === 0
303
454
  ? `No executions found for workflow ${workflowId}.`
@@ -322,14 +473,262 @@ async function handleExecutions(
322
473
  }
323
474
  }
324
475
 
476
+ async function handleRunWorkflow(
477
+ service: WorkflowService,
478
+ params: WorkflowActionParameters,
479
+ callback: HandlerCallback | undefined
480
+ ): Promise<ActionResult> {
481
+ const workflowId = readString(params.workflowId);
482
+ if (!workflowId) {
483
+ return { success: false, text: 'workflowId is required to run a workflow.' };
484
+ }
485
+ try {
486
+ const execution = await service.runWorkflow(workflowId, { throwOnError: false });
487
+ const text = `Ran workflow ${workflowId}: ${execution.status}.`;
488
+ if (callback) {
489
+ await callback({
490
+ text,
491
+ action: WORKFLOW_ACTION,
492
+ metadata: { workflowId, executionId: execution.id, status: execution.status },
493
+ });
494
+ }
495
+ return {
496
+ success: execution.status !== 'error' && execution.status !== 'crashed',
497
+ text,
498
+ values: { workflowId, executionId: execution.id, status: execution.status },
499
+ data: { execution },
500
+ };
501
+ } catch (err) {
502
+ const msg = err instanceof Error ? err.message : String(err);
503
+ logger.warn({ src: 'plugin:workflow:action:run' }, msg);
504
+ return { success: false, text: msg };
505
+ }
506
+ }
507
+
508
+ async function handleRevisions(
509
+ service: WorkflowService,
510
+ params: WorkflowActionParameters,
511
+ callback: HandlerCallback | undefined
512
+ ): Promise<ActionResult> {
513
+ const workflowId = readString(params.workflowId);
514
+ if (!workflowId) {
515
+ return { success: false, text: 'workflowId is required to fetch workflow revisions.' };
516
+ }
517
+ const limit = readNumber(params.limit) ?? 10;
518
+ try {
519
+ const revisions = await service.listWorkflowRevisions(workflowId, limit);
520
+ const text =
521
+ revisions.length === 0
522
+ ? `No revisions found for workflow ${workflowId}.`
523
+ : `Fetched ${revisions.length} revisions for workflow ${workflowId}.`;
524
+ if (callback) {
525
+ await callback({
526
+ text,
527
+ action: WORKFLOW_ACTION,
528
+ metadata: { workflowId, count: revisions.length },
529
+ });
530
+ }
531
+ return {
532
+ success: true,
533
+ text,
534
+ values: { workflowId, count: revisions.length },
535
+ data: { revisions },
536
+ };
537
+ } catch (err) {
538
+ const msg = err instanceof Error ? err.message : String(err);
539
+ logger.warn({ src: 'plugin:workflow:action:revisions' }, msg);
540
+ return { success: false, text: msg };
541
+ }
542
+ }
543
+
544
+ async function handleRestoreRevision(
545
+ service: WorkflowService,
546
+ params: WorkflowActionParameters,
547
+ callback: HandlerCallback | undefined
548
+ ): Promise<ActionResult> {
549
+ const workflowId = readString(params.workflowId);
550
+ const versionId = readString(params.versionId);
551
+ if (!workflowId) {
552
+ return { success: false, text: 'workflowId is required to restore a workflow revision.' };
553
+ }
554
+ if (!versionId) {
555
+ return { success: false, text: 'versionId is required to restore a workflow revision.' };
556
+ }
557
+ try {
558
+ const workflow = await service.restoreWorkflowRevision(workflowId, versionId);
559
+ const text = `Restored workflow "${workflow.name}".`;
560
+ if (callback) {
561
+ await callback({
562
+ text,
563
+ action: WORKFLOW_ACTION,
564
+ metadata: { workflowId, versionId, workflowName: workflow.name },
565
+ });
566
+ }
567
+ return {
568
+ success: true,
569
+ text,
570
+ values: { workflowId, workflowName: workflow.name, versionId },
571
+ data: { workflow: summarizeWorkflow(workflow) },
572
+ };
573
+ } catch (err) {
574
+ const msg = err instanceof Error ? err.message : String(err);
575
+ logger.warn({ src: 'plugin:workflow:action:restore' }, msg);
576
+ return { success: false, text: msg };
577
+ }
578
+ }
579
+
580
+ function isProblemExecution(execution: WorkflowExecution): boolean {
581
+ return (
582
+ execution.status === 'error' ||
583
+ execution.status === 'crashed' ||
584
+ execution.status === 'canceled' ||
585
+ Boolean(getWorkflowExecutionError(execution))
586
+ );
587
+ }
588
+
589
+ async function handleDiagnoseExecution(
590
+ service: WorkflowService,
591
+ params: WorkflowActionParameters,
592
+ callback: HandlerCallback | undefined
593
+ ): Promise<ActionResult> {
594
+ const workflowId = readString(params.workflowId);
595
+ const executionId = readString(params.executionId);
596
+ const limit = Math.min(Math.max(1, readNumber(params.limit) ?? 10), 50);
597
+ if (!executionId && !workflowId) {
598
+ return {
599
+ success: false,
600
+ text: 'workflowId or executionId is required to diagnose a workflow run.',
601
+ };
602
+ }
603
+
604
+ try {
605
+ let execution: WorkflowExecution | undefined;
606
+ if (executionId) {
607
+ execution = await service.getExecutionDetail(executionId);
608
+ if (workflowId && execution.workflowId !== workflowId) {
609
+ return {
610
+ success: false,
611
+ text: `Execution ${executionId} belongs to workflow ${execution.workflowId}, not ${workflowId}.`,
612
+ };
613
+ }
614
+ } else if (workflowId) {
615
+ const response = await service.listExecutions({ workflowId, limit });
616
+ execution = response.data.find(isProblemExecution) ?? response.data[0];
617
+ if (!execution) {
618
+ return {
619
+ success: false,
620
+ text: `No executions found for workflow ${workflowId}. Run it before diagnosing.`,
621
+ };
622
+ }
623
+ }
624
+
625
+ if (!execution) {
626
+ return { success: false, text: 'No workflow execution was available to diagnose.' };
627
+ }
628
+
629
+ const summary = summarizeWorkflowExecution(execution);
630
+ const diagnostics = buildWorkflowExecutionDiagnostics(execution);
631
+ const text = summary.error
632
+ ? `Diagnosed workflow ${execution.workflowId} execution ${execution.id}: ${summary.statusLabel} - ${summary.error}`
633
+ : `Diagnosed workflow ${execution.workflowId} execution ${execution.id}: ${summary.statusLabel}.`;
634
+ if (callback) {
635
+ await callback({
636
+ text,
637
+ action: WORKFLOW_ACTION,
638
+ metadata: {
639
+ workflowId: execution.workflowId,
640
+ executionId: execution.id,
641
+ status: execution.status,
642
+ ...(summary.error ? { error: summary.error } : {}),
643
+ },
644
+ });
645
+ }
646
+ return {
647
+ success: true,
648
+ text,
649
+ values: {
650
+ workflowId: execution.workflowId,
651
+ executionId: execution.id,
652
+ status: execution.status,
653
+ ...(summary.error ? { error: summary.error } : {}),
654
+ },
655
+ data: { execution, summary, diagnostics },
656
+ };
657
+ } catch (err) {
658
+ const msg = err instanceof Error ? err.message : String(err);
659
+ logger.warn({ src: 'plugin:workflow:action:diagnose' }, msg);
660
+ return { success: false, text: msg };
661
+ }
662
+ }
663
+
664
+ async function handleEvaluationSamples(
665
+ service: WorkflowService,
666
+ params: WorkflowActionParameters,
667
+ callback: HandlerCallback | undefined
668
+ ): Promise<ActionResult> {
669
+ const workflowId = readString(params.workflowId);
670
+ if (!workflowId) {
671
+ return {
672
+ success: false,
673
+ text: 'workflowId is required to generate workflow evaluation samples.',
674
+ };
675
+ }
676
+ const limit = readNumber(params.limit) ?? 10;
677
+ try {
678
+ const suite = await service.getWorkflowEvaluationSuite(workflowId, limit);
679
+ const text =
680
+ suite.sampleCount === 0
681
+ ? `No executions found for workflow ${workflowId}; run it before generating eval samples.`
682
+ : [
683
+ `Generated ${suite.sampleCount} workflow eval sample${suite.sampleCount === 1 ? '' : 's'} for ${workflowId}.`,
684
+ `Save cases to ${suite.optimizer.caseFile}.`,
685
+ `Eval: ${suite.optimizer.recommendedEvalCommand}`,
686
+ `Optimize: ${suite.optimizer.recommendedOptimizeCommand}`,
687
+ ].join('\n');
688
+ if (callback) {
689
+ await callback({
690
+ text,
691
+ action: WORKFLOW_ACTION,
692
+ metadata: {
693
+ workflowId,
694
+ count: suite.sampleCount,
695
+ caseFile: suite.optimizer.caseFile,
696
+ suiteName: suite.optimizer.suiteName,
697
+ },
698
+ });
699
+ }
700
+ return {
701
+ success: true,
702
+ text,
703
+ values: {
704
+ workflowId,
705
+ count: suite.sampleCount,
706
+ caseFile: suite.optimizer.caseFile,
707
+ suiteName: suite.optimizer.suiteName,
708
+ },
709
+ data: { suite },
710
+ };
711
+ } catch (err) {
712
+ const msg = err instanceof Error ? err.message : String(err);
713
+ logger.warn({ src: 'plugin:workflow:action:eval_samples' }, msg);
714
+ return { success: false, text: msg };
715
+ }
716
+ }
717
+
325
718
  export const workflowAction: Action = {
326
719
  name: WORKFLOW_ACTION,
327
720
  contexts: [...WORKFLOW_CONTEXTS],
328
721
  contextGate: { anyOf: [...WORKFLOW_CONTEXTS] },
329
722
  roleGate: { minRole: 'OWNER' },
330
723
  similes: [
724
+ 'LIST_WORKFLOWS',
725
+ 'SHOW_WORKFLOWS',
726
+ 'GET_WORKFLOW',
727
+ 'REVIEW_WORKFLOW',
331
728
  'CREATE_WORKFLOW',
332
729
  'DELETE_WORKFLOW',
730
+ 'RUN_WORKFLOW',
731
+ 'RUN_WORKFLOW_NOW',
333
732
  'TOGGLE_WORKFLOW_ACTIVE',
334
733
  'ACTIVATE_WORKFLOW',
335
734
  'DEACTIVATE_WORKFLOW',
@@ -350,27 +749,53 @@ export const workflowAction: Action = {
350
749
  'EXECUTION_HISTORY',
351
750
  'WORKFLOW_RUNS',
352
751
  'WORKFLOW_EXECUTIONS',
752
+ 'WORKFLOW_REVISIONS',
753
+ 'RESTORE_WORKFLOW',
754
+ 'ROLL_BACK_WORKFLOW',
755
+ 'ROLLBACK_WORKFLOW',
756
+ 'DIAGNOSE_WORKFLOW',
757
+ 'TROUBLESHOOT_WORKFLOW',
758
+ 'EXPLAIN_WORKFLOW_FAILURE',
759
+ 'GET_WORKFLOW_DIAGNOSTICS',
760
+ 'WORKFLOW_RUN_DIAGNOSTICS',
761
+ 'WORKFLOW_EVAL_SAMPLES',
762
+ 'GENERATE_WORKFLOW_TRAINING_SAMPLES',
763
+ 'GENERATE_WORKFLOW_EVAL_CASES',
764
+ 'GEPA_WORKFLOW_SAMPLES',
765
+ 'OPTIMIZE_WORKFLOW_SAMPLES',
353
766
  ],
354
767
  description:
355
768
  'Manage workflows. Action-based dispatch - provide an `action` parameter:\n' +
356
- ' create, modify, activate, deactivate, toggle_active, delete, executions.\n' +
769
+ ' list, get, create, modify, activate, deactivate, toggle_active, delete, run, executions, revisions, restore, diagnose, eval_samples.\n' +
357
770
  'For creating/updating scheduled triggers (including promoting a task to a workflow), use the TRIGGER action.',
358
771
  descriptionCompressed:
359
- 'manage workflows; action-based dispatch (create modify activate deactivate toggle_active delete executions)',
772
+ 'workflow list|get|create|modify|activate|deactivate|toggle_active|delete|run|executions|revisions|restore|diagnose|eval_samples',
360
773
  parameters: [
361
774
  {
362
775
  name: 'action',
363
776
  description:
364
- 'Operation: create, modify, activate, deactivate, toggle_active, delete, executions.',
777
+ 'Operation: list, get, search, create, modify, activate, deactivate, toggle_active, delete, run, executions, revisions, restore, diagnose, eval_samples.',
365
778
  required: true,
366
779
  schema: { type: 'string' as const, enum: [...WORKFLOW_OPS] },
367
780
  },
781
+ {
782
+ name: 'query',
783
+ description: 'Free text to match a workflow by name / node type for action=search.',
784
+ required: false,
785
+ schema: { type: 'string' as const },
786
+ },
368
787
  {
369
788
  name: 'workflowId',
370
789
  description: 'Workflow id.',
371
790
  required: false,
372
791
  schema: { type: 'string' as const },
373
792
  },
793
+ {
794
+ name: 'executionId',
795
+ description: 'Workflow execution id for action=diagnose.',
796
+ required: false,
797
+ schema: { type: 'string' as const },
798
+ },
374
799
  {
375
800
  name: 'workflowName',
376
801
  description: 'Workflow name fragment for fuzzy matching.',
@@ -397,10 +822,16 @@ export const workflowAction: Action = {
397
822
  },
398
823
  {
399
824
  name: 'limit',
400
- description: 'Max executions to return for action=executions (default 10).',
825
+ description: 'Max executions/revisions/evaluation samples to return (default 10).',
401
826
  required: false,
402
827
  schema: { type: 'number' as const },
403
828
  },
829
+ {
830
+ name: 'versionId',
831
+ description: 'Workflow version id for action=restore.',
832
+ required: false,
833
+ schema: { type: 'string' as const },
834
+ },
404
835
  ],
405
836
  validate: async (runtime: IAgentRuntime, _message: Memory, _state?: State): Promise<boolean> => {
406
837
  return getWorkflowService(runtime) !== null;
@@ -425,6 +856,12 @@ export const workflowAction: Action = {
425
856
  return { success: false, text: 'Workflow service is not registered.' };
426
857
  }
427
858
  switch (op) {
859
+ case 'list':
860
+ return handleListWorkflows(service, params, message, callback);
861
+ case 'search':
862
+ return handleSearchWorkflows(service, params, message, callback);
863
+ case 'get':
864
+ return handleGetWorkflow(service, params, callback);
428
865
  case 'create':
429
866
  return handleCreate(runtime, service, params, message, callback);
430
867
  case 'modify':
@@ -437,11 +874,49 @@ export const workflowAction: Action = {
437
874
  return handleToggleActive(service, params, undefined, callback);
438
875
  case 'delete':
439
876
  return handleDeleteWorkflow(service, params, callback);
877
+ case 'run':
878
+ return handleRunWorkflow(service, params, callback);
440
879
  case 'executions':
441
880
  return handleExecutions(service, params, callback);
881
+ case 'revisions':
882
+ return handleRevisions(service, params, callback);
883
+ case 'restore':
884
+ return handleRestoreRevision(service, params, callback);
885
+ case 'diagnose':
886
+ return handleDiagnoseExecution(service, params, callback);
887
+ case 'eval_samples':
888
+ return handleEvaluationSamples(service, params, callback);
442
889
  }
443
890
  },
444
891
  examples: [
892
+ [
893
+ {
894
+ name: '{{name1}}',
895
+ content: { text: 'Show my workflows.', source: 'chat' },
896
+ },
897
+ {
898
+ name: '{{agentName}}',
899
+ content: {
900
+ text: 'Fetching workflows.',
901
+ actions: ['WORKFLOW'],
902
+ thought: 'Workflow inventory maps to WORKFLOW op=list.',
903
+ },
904
+ },
905
+ ],
906
+ [
907
+ {
908
+ name: '{{name1}}',
909
+ content: { text: 'Review workflow wf-123.', source: 'chat' },
910
+ },
911
+ {
912
+ name: '{{agentName}}',
913
+ content: {
914
+ text: 'Fetching the workflow definition.',
915
+ actions: ['WORKFLOW'],
916
+ thought: 'Workflow review maps to WORKFLOW op=get with workflowId=wf-123.',
917
+ },
918
+ },
919
+ ],
445
920
  [
446
921
  {
447
922
  name: '{{name1}}',
@@ -490,5 +965,38 @@ export const workflowAction: Action = {
490
965
  },
491
966
  },
492
967
  ],
968
+ [
969
+ {
970
+ name: '{{name1}}',
971
+ content: { text: 'Roll back workflow wf-123 to version v-old.', source: 'chat' },
972
+ },
973
+ {
974
+ name: '{{agentName}}',
975
+ content: {
976
+ text: 'Restoring the workflow version.',
977
+ actions: ['WORKFLOW'],
978
+ thought:
979
+ 'Rollback maps to WORKFLOW op=restore with workflowId=wf-123 and versionId=v-old.',
980
+ },
981
+ },
982
+ ],
983
+ [
984
+ {
985
+ name: '{{name1}}',
986
+ content: {
987
+ text: 'Create eval samples from the last 10 runs of workflow wf-123.',
988
+ source: 'chat',
989
+ },
990
+ },
991
+ {
992
+ name: '{{agentName}}',
993
+ content: {
994
+ text: 'Generating workflow eval samples.',
995
+ actions: ['WORKFLOW'],
996
+ thought:
997
+ 'Eval sample generation maps to WORKFLOW op=eval_samples with workflowId=wf-123 and limit=10.',
998
+ },
999
+ },
1000
+ ],
493
1001
  ],
494
1002
  };