@elizaos/plugin-workflow 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -0
- package/auto-enable.ts +18 -0
- package/dist/actions/index.d.ts +2 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/actions/index.js +2 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/actions/workflow.d.ts +23 -0
- package/dist/actions/workflow.d.ts.map +1 -0
- package/dist/actions/workflow.js +425 -0
- package/dist/actions/workflow.js.map +1 -0
- package/dist/data/defaultNodes.json +9887 -0
- package/dist/data/schemaIndex.json +1 -0
- package/dist/data/triggerSchemaIndex.json +1 -0
- package/dist/db/index.d.ts +2 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +2 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema.d.ts +588 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +59 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +126 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/automations-builder.d.ts +21 -0
- package/dist/lib/automations-builder.d.ts.map +1 -0
- package/dist/lib/automations-builder.js +557 -0
- package/dist/lib/automations-builder.js.map +1 -0
- package/dist/lib/automations-types.d.ts +153 -0
- package/dist/lib/automations-types.d.ts.map +1 -0
- package/dist/lib/automations-types.js +191 -0
- package/dist/lib/automations-types.js.map +1 -0
- package/dist/lib/index.d.ts +3 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +3 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/legacy-task-migration.d.ts +20 -0
- package/dist/lib/legacy-task-migration.d.ts.map +1 -0
- package/dist/lib/legacy-task-migration.js +110 -0
- package/dist/lib/legacy-task-migration.js.map +1 -0
- package/dist/lib/legacy-text-trigger-migration.d.ts +18 -0
- package/dist/lib/legacy-text-trigger-migration.d.ts.map +1 -0
- package/dist/lib/legacy-text-trigger-migration.js +131 -0
- package/dist/lib/legacy-text-trigger-migration.js.map +1 -0
- package/dist/lib/workflow-clarification.d.ts +113 -0
- package/dist/lib/workflow-clarification.d.ts.map +1 -0
- package/dist/lib/workflow-clarification.js +425 -0
- package/dist/lib/workflow-clarification.js.map +1 -0
- package/dist/plugin-routes.d.ts +9 -0
- package/dist/plugin-routes.d.ts.map +1 -0
- package/dist/plugin-routes.js +147 -0
- package/dist/plugin-routes.js.map +1 -0
- package/dist/providers/activeWorkflows.d.ts +11 -0
- package/dist/providers/activeWorkflows.d.ts.map +1 -0
- package/dist/providers/activeWorkflows.js +72 -0
- package/dist/providers/activeWorkflows.js.map +1 -0
- package/dist/providers/index.d.ts +4 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +4 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/pendingDraft.d.ts +9 -0
- package/dist/providers/pendingDraft.d.ts.map +1 -0
- package/dist/providers/pendingDraft.js +48 -0
- package/dist/providers/pendingDraft.js.map +1 -0
- package/dist/providers/workflowStatus.d.ts +3 -0
- package/dist/providers/workflowStatus.d.ts.map +1 -0
- package/dist/providers/workflowStatus.js +69 -0
- package/dist/providers/workflowStatus.js.map +1 -0
- package/dist/register-routes.d.ts +2 -0
- package/dist/register-routes.d.ts.map +1 -0
- package/dist/register-routes.js +6 -0
- package/dist/register-routes.js.map +1 -0
- package/dist/routes/_helpers.d.ts +11 -0
- package/dist/routes/_helpers.d.ts.map +1 -0
- package/dist/routes/_helpers.js +22 -0
- package/dist/routes/_helpers.js.map +1 -0
- package/dist/routes/automations.d.ts +19 -0
- package/dist/routes/automations.d.ts.map +1 -0
- package/dist/routes/automations.js +32 -0
- package/dist/routes/automations.js.map +1 -0
- package/dist/routes/embedded-webhooks.d.ts +3 -0
- package/dist/routes/embedded-webhooks.d.ts.map +1 -0
- package/dist/routes/embedded-webhooks.js +47 -0
- package/dist/routes/embedded-webhooks.js.map +1 -0
- package/dist/routes/executions.d.ts +3 -0
- package/dist/routes/executions.d.ts.map +1 -0
- package/dist/routes/executions.js +58 -0
- package/dist/routes/executions.js.map +1 -0
- package/dist/routes/index.d.ts +4 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +14 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/nodes.d.ts +3 -0
- package/dist/routes/nodes.d.ts.map +1 -0
- package/dist/routes/nodes.js +168 -0
- package/dist/routes/nodes.js.map +1 -0
- package/dist/routes/validation.d.ts +3 -0
- package/dist/routes/validation.d.ts.map +1 -0
- package/dist/routes/validation.js +41 -0
- package/dist/routes/validation.js.map +1 -0
- package/dist/routes/workflow-routes.d.ts +27 -0
- package/dist/routes/workflow-routes.d.ts.map +1 -0
- package/dist/routes/workflow-routes.js +326 -0
- package/dist/routes/workflow-routes.js.map +1 -0
- package/dist/routes/workflows.d.ts +3 -0
- package/dist/routes/workflows.d.ts.map +1 -0
- package/dist/routes/workflows.js +252 -0
- package/dist/routes/workflows.js.map +1 -0
- package/dist/schemas/draftIntent.d.ts +22 -0
- package/dist/schemas/draftIntent.d.ts.map +1 -0
- package/dist/schemas/draftIntent.js +22 -0
- package/dist/schemas/draftIntent.js.map +1 -0
- package/dist/schemas/feasibility.d.ts +13 -0
- package/dist/schemas/feasibility.d.ts.map +1 -0
- package/dist/schemas/feasibility.js +9 -0
- package/dist/schemas/feasibility.js.map +1 -0
- package/dist/schemas/index.d.ts +5 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +5 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/keywordExtraction.d.ts +14 -0
- package/dist/schemas/keywordExtraction.d.ts.map +1 -0
- package/dist/schemas/keywordExtraction.js +12 -0
- package/dist/schemas/keywordExtraction.js.map +1 -0
- package/dist/schemas/workflowMatching.d.ts +36 -0
- package/dist/schemas/workflowMatching.d.ts.map +1 -0
- package/dist/schemas/workflowMatching.js +30 -0
- package/dist/schemas/workflowMatching.js.map +1 -0
- package/dist/services/embedded-workflow-service.d.ts +106 -0
- package/dist/services/embedded-workflow-service.d.ts.map +1 -0
- package/dist/services/embedded-workflow-service.js +1900 -0
- package/dist/services/embedded-workflow-service.js.map +1 -0
- package/dist/services/index.d.ts +5 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +5 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/workflow-credential-store.d.ts +27 -0
- package/dist/services/workflow-credential-store.d.ts.map +1 -0
- package/dist/services/workflow-credential-store.js +92 -0
- package/dist/services/workflow-credential-store.js.map +1 -0
- package/dist/services/workflow-dispatch.d.ts +41 -0
- package/dist/services/workflow-dispatch.d.ts.map +1 -0
- package/dist/services/workflow-dispatch.js +86 -0
- package/dist/services/workflow-dispatch.js.map +1 -0
- package/dist/services/workflow-service.d.ts +63 -0
- package/dist/services/workflow-service.d.ts.map +1 -0
- package/dist/services/workflow-service.js +492 -0
- package/dist/services/workflow-service.js.map +1 -0
- package/dist/trigger-routes.d.ts +153 -0
- package/dist/trigger-routes.d.ts.map +1 -0
- package/dist/trigger-routes.js +424 -0
- package/dist/trigger-routes.js.map +1 -0
- package/dist/types/index.d.ts +457 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +59 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/catalog.d.ts +16 -0
- package/dist/utils/catalog.d.ts.map +1 -0
- package/dist/utils/catalog.js +211 -0
- package/dist/utils/catalog.js.map +1 -0
- package/dist/utils/clarification.d.ts +17 -0
- package/dist/utils/clarification.d.ts.map +1 -0
- package/dist/utils/clarification.js +46 -0
- package/dist/utils/clarification.js.map +1 -0
- package/dist/utils/context.d.ts +4 -0
- package/dist/utils/context.d.ts.map +1 -0
- package/dist/utils/context.js +18 -0
- package/dist/utils/context.js.map +1 -0
- package/dist/utils/credentialResolver.d.ts +22 -0
- package/dist/utils/credentialResolver.d.ts.map +1 -0
- package/dist/utils/credentialResolver.js +146 -0
- package/dist/utils/credentialResolver.js.map +1 -0
- package/dist/utils/generation.d.ts +36 -0
- package/dist/utils/generation.d.ts.map +1 -0
- package/dist/utils/generation.js +701 -0
- package/dist/utils/generation.js.map +1 -0
- package/dist/utils/host-capabilities.d.ts +27 -0
- package/dist/utils/host-capabilities.d.ts.map +1 -0
- package/dist/utils/host-capabilities.js +59 -0
- package/dist/utils/host-capabilities.js.map +1 -0
- package/dist/utils/inferSyntheticOutputSchema.d.ts +20 -0
- package/dist/utils/inferSyntheticOutputSchema.d.ts.map +1 -0
- package/dist/utils/inferSyntheticOutputSchema.js +151 -0
- package/dist/utils/inferSyntheticOutputSchema.js.map +1 -0
- package/dist/utils/outputSchema.d.ts +26 -0
- package/dist/utils/outputSchema.d.ts.map +1 -0
- package/dist/utils/outputSchema.js +297 -0
- package/dist/utils/outputSchema.js.map +1 -0
- package/dist/utils/validateAndRepair.d.ts +41 -0
- package/dist/utils/validateAndRepair.d.ts.map +1 -0
- package/dist/utils/validateAndRepair.js +483 -0
- package/dist/utils/validateAndRepair.js.map +1 -0
- package/dist/utils/workflow-prompts/actionResponse.d.ts +2 -0
- package/dist/utils/workflow-prompts/actionResponse.d.ts.map +1 -0
- package/dist/utils/workflow-prompts/actionResponse.js +17 -0
- package/dist/utils/workflow-prompts/actionResponse.js.map +1 -0
- package/dist/utils/workflow-prompts/draftIntent.d.ts +2 -0
- package/dist/utils/workflow-prompts/draftIntent.d.ts.map +1 -0
- package/dist/utils/workflow-prompts/draftIntent.js +23 -0
- package/dist/utils/workflow-prompts/draftIntent.js.map +1 -0
- package/dist/utils/workflow-prompts/feasibilityCheck.d.ts +2 -0
- package/dist/utils/workflow-prompts/feasibilityCheck.d.ts.map +1 -0
- package/dist/utils/workflow-prompts/feasibilityCheck.js +21 -0
- package/dist/utils/workflow-prompts/feasibilityCheck.js.map +1 -0
- package/dist/utils/workflow-prompts/fieldCorrection.d.ts +3 -0
- package/dist/utils/workflow-prompts/fieldCorrection.d.ts.map +1 -0
- package/dist/utils/workflow-prompts/fieldCorrection.js +20 -0
- package/dist/utils/workflow-prompts/fieldCorrection.js.map +1 -0
- package/dist/utils/workflow-prompts/index.d.ts +8 -0
- package/dist/utils/workflow-prompts/index.d.ts.map +1 -0
- package/dist/utils/workflow-prompts/index.js +8 -0
- package/dist/utils/workflow-prompts/index.js.map +1 -0
- package/dist/utils/workflow-prompts/keywordExtraction.d.ts +2 -0
- package/dist/utils/workflow-prompts/keywordExtraction.d.ts.map +1 -0
- package/dist/utils/workflow-prompts/keywordExtraction.js +21 -0
- package/dist/utils/workflow-prompts/keywordExtraction.js.map +1 -0
- package/dist/utils/workflow-prompts/parameterCorrection.d.ts +3 -0
- package/dist/utils/workflow-prompts/parameterCorrection.d.ts.map +1 -0
- package/dist/utils/workflow-prompts/parameterCorrection.js +29 -0
- package/dist/utils/workflow-prompts/parameterCorrection.js.map +1 -0
- package/dist/utils/workflow-prompts/workflowGeneration.d.ts +2 -0
- package/dist/utils/workflow-prompts/workflowGeneration.d.ts.map +1 -0
- package/dist/utils/workflow-prompts/workflowGeneration.js +529 -0
- package/dist/utils/workflow-prompts/workflowGeneration.js.map +1 -0
- package/dist/utils/workflow-prompts/workflowMatching.d.ts +2 -0
- package/dist/utils/workflow-prompts/workflowMatching.d.ts.map +1 -0
- package/dist/utils/workflow-prompts/workflowMatching.js +23 -0
- package/dist/utils/workflow-prompts/workflowMatching.js.map +1 -0
- package/dist/utils/workflow.d.ts +62 -0
- package/dist/utils/workflow.d.ts.map +1 -0
- package/dist/utils/workflow.js +712 -0
- package/dist/utils/workflow.js.map +1 -0
- package/package.json +87 -0
- package/src/actions/index.ts +1 -0
- package/src/actions/workflow.ts +494 -0
- package/src/data/defaultNodes.json +9887 -0
- package/src/data/schemaIndex.json +1 -0
- package/src/data/triggerSchemaIndex.json +1 -0
- package/src/db/index.ts +8 -0
- package/src/db/schema.ts +94 -0
- package/src/index.ts +179 -0
- package/src/lib/automations-builder.ts +679 -0
- package/src/lib/automations-types.ts +391 -0
- package/src/lib/index.ts +8 -0
- package/src/lib/legacy-task-migration.ts +143 -0
- package/src/lib/legacy-text-trigger-migration.ts +178 -0
- package/src/lib/workflow-clarification.ts +497 -0
- package/src/plugin-routes.ts +164 -0
- package/src/providers/activeWorkflows.ts +81 -0
- package/src/providers/index.ts +3 -0
- package/src/providers/pendingDraft.ts +55 -0
- package/src/providers/workflowStatus.ts +88 -0
- package/src/register-routes.ts +6 -0
- package/src/routes/_helpers.ts +27 -0
- package/src/routes/automations.ts +46 -0
- package/src/routes/embedded-webhooks.ts +64 -0
- package/src/routes/executions.ts +75 -0
- package/src/routes/index.ts +16 -0
- package/src/routes/nodes.ts +211 -0
- package/src/routes/validation.ts +51 -0
- package/src/routes/workflow-routes.ts +469 -0
- package/src/routes/workflows.ts +310 -0
- package/src/schemas/draftIntent.ts +21 -0
- package/src/schemas/feasibility.ts +8 -0
- package/src/schemas/index.ts +4 -0
- package/src/schemas/keywordExtraction.ts +11 -0
- package/src/schemas/workflowMatching.ts +29 -0
- package/src/services/embedded-workflow-service.ts +2224 -0
- package/src/services/index.ts +17 -0
- package/src/services/workflow-credential-store.ts +132 -0
- package/src/services/workflow-dispatch.ts +121 -0
- package/src/services/workflow-service.ts +839 -0
- package/src/trigger-routes.ts +714 -0
- package/src/types/index.ts +562 -0
- package/src/utils/catalog.ts +260 -0
- package/src/utils/clarification.ts +52 -0
- package/src/utils/context.ts +22 -0
- package/src/utils/credentialResolver.ts +234 -0
- package/src/utils/generation.ts +987 -0
- package/src/utils/host-capabilities.ts +81 -0
- package/src/utils/inferSyntheticOutputSchema.ts +163 -0
- package/src/utils/outputSchema.ts +372 -0
- package/src/utils/validateAndRepair.ts +610 -0
- package/src/utils/workflow-prompts/actionResponse.ts +16 -0
- package/src/utils/workflow-prompts/draftIntent.ts +22 -0
- package/src/utils/workflow-prompts/feasibilityCheck.ts +20 -0
- package/src/utils/workflow-prompts/fieldCorrection.ts +20 -0
- package/src/utils/workflow-prompts/index.ts +10 -0
- package/src/utils/workflow-prompts/keywordExtraction.ts +20 -0
- package/src/utils/workflow-prompts/parameterCorrection.ts +29 -0
- package/src/utils/workflow-prompts/workflowGeneration.ts +528 -0
- package/src/utils/workflow-prompts/workflowMatching.ts +22 -0
- package/src/utils/workflow.ts +895 -0
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
import type http from 'node:http';
|
|
2
|
+
import type { AgentRuntime } from '@elizaos/core';
|
|
3
|
+
import {
|
|
4
|
+
applyResolutions,
|
|
5
|
+
buildCatalogSnapshot,
|
|
6
|
+
type CatalogLike,
|
|
7
|
+
coerceClarifications,
|
|
8
|
+
pruneResolvedClarifications,
|
|
9
|
+
type WorkflowClarificationResolution,
|
|
10
|
+
} from '../lib/workflow-clarification';
|
|
11
|
+
import { WORKFLOW_SERVICE_TYPE, type WorkflowService } from '../services/workflow-service';
|
|
12
|
+
import type {
|
|
13
|
+
TriggerContext,
|
|
14
|
+
WorkflowCreationResult,
|
|
15
|
+
WorkflowDefinition,
|
|
16
|
+
WorkflowDefinitionResponse,
|
|
17
|
+
} from '../types/index';
|
|
18
|
+
|
|
19
|
+
export type WorkflowMode = 'local' | 'disabled';
|
|
20
|
+
export type WorkflowRuntimeStatus = 'ready' | 'error';
|
|
21
|
+
|
|
22
|
+
export interface WorkflowStatusResponse {
|
|
23
|
+
mode: WorkflowMode;
|
|
24
|
+
host: string | null;
|
|
25
|
+
status: WorkflowRuntimeStatus;
|
|
26
|
+
cloudConnected: false;
|
|
27
|
+
localEnabled: boolean;
|
|
28
|
+
platform: 'desktop';
|
|
29
|
+
cloudHealth: 'unknown';
|
|
30
|
+
errorMessage?: string | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type WorkflowJsonResponder = (res: http.ServerResponse, body: unknown, status?: number) => void;
|
|
34
|
+
|
|
35
|
+
export interface WorkflowRouteContext {
|
|
36
|
+
req: http.IncomingMessage;
|
|
37
|
+
res: http.ServerResponse;
|
|
38
|
+
method: string;
|
|
39
|
+
pathname: string;
|
|
40
|
+
runtime: AgentRuntime | null;
|
|
41
|
+
agentId?: string;
|
|
42
|
+
json: WorkflowJsonResponder;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function sendJson(
|
|
46
|
+
ctx: Pick<WorkflowRouteContext, 'res' | 'json'>,
|
|
47
|
+
status: number,
|
|
48
|
+
body: unknown
|
|
49
|
+
): void {
|
|
50
|
+
ctx.json(ctx.res, body, status);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function normalizePath(pathname: string): string {
|
|
54
|
+
const withoutPrefix = pathname.replace(/^\/api\/workflow/, '');
|
|
55
|
+
return withoutPrefix.length > 0 ? withoutPrefix : '/';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function readId(path: string): string | null {
|
|
59
|
+
const match = /^\/workflows\/([^/]+)(?:\/.*)?$/.exec(path);
|
|
60
|
+
return match?.[1] ? decodeURIComponent(match[1]) : null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function resolveAgentId(ctx: WorkflowRouteContext): string {
|
|
64
|
+
if (ctx.agentId?.trim()) {
|
|
65
|
+
return ctx.agentId.trim();
|
|
66
|
+
}
|
|
67
|
+
return (
|
|
68
|
+
ctx.runtime?.agentId ?? ctx.runtime?.character?.id ?? '00000000-0000-0000-0000-000000000000'
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function getWorkflowService(ctx: WorkflowRouteContext): WorkflowService | null {
|
|
73
|
+
return (ctx.runtime?.getService?.(WORKFLOW_SERVICE_TYPE) as WorkflowService | null) ?? null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function getConnectorTargetCatalog(ctx: WorkflowRouteContext): CatalogLike | null {
|
|
77
|
+
const raw = ctx.runtime?.getService?.('connector_target_catalog');
|
|
78
|
+
const candidate = raw as unknown as CatalogLike | undefined;
|
|
79
|
+
return candidate && typeof candidate.listGroups === 'function' ? candidate : null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
83
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function asClarificationResolution(value: unknown): WorkflowClarificationResolution | null {
|
|
87
|
+
if (!isRecord(value) || typeof value.paramPath !== 'string' || typeof value.value !== 'string') {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
return { paramPath: value.paramPath, value: value.value };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function isWorkflowDefinition(value: unknown): value is WorkflowDefinition {
|
|
94
|
+
return (
|
|
95
|
+
isRecord(value) &&
|
|
96
|
+
typeof value.name === 'string' &&
|
|
97
|
+
Array.isArray(value.nodes) &&
|
|
98
|
+
value.nodes.every(isRecord) &&
|
|
99
|
+
isRecord(value.connections)
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function readJsonBody(
|
|
104
|
+
req: http.IncomingMessage,
|
|
105
|
+
res: http.ServerResponse,
|
|
106
|
+
maxBytes = 1_048_576
|
|
107
|
+
): Promise<Record<string, unknown> | null> {
|
|
108
|
+
const chunks: Buffer[] = [];
|
|
109
|
+
let totalBytes = 0;
|
|
110
|
+
for await (const chunk of req) {
|
|
111
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
112
|
+
totalBytes += buffer.length;
|
|
113
|
+
if (totalBytes > maxBytes) {
|
|
114
|
+
res.statusCode = 413;
|
|
115
|
+
res.setHeader('content-type', 'application/json; charset=utf-8');
|
|
116
|
+
res.end(JSON.stringify({ error: 'request body too large' }));
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
chunks.push(buffer);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (chunks.length === 0) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
const parsed = JSON.parse(Buffer.concat(chunks).toString('utf-8'));
|
|
128
|
+
return isRecord(parsed) ? parsed : null;
|
|
129
|
+
} catch {
|
|
130
|
+
res.statusCode = 400;
|
|
131
|
+
res.setHeader('content-type', 'application/json; charset=utf-8');
|
|
132
|
+
res.end(JSON.stringify({ error: 'invalid JSON body' }));
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function asWorkflow(value: unknown): WorkflowDefinition | null {
|
|
138
|
+
return isWorkflowDefinition(value) ? value : null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function readWorkflowPayload(
|
|
142
|
+
ctx: WorkflowRouteContext
|
|
143
|
+
): Promise<{ workflow: WorkflowDefinition; activate?: boolean } | null> {
|
|
144
|
+
const body = await readJsonBody(ctx.req, ctx.res);
|
|
145
|
+
if (!body) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const record = body as Record<string, unknown>;
|
|
150
|
+
const workflow = asWorkflow(record.workflow) ?? asWorkflow(record);
|
|
151
|
+
if (!workflow) {
|
|
152
|
+
sendJson(ctx, 400, { error: 'workflow payload required' });
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
workflow,
|
|
157
|
+
activate: typeof record.activate === 'boolean' ? record.activate : undefined,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function toWorkflowResponse(result: WorkflowCreationResult): Pick<
|
|
162
|
+
WorkflowDefinitionResponse,
|
|
163
|
+
'id' | 'name' | 'active'
|
|
164
|
+
> & {
|
|
165
|
+
nodeCount: number;
|
|
166
|
+
missingCredentials: WorkflowCreationResult['missingCredentials'];
|
|
167
|
+
} {
|
|
168
|
+
return {
|
|
169
|
+
id: result.id,
|
|
170
|
+
name: result.name,
|
|
171
|
+
active: result.active,
|
|
172
|
+
nodeCount: result.nodeCount,
|
|
173
|
+
missingCredentials: result.missingCredentials,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function deployWorkflow(
|
|
178
|
+
ctx: WorkflowRouteContext,
|
|
179
|
+
service: WorkflowService,
|
|
180
|
+
workflow: WorkflowDefinition,
|
|
181
|
+
activate?: boolean
|
|
182
|
+
): Promise<void> {
|
|
183
|
+
const deployed = await service.deployWorkflow(workflow, resolveAgentId(ctx));
|
|
184
|
+
if (deployed.missingCredentials.length > 0 && !deployed.id) {
|
|
185
|
+
sendJson(ctx, 200, {
|
|
186
|
+
...toWorkflowResponse(deployed),
|
|
187
|
+
warning: 'missing credentials',
|
|
188
|
+
});
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (activate === false && deployed.id && deployed.active) {
|
|
193
|
+
await service.deactivateWorkflow(deployed.id);
|
|
194
|
+
deployed.active = false;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const full = deployed.id ? await service.getWorkflow(deployed.id) : toWorkflowResponse(deployed);
|
|
198
|
+
sendJson(ctx, 200, full);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function buildTriggerContextFromConversation(
|
|
202
|
+
runtime: AgentRuntime | null,
|
|
203
|
+
conversationId: string
|
|
204
|
+
): Promise<TriggerContext | undefined> {
|
|
205
|
+
const room = await runtime?.getRoom?.(conversationId);
|
|
206
|
+
const metadata = isRecord(room?.metadata) ? room.metadata : null;
|
|
207
|
+
const inbound = isRecord(metadata?.inbound) ? metadata.inbound : null;
|
|
208
|
+
if (!inbound) {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
const platform = typeof inbound.platform === 'string' ? inbound.platform : undefined;
|
|
212
|
+
const channelId = typeof inbound.channelId === 'string' ? inbound.channelId : undefined;
|
|
213
|
+
const guildId = typeof inbound.guildId === 'string' ? inbound.guildId : undefined;
|
|
214
|
+
const threadId = typeof inbound.threadId === 'string' ? inbound.threadId : undefined;
|
|
215
|
+
return {
|
|
216
|
+
source: platform,
|
|
217
|
+
...(platform === 'discord' || channelId || guildId || threadId
|
|
218
|
+
? { discord: { channelId, guildId, threadId } }
|
|
219
|
+
: {}),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async function handleStatus(ctx: WorkflowRouteContext): Promise<void> {
|
|
224
|
+
const service = getWorkflowService(ctx);
|
|
225
|
+
sendJson(ctx, 200, {
|
|
226
|
+
mode: service ? 'local' : 'disabled',
|
|
227
|
+
host: 'in-process',
|
|
228
|
+
status: service ? 'ready' : 'error',
|
|
229
|
+
cloudConnected: false,
|
|
230
|
+
localEnabled: Boolean(service),
|
|
231
|
+
platform: 'desktop',
|
|
232
|
+
cloudHealth: 'unknown',
|
|
233
|
+
errorMessage: service ? null : 'Workflow service is not registered',
|
|
234
|
+
} satisfies WorkflowStatusResponse);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async function handleList(ctx: WorkflowRouteContext, service: WorkflowService): Promise<void> {
|
|
238
|
+
const workflows = await service.listWorkflows(resolveAgentId(ctx));
|
|
239
|
+
sendJson(ctx, 200, { workflows });
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async function handleGet(
|
|
243
|
+
ctx: WorkflowRouteContext,
|
|
244
|
+
service: WorkflowService,
|
|
245
|
+
id: string
|
|
246
|
+
): Promise<void> {
|
|
247
|
+
sendJson(ctx, 200, await service.getWorkflow(id));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async function handleGenerate(ctx: WorkflowRouteContext, service: WorkflowService): Promise<void> {
|
|
251
|
+
const body = await readJsonBody(ctx.req, ctx.res);
|
|
252
|
+
if (!isRecord(body)) {
|
|
253
|
+
sendJson(ctx, 400, { error: 'request body required' });
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const prompt = typeof body.prompt === 'string' ? body.prompt.trim() : '';
|
|
258
|
+
if (!prompt) {
|
|
259
|
+
sendJson(ctx, 400, { error: 'prompt required' });
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const triggerContext =
|
|
264
|
+
typeof body.bridgeConversationId === 'string'
|
|
265
|
+
? await buildTriggerContextFromConversation(ctx.runtime, body.bridgeConversationId)
|
|
266
|
+
: undefined;
|
|
267
|
+
|
|
268
|
+
const draft = await service.generateWorkflowDraft(
|
|
269
|
+
prompt,
|
|
270
|
+
triggerContext ? { triggerContext } : undefined
|
|
271
|
+
);
|
|
272
|
+
if (typeof body.name === 'string' && body.name.trim()) {
|
|
273
|
+
draft.name = body.name.trim();
|
|
274
|
+
}
|
|
275
|
+
if (typeof body.workflowId === 'string' && body.workflowId.trim()) {
|
|
276
|
+
draft.id = body.workflowId.trim();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const clarifications = coerceClarifications(draft._meta?.requiresClarification);
|
|
280
|
+
if (clarifications.length > 0) {
|
|
281
|
+
const catalog = getConnectorTargetCatalog(ctx);
|
|
282
|
+
sendJson(ctx, 200, {
|
|
283
|
+
status: 'needs_clarification',
|
|
284
|
+
draft,
|
|
285
|
+
clarifications,
|
|
286
|
+
catalog: catalog ? await buildCatalogSnapshot(catalog, clarifications) : [],
|
|
287
|
+
});
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
await deployWorkflow(ctx, service, draft);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
async function handleResolveClarification(
|
|
295
|
+
ctx: WorkflowRouteContext,
|
|
296
|
+
service: WorkflowService
|
|
297
|
+
): Promise<void> {
|
|
298
|
+
const body = await readJsonBody(ctx.req, ctx.res);
|
|
299
|
+
if (!isRecord(body) || !isRecord(body.draft) || !Array.isArray(body.resolutions)) {
|
|
300
|
+
sendJson(ctx, 400, { error: 'draft and resolutions required' });
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const draftRecord = body.draft;
|
|
305
|
+
const draft = asWorkflow(draftRecord);
|
|
306
|
+
if (!draft) {
|
|
307
|
+
sendJson(ctx, 400, { error: 'valid draft workflow required' });
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
const resolutions = body.resolutions.map(asClarificationResolution);
|
|
311
|
+
const validResolutions = resolutions.filter(
|
|
312
|
+
(resolution): resolution is WorkflowClarificationResolution => resolution !== null
|
|
313
|
+
);
|
|
314
|
+
if (validResolutions.length !== body.resolutions.length) {
|
|
315
|
+
sendJson(ctx, 400, { error: 'resolution missing paramPath or string value' });
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const result = applyResolutions(draftRecord, validResolutions);
|
|
319
|
+
if (result.ok === false) {
|
|
320
|
+
sendJson(ctx, 400, { error: result.error, paramPath: result.paramPath });
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const resolvedPaths = new Set(
|
|
325
|
+
body.resolutions
|
|
326
|
+
.map((resolution) => (isRecord(resolution) ? resolution.paramPath : undefined))
|
|
327
|
+
.filter((path): path is string => typeof path === 'string' && path.length > 0)
|
|
328
|
+
);
|
|
329
|
+
const freeFormCount = body.resolutions.filter(
|
|
330
|
+
(resolution) => !isRecord(resolution) || typeof resolution.paramPath !== 'string'
|
|
331
|
+
).length;
|
|
332
|
+
pruneResolvedClarifications(draftRecord, resolvedPaths, freeFormCount);
|
|
333
|
+
|
|
334
|
+
if (typeof body.name === 'string' && body.name.trim()) {
|
|
335
|
+
draft.name = body.name.trim();
|
|
336
|
+
}
|
|
337
|
+
if (typeof body.workflowId === 'string' && body.workflowId.trim()) {
|
|
338
|
+
draft.id = body.workflowId.trim();
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const remaining = coerceClarifications(draft._meta?.requiresClarification);
|
|
342
|
+
if (remaining.length > 0) {
|
|
343
|
+
const catalog = getConnectorTargetCatalog(ctx);
|
|
344
|
+
sendJson(ctx, 200, {
|
|
345
|
+
status: 'needs_clarification',
|
|
346
|
+
draft,
|
|
347
|
+
clarifications: remaining,
|
|
348
|
+
catalog: catalog ? await buildCatalogSnapshot(catalog, remaining) : [],
|
|
349
|
+
});
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
await deployWorkflow(ctx, service, draft);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
async function handleWrite(
|
|
357
|
+
ctx: WorkflowRouteContext,
|
|
358
|
+
service: WorkflowService,
|
|
359
|
+
id?: string
|
|
360
|
+
): Promise<void> {
|
|
361
|
+
const payload = await readWorkflowPayload(ctx);
|
|
362
|
+
if (!payload) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const workflow = id ? { ...payload.workflow, id } : payload.workflow;
|
|
366
|
+
await deployWorkflow(ctx, service, workflow, payload.activate);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async function handleToggle(
|
|
370
|
+
ctx: WorkflowRouteContext,
|
|
371
|
+
service: WorkflowService,
|
|
372
|
+
id: string,
|
|
373
|
+
active: boolean
|
|
374
|
+
): Promise<void> {
|
|
375
|
+
if (active) {
|
|
376
|
+
await service.activateWorkflow(id);
|
|
377
|
+
} else {
|
|
378
|
+
await service.deactivateWorkflow(id);
|
|
379
|
+
}
|
|
380
|
+
sendJson(ctx, 200, await service.getWorkflow(id));
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
async function handleListExecutions(
|
|
384
|
+
ctx: WorkflowRouteContext,
|
|
385
|
+
service: WorkflowService,
|
|
386
|
+
id: string
|
|
387
|
+
): Promise<void> {
|
|
388
|
+
const url = new URL(`http://x${ctx.req.url ?? ''}`);
|
|
389
|
+
const rawLimit = url.searchParams.get('limit');
|
|
390
|
+
const limit = Math.min(Math.max(1, Number(rawLimit) || 10), 50);
|
|
391
|
+
const response = await service.listExecutions({ workflowId: id, limit });
|
|
392
|
+
sendJson(ctx, 200, { executions: response.data });
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export async function handleWorkflowRoutes(ctx: WorkflowRouteContext): Promise<void> {
|
|
396
|
+
const path = normalizePath(ctx.pathname);
|
|
397
|
+
const method = ctx.method.toUpperCase();
|
|
398
|
+
|
|
399
|
+
try {
|
|
400
|
+
if (method === 'GET' && path === '/status') {
|
|
401
|
+
await handleStatus(ctx);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (method === 'POST' && path === '/runtime/start') {
|
|
406
|
+
sendJson(ctx, 200, { ok: true });
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const service = getWorkflowService(ctx);
|
|
411
|
+
if (!service) {
|
|
412
|
+
sendJson(ctx, 503, { error: 'workflow service unavailable' });
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (method === 'GET' && path === '/workflows') {
|
|
417
|
+
await handleList(ctx, service);
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (method === 'POST' && path === '/workflows') {
|
|
422
|
+
await handleWrite(ctx, service);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if (method === 'POST' && path === '/workflows/generate') {
|
|
427
|
+
await handleGenerate(ctx, service);
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (method === 'POST' && path === '/workflows/resolve-clarification') {
|
|
432
|
+
await handleResolveClarification(ctx, service);
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const id = readId(path);
|
|
437
|
+
if (id && method === 'GET' && path === `/workflows/${encodeURIComponent(id)}`) {
|
|
438
|
+
await handleGet(ctx, service, id);
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
if (id && method === 'PUT' && path === `/workflows/${encodeURIComponent(id)}`) {
|
|
442
|
+
await handleWrite(ctx, service, id);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
if (id && method === 'DELETE' && path === `/workflows/${encodeURIComponent(id)}`) {
|
|
446
|
+
await service.deleteWorkflow(id);
|
|
447
|
+
sendJson(ctx, 200, { ok: true });
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
if (id && method === 'POST' && path === `/workflows/${encodeURIComponent(id)}/activate`) {
|
|
451
|
+
await handleToggle(ctx, service, id, true);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
if (id && method === 'POST' && path === `/workflows/${encodeURIComponent(id)}/deactivate`) {
|
|
455
|
+
await handleToggle(ctx, service, id, false);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
if (id && method === 'GET' && path === `/workflows/${encodeURIComponent(id)}/executions`) {
|
|
459
|
+
await handleListExecutions(ctx, service, id);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
sendJson(ctx, 404, { error: 'workflow route not found' });
|
|
464
|
+
} catch (error) {
|
|
465
|
+
sendJson(ctx, 500, {
|
|
466
|
+
error: error instanceof Error ? error.message : String(error),
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
}
|