@elizaos/plugin-workflow 2.0.0-beta.1 → 2.0.3-beta.6
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/LICENSE +21 -0
- package/README.md +28 -26
- package/dist/actions/eval-code.d.ts +12 -0
- package/dist/actions/eval-code.d.ts.map +1 -0
- package/dist/actions/eval-code.js +59 -0
- package/dist/actions/eval-code.js.map +1 -0
- package/dist/actions/index.d.ts +1 -0
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +1 -0
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/workflow.d.ts +7 -0
- package/dist/actions/workflow.d.ts.map +1 -1
- package/dist/actions/workflow.js +462 -10
- package/dist/actions/workflow.js.map +1 -1
- package/dist/db/schema.d.ts +196 -0
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +23 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -64
- package/dist/index.js.map +1 -1
- package/dist/lib/automations-builder.d.ts.map +1 -1
- package/dist/lib/automations-builder.js +10 -35
- package/dist/lib/automations-builder.js.map +1 -1
- package/dist/lib/automations-types.d.ts +2 -2
- package/dist/lib/automations-types.d.ts.map +1 -1
- package/dist/lib/automations-types.js.map +1 -1
- package/dist/lib/index.d.ts +0 -2
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +1 -2
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/workflow-clarification.d.ts +2 -2
- package/dist/lib/workflow-clarification.d.ts.map +1 -1
- package/dist/lib/workflow-clarification.js +15 -11
- package/dist/lib/workflow-clarification.js.map +1 -1
- package/dist/plugin-routes.d.ts.map +1 -1
- package/dist/plugin-routes.js +6 -0
- package/dist/plugin-routes.js.map +1 -1
- package/dist/providers/activeWorkflows.js +2 -2
- package/dist/providers/activeWorkflows.js.map +1 -1
- package/dist/providers/workflowStatus.js +1 -1
- package/dist/providers/workflowStatus.js.map +1 -1
- package/dist/routes/workflow-routes.d.ts.map +1 -1
- package/dist/routes/workflow-routes.js +68 -2
- package/dist/routes/workflow-routes.js.map +1 -1
- package/dist/routes/workflows.d.ts.map +1 -1
- package/dist/routes/workflows.js +5 -1
- package/dist/routes/workflows.js.map +1 -1
- package/dist/services/embedded-workflow-service.d.ts +74 -17
- package/dist/services/embedded-workflow-service.d.ts.map +1 -1
- package/dist/services/embedded-workflow-service.js +343 -149
- package/dist/services/embedded-workflow-service.js.map +1 -1
- package/dist/services/smithers-runtime.d.ts +47 -0
- package/dist/services/smithers-runtime.d.ts.map +1 -0
- package/dist/services/smithers-runtime.js +444 -0
- package/dist/services/smithers-runtime.js.map +1 -0
- package/dist/services/workflow-credential-store.js +1 -1
- package/dist/services/workflow-credential-store.js.map +1 -1
- package/dist/services/workflow-dispatch.d.ts +31 -1
- package/dist/services/workflow-dispatch.d.ts.map +1 -1
- package/dist/services/workflow-dispatch.js +75 -10
- package/dist/services/workflow-dispatch.js.map +1 -1
- package/dist/services/workflow-service.d.ts +27 -1
- package/dist/services/workflow-service.d.ts.map +1 -1
- package/dist/services/workflow-service.js +133 -11
- package/dist/services/workflow-service.js.map +1 -1
- package/dist/trigger-routes.d.ts +2 -18
- package/dist/trigger-routes.d.ts.map +1 -1
- package/dist/trigger-routes.js +11 -39
- package/dist/trigger-routes.js.map +1 -1
- package/dist/types/index.d.ts +82 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/workflow-contracts.d.ts +118 -0
- package/dist/types/workflow-contracts.d.ts.map +1 -0
- package/dist/types/workflow-contracts.js +2 -0
- package/dist/types/workflow-contracts.js.map +1 -0
- package/dist/utils/catalog.js +2 -2
- package/dist/utils/catalog.js.map +1 -1
- package/dist/utils/clarification.d.ts +1 -1
- package/dist/utils/clarification.d.ts.map +1 -1
- package/dist/utils/clarification.js +15 -4
- package/dist/utils/clarification.js.map +1 -1
- package/dist/utils/context.js +1 -1
- package/dist/utils/context.js.map +1 -1
- package/dist/utils/evaluation-samples.d.ts +6 -0
- package/dist/utils/evaluation-samples.d.ts.map +1 -0
- package/dist/utils/evaluation-samples.js +216 -0
- package/dist/utils/evaluation-samples.js.map +1 -0
- package/dist/utils/execution-diagnostics.d.ts +26 -0
- package/dist/utils/execution-diagnostics.d.ts.map +1 -0
- package/dist/utils/execution-diagnostics.js +159 -0
- package/dist/utils/execution-diagnostics.js.map +1 -0
- package/dist/utils/generation.d.ts.map +1 -1
- package/dist/utils/generation.js +134 -19
- package/dist/utils/generation.js.map +1 -1
- package/dist/utils/host-capabilities.d.ts.map +1 -1
- package/dist/utils/host-capabilities.js +20 -5
- package/dist/utils/host-capabilities.js.map +1 -1
- package/dist/utils/inferSyntheticOutputSchema.js +3 -3
- package/dist/utils/inferSyntheticOutputSchema.js.map +1 -1
- package/dist/utils/outputSchema.js +1 -1
- package/dist/utils/outputSchema.js.map +1 -1
- package/dist/utils/validateAndRepair.js +10 -10
- package/dist/utils/validateAndRepair.js.map +1 -1
- package/dist/utils/workflow-prompts/draftIntent.d.ts +1 -1
- package/dist/utils/workflow-prompts/draftIntent.d.ts.map +1 -1
- package/dist/utils/workflow-prompts/draftIntent.js +1 -1
- package/dist/utils/workflow-prompts/keywordExtraction.d.ts +1 -1
- package/dist/utils/workflow-prompts/keywordExtraction.d.ts.map +1 -1
- package/dist/utils/workflow-prompts/keywordExtraction.js +1 -1
- package/dist/utils/workflow-prompts/workflowGeneration.d.ts +1 -1
- package/dist/utils/workflow-prompts/workflowGeneration.d.ts.map +1 -1
- package/dist/utils/workflow-prompts/workflowGeneration.js +4 -4
- package/dist/utils/workflow-prompts/workflowMatching.d.ts +1 -1
- package/dist/utils/workflow-prompts/workflowMatching.d.ts.map +1 -1
- package/dist/utils/workflow-prompts/workflowMatching.js +1 -1
- package/dist/utils/workflow.d.ts +1 -0
- package/dist/utils/workflow.d.ts.map +1 -1
- package/dist/utils/workflow.js +44 -8
- package/dist/utils/workflow.js.map +1 -1
- package/package.json +27 -8
- package/registry-entry.json +25 -0
- package/src/actions/eval-code.ts +81 -0
- package/src/actions/index.ts +1 -0
- package/src/actions/workflow.ts +518 -10
- package/src/db/schema.ts +31 -0
- package/src/index.ts +9 -82
- package/src/lib/automations-builder.ts +11 -35
- package/src/lib/automations-types.ts +1 -2
- package/src/lib/index.ts +0 -8
- package/src/lib/workflow-clarification.ts +18 -13
- package/src/plugin-routes.ts +6 -0
- package/src/providers/activeWorkflows.ts +2 -2
- package/src/providers/workflowStatus.ts +1 -1
- package/src/routes/workflow-routes.ts +100 -2
- package/src/routes/workflows.ts +5 -1
- package/src/services/embedded-workflow-service.ts +447 -172
- package/src/services/smithers-runtime.ts +526 -0
- package/src/services/workflow-credential-store.ts +1 -1
- package/src/services/workflow-dispatch.ts +116 -13
- package/src/services/workflow-service.ts +186 -10
- package/src/trigger-routes.ts +12 -70
- package/src/types/index.ts +94 -2
- package/src/types/workflow-contracts.ts +166 -0
- package/src/utils/catalog.ts +2 -2
- package/src/utils/clarification.ts +19 -5
- package/src/utils/context.ts +1 -1
- package/src/utils/evaluation-samples.ts +239 -0
- package/src/utils/execution-diagnostics.ts +192 -0
- package/src/utils/generation.ts +224 -32
- package/src/utils/host-capabilities.ts +21 -5
- package/src/utils/inferSyntheticOutputSchema.ts +3 -3
- package/src/utils/outputSchema.ts +1 -1
- package/src/utils/validateAndRepair.ts +10 -10
- package/src/utils/workflow-prompts/draftIntent.ts +1 -1
- package/src/utils/workflow-prompts/keywordExtraction.ts +1 -1
- package/src/utils/workflow-prompts/workflowGeneration.ts +4 -4
- package/src/utils/workflow-prompts/workflowMatching.ts +1 -1
- package/src/utils/workflow.ts +56 -8
- package/dist/lib/legacy-task-migration.d.ts +0 -20
- package/dist/lib/legacy-task-migration.d.ts.map +0 -1
- package/dist/lib/legacy-task-migration.js +0 -110
- package/dist/lib/legacy-task-migration.js.map +0 -1
- package/dist/lib/legacy-text-trigger-migration.d.ts +0 -18
- package/dist/lib/legacy-text-trigger-migration.d.ts.map +0 -1
- package/dist/lib/legacy-text-trigger-migration.js +0 -131
- package/dist/lib/legacy-text-trigger-migration.js.map +0 -1
- package/src/lib/legacy-task-migration.ts +0 -143
- package/src/lib/legacy-text-trigger-migration.ts +0 -178
package/src/actions/workflow.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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
|
-
'
|
|
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
|
|
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
|
};
|