@ai-setting/roy-agent-core 1.4.12 → 1.4.14
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/dist/packages/core/src/config/index.js +32 -0
- package/dist/packages/core/src/env/agent/index.js +24 -0
- package/dist/packages/core/src/env/commands/index.js +14 -0
- package/dist/packages/core/src/env/debug/formatters/index.js +11 -0
- package/dist/packages/core/src/env/debug/index.js +26 -0
- package/dist/packages/core/src/env/hook/index.js +29 -0
- package/dist/packages/core/src/env/index.js +81 -0
- package/dist/packages/core/src/env/llm/index.js +40 -0
- package/dist/packages/core/src/env/log-trace/index.js +83 -0
- package/dist/packages/core/src/env/mcp/index.js +39 -0
- package/dist/packages/core/src/env/mcp/tool/index.js +14 -0
- package/dist/packages/core/src/env/memory/built-in/index.js +11 -0
- package/dist/packages/core/src/env/memory/index.js +56 -0
- package/dist/packages/core/src/env/memory/plugin/index.js +36 -0
- package/dist/packages/core/src/env/prompt/index.js +20 -0
- package/dist/packages/core/src/env/session/index.js +25 -0
- package/dist/packages/core/src/env/session/storage/index.js +18 -0
- package/dist/packages/core/src/env/skill/index.js +34 -0
- package/dist/packages/core/src/env/skill/tool/index.js +9 -0
- package/dist/packages/core/src/env/task/delegate/index.js +18 -0
- package/dist/packages/core/src/env/task/hooks/index.js +7 -0
- package/dist/packages/core/src/env/task/index.js +30 -0
- package/dist/packages/core/src/env/task/plugins/index.js +23 -0
- package/dist/packages/core/src/env/task/storage/index.js +14 -0
- package/dist/packages/core/src/env/task/tools/index.js +17 -0
- package/dist/packages/core/src/env/task/tools/operation/index.js +15 -0
- package/dist/packages/core/src/env/tool/built-in/index.js +25 -0
- package/dist/packages/core/src/env/tool/index.js +39 -0
- package/dist/packages/core/src/env/workflow/decorators/index.js +27 -0
- package/dist/packages/core/src/env/workflow/engine/index.js +28 -0
- package/dist/packages/core/src/env/workflow/index.js +132 -0
- package/dist/packages/core/src/env/workflow/nodes/index.js +19 -0
- package/dist/packages/core/src/env/workflow/service/index.js +13 -0
- package/dist/packages/core/src/env/workflow/storage/index.js +27 -0
- package/dist/packages/core/src/env/workflow/tools/index.js +159 -0
- package/dist/packages/core/src/env/workflow/types/index.js +94 -0
- package/dist/packages/core/src/env/workflow/utils/index.js +637 -0
- package/dist/packages/core/src/index.js +398 -0
- package/dist/shared/@ai-setting/roy-agent-core-04fm8177.js +393 -0
- package/dist/shared/@ai-setting/roy-agent-core-04qgbjbe.js +172 -0
- package/dist/shared/@ai-setting/roy-agent-core-084qqd7t.js +11 -0
- package/dist/shared/@ai-setting/roy-agent-core-0gekht4e.js +1130 -0
- package/dist/shared/@ai-setting/roy-agent-core-0hdry23r.js +419 -0
- package/dist/shared/@ai-setting/roy-agent-core-0sgn3de4.js +102 -0
- package/dist/{env/task/tools/index.js → shared/@ai-setting/roy-agent-core-12x57kf1.js} +1 -59
- package/dist/shared/@ai-setting/roy-agent-core-1f3xrrm6.js +393 -0
- package/dist/shared/@ai-setting/roy-agent-core-1k28kg7h.js +368 -0
- package/dist/shared/@ai-setting/roy-agent-core-1z1zv5g8.js +258 -0
- package/dist/shared/@ai-setting/roy-agent-core-2hqxnaf3.js +851 -0
- package/dist/shared/@ai-setting/roy-agent-core-3dfq8awb.js +587 -0
- package/dist/shared/@ai-setting/roy-agent-core-3takar0s.js +93 -0
- package/dist/shared/@ai-setting/roy-agent-core-3tnb2005.js +117 -0
- package/dist/shared/@ai-setting/roy-agent-core-4vmcvkav.js +14 -0
- package/dist/shared/@ai-setting/roy-agent-core-4ws8atva.js +107 -0
- package/dist/{env/workflow/nodes/index.js → shared/@ai-setting/roy-agent-core-5fbp24se.js} +8 -55
- package/dist/shared/@ai-setting/roy-agent-core-5my94ywp.js +66 -0
- package/dist/shared/@ai-setting/roy-agent-core-6j0zcmwk.js +2146 -0
- package/dist/shared/@ai-setting/roy-agent-core-6w4pmxc7.js +266 -0
- package/dist/shared/@ai-setting/roy-agent-core-7vrk3add.js +10 -0
- package/dist/shared/@ai-setting/roy-agent-core-8dvbn7tw.js +64 -0
- package/dist/{env/memory/built-in/index.js → shared/@ai-setting/roy-agent-core-8mbmrwzs.js} +22 -76
- package/dist/shared/@ai-setting/roy-agent-core-8wzz66qe.js +620 -0
- package/dist/shared/@ai-setting/roy-agent-core-9ykq91jc.js +762 -0
- package/dist/shared/@ai-setting/roy-agent-core-dde19zke.js +1305 -0
- package/dist/shared/@ai-setting/roy-agent-core-f7g67gce.js +913 -0
- package/dist/{env/workflow/types/index.js → shared/@ai-setting/roy-agent-core-fq5mtxsy.js} +16 -154
- package/dist/{env/task/hooks/index.js → shared/@ai-setting/roy-agent-core-fs0mn2jk.js} +3 -18
- package/dist/{config/index.js → shared/@ai-setting/roy-agent-core-fvd9g6k8.js} +140 -605
- package/dist/shared/@ai-setting/roy-agent-core-gv1hrn3x.js +378 -0
- package/dist/{env/task/tools/operation/index.js → shared/@ai-setting/roy-agent-core-gy0wp5h7.js} +1 -58
- package/dist/shared/@ai-setting/roy-agent-core-hyza1gm7.js +15 -0
- package/dist/shared/@ai-setting/roy-agent-core-j8zx62zr.js +154 -0
- package/dist/shared/@ai-setting/roy-agent-core-jb2exr0d.js +442 -0
- package/dist/shared/@ai-setting/roy-agent-core-jv3b7v9w.js +57 -0
- package/dist/shared/@ai-setting/roy-agent-core-k1rxf9ya.js +513 -0
- package/dist/shared/@ai-setting/roy-agent-core-kydc9nwb.js +60 -0
- package/dist/shared/@ai-setting/roy-agent-core-m2x48hw6.js +97 -0
- package/dist/shared/@ai-setting/roy-agent-core-m6y668cc.js +377 -0
- package/dist/shared/@ai-setting/roy-agent-core-nczzf0ms.js +15 -0
- package/dist/shared/@ai-setting/roy-agent-core-nfj6knp5.js +36 -0
- package/dist/shared/@ai-setting/roy-agent-core-ntrp979d.js +204 -0
- package/dist/shared/@ai-setting/roy-agent-core-pd7g8z5v.js +1387 -0
- package/dist/shared/@ai-setting/roy-agent-core-pzk1syce.js +14 -0
- package/dist/shared/@ai-setting/roy-agent-core-q50tg9m2.js +862 -0
- package/dist/shared/@ai-setting/roy-agent-core-qg9tcaph.js +11 -0
- package/dist/shared/@ai-setting/roy-agent-core-qhyerewk.js +20 -0
- package/dist/shared/@ai-setting/roy-agent-core-qxybm159.js +82 -0
- package/dist/shared/@ai-setting/roy-agent-core-rh9dpkpw.js +549 -0
- package/dist/shared/@ai-setting/roy-agent-core-rr9p1g43.js +205 -0
- package/dist/{env/workflow/decorators/index.js → shared/@ai-setting/roy-agent-core-sbzvpfn7.js} +8 -173
- package/dist/shared/@ai-setting/roy-agent-core-t22nqt4d.js +788 -0
- package/dist/shared/@ai-setting/roy-agent-core-tkr5ynkh.js +200 -0
- package/dist/shared/@ai-setting/roy-agent-core-v4aabsf0.js +303 -0
- package/dist/{env/hook/index.js → shared/@ai-setting/roy-agent-core-w75rafhy.js} +3 -74
- package/dist/{env/debug/formatters/index.js → shared/@ai-setting/roy-agent-core-w76hqkmg.js} +11 -66
- package/dist/shared/@ai-setting/roy-agent-core-yfbgwes2.js +408 -0
- package/dist/shared/@ai-setting/roy-agent-core-yn761yve.js +299 -0
- package/dist/shared/@ai-setting/roy-agent-core-yrzmn4m1.js +492 -0
- package/dist/{env/workflow/service/index.js → shared/@ai-setting/roy-agent-core-yt8wdh2w.js} +1 -57
- package/package.json +3 -2
- package/dist/env/agent/index.js +0 -3035
- package/dist/env/commands/index.js +0 -1685
- package/dist/env/debug/index.js +0 -2300
- package/dist/env/index.js +0 -12591
- package/dist/env/llm/index.js +0 -2736
- package/dist/env/log-trace/index.js +0 -1779
- package/dist/env/mcp/index.js +0 -2173
- package/dist/env/mcp/tool/index.js +0 -1149
- package/dist/env/memory/index.js +0 -2171
- package/dist/env/memory/plugin/index.js +0 -1263
- package/dist/env/prompt/index.js +0 -2107
- package/dist/env/session/index.js +0 -3594
- package/dist/env/session/storage/index.js +0 -2049
- package/dist/env/skill/index.js +0 -1635
- package/dist/env/skill/tool/index.js +0 -114
- package/dist/env/task/delegate/index.js +0 -1844
- package/dist/env/task/index.js +0 -3578
- package/dist/env/task/plugins/index.js +0 -1626
- package/dist/env/task/storage/index.js +0 -1464
- package/dist/env/tool/built-in/index.js +0 -1151
- package/dist/env/tool/index.js +0 -2284
- package/dist/env/workflow/engine/index.js +0 -4391
- package/dist/env/workflow/index.js +0 -6214
- package/dist/env/workflow/storage/index.js +0 -1236
- package/dist/env/workflow/tools/index.js +0 -1081
- package/dist/env/workflow/utils/index.js +0 -1631
- package/dist/index.js +0 -22778
|
@@ -1,4391 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
function __accessProp(key) {
|
|
7
|
-
return this[key];
|
|
8
|
-
}
|
|
9
|
-
var __toCommonJS = (from) => {
|
|
10
|
-
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
11
|
-
if (entry)
|
|
12
|
-
return entry;
|
|
13
|
-
entry = __defProp({}, "__esModule", { value: true });
|
|
14
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
-
for (var key of __getOwnPropNames(from))
|
|
16
|
-
if (!__hasOwnProp.call(entry, key))
|
|
17
|
-
__defProp(entry, key, {
|
|
18
|
-
get: __accessProp.bind(from, key),
|
|
19
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
__moduleCache.set(from, entry);
|
|
23
|
-
return entry;
|
|
24
|
-
};
|
|
25
|
-
var __moduleCache;
|
|
26
|
-
var __returnValue = (v) => v;
|
|
27
|
-
function __exportSetter(name, newValue) {
|
|
28
|
-
this[name] = __returnValue.bind(null, newValue);
|
|
29
|
-
}
|
|
30
|
-
var __export = (target, all) => {
|
|
31
|
-
for (var name in all)
|
|
32
|
-
__defProp(target, name, {
|
|
33
|
-
get: all[name],
|
|
34
|
-
enumerable: true,
|
|
35
|
-
configurable: true,
|
|
36
|
-
set: __exportSetter.bind(all, name)
|
|
37
|
-
});
|
|
38
|
-
};
|
|
39
|
-
var __legacyDecorateClassTS = function(decorators, target, key, desc) {
|
|
40
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
41
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
42
|
-
r = Reflect.decorate(decorators, target, key, desc);
|
|
43
|
-
else
|
|
44
|
-
for (var i = decorators.length - 1;i >= 0; i--)
|
|
45
|
-
if (d = decorators[i])
|
|
46
|
-
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
47
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
48
|
-
};
|
|
49
|
-
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
50
|
-
var __require = import.meta.require;
|
|
51
|
-
|
|
52
|
-
// packages/core/src/env/workflow/types/workflow.ts
|
|
53
|
-
import { z } from "zod";
|
|
54
|
-
async function getYamlParser() {
|
|
55
|
-
if (!yamlParser) {
|
|
56
|
-
yamlParser = await import("yaml");
|
|
57
|
-
}
|
|
58
|
-
return yamlParser;
|
|
59
|
-
}
|
|
60
|
-
async function parseWorkflowFile(content, filename) {
|
|
61
|
-
const isYaml = filename.endsWith(".yaml") || filename.endsWith(".yml");
|
|
62
|
-
const isJson = filename.endsWith(".json");
|
|
63
|
-
let definition;
|
|
64
|
-
if (isYaml) {
|
|
65
|
-
const yaml = await getYamlParser();
|
|
66
|
-
definition = WorkflowDefinitionSchema.parse(yaml.parse(content));
|
|
67
|
-
} else if (isJson) {
|
|
68
|
-
definition = WorkflowDefinitionSchema.parse(JSON.parse(content));
|
|
69
|
-
} else {
|
|
70
|
-
try {
|
|
71
|
-
definition = WorkflowDefinitionSchema.parse(JSON.parse(content));
|
|
72
|
-
} catch {
|
|
73
|
-
const yaml = await getYamlParser();
|
|
74
|
-
definition = WorkflowDefinitionSchema.parse(yaml.parse(content));
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
return {
|
|
78
|
-
format: isYaml ? "yaml" : "json",
|
|
79
|
-
definition
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
function parseWorkflowFileSync(content, filename) {
|
|
83
|
-
const isYaml = filename.endsWith(".yaml") || filename.endsWith(".yml");
|
|
84
|
-
const isJson = filename.endsWith(".json");
|
|
85
|
-
let definition;
|
|
86
|
-
if (isJson) {
|
|
87
|
-
definition = WorkflowDefinitionSchema.parse(JSON.parse(content));
|
|
88
|
-
} else if (isYaml) {
|
|
89
|
-
throw new Error("Synchronous YAML parsing not supported. Use parseWorkflowFile() instead.");
|
|
90
|
-
} else {
|
|
91
|
-
try {
|
|
92
|
-
definition = WorkflowDefinitionSchema.parse(JSON.parse(content));
|
|
93
|
-
} catch {
|
|
94
|
-
throw new Error("Cannot auto-detect format. Please use .yaml, .yml, or .json extension.");
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return {
|
|
98
|
-
format: isJson ? "json" : "yaml",
|
|
99
|
-
definition
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
var DependsOnSchema, RetryConfigSchema, NodeDefinitionSchema, WorkflowConfigSchema, OutputDefinitionSchema, WorkflowMetadataSchema, WorkflowDefinitionSchema, yamlParser = null;
|
|
103
|
-
var init_workflow = __esm(() => {
|
|
104
|
-
DependsOnSchema = z.array(z.string());
|
|
105
|
-
RetryConfigSchema = z.object({
|
|
106
|
-
max_attempts: z.number().min(1).default(1),
|
|
107
|
-
backoff: z.enum(["fixed", "exponential"]).default("exponential"),
|
|
108
|
-
initial_delay: z.number().min(0).default(1000)
|
|
109
|
-
});
|
|
110
|
-
NodeDefinitionSchema = z.object({
|
|
111
|
-
id: z.string().min(1, "Node ID is required"),
|
|
112
|
-
type: z.string().min(1, "Node type is required"),
|
|
113
|
-
name: z.string().optional(),
|
|
114
|
-
config: z.record(z.string(), z.unknown()).optional().default({}),
|
|
115
|
-
depends_on: z.array(z.string()).optional(),
|
|
116
|
-
condition: z.string().optional(),
|
|
117
|
-
retry: RetryConfigSchema.optional(),
|
|
118
|
-
timeout: z.number().optional()
|
|
119
|
-
});
|
|
120
|
-
WorkflowConfigSchema = z.object({
|
|
121
|
-
parallel_limit: z.number().nullable().optional(),
|
|
122
|
-
timeout: z.number().nullable().optional(),
|
|
123
|
-
retry: RetryConfigSchema.optional(),
|
|
124
|
-
debug: z.boolean().optional()
|
|
125
|
-
});
|
|
126
|
-
OutputDefinitionSchema = z.object({
|
|
127
|
-
name: z.string(),
|
|
128
|
-
source: z.string(),
|
|
129
|
-
path: z.string()
|
|
130
|
-
});
|
|
131
|
-
WorkflowMetadataSchema = z.object({
|
|
132
|
-
author: z.string().optional(),
|
|
133
|
-
taskId: z.number().optional(),
|
|
134
|
-
tags: z.array(z.string()).optional().default([]),
|
|
135
|
-
created_at: z.string().optional(),
|
|
136
|
-
updated_at: z.string().optional()
|
|
137
|
-
});
|
|
138
|
-
WorkflowDefinitionSchema = z.object({
|
|
139
|
-
name: z.string().min(1, "Workflow name is required"),
|
|
140
|
-
version: z.string().default("1.0"),
|
|
141
|
-
description: z.string().optional(),
|
|
142
|
-
config: WorkflowConfigSchema.optional().default({}),
|
|
143
|
-
nodes: z.array(NodeDefinitionSchema).min(1, "At least one node is required"),
|
|
144
|
-
entry: z.union([z.string(), z.array(z.string())]).default("__default_entry__"),
|
|
145
|
-
outputs: z.array(OutputDefinitionSchema).optional().default([]),
|
|
146
|
-
metadata: WorkflowMetadataSchema.optional().default({})
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
// packages/core/src/env/workflow/types/workflow-hil.ts
|
|
151
|
-
function createNodeInterruptEvent(runId, nodeId, nodeType, query, agentSessionId) {
|
|
152
|
-
return {
|
|
153
|
-
type: "node.interrupt",
|
|
154
|
-
run_id: runId,
|
|
155
|
-
timestamp: Date.now(),
|
|
156
|
-
node_id: nodeId,
|
|
157
|
-
node_type: nodeType,
|
|
158
|
-
query,
|
|
159
|
-
...agentSessionId ? { agent_session_id: agentSessionId } : {}
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
function createWorkflowAskUserEvent(runId, sessionId, nodeId, nodeType, query) {
|
|
163
|
-
return {
|
|
164
|
-
type: "workflow.ask-user",
|
|
165
|
-
run_id: runId,
|
|
166
|
-
timestamp: Date.now(),
|
|
167
|
-
session_id: sessionId,
|
|
168
|
-
node_id: nodeId,
|
|
169
|
-
node_type: nodeType,
|
|
170
|
-
query
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
var AskUserError;
|
|
174
|
-
var init_workflow_hil = __esm(() => {
|
|
175
|
-
AskUserError = class AskUserError extends Error {
|
|
176
|
-
runId;
|
|
177
|
-
sessionId;
|
|
178
|
-
nodeId;
|
|
179
|
-
nodeType;
|
|
180
|
-
query;
|
|
181
|
-
agentSessionId;
|
|
182
|
-
timestamp;
|
|
183
|
-
type = "ask-user";
|
|
184
|
-
name = "AskUserError";
|
|
185
|
-
constructor(runId, sessionId, nodeId, nodeType, query, agentSessionId, timestamp = Date.now()) {
|
|
186
|
-
super(`[${nodeType}:${nodeId}] Ask user: ${query}`);
|
|
187
|
-
this.runId = runId;
|
|
188
|
-
this.sessionId = sessionId;
|
|
189
|
-
this.nodeId = nodeId;
|
|
190
|
-
this.nodeType = nodeType;
|
|
191
|
-
this.query = query;
|
|
192
|
-
this.agentSessionId = agentSessionId;
|
|
193
|
-
this.timestamp = timestamp;
|
|
194
|
-
}
|
|
195
|
-
toEvent() {
|
|
196
|
-
return {
|
|
197
|
-
type: "workflow.ask-user",
|
|
198
|
-
run_id: this.runId,
|
|
199
|
-
timestamp: this.timestamp,
|
|
200
|
-
session_id: this.sessionId,
|
|
201
|
-
node_id: this.nodeId,
|
|
202
|
-
node_type: this.nodeType,
|
|
203
|
-
query: this.query
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
// packages/core/src/env/workflow/types/workflow-message.ts
|
|
210
|
-
import { z as z2 } from "zod";
|
|
211
|
-
var WorkflowMessageRoleSchema;
|
|
212
|
-
var init_workflow_message = __esm(() => {
|
|
213
|
-
init_workflow_hil();
|
|
214
|
-
WorkflowMessageRoleSchema = z2.enum([
|
|
215
|
-
"workflow.node.call",
|
|
216
|
-
"workflow.node.interrupt",
|
|
217
|
-
"workflow.node.result",
|
|
218
|
-
"workflow.node.resume"
|
|
219
|
-
]);
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
// packages/core/src/env/workflow/types/workflow-session.ts
|
|
223
|
-
function isWorkflowSessionMetadata(metadata) {
|
|
224
|
-
if (typeof metadata !== "object" || metadata === null || !("type" in metadata) || metadata.type !== "workflow") {
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
const m = metadata;
|
|
228
|
-
if (!m.workflowId || typeof m.workflowId !== "string") {
|
|
229
|
-
return false;
|
|
230
|
-
}
|
|
231
|
-
if (!m.workflowName || typeof m.workflowName !== "string") {
|
|
232
|
-
return false;
|
|
233
|
-
}
|
|
234
|
-
if (!m.status || typeof m.status !== "string") {
|
|
235
|
-
return false;
|
|
236
|
-
}
|
|
237
|
-
const validStatuses = ["running", "paused", "completed", "failed", "stopped"];
|
|
238
|
-
if (!validStatuses.includes(m.status)) {
|
|
239
|
-
return false;
|
|
240
|
-
}
|
|
241
|
-
return true;
|
|
242
|
-
}
|
|
243
|
-
function getWorkflowSessionStatus(metadata) {
|
|
244
|
-
return metadata.status || "running";
|
|
245
|
-
}
|
|
246
|
-
// packages/core/src/env/workflow/types/event.ts
|
|
247
|
-
import { z as z3 } from "zod";
|
|
248
|
-
function createWorkflowEvent(type, runId, data) {
|
|
249
|
-
return {
|
|
250
|
-
type,
|
|
251
|
-
run_id: runId,
|
|
252
|
-
timestamp: Date.now(),
|
|
253
|
-
...data
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
var BaseEventSchema, WorkflowStartedEventSchema, WorkflowPausedEventSchema, WorkflowResumedEventSchema, WorkflowStoppedEventSchema, WorkflowCompletedEventSchema, WorkflowFailedEventSchema, WorkflowOutputEventSchema, NodeScheduledEventSchema, NodeStartedEventSchema, NodeProgressEventSchema, NodeCompletedEventSchema, NodeFailedEventSchema, NodeSkippedEventSchema, NodeDataEventSchema, NodeAddedEventSchema, NodeRemovedEventSchema, ControlPauseEventSchema, ControlResumeEventSchema, ControlStopEventSchema, NodeInterruptEventSchema, WorkflowAskUserEventSchema, WorkflowEventSchema;
|
|
257
|
-
var init_event = __esm(() => {
|
|
258
|
-
BaseEventSchema = z3.object({
|
|
259
|
-
type: z3.string(),
|
|
260
|
-
run_id: z3.string(),
|
|
261
|
-
timestamp: z3.number()
|
|
262
|
-
});
|
|
263
|
-
WorkflowStartedEventSchema = BaseEventSchema.extend({
|
|
264
|
-
type: z3.literal("workflow.started"),
|
|
265
|
-
workflow_name: z3.string(),
|
|
266
|
-
input: z3.record(z3.string(), z3.unknown()).optional()
|
|
267
|
-
});
|
|
268
|
-
WorkflowPausedEventSchema = BaseEventSchema.extend({
|
|
269
|
-
type: z3.literal("workflow.paused")
|
|
270
|
-
});
|
|
271
|
-
WorkflowResumedEventSchema = BaseEventSchema.extend({
|
|
272
|
-
type: z3.literal("workflow.resumed")
|
|
273
|
-
});
|
|
274
|
-
WorkflowStoppedEventSchema = BaseEventSchema.extend({
|
|
275
|
-
type: z3.literal("workflow.stopped"),
|
|
276
|
-
reason: z3.string()
|
|
277
|
-
});
|
|
278
|
-
WorkflowCompletedEventSchema = BaseEventSchema.extend({
|
|
279
|
-
type: z3.literal("workflow.completed"),
|
|
280
|
-
result: z3.record(z3.string(), z3.unknown()).optional(),
|
|
281
|
-
duration_ms: z3.number()
|
|
282
|
-
});
|
|
283
|
-
WorkflowFailedEventSchema = BaseEventSchema.extend({
|
|
284
|
-
type: z3.literal("workflow.failed"),
|
|
285
|
-
error: z3.object({
|
|
286
|
-
message: z3.string(),
|
|
287
|
-
stack: z3.string().optional()
|
|
288
|
-
}),
|
|
289
|
-
failed_at: z3.string()
|
|
290
|
-
});
|
|
291
|
-
WorkflowOutputEventSchema = BaseEventSchema.extend({
|
|
292
|
-
type: z3.literal("workflow.output"),
|
|
293
|
-
output: z3.record(z3.string(), z3.unknown())
|
|
294
|
-
});
|
|
295
|
-
NodeScheduledEventSchema = BaseEventSchema.extend({
|
|
296
|
-
type: z3.literal("node.scheduled"),
|
|
297
|
-
node_id: z3.string()
|
|
298
|
-
});
|
|
299
|
-
NodeStartedEventSchema = BaseEventSchema.extend({
|
|
300
|
-
type: z3.literal("node.started"),
|
|
301
|
-
node_id: z3.string(),
|
|
302
|
-
input: z3.any(),
|
|
303
|
-
agentSessionId: z3.string().optional(),
|
|
304
|
-
userResponse: z3.string().optional()
|
|
305
|
-
});
|
|
306
|
-
NodeProgressEventSchema = BaseEventSchema.extend({
|
|
307
|
-
type: z3.literal("node.progress"),
|
|
308
|
-
node_id: z3.string(),
|
|
309
|
-
progress: z3.number(),
|
|
310
|
-
message: z3.string().optional()
|
|
311
|
-
});
|
|
312
|
-
NodeCompletedEventSchema = BaseEventSchema.extend({
|
|
313
|
-
type: z3.literal("node.completed"),
|
|
314
|
-
node_id: z3.string(),
|
|
315
|
-
output: z3.any(),
|
|
316
|
-
duration_ms: z3.number()
|
|
317
|
-
});
|
|
318
|
-
NodeFailedEventSchema = BaseEventSchema.extend({
|
|
319
|
-
type: z3.literal("node.failed"),
|
|
320
|
-
node_id: z3.string(),
|
|
321
|
-
error: z3.object({
|
|
322
|
-
message: z3.string(),
|
|
323
|
-
stack: z3.string().optional()
|
|
324
|
-
})
|
|
325
|
-
});
|
|
326
|
-
NodeSkippedEventSchema = BaseEventSchema.extend({
|
|
327
|
-
type: z3.literal("node.skipped"),
|
|
328
|
-
node_id: z3.string(),
|
|
329
|
-
reason: z3.string()
|
|
330
|
-
});
|
|
331
|
-
NodeDataEventSchema = BaseEventSchema.extend({
|
|
332
|
-
type: z3.literal("node.data"),
|
|
333
|
-
from_node: z3.string(),
|
|
334
|
-
to_node: z3.string(),
|
|
335
|
-
data: z3.any()
|
|
336
|
-
});
|
|
337
|
-
NodeAddedEventSchema = BaseEventSchema.extend({
|
|
338
|
-
type: z3.literal("node.added"),
|
|
339
|
-
node_id: z3.string(),
|
|
340
|
-
node: z3.any()
|
|
341
|
-
});
|
|
342
|
-
NodeRemovedEventSchema = BaseEventSchema.extend({
|
|
343
|
-
type: z3.literal("node.removed"),
|
|
344
|
-
node_id: z3.string()
|
|
345
|
-
});
|
|
346
|
-
ControlPauseEventSchema = BaseEventSchema.extend({
|
|
347
|
-
type: z3.literal("control.pause")
|
|
348
|
-
});
|
|
349
|
-
ControlResumeEventSchema = BaseEventSchema.extend({
|
|
350
|
-
type: z3.literal("control.resume")
|
|
351
|
-
});
|
|
352
|
-
ControlStopEventSchema = BaseEventSchema.extend({
|
|
353
|
-
type: z3.literal("control.stop")
|
|
354
|
-
});
|
|
355
|
-
NodeInterruptEventSchema = BaseEventSchema.extend({
|
|
356
|
-
type: z3.literal("node.interrupt"),
|
|
357
|
-
node_id: z3.string(),
|
|
358
|
-
node_type: z3.string(),
|
|
359
|
-
query: z3.string()
|
|
360
|
-
});
|
|
361
|
-
WorkflowAskUserEventSchema = BaseEventSchema.extend({
|
|
362
|
-
type: z3.literal("workflow.ask-user"),
|
|
363
|
-
session_id: z3.string(),
|
|
364
|
-
node_id: z3.string(),
|
|
365
|
-
node_type: z3.string(),
|
|
366
|
-
query: z3.string()
|
|
367
|
-
});
|
|
368
|
-
WorkflowEventSchema = z3.union([
|
|
369
|
-
WorkflowStartedEventSchema,
|
|
370
|
-
WorkflowPausedEventSchema,
|
|
371
|
-
WorkflowResumedEventSchema,
|
|
372
|
-
WorkflowStoppedEventSchema,
|
|
373
|
-
WorkflowCompletedEventSchema,
|
|
374
|
-
WorkflowFailedEventSchema,
|
|
375
|
-
WorkflowOutputEventSchema,
|
|
376
|
-
NodeScheduledEventSchema,
|
|
377
|
-
NodeStartedEventSchema,
|
|
378
|
-
NodeProgressEventSchema,
|
|
379
|
-
NodeCompletedEventSchema,
|
|
380
|
-
NodeFailedEventSchema,
|
|
381
|
-
NodeSkippedEventSchema,
|
|
382
|
-
NodeDataEventSchema,
|
|
383
|
-
NodeAddedEventSchema,
|
|
384
|
-
NodeRemovedEventSchema,
|
|
385
|
-
ControlPauseEventSchema,
|
|
386
|
-
ControlResumeEventSchema,
|
|
387
|
-
ControlStopEventSchema,
|
|
388
|
-
NodeInterruptEventSchema,
|
|
389
|
-
WorkflowAskUserEventSchema
|
|
390
|
-
]);
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
// packages/core/src/env/workflow/types/run.ts
|
|
394
|
-
import { z as z4 } from "zod";
|
|
395
|
-
function createNodeExecutionContext(params) {
|
|
396
|
-
return {
|
|
397
|
-
...params,
|
|
398
|
-
askUser: (query) => {
|
|
399
|
-
throw new AskUserError(params.runId, params.sessionId, params.nodeId, "unknown", query);
|
|
400
|
-
}
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
var RunStatusSchema, NodeStatusSchema;
|
|
404
|
-
var init_run = __esm(() => {
|
|
405
|
-
init_workflow_message();
|
|
406
|
-
RunStatusSchema = z4.enum([
|
|
407
|
-
"idle",
|
|
408
|
-
"running",
|
|
409
|
-
"paused",
|
|
410
|
-
"stopped",
|
|
411
|
-
"completed",
|
|
412
|
-
"failed"
|
|
413
|
-
]);
|
|
414
|
-
NodeStatusSchema = z4.enum([
|
|
415
|
-
"pending",
|
|
416
|
-
"scheduled",
|
|
417
|
-
"started",
|
|
418
|
-
"running",
|
|
419
|
-
"completed",
|
|
420
|
-
"failed",
|
|
421
|
-
"skipped"
|
|
422
|
-
]);
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
// packages/core/src/env/workflow/types/index.ts
|
|
426
|
-
var init_types = __esm(() => {
|
|
427
|
-
init_run();
|
|
428
|
-
init_workflow();
|
|
429
|
-
init_workflow_message();
|
|
430
|
-
init_workflow_hil();
|
|
431
|
-
init_event();
|
|
432
|
-
init_run();
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
// packages/core/src/env/workflow/engine/event-bus.ts
|
|
436
|
-
class EventBus {
|
|
437
|
-
handlers = new Map;
|
|
438
|
-
wildcardHandlers = new Set;
|
|
439
|
-
constructor() {}
|
|
440
|
-
on(eventType, handler) {
|
|
441
|
-
let handlers = this.handlers.get(eventType);
|
|
442
|
-
if (!handlers) {
|
|
443
|
-
handlers = new Set;
|
|
444
|
-
this.handlers.set(eventType, handlers);
|
|
445
|
-
}
|
|
446
|
-
handlers.add(handler);
|
|
447
|
-
return () => this.off(eventType, handler);
|
|
448
|
-
}
|
|
449
|
-
once(eventType, handler) {
|
|
450
|
-
let executed = false;
|
|
451
|
-
const wrappedHandler = async (event2) => {
|
|
452
|
-
if (executed) {
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
executed = true;
|
|
456
|
-
try {
|
|
457
|
-
await handler(event2);
|
|
458
|
-
} catch (error) {
|
|
459
|
-
console.error("Event handler error:", error);
|
|
460
|
-
}
|
|
461
|
-
this.off(eventType, wrappedHandler);
|
|
462
|
-
};
|
|
463
|
-
return this.on(eventType, wrappedHandler);
|
|
464
|
-
}
|
|
465
|
-
off(eventType, handler) {
|
|
466
|
-
const handlers = this.handlers.get(eventType);
|
|
467
|
-
if (handlers) {
|
|
468
|
-
handlers.delete(handler);
|
|
469
|
-
if (handlers.size === 0) {
|
|
470
|
-
this.handlers.delete(eventType);
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
onAny(handler) {
|
|
475
|
-
this.wildcardHandlers.add(handler);
|
|
476
|
-
return () => {
|
|
477
|
-
this.wildcardHandlers.delete(handler);
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
async publish(event2, waitForHandlers = false) {
|
|
481
|
-
const handlers = this.handlers.get(event2.type);
|
|
482
|
-
const handlerPromises = [];
|
|
483
|
-
if (handlers) {
|
|
484
|
-
for (const handler of handlers) {
|
|
485
|
-
const promise = this.executeHandler(handler, event2);
|
|
486
|
-
handlerPromises.push(promise);
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
for (const handler of this.wildcardHandlers) {
|
|
490
|
-
const promise = this.executeHandler(handler, event2);
|
|
491
|
-
handlerPromises.push(promise);
|
|
492
|
-
}
|
|
493
|
-
if (waitForHandlers && handlerPromises.length > 0) {
|
|
494
|
-
await Promise.allSettled(handlerPromises);
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
async executeHandler(handler, event2) {
|
|
498
|
-
try {
|
|
499
|
-
await handler(event2);
|
|
500
|
-
} catch (error) {
|
|
501
|
-
console.error("Event handler error:", error);
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
clear() {
|
|
505
|
-
this.handlers.clear();
|
|
506
|
-
this.wildcardHandlers.clear();
|
|
507
|
-
}
|
|
508
|
-
getStats() {
|
|
509
|
-
let totalHandlers = 0;
|
|
510
|
-
for (const handlers of this.handlers.values()) {
|
|
511
|
-
totalHandlers += handlers.size;
|
|
512
|
-
}
|
|
513
|
-
totalHandlers += this.wildcardHandlers.size;
|
|
514
|
-
return {
|
|
515
|
-
eventTypes: this.handlers.size,
|
|
516
|
-
wildcardHandlers: this.wildcardHandlers.size,
|
|
517
|
-
totalHandlers
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
// packages/core/src/env/workflow/engine/dag-manager.ts
|
|
523
|
-
class DAGManager {
|
|
524
|
-
workflow;
|
|
525
|
-
nodeMap;
|
|
526
|
-
extendedDefinition = null;
|
|
527
|
-
cachedAnalysis = null;
|
|
528
|
-
constructor(workflow2) {
|
|
529
|
-
if (!workflow2.nodes || workflow2.nodes.length === 0) {
|
|
530
|
-
throw new Error("At least one node is required");
|
|
531
|
-
}
|
|
532
|
-
this.workflow = workflow2;
|
|
533
|
-
this.nodeMap = new Map;
|
|
534
|
-
for (const node of workflow2.nodes) {
|
|
535
|
-
if (node.id === "") {
|
|
536
|
-
throw new Error("Node ID cannot be empty");
|
|
537
|
-
}
|
|
538
|
-
if (this.nodeMap.has(node.id)) {
|
|
539
|
-
throw new Error(`Duplicate node ID: ${node.id}`);
|
|
540
|
-
}
|
|
541
|
-
this.nodeMap.set(node.id, node);
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
getExtendedDefinition() {
|
|
545
|
-
if (this.extendedDefinition) {
|
|
546
|
-
return this.extendedDefinition;
|
|
547
|
-
}
|
|
548
|
-
const analysis = this.analyze();
|
|
549
|
-
this.extendedDefinition = {
|
|
550
|
-
...this.workflow,
|
|
551
|
-
computedEntry: analysis.entryNodes,
|
|
552
|
-
nodeMap: this.nodeMap,
|
|
553
|
-
topologicalOrder: this.getTopologicalOrder()
|
|
554
|
-
};
|
|
555
|
-
return this.extendedDefinition;
|
|
556
|
-
}
|
|
557
|
-
analyze() {
|
|
558
|
-
if (this.cachedAnalysis) {
|
|
559
|
-
return this.cachedAnalysis;
|
|
560
|
-
}
|
|
561
|
-
const dependencies = this.buildDependenciesMap();
|
|
562
|
-
const dependents = this.buildDependentsMap(dependencies);
|
|
563
|
-
const entryNodes = this.findEntryNodes(dependencies);
|
|
564
|
-
const exitNodes = this.findExitNodes(dependents);
|
|
565
|
-
const levels = this.computeLevels(dependencies);
|
|
566
|
-
const criticalPath = this.findCriticalPath(levels, dependencies);
|
|
567
|
-
this.cachedAnalysis = {
|
|
568
|
-
entryNodes,
|
|
569
|
-
exitNodes,
|
|
570
|
-
levels,
|
|
571
|
-
dependencies,
|
|
572
|
-
dependents,
|
|
573
|
-
criticalPath
|
|
574
|
-
};
|
|
575
|
-
return this.cachedAnalysis;
|
|
576
|
-
}
|
|
577
|
-
buildDependenciesMap() {
|
|
578
|
-
const dependencies = new Map;
|
|
579
|
-
for (const node of this.workflow.nodes) {
|
|
580
|
-
const deps = node.depends_on || [];
|
|
581
|
-
dependencies.set(node.id, [...deps]);
|
|
582
|
-
}
|
|
583
|
-
return dependencies;
|
|
584
|
-
}
|
|
585
|
-
buildDependentsMap(dependencies) {
|
|
586
|
-
const dependentsMap = new Map;
|
|
587
|
-
for (const nodeId of dependencies.keys()) {
|
|
588
|
-
dependentsMap.set(nodeId, []);
|
|
589
|
-
}
|
|
590
|
-
for (const [nodeId, deps] of dependencies.entries()) {
|
|
591
|
-
for (const dep of deps) {
|
|
592
|
-
const nodeDependents = dependentsMap.get(dep) || [];
|
|
593
|
-
nodeDependents.push(nodeId);
|
|
594
|
-
dependentsMap.set(dep, nodeDependents);
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
return dependentsMap;
|
|
598
|
-
}
|
|
599
|
-
findEntryNodes(dependencies) {
|
|
600
|
-
const entryNodes = [];
|
|
601
|
-
for (const [nodeId, deps] of dependencies.entries()) {
|
|
602
|
-
if (deps.length === 0) {
|
|
603
|
-
entryNodes.push(nodeId);
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
return entryNodes;
|
|
607
|
-
}
|
|
608
|
-
findExitNodes(dependents) {
|
|
609
|
-
const exitNodes = [];
|
|
610
|
-
for (const [nodeId, deps] of dependents.entries()) {
|
|
611
|
-
if (deps.length === 0) {
|
|
612
|
-
exitNodes.push(nodeId);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
return exitNodes;
|
|
616
|
-
}
|
|
617
|
-
computeLevels(dependencies) {
|
|
618
|
-
const levels = [];
|
|
619
|
-
const assigned = new Set;
|
|
620
|
-
const nodeLevels = new Map;
|
|
621
|
-
const dependentsMap = this.buildDependentsMap(dependencies);
|
|
622
|
-
const entryNodes = this.findEntryNodes(dependencies);
|
|
623
|
-
const queue = [];
|
|
624
|
-
for (const entry of entryNodes) {
|
|
625
|
-
queue.push({ nodeId: entry, level: 0 });
|
|
626
|
-
nodeLevels.set(entry, 0);
|
|
627
|
-
}
|
|
628
|
-
while (queue.length > 0) {
|
|
629
|
-
const { nodeId, level } = queue.shift();
|
|
630
|
-
if (assigned.has(nodeId)) {
|
|
631
|
-
const currentLevel = nodeLevels.get(nodeId) || 0;
|
|
632
|
-
if (level > currentLevel) {
|
|
633
|
-
nodeLevels.set(nodeId, level);
|
|
634
|
-
}
|
|
635
|
-
continue;
|
|
636
|
-
}
|
|
637
|
-
assigned.add(nodeId);
|
|
638
|
-
nodeLevels.set(nodeId, level);
|
|
639
|
-
const dependentsOfNode = dependentsMap.get(nodeId) || [];
|
|
640
|
-
for (const dependent of dependentsOfNode) {
|
|
641
|
-
if (!assigned.has(dependent)) {
|
|
642
|
-
queue.push({ nodeId: dependent, level: level + 1 });
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
for (const nodeId of dependencies.keys()) {
|
|
647
|
-
if (!nodeLevels.has(nodeId)) {
|
|
648
|
-
nodeLevels.set(nodeId, 0);
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
const maxLevel = Math.max(...nodeLevels.values(), 0);
|
|
652
|
-
for (let i = 0;i <= maxLevel; i++) {
|
|
653
|
-
levels.push([]);
|
|
654
|
-
}
|
|
655
|
-
for (const [nodeId, level] of nodeLevels.entries()) {
|
|
656
|
-
levels[level].push(nodeId);
|
|
657
|
-
}
|
|
658
|
-
return levels;
|
|
659
|
-
}
|
|
660
|
-
findCriticalPath(levels, dependencies) {
|
|
661
|
-
if (levels.length === 0) {
|
|
662
|
-
return [];
|
|
663
|
-
}
|
|
664
|
-
const longestPath = new Map;
|
|
665
|
-
const allNodes = [];
|
|
666
|
-
for (const level of levels) {
|
|
667
|
-
allNodes.push(...level);
|
|
668
|
-
}
|
|
669
|
-
for (const nodeId of allNodes) {
|
|
670
|
-
const deps = dependencies.get(nodeId) || [];
|
|
671
|
-
if (deps.length === 0) {
|
|
672
|
-
longestPath.set(nodeId, { length: 1, path: [nodeId] });
|
|
673
|
-
} else {
|
|
674
|
-
let maxLength2 = 0;
|
|
675
|
-
let maxPath = [];
|
|
676
|
-
for (const dep of deps) {
|
|
677
|
-
const depInfo = longestPath.get(dep);
|
|
678
|
-
if (depInfo && depInfo.length > maxLength2) {
|
|
679
|
-
maxLength2 = depInfo.length;
|
|
680
|
-
maxPath = depInfo.path;
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
longestPath.set(nodeId, {
|
|
684
|
-
length: maxLength2 + 1,
|
|
685
|
-
path: [...maxPath, nodeId]
|
|
686
|
-
});
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
let maxLength = 0;
|
|
690
|
-
let criticalPath = [];
|
|
691
|
-
for (const [, info] of longestPath.entries()) {
|
|
692
|
-
if (info.length > maxLength) {
|
|
693
|
-
maxLength = info.length;
|
|
694
|
-
criticalPath = info.path;
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
return criticalPath;
|
|
698
|
-
}
|
|
699
|
-
getTopologicalOrder() {
|
|
700
|
-
const dependencies = this.buildDependenciesMap();
|
|
701
|
-
const dependents = this.buildDependentsMap(dependencies);
|
|
702
|
-
const inDegree = new Map;
|
|
703
|
-
for (const nodeId of dependencies.keys()) {
|
|
704
|
-
inDegree.set(nodeId, dependencies.get(nodeId)?.length || 0);
|
|
705
|
-
}
|
|
706
|
-
const queue = [];
|
|
707
|
-
for (const [nodeId, degree] of inDegree.entries()) {
|
|
708
|
-
if (degree === 0) {
|
|
709
|
-
queue.push(nodeId);
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
const result = [];
|
|
713
|
-
while (queue.length > 0) {
|
|
714
|
-
const nodeId = queue.shift();
|
|
715
|
-
result.push(nodeId);
|
|
716
|
-
const nodeDependents = dependents.get(nodeId) || [];
|
|
717
|
-
for (const dependent of nodeDependents) {
|
|
718
|
-
const currentDegree = inDegree.get(dependent) || 0;
|
|
719
|
-
inDegree.set(dependent, currentDegree - 1);
|
|
720
|
-
if (currentDegree - 1 === 0) {
|
|
721
|
-
queue.push(dependent);
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
return result;
|
|
726
|
-
}
|
|
727
|
-
getReadyNodes(completedNodes) {
|
|
728
|
-
const dependencies = this.buildDependenciesMap();
|
|
729
|
-
const ready = [];
|
|
730
|
-
for (const nodeId of dependencies.keys()) {
|
|
731
|
-
if (completedNodes.has(nodeId)) {
|
|
732
|
-
continue;
|
|
733
|
-
}
|
|
734
|
-
if (this.areDependenciesMet(nodeId, completedNodes)) {
|
|
735
|
-
ready.push(nodeId);
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
return ready;
|
|
739
|
-
}
|
|
740
|
-
areDependenciesMet(nodeId, completedNodes) {
|
|
741
|
-
const node = this.nodeMap.get(nodeId);
|
|
742
|
-
if (!node) {
|
|
743
|
-
return false;
|
|
744
|
-
}
|
|
745
|
-
const dependencies = node.depends_on || [];
|
|
746
|
-
for (const dep of dependencies) {
|
|
747
|
-
if (!completedNodes.has(dep)) {
|
|
748
|
-
return false;
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
return true;
|
|
752
|
-
}
|
|
753
|
-
isCyclic() {
|
|
754
|
-
const dependencies = this.buildDependenciesMap();
|
|
755
|
-
const order = this.getTopologicalOrderInternal(dependencies);
|
|
756
|
-
return order.length !== this.workflow.nodes.length;
|
|
757
|
-
}
|
|
758
|
-
getTopologicalOrderInternal(dependencies) {
|
|
759
|
-
const dependents = this.buildDependentsMap(dependencies);
|
|
760
|
-
const inDegree = new Map;
|
|
761
|
-
for (const nodeId of dependencies.keys()) {
|
|
762
|
-
inDegree.set(nodeId, dependencies.get(nodeId)?.length || 0);
|
|
763
|
-
}
|
|
764
|
-
const queue = [];
|
|
765
|
-
for (const [nodeId, degree] of inDegree.entries()) {
|
|
766
|
-
if (degree === 0) {
|
|
767
|
-
queue.push(nodeId);
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
const result = [];
|
|
771
|
-
while (queue.length > 0) {
|
|
772
|
-
const nodeId = queue.shift();
|
|
773
|
-
result.push(nodeId);
|
|
774
|
-
const nodeDependents = dependents.get(nodeId) || [];
|
|
775
|
-
for (const dependent of nodeDependents) {
|
|
776
|
-
const currentDegree = inDegree.get(dependent) || 0;
|
|
777
|
-
inDegree.set(dependent, currentDegree - 1);
|
|
778
|
-
if (currentDegree - 1 === 0) {
|
|
779
|
-
queue.push(dependent);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
return result;
|
|
784
|
-
}
|
|
785
|
-
validate() {
|
|
786
|
-
const errors = [];
|
|
787
|
-
const nodeIds = new Set;
|
|
788
|
-
for (const node of this.workflow.nodes) {
|
|
789
|
-
if (node.id === "") {
|
|
790
|
-
errors.push("Node ID cannot be empty");
|
|
791
|
-
continue;
|
|
792
|
-
}
|
|
793
|
-
if (nodeIds.has(node.id)) {
|
|
794
|
-
errors.push(`Duplicate node ID: ${node.id}`);
|
|
795
|
-
}
|
|
796
|
-
nodeIds.add(node.id);
|
|
797
|
-
}
|
|
798
|
-
for (const node of this.workflow.nodes) {
|
|
799
|
-
const deps = node.depends_on || [];
|
|
800
|
-
for (const dep of deps) {
|
|
801
|
-
if (!nodeIds.has(dep)) {
|
|
802
|
-
errors.push(`Node '${node.id}' depends on non-existent node '${dep}'`);
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
if (this.isCyclic()) {
|
|
807
|
-
errors.push("Workflow contains a cycle");
|
|
808
|
-
}
|
|
809
|
-
return {
|
|
810
|
-
valid: errors.length === 0,
|
|
811
|
-
errors
|
|
812
|
-
};
|
|
813
|
-
}
|
|
814
|
-
addNode(node) {
|
|
815
|
-
if (!node.id || node.id.trim() === "") {
|
|
816
|
-
throw new Error("Node ID cannot be empty");
|
|
817
|
-
}
|
|
818
|
-
if (this.nodeMap.has(node.id)) {
|
|
819
|
-
throw new Error(`Node with ID '${node.id}' already exists`);
|
|
820
|
-
}
|
|
821
|
-
const deps = node.depends_on || [];
|
|
822
|
-
for (const dep of deps) {
|
|
823
|
-
if (!this.nodeMap.has(dep)) {
|
|
824
|
-
throw new Error(`Cannot add node '${node.id}': depends on non-existent node '${dep}'`);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
const originalNodes = [...this.workflow.nodes];
|
|
828
|
-
this.workflow.nodes.push(node);
|
|
829
|
-
if (this.isCyclic()) {
|
|
830
|
-
this.workflow.nodes = originalNodes;
|
|
831
|
-
throw new Error(`Cannot add node '${node.id}': would create a cycle in the workflow`);
|
|
832
|
-
}
|
|
833
|
-
this.nodeMap.set(node.id, node);
|
|
834
|
-
this.cachedAnalysis = null;
|
|
835
|
-
this.extendedDefinition = null;
|
|
836
|
-
}
|
|
837
|
-
removeNode(nodeId) {
|
|
838
|
-
if (!this.nodeMap.has(nodeId)) {
|
|
839
|
-
throw new Error(`Node '${nodeId}' does not exist`);
|
|
840
|
-
}
|
|
841
|
-
const dependents = this.getDependents(nodeId);
|
|
842
|
-
if (dependents.length > 0) {
|
|
843
|
-
throw new Error(`Cannot remove node '${nodeId}': other nodes depend on it: ${dependents.join(", ")}`);
|
|
844
|
-
}
|
|
845
|
-
this.workflow.nodes = this.workflow.nodes.filter((n) => n.id !== nodeId);
|
|
846
|
-
this.nodeMap.delete(nodeId);
|
|
847
|
-
this.cachedAnalysis = null;
|
|
848
|
-
this.extendedDefinition = null;
|
|
849
|
-
}
|
|
850
|
-
getDependents(nodeId) {
|
|
851
|
-
const analysis = this.analyze();
|
|
852
|
-
return analysis.dependents.get(nodeId) || [];
|
|
853
|
-
}
|
|
854
|
-
getDefinition() {
|
|
855
|
-
return this.workflow;
|
|
856
|
-
}
|
|
857
|
-
getNode(nodeId) {
|
|
858
|
-
return this.nodeMap.get(nodeId);
|
|
859
|
-
}
|
|
860
|
-
getNodeIds() {
|
|
861
|
-
return Array.from(this.nodeMap.keys());
|
|
862
|
-
}
|
|
863
|
-
getNodeCount() {
|
|
864
|
-
return this.nodeMap.size;
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
// packages/core/src/env/workflow/engine/scheduler.ts
|
|
869
|
-
class Scheduler {
|
|
870
|
-
dagManager;
|
|
871
|
-
options;
|
|
872
|
-
pending = new Set;
|
|
873
|
-
ready = new Set;
|
|
874
|
-
running = new Set;
|
|
875
|
-
completed = new Set;
|
|
876
|
-
failed = new Set;
|
|
877
|
-
skipped = new Set;
|
|
878
|
-
constructor(dagManager, options) {
|
|
879
|
-
this.dagManager = dagManager;
|
|
880
|
-
const parallelLimit = options?.parallelLimit;
|
|
881
|
-
this.options = {
|
|
882
|
-
parallelLimit: parallelLimit === undefined ? 1 : parallelLimit
|
|
883
|
-
};
|
|
884
|
-
const analysis = dagManager.analyze();
|
|
885
|
-
for (const nodeId of analysis.dependencies.keys()) {
|
|
886
|
-
this.pending.add(nodeId);
|
|
887
|
-
}
|
|
888
|
-
this.updateReadyNodes(new Set);
|
|
889
|
-
}
|
|
890
|
-
getReadyNodes(completedNodes) {
|
|
891
|
-
const allCompleted = new Set(completedNodes);
|
|
892
|
-
for (const nodeId of this.completed) {
|
|
893
|
-
allCompleted.add(nodeId);
|
|
894
|
-
}
|
|
895
|
-
const readyFromDag = this.dagManager.getReadyNodes(allCompleted);
|
|
896
|
-
const ready = [];
|
|
897
|
-
for (const nodeId of readyFromDag) {
|
|
898
|
-
const isProcessed = this.running.has(nodeId) || this.completed.has(nodeId) || this.failed.has(nodeId) || this.skipped.has(nodeId);
|
|
899
|
-
if (!isProcessed) {
|
|
900
|
-
ready.push(nodeId);
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
return ready.sort();
|
|
904
|
-
}
|
|
905
|
-
getRunningCount() {
|
|
906
|
-
return this.running.size;
|
|
907
|
-
}
|
|
908
|
-
canStartMore() {
|
|
909
|
-
if (this.options.parallelLimit === null) {
|
|
910
|
-
return true;
|
|
911
|
-
}
|
|
912
|
-
if (this.options.parallelLimit <= 0) {
|
|
913
|
-
return false;
|
|
914
|
-
}
|
|
915
|
-
return this.running.size < this.options.parallelLimit;
|
|
916
|
-
}
|
|
917
|
-
markStarted(nodeId) {
|
|
918
|
-
if (!this.running.has(nodeId)) {
|
|
919
|
-
this.running.add(nodeId);
|
|
920
|
-
this.ready.delete(nodeId);
|
|
921
|
-
this.pending.delete(nodeId);
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
isRunning(nodeId) {
|
|
925
|
-
return this.running.has(nodeId);
|
|
926
|
-
}
|
|
927
|
-
isCompleted(nodeId) {
|
|
928
|
-
return this.completed.has(nodeId);
|
|
929
|
-
}
|
|
930
|
-
isFailed(nodeId) {
|
|
931
|
-
return this.failed.has(nodeId);
|
|
932
|
-
}
|
|
933
|
-
isPending(nodeId) {
|
|
934
|
-
return this.pending.has(nodeId);
|
|
935
|
-
}
|
|
936
|
-
isReady(nodeId) {
|
|
937
|
-
return this.ready.has(nodeId);
|
|
938
|
-
}
|
|
939
|
-
markCompleted(nodeId) {
|
|
940
|
-
this.running.delete(nodeId);
|
|
941
|
-
this.ready.delete(nodeId);
|
|
942
|
-
this.pending.delete(nodeId);
|
|
943
|
-
this.failed.delete(nodeId);
|
|
944
|
-
this.skipped.delete(nodeId);
|
|
945
|
-
this.completed.add(nodeId);
|
|
946
|
-
}
|
|
947
|
-
markFailed(nodeId) {
|
|
948
|
-
this.running.delete(nodeId);
|
|
949
|
-
this.ready.delete(nodeId);
|
|
950
|
-
this.pending.delete(nodeId);
|
|
951
|
-
this.completed.delete(nodeId);
|
|
952
|
-
this.skipped.delete(nodeId);
|
|
953
|
-
this.failed.add(nodeId);
|
|
954
|
-
}
|
|
955
|
-
markSkipped(nodeId) {
|
|
956
|
-
if (this.running.has(nodeId)) {
|
|
957
|
-
this.running.delete(nodeId);
|
|
958
|
-
}
|
|
959
|
-
if (this.ready.has(nodeId)) {
|
|
960
|
-
this.ready.delete(nodeId);
|
|
961
|
-
}
|
|
962
|
-
if (this.pending.has(nodeId)) {
|
|
963
|
-
this.pending.delete(nodeId);
|
|
964
|
-
}
|
|
965
|
-
this.skipped.add(nodeId);
|
|
966
|
-
}
|
|
967
|
-
reset() {
|
|
968
|
-
this.running.clear();
|
|
969
|
-
this.completed.clear();
|
|
970
|
-
this.failed.clear();
|
|
971
|
-
this.skipped.clear();
|
|
972
|
-
const analysis = this.dagManager.analyze();
|
|
973
|
-
this.pending.clear();
|
|
974
|
-
this.ready.clear();
|
|
975
|
-
for (const nodeId of analysis.dependencies.keys()) {
|
|
976
|
-
this.pending.add(nodeId);
|
|
977
|
-
}
|
|
978
|
-
this.updateReadyNodes(new Set);
|
|
979
|
-
}
|
|
980
|
-
getState() {
|
|
981
|
-
this.updateReadyNodes(new Set);
|
|
982
|
-
return {
|
|
983
|
-
pending: Array.from(this.pending).sort(),
|
|
984
|
-
ready: Array.from(this.ready).sort(),
|
|
985
|
-
running: Array.from(this.running).sort(),
|
|
986
|
-
completed: Array.from(this.completed).sort(),
|
|
987
|
-
failed: Array.from(this.failed).sort(),
|
|
988
|
-
skipped: Array.from(this.skipped).sort()
|
|
989
|
-
};
|
|
990
|
-
}
|
|
991
|
-
updateReadyNodes(completedNodes) {
|
|
992
|
-
const allCompleted = new Set(completedNodes);
|
|
993
|
-
for (const nodeId of this.completed) {
|
|
994
|
-
allCompleted.add(nodeId);
|
|
995
|
-
}
|
|
996
|
-
const analysis = this.dagManager.analyze();
|
|
997
|
-
const allNodeIds = Array.from(analysis.dependencies.keys());
|
|
998
|
-
this.ready.clear();
|
|
999
|
-
for (const nodeId of allNodeIds) {
|
|
1000
|
-
if (this.running.has(nodeId) || this.completed.has(nodeId) || this.failed.has(nodeId) || this.skipped.has(nodeId)) {
|
|
1001
|
-
continue;
|
|
1002
|
-
}
|
|
1003
|
-
if (this.dagManager.areDependenciesMet(nodeId, allCompleted)) {
|
|
1004
|
-
this.ready.add(nodeId);
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
getParallelLimit() {
|
|
1009
|
-
return this.options.parallelLimit;
|
|
1010
|
-
}
|
|
1011
|
-
setParallelLimit(limit) {
|
|
1012
|
-
this.options.parallelLimit = limit;
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
// packages/core/src/env/log-trace/span-storage.ts
|
|
1017
|
-
var exports_span_storage = {};
|
|
1018
|
-
__export(exports_span_storage, {
|
|
1019
|
-
SQLiteSpanStorage: () => SQLiteSpanStorage
|
|
1020
|
-
});
|
|
1021
|
-
|
|
1022
|
-
class SQLiteSpanStorage {
|
|
1023
|
-
db = null;
|
|
1024
|
-
dbPath;
|
|
1025
|
-
initialized = false;
|
|
1026
|
-
constructor(dbPath) {
|
|
1027
|
-
if (!dbPath) {
|
|
1028
|
-
throw new Error("SQLiteSpanStorage requires a valid dbPath parameter");
|
|
1029
|
-
}
|
|
1030
|
-
if (dbPath === ":memory:") {
|
|
1031
|
-
throw new Error("SQLiteSpanStorage does not support :memory: mode. Use a file path instead.");
|
|
1032
|
-
}
|
|
1033
|
-
this.dbPath = dbPath;
|
|
1034
|
-
}
|
|
1035
|
-
async initialize() {
|
|
1036
|
-
if (this.initialized)
|
|
1037
|
-
return;
|
|
1038
|
-
const { Database } = __require("bun:sqlite");
|
|
1039
|
-
const fs = __require("fs");
|
|
1040
|
-
const path = __require("path");
|
|
1041
|
-
const dir = path.dirname(this.dbPath);
|
|
1042
|
-
if (!fs.existsSync(dir)) {
|
|
1043
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
1044
|
-
}
|
|
1045
|
-
this.db = new Database(this.dbPath);
|
|
1046
|
-
this.db.run("PRAGMA journal_mode=WAL");
|
|
1047
|
-
this.db.run("PRAGMA busy_timeout=5000");
|
|
1048
|
-
this.db.run("PRAGMA synchronous=NORMAL");
|
|
1049
|
-
this.db.run(`
|
|
1050
|
-
CREATE TABLE IF NOT EXISTS span (
|
|
1051
|
-
span_id TEXT PRIMARY KEY,
|
|
1052
|
-
trace_id TEXT NOT NULL,
|
|
1053
|
-
parent_span_id TEXT,
|
|
1054
|
-
name TEXT NOT NULL,
|
|
1055
|
-
kind TEXT NOT NULL,
|
|
1056
|
-
status TEXT NOT NULL,
|
|
1057
|
-
start_time INTEGER NOT NULL,
|
|
1058
|
-
end_time INTEGER,
|
|
1059
|
-
attributes TEXT,
|
|
1060
|
-
result TEXT,
|
|
1061
|
-
error TEXT,
|
|
1062
|
-
time_created INTEGER NOT NULL
|
|
1063
|
-
)
|
|
1064
|
-
`);
|
|
1065
|
-
this.db.run("CREATE INDEX IF NOT EXISTS idx_span_trace ON span(trace_id)");
|
|
1066
|
-
this.db.run("CREATE INDEX IF NOT EXISTS idx_span_parent ON span(parent_span_id)");
|
|
1067
|
-
this.initialized = true;
|
|
1068
|
-
}
|
|
1069
|
-
save(span) {
|
|
1070
|
-
if (!this.db)
|
|
1071
|
-
return;
|
|
1072
|
-
const stmt = this.db.prepare(`
|
|
1073
|
-
INSERT OR REPLACE INTO span
|
|
1074
|
-
(span_id, trace_id, parent_span_id, name, kind, status, start_time, end_time, attributes, result, error, time_created)
|
|
1075
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1076
|
-
`);
|
|
1077
|
-
const resultValue = span.result !== undefined && span.result !== null ? typeof span.result === "string" ? span.result : JSON.stringify(span.result) : null;
|
|
1078
|
-
stmt.run(span.spanId, span.traceId, span.parentSpanId || null, span.name, span.kind, span.status, span.startTime, span.endTime || null, JSON.stringify(span.attributes), resultValue, span.error || null, Date.now());
|
|
1079
|
-
}
|
|
1080
|
-
saveBatch(spans) {
|
|
1081
|
-
for (const span of spans) {
|
|
1082
|
-
this.save(span);
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
findByTraceId(traceId) {
|
|
1086
|
-
if (!this.db)
|
|
1087
|
-
return [];
|
|
1088
|
-
const rows = this.db.prepare("SELECT * FROM span WHERE trace_id = ?").all(traceId);
|
|
1089
|
-
return this.buildTree(rows.map(this.rowToSpan));
|
|
1090
|
-
}
|
|
1091
|
-
findBySpanId(spanId) {
|
|
1092
|
-
if (!this.db)
|
|
1093
|
-
return;
|
|
1094
|
-
const row = this.db.prepare("SELECT * FROM span WHERE span_id = ?").get(spanId);
|
|
1095
|
-
return row ? this.rowToSpan(row) : undefined;
|
|
1096
|
-
}
|
|
1097
|
-
listTraces(limit = 10) {
|
|
1098
|
-
if (!this.db)
|
|
1099
|
-
return [];
|
|
1100
|
-
const rows = this.db.prepare(`
|
|
1101
|
-
SELECT trace_id,
|
|
1102
|
-
MIN(start_time) as start_time,
|
|
1103
|
-
MAX(end_time) as end_time,
|
|
1104
|
-
COUNT(*) as span_count
|
|
1105
|
-
FROM span
|
|
1106
|
-
GROUP BY trace_id
|
|
1107
|
-
ORDER BY start_time DESC
|
|
1108
|
-
LIMIT ?
|
|
1109
|
-
`).all(limit);
|
|
1110
|
-
return rows.map((row) => ({
|
|
1111
|
-
traceId: row.trace_id,
|
|
1112
|
-
rootSpanName: "unknown",
|
|
1113
|
-
startTime: row.start_time,
|
|
1114
|
-
endTime: row.end_time,
|
|
1115
|
-
duration: row.end_time - row.start_time,
|
|
1116
|
-
spanCount: row.span_count,
|
|
1117
|
-
status: "ok"
|
|
1118
|
-
}));
|
|
1119
|
-
}
|
|
1120
|
-
deleteByTraceId(traceId) {
|
|
1121
|
-
if (this.db) {
|
|
1122
|
-
this.db.prepare("DELETE FROM span WHERE trace_id = ?").run(traceId);
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
close() {
|
|
1126
|
-
if (this.db) {
|
|
1127
|
-
this.db.close();
|
|
1128
|
-
this.db = null;
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
rowToSpan(row) {
|
|
1132
|
-
return {
|
|
1133
|
-
traceId: row.trace_id,
|
|
1134
|
-
spanId: row.span_id,
|
|
1135
|
-
parentSpanId: row.parent_span_id,
|
|
1136
|
-
name: row.name,
|
|
1137
|
-
kind: row.kind,
|
|
1138
|
-
status: row.status,
|
|
1139
|
-
startTime: row.start_time,
|
|
1140
|
-
endTime: row.end_time,
|
|
1141
|
-
attributes: row.attributes ? JSON.parse(row.attributes) : {},
|
|
1142
|
-
result: row.result || undefined,
|
|
1143
|
-
error: row.error || undefined
|
|
1144
|
-
};
|
|
1145
|
-
}
|
|
1146
|
-
buildTree(spans) {
|
|
1147
|
-
const spanMap = new Map;
|
|
1148
|
-
const roots = [];
|
|
1149
|
-
for (const span of spans) {
|
|
1150
|
-
spanMap.set(span.spanId, { ...span, children: [] });
|
|
1151
|
-
}
|
|
1152
|
-
for (const span of spanMap.values()) {
|
|
1153
|
-
if (span.parentSpanId) {
|
|
1154
|
-
const parent = spanMap.get(span.parentSpanId);
|
|
1155
|
-
if (parent) {
|
|
1156
|
-
parent.children.push(span);
|
|
1157
|
-
} else {
|
|
1158
|
-
roots.push(span);
|
|
1159
|
-
}
|
|
1160
|
-
} else {
|
|
1161
|
-
roots.push(span);
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
return roots;
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
// packages/core/src/env/log-trace/opentelemetry/propagation.ts
|
|
1169
|
-
function padLeft(str, length) {
|
|
1170
|
-
return str.padStart(length, "0");
|
|
1171
|
-
}
|
|
1172
|
-
function isValidHex(str) {
|
|
1173
|
-
return /^[0-9a-f]+$/i.test(str);
|
|
1174
|
-
}
|
|
1175
|
-
function serialize(context2) {
|
|
1176
|
-
const traceId = padLeft(context2.traceId.toLowerCase(), TRACE_ID_LENGTH);
|
|
1177
|
-
const spanId = padLeft(context2.spanId.toLowerCase(), PARENT_SPAN_ID_LENGTH);
|
|
1178
|
-
const parts = [
|
|
1179
|
-
TRACE_CONTEXT_VERSION,
|
|
1180
|
-
traceId,
|
|
1181
|
-
spanId,
|
|
1182
|
-
TRACE_FLAGS_SAMPLED
|
|
1183
|
-
];
|
|
1184
|
-
return parts.join("-");
|
|
1185
|
-
}
|
|
1186
|
-
function parse(traceparent) {
|
|
1187
|
-
if (!traceparent || typeof traceparent !== "string") {
|
|
1188
|
-
return;
|
|
1189
|
-
}
|
|
1190
|
-
const trimmed = traceparent.trim();
|
|
1191
|
-
const parts = trimmed.split("-");
|
|
1192
|
-
if (parts.length !== 4) {
|
|
1193
|
-
return;
|
|
1194
|
-
}
|
|
1195
|
-
const [version, traceId, senderSpanId, flags] = parts;
|
|
1196
|
-
if (version !== TRACE_CONTEXT_VERSION) {
|
|
1197
|
-
if (version > TRACE_CONTEXT_VERSION) {
|
|
1198
|
-
return;
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
if (traceId.length !== TRACE_ID_LENGTH || !isValidHex(traceId)) {
|
|
1202
|
-
return;
|
|
1203
|
-
}
|
|
1204
|
-
if (senderSpanId.length !== PARENT_SPAN_ID_LENGTH || !isValidHex(senderSpanId)) {
|
|
1205
|
-
return;
|
|
1206
|
-
}
|
|
1207
|
-
if (flags.length !== FLAGS_LENGTH || !isValidHex(flags)) {
|
|
1208
|
-
return;
|
|
1209
|
-
}
|
|
1210
|
-
return {
|
|
1211
|
-
traceId: traceId.toLowerCase(),
|
|
1212
|
-
spanId: senderSpanId.toLowerCase()
|
|
1213
|
-
};
|
|
1214
|
-
}
|
|
1215
|
-
var TRACE_CONTEXT_VERSION = "00", TRACE_FLAGS_SAMPLED = "01", TRACEPARENT_HEADER = "TRACEPARENT", TRACE_ID_LENGTH = 32, PARENT_SPAN_ID_LENGTH = 16, FLAGS_LENGTH = 2, propagation;
|
|
1216
|
-
var init_propagation = __esm(() => {
|
|
1217
|
-
propagation = {
|
|
1218
|
-
inject(carrier, context2) {
|
|
1219
|
-
carrier[TRACEPARENT_HEADER] = serialize(context2);
|
|
1220
|
-
},
|
|
1221
|
-
extract(carrier) {
|
|
1222
|
-
const traceparent = carrier[TRACEPARENT_HEADER];
|
|
1223
|
-
if (!traceparent) {
|
|
1224
|
-
return;
|
|
1225
|
-
}
|
|
1226
|
-
return parse(traceparent);
|
|
1227
|
-
},
|
|
1228
|
-
getTraceparentHeader() {
|
|
1229
|
-
return TRACEPARENT_HEADER;
|
|
1230
|
-
}
|
|
1231
|
-
};
|
|
1232
|
-
});
|
|
1233
|
-
|
|
1234
|
-
// packages/core/src/env/log-trace/types.ts
|
|
1235
|
-
var SpanKind, SpanStatus;
|
|
1236
|
-
var init_types2 = __esm(() => {
|
|
1237
|
-
((SpanKind2) => {
|
|
1238
|
-
SpanKind2["CLIENT"] = "client";
|
|
1239
|
-
SpanKind2["SERVER"] = "server";
|
|
1240
|
-
SpanKind2["INTERNAL"] = "internal";
|
|
1241
|
-
})(SpanKind ||= {});
|
|
1242
|
-
((SpanStatus2) => {
|
|
1243
|
-
SpanStatus2["OK"] = "ok";
|
|
1244
|
-
SpanStatus2["ERROR"] = "error";
|
|
1245
|
-
})(SpanStatus ||= {});
|
|
1246
|
-
});
|
|
1247
|
-
|
|
1248
|
-
// packages/core/src/env/log-trace/opentelemetry/tracer-provider.ts
|
|
1249
|
-
var exports_tracer_provider = {};
|
|
1250
|
-
__export(exports_tracer_provider, {
|
|
1251
|
-
resetTracerProvider: () => resetTracerProvider,
|
|
1252
|
-
getTracerProvider: () => getTracerProvider,
|
|
1253
|
-
OTelTracerProvider: () => OTelTracerProvider
|
|
1254
|
-
});
|
|
1255
|
-
|
|
1256
|
-
class OTelSpanImpl {
|
|
1257
|
-
name;
|
|
1258
|
-
kind;
|
|
1259
|
-
spanContext;
|
|
1260
|
-
attributes = {};
|
|
1261
|
-
startTime;
|
|
1262
|
-
endTime;
|
|
1263
|
-
error;
|
|
1264
|
-
storage;
|
|
1265
|
-
parentSpanContext;
|
|
1266
|
-
onEnd;
|
|
1267
|
-
constructor(name, spanContext, storage, parentSpanContext, onEnd) {
|
|
1268
|
-
this.name = name;
|
|
1269
|
-
this.kind = "internal";
|
|
1270
|
-
this.spanContext = spanContext;
|
|
1271
|
-
this.parentSpanContext = parentSpanContext;
|
|
1272
|
-
this.startTime = Date.now();
|
|
1273
|
-
this.storage = storage;
|
|
1274
|
-
this.onEnd = onEnd;
|
|
1275
|
-
}
|
|
1276
|
-
setAttribute(key, value) {
|
|
1277
|
-
this.attributes[key] = value;
|
|
1278
|
-
}
|
|
1279
|
-
addEvent(name, attributes) {
|
|
1280
|
-
const events = this.attributes._events || [];
|
|
1281
|
-
events.push({ name, attributes });
|
|
1282
|
-
this.attributes._events = events;
|
|
1283
|
-
}
|
|
1284
|
-
end(result, error) {
|
|
1285
|
-
this.endTime = Date.now();
|
|
1286
|
-
if (error) {
|
|
1287
|
-
this.error = error.message;
|
|
1288
|
-
}
|
|
1289
|
-
this.storage.save({
|
|
1290
|
-
traceId: this.spanContext.traceId,
|
|
1291
|
-
spanId: this.spanContext.spanId,
|
|
1292
|
-
parentSpanId: this.spanContext.parentSpanId,
|
|
1293
|
-
name: this.name,
|
|
1294
|
-
kind: this.kind,
|
|
1295
|
-
status: error ? "error" /* ERROR */ : "ok" /* OK */,
|
|
1296
|
-
startTime: this.startTime,
|
|
1297
|
-
endTime: this.endTime,
|
|
1298
|
-
attributes: this.attributes,
|
|
1299
|
-
result,
|
|
1300
|
-
error: this.error
|
|
1301
|
-
});
|
|
1302
|
-
this.onEnd?.();
|
|
1303
|
-
}
|
|
1304
|
-
}
|
|
1305
|
-
|
|
1306
|
-
class OTelTracerImpl {
|
|
1307
|
-
name;
|
|
1308
|
-
version;
|
|
1309
|
-
storage;
|
|
1310
|
-
currentContext;
|
|
1311
|
-
activeSpans = new Map;
|
|
1312
|
-
onSpanEndCallback;
|
|
1313
|
-
provider;
|
|
1314
|
-
constructor(name, version, storage, provider) {
|
|
1315
|
-
this.name = name;
|
|
1316
|
-
this.version = version;
|
|
1317
|
-
this.storage = storage;
|
|
1318
|
-
this.provider = provider;
|
|
1319
|
-
}
|
|
1320
|
-
setOnSpanEndCallback(callback) {
|
|
1321
|
-
this.onSpanEndCallback = callback;
|
|
1322
|
-
}
|
|
1323
|
-
getActiveSpanCount() {
|
|
1324
|
-
return this.activeSpans.size;
|
|
1325
|
-
}
|
|
1326
|
-
startSpan(name, options) {
|
|
1327
|
-
const parentFromOptions = options?.parent;
|
|
1328
|
-
const hasExplicitParent = options && "parent" in options;
|
|
1329
|
-
const globalContext = this.provider.getGlobalContext();
|
|
1330
|
-
let effectiveParentContext;
|
|
1331
|
-
if (hasExplicitParent) {
|
|
1332
|
-
effectiveParentContext = parentFromOptions;
|
|
1333
|
-
} else if (this.currentContext) {
|
|
1334
|
-
effectiveParentContext = this.currentContext;
|
|
1335
|
-
} else if (globalContext) {
|
|
1336
|
-
effectiveParentContext = globalContext;
|
|
1337
|
-
}
|
|
1338
|
-
const traceId = effectiveParentContext?.traceId || this.generateTraceId();
|
|
1339
|
-
const spanId = this.generateSpanId();
|
|
1340
|
-
let parentSpanId;
|
|
1341
|
-
if (hasExplicitParent && parentFromOptions) {
|
|
1342
|
-
parentSpanId = parentFromOptions.parentSpanId || parentFromOptions.spanId;
|
|
1343
|
-
} else if (this.currentContext) {
|
|
1344
|
-
parentSpanId = this.currentContext.spanId;
|
|
1345
|
-
} else if (globalContext) {
|
|
1346
|
-
parentSpanId = globalContext.spanId;
|
|
1347
|
-
}
|
|
1348
|
-
const spanContext = {
|
|
1349
|
-
traceId,
|
|
1350
|
-
spanId,
|
|
1351
|
-
parentSpanId
|
|
1352
|
-
};
|
|
1353
|
-
this.currentContext = {
|
|
1354
|
-
traceId,
|
|
1355
|
-
spanId,
|
|
1356
|
-
parentSpanId
|
|
1357
|
-
};
|
|
1358
|
-
const span = new OTelSpanImpl(name, spanContext, this.storage, effectiveParentContext, () => this.handleSpanEnd(spanContext.spanId, effectiveParentContext?.spanId));
|
|
1359
|
-
if (options?.attributes) {
|
|
1360
|
-
for (const [key, value] of Object.entries(options.attributes)) {
|
|
1361
|
-
span.setAttribute(key, value);
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
this.activeSpans.set(spanId, span);
|
|
1365
|
-
return span;
|
|
1366
|
-
}
|
|
1367
|
-
injectToEnv(env) {
|
|
1368
|
-
if (this.currentContext) {
|
|
1369
|
-
propagation.inject(env, this.currentContext);
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1372
|
-
getCurrentContext() {
|
|
1373
|
-
return this.currentContext;
|
|
1374
|
-
}
|
|
1375
|
-
setCurrentContext(context2) {
|
|
1376
|
-
this.currentContext = context2;
|
|
1377
|
-
}
|
|
1378
|
-
endSpan(span) {
|
|
1379
|
-
const spanContext = span.spanContext;
|
|
1380
|
-
this.activeSpans.delete(spanContext.spanId);
|
|
1381
|
-
const currentTraceId = this.currentContext?.traceId;
|
|
1382
|
-
if (spanContext.parentSpanId) {
|
|
1383
|
-
const parentSpan = this.activeSpans.get(spanContext.parentSpanId);
|
|
1384
|
-
if (parentSpan) {
|
|
1385
|
-
const parentContext = {
|
|
1386
|
-
traceId: spanContext.traceId,
|
|
1387
|
-
spanId: parentSpan.spanContext.spanId,
|
|
1388
|
-
parentSpanId: parentSpan.spanContext.parentSpanId
|
|
1389
|
-
};
|
|
1390
|
-
this.currentContext = parentContext;
|
|
1391
|
-
return parentContext;
|
|
1392
|
-
}
|
|
1393
|
-
if (currentTraceId) {
|
|
1394
|
-
const parentContext = {
|
|
1395
|
-
traceId: currentTraceId,
|
|
1396
|
-
spanId: spanContext.parentSpanId,
|
|
1397
|
-
parentSpanId: undefined
|
|
1398
|
-
};
|
|
1399
|
-
this.currentContext = parentContext;
|
|
1400
|
-
return parentContext;
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
this.currentContext = undefined;
|
|
1404
|
-
return;
|
|
1405
|
-
}
|
|
1406
|
-
generateTraceId() {
|
|
1407
|
-
const timestamp = Date.now().toString(16).padStart(12, "0");
|
|
1408
|
-
const random = Array.from({ length: 5 }, () => Math.floor(Math.random() * 4294967295).toString(16).padStart(8, "0")).join("");
|
|
1409
|
-
return (timestamp + random).slice(0, 32).padStart(32, "0");
|
|
1410
|
-
}
|
|
1411
|
-
generateSpanId() {
|
|
1412
|
-
return Math.floor(Math.random() * 18446744073709552000).toString(16).padStart(16, "0");
|
|
1413
|
-
}
|
|
1414
|
-
handleSpanEnd(spanId, parentSpanId) {
|
|
1415
|
-
this.activeSpans.delete(spanId);
|
|
1416
|
-
const currentTraceId = this.currentContext?.traceId;
|
|
1417
|
-
if (parentSpanId) {
|
|
1418
|
-
const parentSpan = this.activeSpans.get(parentSpanId);
|
|
1419
|
-
if (parentSpan) {
|
|
1420
|
-
this.currentContext = {
|
|
1421
|
-
traceId: parentSpan.spanContext.traceId,
|
|
1422
|
-
spanId: parentSpan.spanContext.spanId,
|
|
1423
|
-
parentSpanId: parentSpan.spanContext.parentSpanId
|
|
1424
|
-
};
|
|
1425
|
-
return;
|
|
1426
|
-
}
|
|
1427
|
-
if (currentTraceId) {
|
|
1428
|
-
this.currentContext = {
|
|
1429
|
-
traceId: currentTraceId,
|
|
1430
|
-
spanId: parentSpanId,
|
|
1431
|
-
parentSpanId: undefined
|
|
1432
|
-
};
|
|
1433
|
-
return;
|
|
1434
|
-
}
|
|
1435
|
-
}
|
|
1436
|
-
this.currentContext = undefined;
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
|
|
1440
|
-
class OTelTracerProvider {
|
|
1441
|
-
tracers = new Map;
|
|
1442
|
-
storage;
|
|
1443
|
-
initialized = false;
|
|
1444
|
-
globalContext;
|
|
1445
|
-
constructor(storage, dbPath) {
|
|
1446
|
-
this.storage = storage || new SQLiteSpanStorage(dbPath || getDefaultDbPath());
|
|
1447
|
-
}
|
|
1448
|
-
async initialize() {
|
|
1449
|
-
if (this.initialized)
|
|
1450
|
-
return;
|
|
1451
|
-
await this.storage.initialize();
|
|
1452
|
-
this.initialized = true;
|
|
1453
|
-
}
|
|
1454
|
-
isInitialized() {
|
|
1455
|
-
return this.initialized;
|
|
1456
|
-
}
|
|
1457
|
-
getGlobalContext() {
|
|
1458
|
-
return this.globalContext;
|
|
1459
|
-
}
|
|
1460
|
-
setGlobalContext(context2) {
|
|
1461
|
-
this.globalContext = context2;
|
|
1462
|
-
}
|
|
1463
|
-
getTracer(name, version) {
|
|
1464
|
-
const key = `${name}@${version || "0.0.0"}`;
|
|
1465
|
-
let tracer = this.tracers.get(key);
|
|
1466
|
-
if (!tracer) {
|
|
1467
|
-
tracer = new OTelTracerImpl(name, version, this.storage, this);
|
|
1468
|
-
this.tracers.set(key, tracer);
|
|
1469
|
-
if (this.initialized) {
|
|
1470
|
-
this.restoreFromEnv(tracer);
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
return tracer;
|
|
1474
|
-
}
|
|
1475
|
-
restoreFromEnv(tracer) {
|
|
1476
|
-
const extracted = propagation.extract(process.env);
|
|
1477
|
-
if (extracted) {
|
|
1478
|
-
tracer.setCurrentContext({
|
|
1479
|
-
traceId: extracted.traceId,
|
|
1480
|
-
spanId: extracted.spanId,
|
|
1481
|
-
parentSpanId: undefined
|
|
1482
|
-
});
|
|
1483
|
-
}
|
|
1484
|
-
}
|
|
1485
|
-
shutdown() {
|
|
1486
|
-
for (const tracer of this.tracers.values()) {}
|
|
1487
|
-
this.tracers.clear();
|
|
1488
|
-
this.storage.close();
|
|
1489
|
-
this.initialized = false;
|
|
1490
|
-
this.globalContext = undefined;
|
|
1491
|
-
delete process.env["TRACEPARENT"];
|
|
1492
|
-
delete process.env["TRACE_ID"];
|
|
1493
|
-
delete process.env["LOG_TRACE_REQUEST_ID"];
|
|
1494
|
-
}
|
|
1495
|
-
getStorage() {
|
|
1496
|
-
return this.storage;
|
|
1497
|
-
}
|
|
1498
|
-
}
|
|
1499
|
-
function getTracerProvider() {
|
|
1500
|
-
if (!providerInstance) {
|
|
1501
|
-
providerInstance = new OTelTracerProvider;
|
|
1502
|
-
}
|
|
1503
|
-
return providerInstance;
|
|
1504
|
-
}
|
|
1505
|
-
function resetTracerProvider() {
|
|
1506
|
-
if (providerInstance) {
|
|
1507
|
-
providerInstance.shutdown();
|
|
1508
|
-
providerInstance = null;
|
|
1509
|
-
}
|
|
1510
|
-
}
|
|
1511
|
-
function getDefaultDbPath() {
|
|
1512
|
-
const os = __require("os");
|
|
1513
|
-
const path = __require("path");
|
|
1514
|
-
const home = os.homedir();
|
|
1515
|
-
const dataHome = process.env.XDG_DATA_HOME || path.join(home, ".local", "share");
|
|
1516
|
-
return path.join(dataHome, "roy-agent", "traces.db");
|
|
1517
|
-
}
|
|
1518
|
-
var providerInstance = null;
|
|
1519
|
-
var init_tracer_provider = __esm(() => {
|
|
1520
|
-
init_propagation();
|
|
1521
|
-
init_types2();
|
|
1522
|
-
});
|
|
1523
|
-
|
|
1524
|
-
// packages/core/src/env/log-trace/logger.ts
|
|
1525
|
-
import { appendFileSync, existsSync, mkdirSync } from "fs";
|
|
1526
|
-
import { join } from "path";
|
|
1527
|
-
function simplifyFilePath(fullPath) {
|
|
1528
|
-
let path = fullPath.replace(/\\/g, "/");
|
|
1529
|
-
const bunfsMatch = path.match(/\/\$bunfs\/root\/(.+)$/);
|
|
1530
|
-
if (bunfsMatch) {
|
|
1531
|
-
const virtualPath = bunfsMatch[1];
|
|
1532
|
-
const packagesMatch = virtualPath.match(/(packages\/[^/]+\/src\/[^/]+\/.+)$/);
|
|
1533
|
-
if (packagesMatch) {
|
|
1534
|
-
return packagesMatch[1];
|
|
1535
|
-
}
|
|
1536
|
-
return virtualPath;
|
|
1537
|
-
}
|
|
1538
|
-
const fileProtocolMatch = path.match(/@roy-agent\+core@file\+([^/]+)\/node_modules\/@roy-agent\/core\/(.+)$/);
|
|
1539
|
-
if (fileProtocolMatch) {
|
|
1540
|
-
const rootPkg = fileProtocolMatch[1].replace(/\+/g, "/");
|
|
1541
|
-
const remaining = fileProtocolMatch[2];
|
|
1542
|
-
const prefix = rootPkg;
|
|
1543
|
-
const suffix = remaining.startsWith("src/") ? remaining : `src/${remaining}`;
|
|
1544
|
-
return `${prefix}/${suffix}`;
|
|
1545
|
-
}
|
|
1546
|
-
const packagesRootMatch = path.match(/(packages\/[^/]+\/src\/[^/]+\/.+)$/);
|
|
1547
|
-
if (packagesRootMatch) {
|
|
1548
|
-
return packagesRootMatch[1];
|
|
1549
|
-
}
|
|
1550
|
-
const rootMarkers = ["packages/core/src", "packages/core", "packages"];
|
|
1551
|
-
for (const marker of rootMarkers) {
|
|
1552
|
-
const idx = path.indexOf(marker);
|
|
1553
|
-
if (idx !== -1) {
|
|
1554
|
-
return path.substring(idx);
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
return path;
|
|
1558
|
-
}
|
|
1559
|
-
function getDefaultLogDir() {
|
|
1560
|
-
const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
|
|
1561
|
-
try {
|
|
1562
|
-
const xdg = __require("xdg-basedir");
|
|
1563
|
-
if (xdg.xdgData) {
|
|
1564
|
-
return join(xdg.xdgData, "roy-agent", "logs");
|
|
1565
|
-
}
|
|
1566
|
-
} catch {}
|
|
1567
|
-
return join(home, ".local", "share", "roy-agent", "logs");
|
|
1568
|
-
}
|
|
1569
|
-
function isQuietMode() {
|
|
1570
|
-
return quietMode;
|
|
1571
|
-
}
|
|
1572
|
-
function setQuietMode(enabled) {
|
|
1573
|
-
quietMode = enabled;
|
|
1574
|
-
}
|
|
1575
|
-
function setConfigComponent(component) {
|
|
1576
|
-
configComponentInstance = component;
|
|
1577
|
-
}
|
|
1578
|
-
function getLogLevel() {
|
|
1579
|
-
if (configComponentInstance) {
|
|
1580
|
-
const level = configComponentInstance.get("log_trace.logging.level");
|
|
1581
|
-
if (level && ["debug", "info", "warn", "error"].includes(level)) {
|
|
1582
|
-
return level;
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
const envLevel = process.env.LOG_LEVEL;
|
|
1586
|
-
if (envLevel && ["debug", "info", "warn", "error"].includes(envLevel)) {
|
|
1587
|
-
return envLevel;
|
|
1588
|
-
}
|
|
1589
|
-
return "info";
|
|
1590
|
-
}
|
|
1591
|
-
function getCategoryLogLevel(category) {
|
|
1592
|
-
if (configComponentInstance) {
|
|
1593
|
-
const levels = configComponentInstance.get("log_trace.logging.levels");
|
|
1594
|
-
if (levels && typeof levels === "object") {
|
|
1595
|
-
const categoryLevel = levels[category];
|
|
1596
|
-
if (categoryLevel && ["debug", "info", "warn", "error"].includes(categoryLevel)) {
|
|
1597
|
-
return categoryLevel;
|
|
1598
|
-
}
|
|
1599
|
-
}
|
|
1600
|
-
const directLevel = configComponentInstance.get(`log_trace.logging.levels.${category}`);
|
|
1601
|
-
if (directLevel && ["debug", "info", "warn", "error"].includes(directLevel)) {
|
|
1602
|
-
return directLevel;
|
|
1603
|
-
}
|
|
1604
|
-
}
|
|
1605
|
-
const envKey = `LOG_LEVEL_${category.toUpperCase().replace(/:/g, "_")}`;
|
|
1606
|
-
const envLevel = process.env[envKey];
|
|
1607
|
-
if (envLevel && ["debug", "info", "warn", "error"].includes(envLevel)) {
|
|
1608
|
-
return envLevel;
|
|
1609
|
-
}
|
|
1610
|
-
return getLogLevel();
|
|
1611
|
-
}
|
|
1612
|
-
function isAbsolutePath(path) {
|
|
1613
|
-
if (path.startsWith("/")) {
|
|
1614
|
-
return true;
|
|
1615
|
-
}
|
|
1616
|
-
if (/^[a-zA-Z]:[/\\]/.test(path)) {
|
|
1617
|
-
return true;
|
|
1618
|
-
}
|
|
1619
|
-
return false;
|
|
1620
|
-
}
|
|
1621
|
-
function expandHomeDir(path) {
|
|
1622
|
-
if (path.startsWith("~")) {
|
|
1623
|
-
const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
|
|
1624
|
-
return join(home, path.slice(1));
|
|
1625
|
-
}
|
|
1626
|
-
return path;
|
|
1627
|
-
}
|
|
1628
|
-
function getLogFile() {
|
|
1629
|
-
if (configComponentInstance) {
|
|
1630
|
-
const file = configComponentInstance.get("log_trace.logging.file");
|
|
1631
|
-
if (file) {
|
|
1632
|
-
return file;
|
|
1633
|
-
}
|
|
1634
|
-
}
|
|
1635
|
-
return "app.log";
|
|
1636
|
-
}
|
|
1637
|
-
function getLogDir() {
|
|
1638
|
-
if (configComponentInstance) {
|
|
1639
|
-
const dir = configComponentInstance.get("log_trace.logging.dir");
|
|
1640
|
-
if (dir) {
|
|
1641
|
-
return dir;
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
return getDefaultLogDir();
|
|
1645
|
-
}
|
|
1646
|
-
function getMaxOutput() {
|
|
1647
|
-
if (configComponentInstance) {
|
|
1648
|
-
const maxOutput = configComponentInstance.get("log-trace.logging.maxOutput");
|
|
1649
|
-
if (typeof maxOutput === "number") {
|
|
1650
|
-
return maxOutput;
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
return;
|
|
1654
|
-
}
|
|
1655
|
-
function setLogDirOverride(dir) {
|
|
1656
|
-
logDirOverride = dir;
|
|
1657
|
-
}
|
|
1658
|
-
function getLogDirOverride() {
|
|
1659
|
-
return logDirOverride;
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
class Logger {
|
|
1663
|
-
prefix;
|
|
1664
|
-
constructor(prefix) {
|
|
1665
|
-
this.prefix = prefix;
|
|
1666
|
-
}
|
|
1667
|
-
shouldLog(level) {
|
|
1668
|
-
const categoryLevel = getCategoryLogLevel(this.prefix);
|
|
1669
|
-
return levelPriority[level] >= levelPriority[categoryLevel];
|
|
1670
|
-
}
|
|
1671
|
-
ensureLogDirectory(dir) {
|
|
1672
|
-
if (!existsSync(dir)) {
|
|
1673
|
-
try {
|
|
1674
|
-
mkdirSync(dir, { recursive: true });
|
|
1675
|
-
} catch (err) {
|
|
1676
|
-
console.error("[Logger] Failed to create log directory:", dir, err);
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
|
-
}
|
|
1680
|
-
getCallerLocation() {
|
|
1681
|
-
const originalLimit = Error.stackTraceLimit;
|
|
1682
|
-
Error.stackTraceLimit = 10;
|
|
1683
|
-
const err = new Error;
|
|
1684
|
-
Error.captureStackTrace(err, this.formatMessage);
|
|
1685
|
-
const stack = err.stack?.split(`
|
|
1686
|
-
`) || [];
|
|
1687
|
-
Error.stackTraceLimit = originalLimit;
|
|
1688
|
-
for (let i = 1;i < stack.length; i++) {
|
|
1689
|
-
const line = stack[i];
|
|
1690
|
-
if (line.includes("at ") && !line.includes("logger.ts") && !line.includes("formatMessage")) {
|
|
1691
|
-
const match = line.match(/at\s+.+\s+\((.+):(\d+):\d+\)/) || line.match(/at\s+(.+):(\d+):\d+/);
|
|
1692
|
-
if (match) {
|
|
1693
|
-
const filePath = match[1];
|
|
1694
|
-
const relativePath = this.getRelativePath(filePath);
|
|
1695
|
-
return {
|
|
1696
|
-
file: relativePath,
|
|
1697
|
-
line: parseInt(match[2], 10)
|
|
1698
|
-
};
|
|
1699
|
-
}
|
|
1700
|
-
}
|
|
1701
|
-
}
|
|
1702
|
-
return null;
|
|
1703
|
-
}
|
|
1704
|
-
getRelativePath(fullPath) {
|
|
1705
|
-
return simplifyFilePath(fullPath);
|
|
1706
|
-
}
|
|
1707
|
-
formatMessage(level, message, data) {
|
|
1708
|
-
const now = new Date;
|
|
1709
|
-
const timestamp = now.toLocaleString("zh-CN", {
|
|
1710
|
-
timeZone: "Asia/Shanghai",
|
|
1711
|
-
year: "numeric",
|
|
1712
|
-
month: "2-digit",
|
|
1713
|
-
day: "2-digit",
|
|
1714
|
-
hour: "2-digit",
|
|
1715
|
-
minute: "2-digit",
|
|
1716
|
-
second: "2-digit",
|
|
1717
|
-
hour12: false
|
|
1718
|
-
}).replace(/\//g, "-") + "." + String(now.getMilliseconds()).padStart(3, "0");
|
|
1719
|
-
const prefix = this.prefix ? `[${this.prefix}]` : "";
|
|
1720
|
-
let traceIdStr = "";
|
|
1721
|
-
try {
|
|
1722
|
-
const provider = getTracerProvider();
|
|
1723
|
-
const tracer = provider.getTracer("roy-tracer");
|
|
1724
|
-
const context2 = tracer.getCurrentContext();
|
|
1725
|
-
if (context2?.traceId) {
|
|
1726
|
-
traceIdStr = `[traceId=${context2.traceId}]`;
|
|
1727
|
-
}
|
|
1728
|
-
} catch {}
|
|
1729
|
-
let locationStr = "";
|
|
1730
|
-
if (data && typeof data === "object" && "callerLocation" in data) {
|
|
1731
|
-
const logData = data;
|
|
1732
|
-
locationStr = logData.callerLocation ? ` [${logData.callerLocation}]` : "";
|
|
1733
|
-
const { callerLocation: _callerLocation, ...rest } = logData;
|
|
1734
|
-
data = Object.keys(rest).length > 0 ? rest : undefined;
|
|
1735
|
-
} else {
|
|
1736
|
-
const location = this.getCallerLocation();
|
|
1737
|
-
if (location) {
|
|
1738
|
-
locationStr = ` [${location.file}:${location.line}]`;
|
|
1739
|
-
}
|
|
1740
|
-
}
|
|
1741
|
-
let formatted = `${timestamp} [${level.toUpperCase()}]${traceIdStr}${locationStr}${prefix} ${message}`;
|
|
1742
|
-
if (data !== undefined) {
|
|
1743
|
-
if (typeof data === "object") {
|
|
1744
|
-
formatted += " " + JSON.stringify(data).replace(/\n/g, "");
|
|
1745
|
-
} else {
|
|
1746
|
-
formatted += " " + String(data);
|
|
1747
|
-
}
|
|
1748
|
-
}
|
|
1749
|
-
const maxOutput = getMaxOutput();
|
|
1750
|
-
if (maxOutput && maxOutput > 0 && formatted.length > maxOutput) {
|
|
1751
|
-
formatted = formatted.substring(0, maxOutput) + " [TRUNCATED]";
|
|
1752
|
-
}
|
|
1753
|
-
return formatted;
|
|
1754
|
-
}
|
|
1755
|
-
writeToFile(message) {
|
|
1756
|
-
try {
|
|
1757
|
-
const dir = getLogDir();
|
|
1758
|
-
const filename = getLogFile();
|
|
1759
|
-
const expandedDir = expandHomeDir(dir);
|
|
1760
|
-
const resolvedDir = isAbsolutePath(expandedDir) ? expandedDir : join(process.cwd(), expandedDir);
|
|
1761
|
-
this.ensureLogDirectory(resolvedDir);
|
|
1762
|
-
const logFile = join(resolvedDir, filename);
|
|
1763
|
-
appendFileSync(logFile, message + `
|
|
1764
|
-
`, "utf-8");
|
|
1765
|
-
} catch (err) {
|
|
1766
|
-
console.error("[Logger] Failed to write to log file:", err);
|
|
1767
|
-
}
|
|
1768
|
-
}
|
|
1769
|
-
log(level, message, data) {
|
|
1770
|
-
if (!this.shouldLog(level))
|
|
1771
|
-
return;
|
|
1772
|
-
const formatted = this.formatMessage(level, message, data);
|
|
1773
|
-
this.writeToFile(formatted);
|
|
1774
|
-
if (!isQuietMode()) {
|
|
1775
|
-
const consoleMethod = level === "error" ? console.error : level === "warn" ? console.warn : level === "info" ? console.log : console.debug;
|
|
1776
|
-
consoleMethod(formatted);
|
|
1777
|
-
}
|
|
1778
|
-
}
|
|
1779
|
-
debug(message, data) {
|
|
1780
|
-
this.log("debug", message, data);
|
|
1781
|
-
}
|
|
1782
|
-
info(message, data) {
|
|
1783
|
-
this.log("info", message, data);
|
|
1784
|
-
}
|
|
1785
|
-
warn(message, data) {
|
|
1786
|
-
this.log("warn", message, data);
|
|
1787
|
-
}
|
|
1788
|
-
error(message, data) {
|
|
1789
|
-
this.log("error", message, data);
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1792
|
-
function createLogger(prefix) {
|
|
1793
|
-
if (!loggerCache.has(prefix)) {
|
|
1794
|
-
loggerCache.set(prefix, new Logger(prefix));
|
|
1795
|
-
}
|
|
1796
|
-
return loggerCache.get(prefix);
|
|
1797
|
-
}
|
|
1798
|
-
function getLogLevels() {
|
|
1799
|
-
return ["debug", "info", "warn", "error"];
|
|
1800
|
-
}
|
|
1801
|
-
var configComponentInstance = null, quietMode = false, logDirOverride, levelPriority, loggerCache;
|
|
1802
|
-
var init_logger = __esm(() => {
|
|
1803
|
-
init_tracer_provider();
|
|
1804
|
-
levelPriority = {
|
|
1805
|
-
debug: 0,
|
|
1806
|
-
info: 1,
|
|
1807
|
-
warn: 2,
|
|
1808
|
-
error: 3
|
|
1809
|
-
};
|
|
1810
|
-
loggerCache = new Map;
|
|
1811
|
-
});
|
|
1812
|
-
|
|
1813
|
-
// packages/core/src/env/log-trace/decorator.ts
|
|
1814
|
-
function Traced(options) {
|
|
1815
|
-
return function(target, propertyKey, descriptor) {
|
|
1816
|
-
const originalFn = descriptor.value;
|
|
1817
|
-
const spanName = options?.name || propertyKey;
|
|
1818
|
-
descriptor.value = wrapFunction(originalFn, spanName, {
|
|
1819
|
-
recordParams: options?.recordParams ?? true,
|
|
1820
|
-
recordResult: options?.recordResult ?? false,
|
|
1821
|
-
recordError: options?.recordError ?? true,
|
|
1822
|
-
log: options?.log ?? false,
|
|
1823
|
-
maxLogSize: options?.maxLogSize,
|
|
1824
|
-
paramFilter: options?.paramFilter
|
|
1825
|
-
});
|
|
1826
|
-
return descriptor;
|
|
1827
|
-
};
|
|
1828
|
-
}
|
|
1829
|
-
function TracedAs(name, options) {
|
|
1830
|
-
return Traced({ name, ...options });
|
|
1831
|
-
}
|
|
1832
|
-
function TracedLightweight(options) {
|
|
1833
|
-
return Traced({ recordParams: false, recordResult: false, log: options?.log ?? false, maxLogSize: options?.maxLogSize });
|
|
1834
|
-
}
|
|
1835
|
-
function wrapFunction(fn, name, options) {
|
|
1836
|
-
const shouldLog = options?.log ?? false;
|
|
1837
|
-
const getMaxLogSize = () => {
|
|
1838
|
-
if (options?.maxLogSize !== undefined) {
|
|
1839
|
-
return options.maxLogSize;
|
|
1840
|
-
}
|
|
1841
|
-
const configMaxOutput = getMaxOutput();
|
|
1842
|
-
return configMaxOutput !== undefined ? configMaxOutput : 500;
|
|
1843
|
-
};
|
|
1844
|
-
const truncate = (obj) => {
|
|
1845
|
-
if (obj === undefined)
|
|
1846
|
-
return;
|
|
1847
|
-
if (obj === null)
|
|
1848
|
-
return null;
|
|
1849
|
-
const maxLogSize = getMaxLogSize();
|
|
1850
|
-
let str;
|
|
1851
|
-
try {
|
|
1852
|
-
str = typeof obj === "string" ? obj : JSON.stringify(obj, null, 0).replace(/\n/g, "");
|
|
1853
|
-
} catch (e) {
|
|
1854
|
-
str = `[Object with circular reference: ${e instanceof Error ? e.message : String(e)}]`;
|
|
1855
|
-
}
|
|
1856
|
-
if (maxLogSize > 0 && str.length > maxLogSize) {
|
|
1857
|
-
return str.slice(0, maxLogSize) + " [TRUNCATED]";
|
|
1858
|
-
}
|
|
1859
|
-
try {
|
|
1860
|
-
return JSON.parse(str);
|
|
1861
|
-
} catch {
|
|
1862
|
-
return str;
|
|
1863
|
-
}
|
|
1864
|
-
};
|
|
1865
|
-
const truncateString = (obj) => {
|
|
1866
|
-
if (obj === undefined)
|
|
1867
|
-
return "undefined";
|
|
1868
|
-
if (obj === null)
|
|
1869
|
-
return "null";
|
|
1870
|
-
const maxLogSize = getMaxLogSize();
|
|
1871
|
-
let str;
|
|
1872
|
-
try {
|
|
1873
|
-
str = typeof obj === "string" ? obj : JSON.stringify(obj, null, 0).replace(/\n/g, "");
|
|
1874
|
-
} catch (e) {
|
|
1875
|
-
str = `[Object with circular reference: ${e instanceof Error ? e.message : String(e)}]`;
|
|
1876
|
-
}
|
|
1877
|
-
return maxLogSize > 0 && str.length > maxLogSize ? str.slice(0, maxLogSize) + " [TRUNCATED]" : str;
|
|
1878
|
-
};
|
|
1879
|
-
const TRACE_LOG_PREFIX = "[TRACE]";
|
|
1880
|
-
const getCallerLocation = () => {
|
|
1881
|
-
const originalLimit = Error.stackTraceLimit;
|
|
1882
|
-
Error.stackTraceLimit = 15;
|
|
1883
|
-
const err = new Error;
|
|
1884
|
-
Error.captureStackTrace(err, getCallerLocation);
|
|
1885
|
-
const stack = err.stack?.split(`
|
|
1886
|
-
`) || [];
|
|
1887
|
-
Error.stackTraceLimit = originalLimit;
|
|
1888
|
-
for (let i = 1;i < stack.length; i++) {
|
|
1889
|
-
const line = stack[i];
|
|
1890
|
-
if (line.includes("decorator.ts") || line.includes("decorator.js") || line.includes("logFn") || line.includes("getCallerLocation"))
|
|
1891
|
-
continue;
|
|
1892
|
-
const match = line.match(/at\s+.+\s+\((.+):(\d+):\d+\)/) || line.match(/at\s+(.+):(\d+):\d+/);
|
|
1893
|
-
if (match) {
|
|
1894
|
-
const filePath = match[1];
|
|
1895
|
-
if (!filePath || filePath === "native")
|
|
1896
|
-
continue;
|
|
1897
|
-
const relativePath = simplifyFilePath(filePath);
|
|
1898
|
-
return `${relativePath}:${match[2]}`;
|
|
1899
|
-
}
|
|
1900
|
-
}
|
|
1901
|
-
return "";
|
|
1902
|
-
};
|
|
1903
|
-
const logFn = (event2, argsOrData, callerLocation) => {
|
|
1904
|
-
if (!shouldLog)
|
|
1905
|
-
return;
|
|
1906
|
-
const logger = createLogger("traced:" + name);
|
|
1907
|
-
const tag = event2 === "enter" ? ">>>" : event2 === "quit" ? "<<<" : "!!!";
|
|
1908
|
-
const prefix = `${TRACE_LOG_PREFIX} ${tag} ${name}`;
|
|
1909
|
-
const originalFnLocation = callerLocation || getCallerLocation();
|
|
1910
|
-
const logMessage = (msg, data) => {
|
|
1911
|
-
if (data !== undefined) {
|
|
1912
|
-
logger.info(`${prefix} ${msg}: ${truncateString(data)}`, { callerLocation: originalFnLocation });
|
|
1913
|
-
} else {
|
|
1914
|
-
logger.info(`${prefix} ${msg}`, { callerLocation: originalFnLocation });
|
|
1915
|
-
}
|
|
1916
|
-
};
|
|
1917
|
-
if (event2 === "enter") {
|
|
1918
|
-
logMessage("enter", argsOrData);
|
|
1919
|
-
} else if (event2 === "quit") {
|
|
1920
|
-
logMessage("quit", options?.recordResult ? argsOrData : undefined);
|
|
1921
|
-
} else {
|
|
1922
|
-
logMessage("error", argsOrData);
|
|
1923
|
-
}
|
|
1924
|
-
};
|
|
1925
|
-
return function(...args) {
|
|
1926
|
-
const tracer = getTracerProvider().getTracer("roy-tracer");
|
|
1927
|
-
const attributes = {};
|
|
1928
|
-
if (options?.recordParams !== false) {
|
|
1929
|
-
if (options?.paramFilter) {
|
|
1930
|
-
attributes["params"] = truncate(options.paramFilter(args));
|
|
1931
|
-
} else {
|
|
1932
|
-
attributes["params"] = truncate(args);
|
|
1933
|
-
}
|
|
1934
|
-
}
|
|
1935
|
-
const callerLocation = getCallerLocation();
|
|
1936
|
-
logFn("enter", args, callerLocation);
|
|
1937
|
-
const span = tracer.startSpan(name, { attributes });
|
|
1938
|
-
try {
|
|
1939
|
-
const result = fn.call(this, ...args);
|
|
1940
|
-
if (result && typeof result === "object" && typeof result.then === "function") {
|
|
1941
|
-
return result.then((resolved) => {
|
|
1942
|
-
span.setAttribute("result", JSON.stringify(truncate(resolved)));
|
|
1943
|
-
span.end(resolved);
|
|
1944
|
-
logFn("quit", options?.recordResult ? resolved : undefined, callerLocation);
|
|
1945
|
-
return resolved;
|
|
1946
|
-
}, (rejected) => {
|
|
1947
|
-
span.setAttribute("error", String(rejected));
|
|
1948
|
-
span.end(undefined, rejected instanceof Error ? rejected : new Error(String(rejected)));
|
|
1949
|
-
logFn("error", rejected.message, callerLocation);
|
|
1950
|
-
throw rejected;
|
|
1951
|
-
});
|
|
1952
|
-
}
|
|
1953
|
-
span.setAttribute("result", JSON.stringify(truncate(result)));
|
|
1954
|
-
span.end(result);
|
|
1955
|
-
logFn("quit", options?.recordResult ? result : undefined, callerLocation);
|
|
1956
|
-
return result;
|
|
1957
|
-
} catch (error) {
|
|
1958
|
-
span.setAttribute("error", String(error));
|
|
1959
|
-
span.end(undefined, error instanceof Error ? error : new Error(String(error)));
|
|
1960
|
-
logFn("error", error.message, callerLocation);
|
|
1961
|
-
throw error;
|
|
1962
|
-
}
|
|
1963
|
-
};
|
|
1964
|
-
}
|
|
1965
|
-
var init_decorator = __esm(() => {
|
|
1966
|
-
init_tracer_provider();
|
|
1967
|
-
init_logger();
|
|
1968
|
-
});
|
|
1969
|
-
|
|
1970
|
-
// packages/core/src/env/workflow/engine/executor.ts
|
|
1971
|
-
var Executor;
|
|
1972
|
-
var init_executor = __esm(() => {
|
|
1973
|
-
init_event();
|
|
1974
|
-
init_types();
|
|
1975
|
-
init_decorator();
|
|
1976
|
-
Executor = class Executor {
|
|
1977
|
-
nodeRegistry;
|
|
1978
|
-
eventBus;
|
|
1979
|
-
options;
|
|
1980
|
-
sessionComponent;
|
|
1981
|
-
abortControllers = new Map;
|
|
1982
|
-
constructor(nodeRegistry, eventBus, options, sessionComponent) {
|
|
1983
|
-
this.nodeRegistry = nodeRegistry;
|
|
1984
|
-
this.eventBus = eventBus;
|
|
1985
|
-
this.options = options;
|
|
1986
|
-
this.sessionComponent = sessionComponent;
|
|
1987
|
-
}
|
|
1988
|
-
async executeNode(definition, context2) {
|
|
1989
|
-
const nodeId = definition.id;
|
|
1990
|
-
const nodeType = definition.type;
|
|
1991
|
-
const agentSessionId = context2.agentSessionId;
|
|
1992
|
-
await this.eventBus.publish(createWorkflowEvent("node.started", context2.runId, {
|
|
1993
|
-
node_id: nodeId,
|
|
1994
|
-
input: context2.input
|
|
1995
|
-
}));
|
|
1996
|
-
await this.writeNodeCall(context2.sessionId, nodeId, nodeType, context2.input, agentSessionId);
|
|
1997
|
-
const abortController = new AbortController;
|
|
1998
|
-
this.abortControllers.set(nodeId, abortController);
|
|
1999
|
-
const timeout = definition.timeout ?? this.options.globalTimeout ?? undefined;
|
|
2000
|
-
const retryConfig = definition.retry ?? this.options.globalRetry;
|
|
2001
|
-
try {
|
|
2002
|
-
let result;
|
|
2003
|
-
if (retryConfig && retryConfig.max_attempts > 1) {
|
|
2004
|
-
result = await this.executeWithRetry(definition, context2, abortController.signal, timeout);
|
|
2005
|
-
} else {
|
|
2006
|
-
result = await this.executeWithTimeout(definition, context2, abortController.signal, timeout);
|
|
2007
|
-
}
|
|
2008
|
-
if (result.error instanceof AskUserError) {
|
|
2009
|
-
const interruptEvent = createNodeInterruptEvent(context2.runId, nodeId, nodeType, result.error.query, result.error.agentSessionId || agentSessionId);
|
|
2010
|
-
await this.eventBus.publish(interruptEvent);
|
|
2011
|
-
await this.writeNodeInterrupt(context2.sessionId, nodeId, nodeType, result.error.query, result.error.agentSessionId || agentSessionId);
|
|
2012
|
-
throw result.error;
|
|
2013
|
-
}
|
|
2014
|
-
if (result.error) {
|
|
2015
|
-
const errorMessage = result.error instanceof Error ? result.error.message : String(result.error);
|
|
2016
|
-
const errorStack = result.error instanceof Error ? result.error.stack : undefined;
|
|
2017
|
-
await this.eventBus.publish(createWorkflowEvent("node.failed", context2.runId, {
|
|
2018
|
-
node_id: nodeId,
|
|
2019
|
-
error: {
|
|
2020
|
-
message: errorMessage,
|
|
2021
|
-
stack: errorStack
|
|
2022
|
-
}
|
|
2023
|
-
}));
|
|
2024
|
-
await this.writeNodeResult(context2.sessionId, nodeId, nodeType, result.output, errorMessage, result.durationMs ?? 0);
|
|
2025
|
-
} else {
|
|
2026
|
-
await this.eventBus.publish(createWorkflowEvent("node.completed", context2.runId, {
|
|
2027
|
-
node_id: nodeId,
|
|
2028
|
-
output: result.output,
|
|
2029
|
-
duration_ms: result.durationMs ?? 0
|
|
2030
|
-
}));
|
|
2031
|
-
await this.writeNodeResult(context2.sessionId, nodeId, nodeType, result.output, undefined, result.durationMs ?? 0);
|
|
2032
|
-
}
|
|
2033
|
-
return result;
|
|
2034
|
-
} finally {
|
|
2035
|
-
this.abortControllers.delete(nodeId);
|
|
2036
|
-
}
|
|
2037
|
-
}
|
|
2038
|
-
async executeWithTimeout(definition, context2, signal, timeout) {
|
|
2039
|
-
const startTime = Date.now();
|
|
2040
|
-
const nodeContext = {
|
|
2041
|
-
runId: context2.runId,
|
|
2042
|
-
workflowName: context2.workflowName,
|
|
2043
|
-
eventBus: this.eventBus,
|
|
2044
|
-
debug: context2.debug
|
|
2045
|
-
};
|
|
2046
|
-
const node = this.nodeRegistry.createNode(definition, nodeContext);
|
|
2047
|
-
if (timeout) {
|
|
2048
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
2049
|
-
const handle = setTimeout(() => {
|
|
2050
|
-
reject(new Error(`Node execution timeout: ${timeout}ms`));
|
|
2051
|
-
}, timeout);
|
|
2052
|
-
signal.addEventListener("abort", () => clearTimeout(handle));
|
|
2053
|
-
});
|
|
2054
|
-
try {
|
|
2055
|
-
const result = await Promise.race([
|
|
2056
|
-
node.execute(context2),
|
|
2057
|
-
timeoutPromise
|
|
2058
|
-
]);
|
|
2059
|
-
return {
|
|
2060
|
-
output: result.output,
|
|
2061
|
-
error: result.error ?? undefined,
|
|
2062
|
-
durationMs: Date.now() - startTime
|
|
2063
|
-
};
|
|
2064
|
-
} catch (error) {
|
|
2065
|
-
if (error instanceof AskUserError) {
|
|
2066
|
-
throw error;
|
|
2067
|
-
}
|
|
2068
|
-
return {
|
|
2069
|
-
output: undefined,
|
|
2070
|
-
error: error instanceof Error ? error : new Error(String(error)),
|
|
2071
|
-
durationMs: Date.now() - startTime
|
|
2072
|
-
};
|
|
2073
|
-
}
|
|
2074
|
-
} else {
|
|
2075
|
-
try {
|
|
2076
|
-
const result = await node.execute(context2);
|
|
2077
|
-
return {
|
|
2078
|
-
output: result.output,
|
|
2079
|
-
durationMs: Date.now() - startTime
|
|
2080
|
-
};
|
|
2081
|
-
} catch (error) {
|
|
2082
|
-
if (error instanceof AskUserError) {
|
|
2083
|
-
throw error;
|
|
2084
|
-
}
|
|
2085
|
-
return {
|
|
2086
|
-
output: undefined,
|
|
2087
|
-
error: error instanceof Error ? error : new Error(String(error)),
|
|
2088
|
-
durationMs: Date.now() - startTime
|
|
2089
|
-
};
|
|
2090
|
-
}
|
|
2091
|
-
}
|
|
2092
|
-
}
|
|
2093
|
-
async executeWithRetry(definition, context2, signal, timeout) {
|
|
2094
|
-
const retryConfig = definition.retry;
|
|
2095
|
-
let lastError;
|
|
2096
|
-
let delay = retryConfig.initial_delay;
|
|
2097
|
-
for (let attempt = 1;attempt <= retryConfig.max_attempts; attempt++) {
|
|
2098
|
-
if (signal.aborted) {
|
|
2099
|
-
return {
|
|
2100
|
-
output: undefined,
|
|
2101
|
-
error: new Error("Execution aborted"),
|
|
2102
|
-
durationMs: 0
|
|
2103
|
-
};
|
|
2104
|
-
}
|
|
2105
|
-
const attemptAbort = new AbortController;
|
|
2106
|
-
const combinedSignal = this.combineAbortSignals(signal, attemptAbort.signal);
|
|
2107
|
-
try {
|
|
2108
|
-
const result = await this.executeWithTimeout(definition, context2, combinedSignal, timeout);
|
|
2109
|
-
if (!result.error) {
|
|
2110
|
-
return result;
|
|
2111
|
-
}
|
|
2112
|
-
lastError = result.error instanceof Error ? result.error : new Error(String(result.error));
|
|
2113
|
-
} catch (error) {
|
|
2114
|
-
lastError = error instanceof Error ? error : new Error(String(error));
|
|
2115
|
-
}
|
|
2116
|
-
if (attempt < retryConfig.max_attempts) {
|
|
2117
|
-
await this.sleep(delay);
|
|
2118
|
-
if (retryConfig.backoff === "exponential") {
|
|
2119
|
-
delay *= 2;
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
return {
|
|
2124
|
-
output: undefined,
|
|
2125
|
-
error: lastError ?? new Error("Unknown error after retries"),
|
|
2126
|
-
durationMs: 0
|
|
2127
|
-
};
|
|
2128
|
-
}
|
|
2129
|
-
cancelNode(nodeId) {
|
|
2130
|
-
const controller = this.abortControllers.get(nodeId);
|
|
2131
|
-
if (controller) {
|
|
2132
|
-
controller.abort();
|
|
2133
|
-
this.abortControllers.delete(nodeId);
|
|
2134
|
-
}
|
|
2135
|
-
}
|
|
2136
|
-
cancelAll() {
|
|
2137
|
-
for (const controller of this.abortControllers.values()) {
|
|
2138
|
-
controller.abort();
|
|
2139
|
-
}
|
|
2140
|
-
this.abortControllers.clear();
|
|
2141
|
-
}
|
|
2142
|
-
combineAbortSignals(signal1, signal2) {
|
|
2143
|
-
const controller = new AbortController;
|
|
2144
|
-
signal1.addEventListener("abort", () => controller.abort());
|
|
2145
|
-
signal2.addEventListener("abort", () => controller.abort());
|
|
2146
|
-
return controller.signal;
|
|
2147
|
-
}
|
|
2148
|
-
sleep(ms) {
|
|
2149
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2150
|
-
}
|
|
2151
|
-
async writeNodeCall(sessionId, nodeId, nodeType, input, agentSessionId) {
|
|
2152
|
-
if (!this.sessionComponent)
|
|
2153
|
-
return;
|
|
2154
|
-
const startTime = Date.now();
|
|
2155
|
-
const part = {
|
|
2156
|
-
type: "workflow-node-call",
|
|
2157
|
-
nodeId,
|
|
2158
|
-
nodeType,
|
|
2159
|
-
input,
|
|
2160
|
-
startTime,
|
|
2161
|
-
...agentSessionId ? { agentSessionId } : {}
|
|
2162
|
-
};
|
|
2163
|
-
const contentSummary = this.summarizeCall(nodeType, nodeId, input);
|
|
2164
|
-
await this.sessionComponent.addMessage(sessionId, {
|
|
2165
|
-
role: "workflow.node.call",
|
|
2166
|
-
content: contentSummary,
|
|
2167
|
-
parts: [part],
|
|
2168
|
-
metadata: {
|
|
2169
|
-
_workflowNodeMetadata: true,
|
|
2170
|
-
type: "workflow.node.call",
|
|
2171
|
-
workflowNodeId: nodeId,
|
|
2172
|
-
workflowNodeType: nodeType,
|
|
2173
|
-
...agentSessionId ? { agentSessionId } : {}
|
|
2174
|
-
}
|
|
2175
|
-
});
|
|
2176
|
-
}
|
|
2177
|
-
summarizeCall(nodeType, nodeId, input) {
|
|
2178
|
-
if (input === undefined || input === null) {
|
|
2179
|
-
return `[${nodeType}] ${nodeId} started`;
|
|
2180
|
-
}
|
|
2181
|
-
if (typeof input === "object") {
|
|
2182
|
-
const keys = Object.keys(input);
|
|
2183
|
-
if (keys.length === 0) {
|
|
2184
|
-
return `[${nodeType}] ${nodeId} started`;
|
|
2185
|
-
}
|
|
2186
|
-
const summary = keys.slice(0, 3).map((k) => `${k}: ${JSON.stringify(input[k])}`).join(", ");
|
|
2187
|
-
return `[${nodeType}] ${nodeId}: ${summary}`;
|
|
2188
|
-
}
|
|
2189
|
-
return `[${nodeType}] ${nodeId}: ${String(input)}`;
|
|
2190
|
-
}
|
|
2191
|
-
async writeNodeInterrupt(sessionId, nodeId, nodeType, query, agentSessionId) {
|
|
2192
|
-
if (!this.sessionComponent)
|
|
2193
|
-
return;
|
|
2194
|
-
const timestamp = Date.now();
|
|
2195
|
-
const part = {
|
|
2196
|
-
type: "workflow-node-interrupt",
|
|
2197
|
-
nodeId,
|
|
2198
|
-
nodeType,
|
|
2199
|
-
query,
|
|
2200
|
-
timestamp,
|
|
2201
|
-
...agentSessionId ? { agentSessionId } : {}
|
|
2202
|
-
};
|
|
2203
|
-
await this.sessionComponent.addMessage(sessionId, {
|
|
2204
|
-
role: "workflow.node.interrupt",
|
|
2205
|
-
content: query,
|
|
2206
|
-
parts: [part],
|
|
2207
|
-
metadata: {
|
|
2208
|
-
_workflowNodeMetadata: true,
|
|
2209
|
-
type: "workflow.node.interrupt",
|
|
2210
|
-
workflowNodeId: nodeId,
|
|
2211
|
-
workflowNodeType: nodeType,
|
|
2212
|
-
query,
|
|
2213
|
-
agentSessionId
|
|
2214
|
-
}
|
|
2215
|
-
});
|
|
2216
|
-
}
|
|
2217
|
-
async writeNodeResult(sessionId, nodeId, nodeType, output, error, durationMs) {
|
|
2218
|
-
if (!this.sessionComponent)
|
|
2219
|
-
return;
|
|
2220
|
-
const part = {
|
|
2221
|
-
type: "workflow-node-result",
|
|
2222
|
-
nodeId,
|
|
2223
|
-
nodeType,
|
|
2224
|
-
output,
|
|
2225
|
-
error,
|
|
2226
|
-
durationMs
|
|
2227
|
-
};
|
|
2228
|
-
const contentSummary = this.summarizeResult(nodeId, output, error, durationMs);
|
|
2229
|
-
await this.sessionComponent.addMessage(sessionId, {
|
|
2230
|
-
role: "workflow.node.result",
|
|
2231
|
-
content: contentSummary,
|
|
2232
|
-
parts: [part],
|
|
2233
|
-
metadata: {
|
|
2234
|
-
_workflowNodeMetadata: true,
|
|
2235
|
-
type: "workflow.node.result",
|
|
2236
|
-
workflowNodeId: nodeId,
|
|
2237
|
-
workflowNodeType: nodeType,
|
|
2238
|
-
success: !error
|
|
2239
|
-
}
|
|
2240
|
-
});
|
|
2241
|
-
}
|
|
2242
|
-
summarizeResult(nodeId, output, error, durationMs) {
|
|
2243
|
-
if (error) {
|
|
2244
|
-
return `\u274C ${nodeId} failed: ${error}`;
|
|
2245
|
-
}
|
|
2246
|
-
if (output === undefined || output === null) {
|
|
2247
|
-
return `\u2705 ${nodeId} completed (${durationMs}ms)`;
|
|
2248
|
-
}
|
|
2249
|
-
if (typeof output === "object") {
|
|
2250
|
-
const keys = Object.keys(output);
|
|
2251
|
-
if (keys.length === 0) {
|
|
2252
|
-
return `\u2705 ${nodeId} completed (${durationMs}ms)`;
|
|
2253
|
-
}
|
|
2254
|
-
const summary = keys.slice(0, 3).join(", ");
|
|
2255
|
-
return `\u2705 ${nodeId}: ${summary} (${durationMs}ms)`;
|
|
2256
|
-
}
|
|
2257
|
-
const strOutput = String(output);
|
|
2258
|
-
const truncated = strOutput.length > 100 ? strOutput.substring(0, 100) + "..." : strOutput;
|
|
2259
|
-
return `\u2705 ${nodeId}: ${truncated} (${durationMs}ms)`;
|
|
2260
|
-
}
|
|
2261
|
-
async writeNodeResume(sessionId, response) {
|
|
2262
|
-
if (!this.sessionComponent)
|
|
2263
|
-
return;
|
|
2264
|
-
const timestamp = Date.now();
|
|
2265
|
-
const part = {
|
|
2266
|
-
type: "workflow-node-resume",
|
|
2267
|
-
response,
|
|
2268
|
-
timestamp
|
|
2269
|
-
};
|
|
2270
|
-
await this.sessionComponent.addMessage(sessionId, {
|
|
2271
|
-
role: "workflow.node.resume",
|
|
2272
|
-
content: response,
|
|
2273
|
-
parts: [part],
|
|
2274
|
-
metadata: {
|
|
2275
|
-
_workflowNodeMetadata: true
|
|
2276
|
-
}
|
|
2277
|
-
});
|
|
2278
|
-
}
|
|
2279
|
-
};
|
|
2280
|
-
__legacyDecorateClassTS([
|
|
2281
|
-
TracedAs("workflow.executor.executeNode", { recordParams: true, recordResult: true, log: true })
|
|
2282
|
-
], Executor.prototype, "executeNode", null);
|
|
2283
|
-
__legacyDecorateClassTS([
|
|
2284
|
-
TracedAs("workflow.executor.writeNodeCall", { recordParams: true, recordResult: true, log: true })
|
|
2285
|
-
], Executor.prototype, "writeNodeCall", null);
|
|
2286
|
-
__legacyDecorateClassTS([
|
|
2287
|
-
TracedAs("workflow.executor.writeNodeInterrupt", { recordParams: true, recordResult: true, log: true })
|
|
2288
|
-
], Executor.prototype, "writeNodeInterrupt", null);
|
|
2289
|
-
__legacyDecorateClassTS([
|
|
2290
|
-
TracedAs("workflow.executor.writeNodeResult", { recordParams: true, recordResult: true, log: true })
|
|
2291
|
-
], Executor.prototype, "writeNodeResult", null);
|
|
2292
|
-
__legacyDecorateClassTS([
|
|
2293
|
-
TracedAs("workflow.executor.writeNodeResume", { recordParams: true, recordResult: true, log: true })
|
|
2294
|
-
], Executor.prototype, "writeNodeResume", null);
|
|
2295
|
-
});
|
|
2296
|
-
|
|
2297
|
-
// packages/core/src/env/workflow/nodes/tool-node.ts
|
|
2298
|
-
class ToolNode {
|
|
2299
|
-
definition;
|
|
2300
|
-
toolRegistry;
|
|
2301
|
-
type = "tool";
|
|
2302
|
-
id;
|
|
2303
|
-
constructor(definition, toolRegistry) {
|
|
2304
|
-
this.definition = definition;
|
|
2305
|
-
this.toolRegistry = toolRegistry;
|
|
2306
|
-
this.id = definition.id;
|
|
2307
|
-
}
|
|
2308
|
-
async execute(context2) {
|
|
2309
|
-
const startTime = Date.now();
|
|
2310
|
-
try {
|
|
2311
|
-
const toolName = this.definition.config?.tool ?? this.definition.config?.toolName;
|
|
2312
|
-
if (!toolName) {
|
|
2313
|
-
throw new Error("Tool name is required. Please specify config.tool or config.toolName in the node definition.");
|
|
2314
|
-
}
|
|
2315
|
-
let tool;
|
|
2316
|
-
if (this.toolRegistry.getTool) {
|
|
2317
|
-
const result = this.toolRegistry.getTool(toolName);
|
|
2318
|
-
if (!result) {
|
|
2319
|
-
throw new Error(`Tool not found: ${toolName}`);
|
|
2320
|
-
}
|
|
2321
|
-
if ("tool" in result) {
|
|
2322
|
-
tool = result.tool;
|
|
2323
|
-
} else {
|
|
2324
|
-
tool = result;
|
|
2325
|
-
}
|
|
2326
|
-
} else if (this.toolRegistry.getToolByName) {
|
|
2327
|
-
tool = this.toolRegistry.getToolByName(toolName);
|
|
2328
|
-
}
|
|
2329
|
-
if (!tool) {
|
|
2330
|
-
throw new Error(`Tool not found: ${toolName}`);
|
|
2331
|
-
}
|
|
2332
|
-
let input;
|
|
2333
|
-
if (this.definition.config?.command !== undefined) {
|
|
2334
|
-
const commandTemplate = this.definition.config.command;
|
|
2335
|
-
const resolvedCommand = this.resolveTemplateReferences(commandTemplate, context2.previousOutputs, context2.input);
|
|
2336
|
-
input = { command: resolvedCommand };
|
|
2337
|
-
console.log(`[ToolNode] command input: ${resolvedCommand}`);
|
|
2338
|
-
} else if (this.definition.config?.message !== undefined && Object.keys(this.definition.config).length === 1) {
|
|
2339
|
-
const messageTemplate = this.definition.config.message;
|
|
2340
|
-
const resolvedMessage = this.resolveTemplateReferences(messageTemplate, context2.previousOutputs, context2.input);
|
|
2341
|
-
input = { message: resolvedMessage };
|
|
2342
|
-
console.log(`[ToolNode] message input: ${resolvedMessage}`);
|
|
2343
|
-
} else {
|
|
2344
|
-
input = this.definition.config?.input ?? this.definition.config?.args ?? {};
|
|
2345
|
-
input = this.resolveTemplateReferences(input, context2.previousOutputs, context2.input);
|
|
2346
|
-
}
|
|
2347
|
-
let output;
|
|
2348
|
-
try {
|
|
2349
|
-
const toolContext = {
|
|
2350
|
-
session_id: context2.sessionId || `workflow_${context2.runId}`,
|
|
2351
|
-
message_id: context2.nodeId,
|
|
2352
|
-
metadata: {
|
|
2353
|
-
workflowRunId: context2.runId,
|
|
2354
|
-
workflowName: context2.workflowName,
|
|
2355
|
-
nodeId: context2.nodeId
|
|
2356
|
-
}
|
|
2357
|
-
};
|
|
2358
|
-
const executePromise = tool.execute(input, toolContext);
|
|
2359
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
2360
|
-
setTimeout(() => reject(new Error(`Tool ${toolName} execution timeout after 30s`)), 30000);
|
|
2361
|
-
});
|
|
2362
|
-
output = await Promise.race([executePromise, timeoutPromise]);
|
|
2363
|
-
} catch (err) {
|
|
2364
|
-
console.log(`[ToolNode] Tool ${toolName} doesn't support context, retrying without context...`);
|
|
2365
|
-
output = await tool.execute(input);
|
|
2366
|
-
}
|
|
2367
|
-
return {
|
|
2368
|
-
output,
|
|
2369
|
-
error: undefined,
|
|
2370
|
-
durationMs: Date.now() - startTime
|
|
2371
|
-
};
|
|
2372
|
-
} catch (error) {
|
|
2373
|
-
return {
|
|
2374
|
-
output: undefined,
|
|
2375
|
-
error: error instanceof Error ? error : new Error(String(error)),
|
|
2376
|
-
durationMs: Date.now() - startTime
|
|
2377
|
-
};
|
|
2378
|
-
}
|
|
2379
|
-
}
|
|
2380
|
-
resolveTemplateReferences(input, previousOutputs, workflowInput) {
|
|
2381
|
-
if (typeof input === "string") {
|
|
2382
|
-
const pureTemplate = this.extractPureTemplate(input) || this.extractDollarTemplate(input);
|
|
2383
|
-
if (pureTemplate) {
|
|
2384
|
-
return this.resolvePureTemplate(pureTemplate, previousOutputs, workflowInput);
|
|
2385
|
-
}
|
|
2386
|
-
return this.resolveStringTemplate(input, previousOutputs, workflowInput);
|
|
2387
|
-
}
|
|
2388
|
-
if (Array.isArray(input)) {
|
|
2389
|
-
return input.map((item) => this.resolveTemplateReferences(item, previousOutputs, workflowInput));
|
|
2390
|
-
}
|
|
2391
|
-
if (input !== null && typeof input === "object") {
|
|
2392
|
-
const resolved = {};
|
|
2393
|
-
for (const [key, value] of Object.entries(input)) {
|
|
2394
|
-
resolved[key] = this.resolveTemplateReferences(value, previousOutputs, workflowInput);
|
|
2395
|
-
}
|
|
2396
|
-
return resolved;
|
|
2397
|
-
}
|
|
2398
|
-
return input;
|
|
2399
|
-
}
|
|
2400
|
-
extractPureTemplate(str) {
|
|
2401
|
-
const trimmed = str.trim();
|
|
2402
|
-
if (trimmed.startsWith("{{") && trimmed.endsWith("}}") && trimmed.length > 4) {
|
|
2403
|
-
const content = trimmed.slice(2, -2).trim();
|
|
2404
|
-
if (!content.includes("{{") && !content.includes("}}")) {
|
|
2405
|
-
return content;
|
|
2406
|
-
}
|
|
2407
|
-
}
|
|
2408
|
-
return null;
|
|
2409
|
-
}
|
|
2410
|
-
extractDollarTemplate(str) {
|
|
2411
|
-
const trimmed = str.trim();
|
|
2412
|
-
if (trimmed.startsWith("${") && trimmed.endsWith("}") && trimmed.length > 3) {
|
|
2413
|
-
const content = trimmed.slice(2, -1).trim();
|
|
2414
|
-
if (!content.includes("${") && !content.includes("}")) {
|
|
2415
|
-
return content;
|
|
2416
|
-
}
|
|
2417
|
-
}
|
|
2418
|
-
return null;
|
|
2419
|
-
}
|
|
2420
|
-
resolvePureTemplate(templateContent, previousOutputs, workflowInput) {
|
|
2421
|
-
const trimmed = templateContent.trim();
|
|
2422
|
-
const originalTemplate = `{{${templateContent}}}`;
|
|
2423
|
-
if (trimmed.startsWith("input.")) {
|
|
2424
|
-
const value = this.getNestedValue(workflowInput, trimmed.slice(6));
|
|
2425
|
-
return value !== undefined ? value : originalTemplate;
|
|
2426
|
-
}
|
|
2427
|
-
if (trimmed.startsWith("nodes.")) {
|
|
2428
|
-
const path = trimmed.slice(6);
|
|
2429
|
-
const segments = path.split(".");
|
|
2430
|
-
const nodeId = segments[0];
|
|
2431
|
-
const restPath = segments.slice(1).join(".") || undefined;
|
|
2432
|
-
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
2433
|
-
return value !== undefined ? value : originalTemplate;
|
|
2434
|
-
}
|
|
2435
|
-
if (trimmed !== "input" && trimmed !== "nodes") {
|
|
2436
|
-
const segments = trimmed.split(".");
|
|
2437
|
-
const nodeId = segments[0];
|
|
2438
|
-
const restPath = segments.slice(1).join(".") || undefined;
|
|
2439
|
-
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
2440
|
-
return value !== undefined ? value : originalTemplate;
|
|
2441
|
-
}
|
|
2442
|
-
return originalTemplate;
|
|
2443
|
-
}
|
|
2444
|
-
resolveStringTemplate(template, previousOutputs, workflowInput) {
|
|
2445
|
-
let resolved = template;
|
|
2446
|
-
resolved = resolved.replace(/\{\{input\.([^}]+)\}\}/g, (match, path) => {
|
|
2447
|
-
const value = this.getNestedValue(workflowInput, path.trim());
|
|
2448
|
-
return this.stringifyValue(value, match);
|
|
2449
|
-
});
|
|
2450
|
-
resolved = resolved.replace(/\$\{input\.([^}]+)\}/g, (match, path) => {
|
|
2451
|
-
const value = this.getNestedValue(workflowInput, path.trim());
|
|
2452
|
-
return this.stringifyValue(value, match);
|
|
2453
|
-
});
|
|
2454
|
-
resolved = resolved.replace(/\{\{([^:.{}][^}]*?)\}\}/g, (match, path) => {
|
|
2455
|
-
if (path.trim().startsWith("nodes.") || path.trim().startsWith("input.")) {
|
|
2456
|
-
return match;
|
|
2457
|
-
}
|
|
2458
|
-
const segments = path.trim().split(".");
|
|
2459
|
-
const nodeId = segments[0];
|
|
2460
|
-
const restPath = segments.slice(1).join(".") || undefined;
|
|
2461
|
-
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
2462
|
-
return this.stringifyValue(value, match);
|
|
2463
|
-
});
|
|
2464
|
-
resolved = resolved.replace(/\$\{([^}]+)\}/g, (match, path) => {
|
|
2465
|
-
if (path.trim().startsWith("nodes.") || path.trim().startsWith("input.")) {
|
|
2466
|
-
return match;
|
|
2467
|
-
}
|
|
2468
|
-
const segments = path.trim().split(".");
|
|
2469
|
-
const nodeId = segments[0];
|
|
2470
|
-
const restPath = segments.slice(1).join(".") || undefined;
|
|
2471
|
-
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
2472
|
-
return this.stringifyValue(value, match);
|
|
2473
|
-
});
|
|
2474
|
-
resolved = resolved.replace(/\{\{nodes\.([^}]+)\}\}/g, (match, path) => {
|
|
2475
|
-
const segments = path.trim().split(".");
|
|
2476
|
-
const nodeId = segments[0];
|
|
2477
|
-
const restPath = segments.slice(1).join(".") || undefined;
|
|
2478
|
-
const nodeOutput = this.resolvePath(nodeId, undefined, previousOutputs);
|
|
2479
|
-
let extractedValue = this.extractFromWrapper(nodeOutput);
|
|
2480
|
-
if (typeof extractedValue === "string" && restPath === "output") {
|
|
2481
|
-
return this.stringifyValue(extractedValue, match);
|
|
2482
|
-
}
|
|
2483
|
-
if (restPath) {
|
|
2484
|
-
const value = this.getNestedValue(extractedValue, restPath);
|
|
2485
|
-
return this.stringifyValue(value, match);
|
|
2486
|
-
} else {
|
|
2487
|
-
return this.stringifyValue(extractedValue, match);
|
|
2488
|
-
}
|
|
2489
|
-
});
|
|
2490
|
-
return resolved;
|
|
2491
|
-
}
|
|
2492
|
-
resolvePath(nodeId, path, previousOutputs) {
|
|
2493
|
-
let nodeOutput = previousOutputs.get(nodeId);
|
|
2494
|
-
if (nodeOutput === undefined) {
|
|
2495
|
-
const normalizedUnderscore = nodeId.replace(/-/g, "_");
|
|
2496
|
-
const normalizedHyphen = nodeId.replace(/_/g, "-");
|
|
2497
|
-
if (normalizedUnderscore !== nodeId) {
|
|
2498
|
-
nodeOutput = previousOutputs.get(normalizedUnderscore);
|
|
2499
|
-
}
|
|
2500
|
-
if (nodeOutput === undefined && normalizedHyphen !== nodeId) {
|
|
2501
|
-
nodeOutput = previousOutputs.get(normalizedHyphen);
|
|
2502
|
-
}
|
|
2503
|
-
}
|
|
2504
|
-
if (nodeOutput === undefined) {
|
|
2505
|
-
return;
|
|
2506
|
-
}
|
|
2507
|
-
if (path === undefined || path === "") {
|
|
2508
|
-
return nodeOutput;
|
|
2509
|
-
}
|
|
2510
|
-
return this.getNestedValue(nodeOutput, path);
|
|
2511
|
-
}
|
|
2512
|
-
getNestedValue(obj, path) {
|
|
2513
|
-
if (obj === null || obj === undefined) {
|
|
2514
|
-
return;
|
|
2515
|
-
}
|
|
2516
|
-
const segments = path.split(".");
|
|
2517
|
-
let current = obj;
|
|
2518
|
-
for (const segment of segments) {
|
|
2519
|
-
if (current === null || current === undefined) {
|
|
2520
|
-
return;
|
|
2521
|
-
}
|
|
2522
|
-
current = current[segment];
|
|
2523
|
-
}
|
|
2524
|
-
return current;
|
|
2525
|
-
}
|
|
2526
|
-
extractFromWrapper(value) {
|
|
2527
|
-
if (value === null || value === undefined) {
|
|
2528
|
-
return value;
|
|
2529
|
-
}
|
|
2530
|
-
if (typeof value !== "object") {
|
|
2531
|
-
return value;
|
|
2532
|
-
}
|
|
2533
|
-
let result;
|
|
2534
|
-
if ("output" in value) {
|
|
2535
|
-
result = value.output;
|
|
2536
|
-
} else if ("result" in value && !("output" in value)) {
|
|
2537
|
-
result = value.result;
|
|
2538
|
-
} else {
|
|
2539
|
-
return value;
|
|
2540
|
-
}
|
|
2541
|
-
if (typeof result === "string") {
|
|
2542
|
-
return result.trimEnd();
|
|
2543
|
-
}
|
|
2544
|
-
return result;
|
|
2545
|
-
}
|
|
2546
|
-
stringifyValue(value, fallback) {
|
|
2547
|
-
if (value === undefined || value === null) {
|
|
2548
|
-
return fallback;
|
|
2549
|
-
}
|
|
2550
|
-
let str;
|
|
2551
|
-
if (typeof value === "object") {
|
|
2552
|
-
str = JSON.stringify(value);
|
|
2553
|
-
} else {
|
|
2554
|
-
str = String(value);
|
|
2555
|
-
}
|
|
2556
|
-
return str.replace(/\\/g, "\\\\").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t").replace(/"/g, "\\\"").replace(/`/g, "\\`").replace(/\$/g, "\\$");
|
|
2557
|
-
}
|
|
2558
|
-
}
|
|
2559
|
-
|
|
2560
|
-
// packages/core/src/env/workflow/nodes/skill-node.ts
|
|
2561
|
-
class SkillNode {
|
|
2562
|
-
definition;
|
|
2563
|
-
skillRegistry;
|
|
2564
|
-
type = "skill";
|
|
2565
|
-
id;
|
|
2566
|
-
constructor(definition, skillRegistry) {
|
|
2567
|
-
this.definition = definition;
|
|
2568
|
-
this.skillRegistry = skillRegistry;
|
|
2569
|
-
this.id = definition.id;
|
|
2570
|
-
}
|
|
2571
|
-
async execute(context2) {
|
|
2572
|
-
const startTime = Date.now();
|
|
2573
|
-
try {
|
|
2574
|
-
const skillName = this.definition.config?.skill;
|
|
2575
|
-
if (!skillName) {
|
|
2576
|
-
throw new Error("Skill name is required. Please specify config.skill in the node definition.");
|
|
2577
|
-
}
|
|
2578
|
-
const skill = this.skillRegistry.getSkill(skillName);
|
|
2579
|
-
if (!skill) {
|
|
2580
|
-
throw new Error(`Skill not found: ${skillName}`);
|
|
2581
|
-
}
|
|
2582
|
-
const input = this.definition.config?.input ?? {};
|
|
2583
|
-
const resolvedInput = this.resolveTemplateReferences(input, context2.previousOutputs, context2.input);
|
|
2584
|
-
const skillContext = {
|
|
2585
|
-
runId: context2.runId,
|
|
2586
|
-
workflowName: context2.workflowName,
|
|
2587
|
-
nodeId: context2.nodeId,
|
|
2588
|
-
debug: context2.debug
|
|
2589
|
-
};
|
|
2590
|
-
const output = await skill.invoke(resolvedInput, skillContext);
|
|
2591
|
-
return {
|
|
2592
|
-
output,
|
|
2593
|
-
error: undefined,
|
|
2594
|
-
durationMs: Date.now() - startTime
|
|
2595
|
-
};
|
|
2596
|
-
} catch (error) {
|
|
2597
|
-
return {
|
|
2598
|
-
output: undefined,
|
|
2599
|
-
error: error instanceof Error ? error : new Error(String(error)),
|
|
2600
|
-
durationMs: Date.now() - startTime
|
|
2601
|
-
};
|
|
2602
|
-
}
|
|
2603
|
-
}
|
|
2604
|
-
resolveTemplateReferences(input, previousOutputs, workflowInput) {
|
|
2605
|
-
if (typeof input === "string") {
|
|
2606
|
-
const pureTemplate = this.extractPureTemplate(input);
|
|
2607
|
-
if (pureTemplate) {
|
|
2608
|
-
return this.resolvePureTemplate(pureTemplate, previousOutputs, workflowInput);
|
|
2609
|
-
}
|
|
2610
|
-
return this.resolveStringTemplate(input, previousOutputs, workflowInput);
|
|
2611
|
-
}
|
|
2612
|
-
if (Array.isArray(input)) {
|
|
2613
|
-
return input.map((item) => this.resolveTemplateReferences(item, previousOutputs, workflowInput));
|
|
2614
|
-
}
|
|
2615
|
-
if (input !== null && typeof input === "object") {
|
|
2616
|
-
const resolved = {};
|
|
2617
|
-
for (const [key, value] of Object.entries(input)) {
|
|
2618
|
-
resolved[key] = this.resolveTemplateReferences(value, previousOutputs, workflowInput);
|
|
2619
|
-
}
|
|
2620
|
-
return resolved;
|
|
2621
|
-
}
|
|
2622
|
-
return input;
|
|
2623
|
-
}
|
|
2624
|
-
extractPureTemplate(str) {
|
|
2625
|
-
const trimmed = str.trim();
|
|
2626
|
-
if (trimmed.startsWith("{{") && trimmed.endsWith("}}") && trimmed.length > 4) {
|
|
2627
|
-
const content = trimmed.slice(2, -2).trim();
|
|
2628
|
-
if (!content.includes("{{") && !content.includes("}}")) {
|
|
2629
|
-
return content;
|
|
2630
|
-
}
|
|
2631
|
-
}
|
|
2632
|
-
return null;
|
|
2633
|
-
}
|
|
2634
|
-
resolvePureTemplate(templateContent, previousOutputs, workflowInput) {
|
|
2635
|
-
const trimmed = templateContent.trim();
|
|
2636
|
-
const originalTemplate = `{{${templateContent}}}`;
|
|
2637
|
-
if (trimmed.startsWith("input.")) {
|
|
2638
|
-
const value = this.getNestedValue(workflowInput, trimmed.slice(6));
|
|
2639
|
-
return value !== undefined ? value : originalTemplate;
|
|
2640
|
-
}
|
|
2641
|
-
if (trimmed.startsWith("nodes.")) {
|
|
2642
|
-
const path = trimmed.slice(6);
|
|
2643
|
-
const segments = path.split(".");
|
|
2644
|
-
const nodeId = segments[0];
|
|
2645
|
-
const restPath = segments.slice(1).join(".") || undefined;
|
|
2646
|
-
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
2647
|
-
return value !== undefined ? value : originalTemplate;
|
|
2648
|
-
}
|
|
2649
|
-
if (trimmed !== "input" && trimmed !== "nodes") {
|
|
2650
|
-
const segments = trimmed.split(".");
|
|
2651
|
-
const nodeId = segments[0];
|
|
2652
|
-
const restPath = segments.slice(1).join(".") || undefined;
|
|
2653
|
-
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
2654
|
-
return value !== undefined ? value : originalTemplate;
|
|
2655
|
-
}
|
|
2656
|
-
return originalTemplate;
|
|
2657
|
-
}
|
|
2658
|
-
resolveStringTemplate(template, previousOutputs, workflowInput) {
|
|
2659
|
-
let resolved = template;
|
|
2660
|
-
resolved = resolved.replace(/\{\{input\.([^}]+)\}\}/g, (match, path) => {
|
|
2661
|
-
const value = this.getNestedValue(workflowInput, path.trim());
|
|
2662
|
-
return this.stringifyValue(value, match);
|
|
2663
|
-
});
|
|
2664
|
-
resolved = resolved.replace(/\{\{([^:.{}][^}]*?)\}\}/g, (match, path) => {
|
|
2665
|
-
if (path.trim().startsWith("nodes.") || path.trim().startsWith("input.")) {
|
|
2666
|
-
return match;
|
|
2667
|
-
}
|
|
2668
|
-
const segments = path.trim().split(".");
|
|
2669
|
-
const nodeId = segments[0];
|
|
2670
|
-
const restPath = segments.slice(1).join(".") || undefined;
|
|
2671
|
-
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
2672
|
-
return this.stringifyValue(value, match);
|
|
2673
|
-
});
|
|
2674
|
-
resolved = resolved.replace(/\{\{nodes\.([^}]+)\}\}/g, (match, path) => {
|
|
2675
|
-
const segments = path.trim().split(".");
|
|
2676
|
-
const nodeId = segments[0];
|
|
2677
|
-
const restPath = segments.slice(1).join(".") || undefined;
|
|
2678
|
-
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
2679
|
-
return this.stringifyValue(value, match);
|
|
2680
|
-
});
|
|
2681
|
-
return resolved;
|
|
2682
|
-
}
|
|
2683
|
-
resolvePath(nodeId, path, previousOutputs) {
|
|
2684
|
-
let nodeOutput = previousOutputs.get(nodeId);
|
|
2685
|
-
if (nodeOutput === undefined) {
|
|
2686
|
-
const normalizedUnderscore = nodeId.replace(/-/g, "_");
|
|
2687
|
-
const normalizedHyphen = nodeId.replace(/_/g, "-");
|
|
2688
|
-
if (normalizedUnderscore !== nodeId) {
|
|
2689
|
-
nodeOutput = previousOutputs.get(normalizedUnderscore);
|
|
2690
|
-
}
|
|
2691
|
-
if (nodeOutput === undefined && normalizedHyphen !== nodeId) {
|
|
2692
|
-
nodeOutput = previousOutputs.get(normalizedHyphen);
|
|
2693
|
-
}
|
|
2694
|
-
}
|
|
2695
|
-
if (nodeOutput === undefined) {
|
|
2696
|
-
return;
|
|
2697
|
-
}
|
|
2698
|
-
let value = this.extractFromWrapper(nodeOutput);
|
|
2699
|
-
if (!path) {
|
|
2700
|
-
return value;
|
|
2701
|
-
}
|
|
2702
|
-
let segments = path.split(".");
|
|
2703
|
-
if (segments.length > 1 && (segments[0] === "output" || segments[0] === "result" || segments[0] === "metadata")) {
|
|
2704
|
-
segments = segments.slice(1);
|
|
2705
|
-
}
|
|
2706
|
-
let current = value;
|
|
2707
|
-
for (const segment of segments) {
|
|
2708
|
-
if (current === null || current === undefined) {
|
|
2709
|
-
return;
|
|
2710
|
-
}
|
|
2711
|
-
current = current[segment];
|
|
2712
|
-
}
|
|
2713
|
-
return current;
|
|
2714
|
-
}
|
|
2715
|
-
extractFromWrapper(value) {
|
|
2716
|
-
if (value === null || value === undefined) {
|
|
2717
|
-
return value;
|
|
2718
|
-
}
|
|
2719
|
-
if (typeof value !== "object") {
|
|
2720
|
-
return value;
|
|
2721
|
-
}
|
|
2722
|
-
if ("result" in value && "metadata" in value) {
|
|
2723
|
-
return value.result;
|
|
2724
|
-
}
|
|
2725
|
-
if ("output" in value) {
|
|
2726
|
-
return value.output;
|
|
2727
|
-
}
|
|
2728
|
-
return value;
|
|
2729
|
-
}
|
|
2730
|
-
getNestedValue(obj, path) {
|
|
2731
|
-
if (!obj) {
|
|
2732
|
-
return;
|
|
2733
|
-
}
|
|
2734
|
-
if ("input" in obj && path in obj["input"]) {
|
|
2735
|
-
return obj["input"][path];
|
|
2736
|
-
}
|
|
2737
|
-
return path.split(".").reduce((current, key) => {
|
|
2738
|
-
if (current && typeof current === "object") {
|
|
2739
|
-
return current[key];
|
|
2740
|
-
}
|
|
2741
|
-
return;
|
|
2742
|
-
}, obj);
|
|
2743
|
-
}
|
|
2744
|
-
stringifyValue(value, originalTemplate) {
|
|
2745
|
-
if (value === undefined) {
|
|
2746
|
-
return originalTemplate;
|
|
2747
|
-
}
|
|
2748
|
-
if (value === null) {
|
|
2749
|
-
return "null";
|
|
2750
|
-
}
|
|
2751
|
-
if (typeof value === "string") {
|
|
2752
|
-
return value;
|
|
2753
|
-
}
|
|
2754
|
-
return JSON.stringify(value);
|
|
2755
|
-
}
|
|
2756
|
-
}
|
|
2757
|
-
|
|
2758
|
-
// packages/core/src/env/workflow/nodes/agent-node.ts
|
|
2759
|
-
var AgentNode;
|
|
2760
|
-
var init_agent_node = __esm(() => {
|
|
2761
|
-
init_workflow_hil();
|
|
2762
|
-
init_decorator();
|
|
2763
|
-
AgentNode = class AgentNode {
|
|
2764
|
-
definition;
|
|
2765
|
-
agentRunner;
|
|
2766
|
-
type = "agent";
|
|
2767
|
-
id;
|
|
2768
|
-
constructor(definition, agentRunner) {
|
|
2769
|
-
this.definition = definition;
|
|
2770
|
-
this.agentRunner = agentRunner;
|
|
2771
|
-
this.id = definition.id;
|
|
2772
|
-
}
|
|
2773
|
-
async execute(context2) {
|
|
2774
|
-
const startTime = Date.now();
|
|
2775
|
-
try {
|
|
2776
|
-
const config = this.definition.config || {};
|
|
2777
|
-
const agentType = config.agent_type || "general";
|
|
2778
|
-
const promptTemplate = config.prompt || "";
|
|
2779
|
-
const options = config.options || {};
|
|
2780
|
-
const resolvedPrompt = this.resolveTemplate(promptTemplate, context2);
|
|
2781
|
-
if (this.agentRunner.registerAgent && this.agentRunner.hasAgent) {
|
|
2782
|
-
if (!this.agentRunner.hasAgent(agentType)) {
|
|
2783
|
-
this.agentRunner.registerAgent(agentType, {
|
|
2784
|
-
type: agentType,
|
|
2785
|
-
systemPrompt: config.system_prompt || `You are a ${agentType} agent.`,
|
|
2786
|
-
model: options.model
|
|
2787
|
-
});
|
|
2788
|
-
}
|
|
2789
|
-
}
|
|
2790
|
-
const userResponse = context2.userResponse;
|
|
2791
|
-
let agentSessionId = context2.agentSessionId;
|
|
2792
|
-
if (!userResponse && context2.sessionComponent && !agentSessionId) {
|
|
2793
|
-
agentSessionId = await this.createAgentSubSession(context2);
|
|
2794
|
-
context2.agentSessionId = agentSessionId;
|
|
2795
|
-
}
|
|
2796
|
-
const agentConfig = {
|
|
2797
|
-
type: agentType,
|
|
2798
|
-
prompt: resolvedPrompt,
|
|
2799
|
-
options: {
|
|
2800
|
-
timeout: options.timeout,
|
|
2801
|
-
model: options.model,
|
|
2802
|
-
allowedTools: ["ask_user"]
|
|
2803
|
-
},
|
|
2804
|
-
workflowHistory: context2.workflowHistory,
|
|
2805
|
-
nodeId: this.definition.id,
|
|
2806
|
-
agentSessionId
|
|
2807
|
-
};
|
|
2808
|
-
const resumeOptions = userResponse ? { userResponse, agentSessionId } : undefined;
|
|
2809
|
-
const result = await this.agentRunner.run(agentConfig, resumeOptions);
|
|
2810
|
-
const duration = Date.now() - startTime;
|
|
2811
|
-
return {
|
|
2812
|
-
output: {
|
|
2813
|
-
result: result.output,
|
|
2814
|
-
metadata: result.metadata,
|
|
2815
|
-
workflowHistory: result.messages
|
|
2816
|
-
},
|
|
2817
|
-
error: undefined,
|
|
2818
|
-
duration
|
|
2819
|
-
};
|
|
2820
|
-
} catch (error) {
|
|
2821
|
-
if (error instanceof AskUserError) {
|
|
2822
|
-
const contextAgentSessionId = context2.agentSessionId;
|
|
2823
|
-
if (contextAgentSessionId && !error.agentSessionId) {
|
|
2824
|
-
throw new AskUserError(error.runId, error.sessionId, error.nodeId, error.nodeType, error.query, contextAgentSessionId, error.timestamp);
|
|
2825
|
-
}
|
|
2826
|
-
throw error;
|
|
2827
|
-
}
|
|
2828
|
-
const duration = Date.now() - startTime;
|
|
2829
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2830
|
-
return {
|
|
2831
|
-
output: undefined,
|
|
2832
|
-
error: errorMessage,
|
|
2833
|
-
duration
|
|
2834
|
-
};
|
|
2835
|
-
}
|
|
2836
|
-
}
|
|
2837
|
-
async createAgentSubSession(context2) {
|
|
2838
|
-
const sessionComponent = context2.sessionComponent;
|
|
2839
|
-
if (!sessionComponent) {
|
|
2840
|
-
return "";
|
|
2841
|
-
}
|
|
2842
|
-
const agentSessionId = `agent_${this.definition.id}_${Date.now()}`;
|
|
2843
|
-
await sessionComponent.create({
|
|
2844
|
-
id: agentSessionId,
|
|
2845
|
-
title: `Agent: ${this.definition.id}`,
|
|
2846
|
-
metadata: {
|
|
2847
|
-
type: "agent",
|
|
2848
|
-
parentSessionId: context2.sessionId,
|
|
2849
|
-
nodeId: this.definition.id,
|
|
2850
|
-
workflowName: context2.workflowName
|
|
2851
|
-
}
|
|
2852
|
-
});
|
|
2853
|
-
const workflowSession = await sessionComponent.get(context2.sessionId);
|
|
2854
|
-
if (workflowSession) {
|
|
2855
|
-
const metadata = workflowSession.metadata || {};
|
|
2856
|
-
const agentSessions = metadata.agentSessions || [];
|
|
2857
|
-
const existingIndex = agentSessions.findIndex((s) => s.nodeId === this.definition.id);
|
|
2858
|
-
if (existingIndex >= 0) {
|
|
2859
|
-
agentSessions[existingIndex] = {
|
|
2860
|
-
nodeId: this.definition.id,
|
|
2861
|
-
sessionId: agentSessionId,
|
|
2862
|
-
status: "active",
|
|
2863
|
-
createdAt: Date.now()
|
|
2864
|
-
};
|
|
2865
|
-
} else {
|
|
2866
|
-
agentSessions.push({
|
|
2867
|
-
nodeId: this.definition.id,
|
|
2868
|
-
sessionId: agentSessionId,
|
|
2869
|
-
status: "active",
|
|
2870
|
-
createdAt: Date.now()
|
|
2871
|
-
});
|
|
2872
|
-
}
|
|
2873
|
-
await sessionComponent.update(context2.sessionId, {
|
|
2874
|
-
metadata: {
|
|
2875
|
-
...metadata,
|
|
2876
|
-
agentSessions
|
|
2877
|
-
}
|
|
2878
|
-
});
|
|
2879
|
-
}
|
|
2880
|
-
return agentSessionId;
|
|
2881
|
-
}
|
|
2882
|
-
resolveTemplate(template, context2) {
|
|
2883
|
-
if (!template) {
|
|
2884
|
-
return "";
|
|
2885
|
-
}
|
|
2886
|
-
let resolved = template;
|
|
2887
|
-
resolved = resolved.replace(/\{\{input\.([^}]+)\}\}/g, (match, path) => {
|
|
2888
|
-
const value = this.getNestedValue(context2.input, path);
|
|
2889
|
-
return this.stringifyValue(value, match);
|
|
2890
|
-
});
|
|
2891
|
-
resolved = resolved.replace(/\{\{nodes\.([^}]+)\}\}/g, (match, path) => {
|
|
2892
|
-
const segments = path.split(".");
|
|
2893
|
-
const nodeId = segments[0];
|
|
2894
|
-
let nodeOutput = context2.previousOutputs.get(nodeId);
|
|
2895
|
-
if (nodeOutput === undefined) {
|
|
2896
|
-
const normalizedUnderscore = nodeId.replace(/-/g, "_");
|
|
2897
|
-
const normalizedHyphen = nodeId.replace(/_/g, "-");
|
|
2898
|
-
if (normalizedUnderscore !== nodeId) {
|
|
2899
|
-
nodeOutput = context2.previousOutputs.get(normalizedUnderscore);
|
|
2900
|
-
}
|
|
2901
|
-
if (nodeOutput === undefined && normalizedHyphen !== nodeId) {
|
|
2902
|
-
nodeOutput = context2.previousOutputs.get(normalizedHyphen);
|
|
2903
|
-
}
|
|
2904
|
-
}
|
|
2905
|
-
if (nodeOutput === undefined) {
|
|
2906
|
-
return match;
|
|
2907
|
-
}
|
|
2908
|
-
nodeOutput = this.extractFromWrapper(nodeOutput);
|
|
2909
|
-
if (segments.length === 1) {
|
|
2910
|
-
return this.stringifyValue(nodeOutput, match);
|
|
2911
|
-
}
|
|
2912
|
-
let value = nodeOutput;
|
|
2913
|
-
let startIndex = 1;
|
|
2914
|
-
if (segments.length > 1 && (segments[1] === "output" || segments[1] === "result" || segments[1] === "metadata")) {
|
|
2915
|
-
startIndex = 2;
|
|
2916
|
-
}
|
|
2917
|
-
for (let i = startIndex;i < segments.length; i++) {
|
|
2918
|
-
if (value === null || value === undefined) {
|
|
2919
|
-
return match;
|
|
2920
|
-
}
|
|
2921
|
-
value = value[segments[i]];
|
|
2922
|
-
}
|
|
2923
|
-
return this.stringifyValue(value, match);
|
|
2924
|
-
});
|
|
2925
|
-
resolved = resolved.replace(/\{\{([^}]+)\}\}/g, (match, path) => {
|
|
2926
|
-
if (path.startsWith("input.") || path.startsWith("nodes.")) {
|
|
2927
|
-
return match;
|
|
2928
|
-
}
|
|
2929
|
-
const segments = path.split(".");
|
|
2930
|
-
const nodeId = segments[0];
|
|
2931
|
-
let nodeOutput = context2.previousOutputs.get(nodeId);
|
|
2932
|
-
if (nodeOutput === undefined) {
|
|
2933
|
-
const normalizedUnderscore = nodeId.replace(/-/g, "_");
|
|
2934
|
-
const normalizedHyphen = nodeId.replace(/_/g, "-");
|
|
2935
|
-
if (normalizedUnderscore !== nodeId) {
|
|
2936
|
-
nodeOutput = context2.previousOutputs.get(normalizedUnderscore);
|
|
2937
|
-
}
|
|
2938
|
-
if (nodeOutput === undefined && normalizedHyphen !== nodeId) {
|
|
2939
|
-
nodeOutput = context2.previousOutputs.get(normalizedHyphen);
|
|
2940
|
-
}
|
|
2941
|
-
}
|
|
2942
|
-
if (nodeOutput === undefined) {
|
|
2943
|
-
return match;
|
|
2944
|
-
}
|
|
2945
|
-
nodeOutput = this.extractFromWrapper(nodeOutput);
|
|
2946
|
-
if (segments.length === 1) {
|
|
2947
|
-
return this.stringifyValue(nodeOutput, match);
|
|
2948
|
-
}
|
|
2949
|
-
let value = nodeOutput;
|
|
2950
|
-
let startIndex = 1;
|
|
2951
|
-
if (segments.length > 1 && (segments[1] === "output" || segments[1] === "result" || segments[1] === "metadata")) {
|
|
2952
|
-
startIndex = 2;
|
|
2953
|
-
}
|
|
2954
|
-
for (let i = startIndex;i < segments.length; i++) {
|
|
2955
|
-
if (value === null || value === undefined) {
|
|
2956
|
-
return match;
|
|
2957
|
-
}
|
|
2958
|
-
value = value[segments[i]];
|
|
2959
|
-
}
|
|
2960
|
-
return this.stringifyValue(value, match);
|
|
2961
|
-
});
|
|
2962
|
-
return resolved;
|
|
2963
|
-
}
|
|
2964
|
-
stringifyValue(value, originalTemplate) {
|
|
2965
|
-
if (value === undefined) {
|
|
2966
|
-
return originalTemplate;
|
|
2967
|
-
}
|
|
2968
|
-
if (value === null) {
|
|
2969
|
-
return "null";
|
|
2970
|
-
}
|
|
2971
|
-
if (typeof value === "string") {
|
|
2972
|
-
return value;
|
|
2973
|
-
}
|
|
2974
|
-
return JSON.stringify(value);
|
|
2975
|
-
}
|
|
2976
|
-
extractFromWrapper(value) {
|
|
2977
|
-
if (value === null || value === undefined) {
|
|
2978
|
-
return value;
|
|
2979
|
-
}
|
|
2980
|
-
if (typeof value !== "object") {
|
|
2981
|
-
return value;
|
|
2982
|
-
}
|
|
2983
|
-
if ("result" in value && "metadata" in value) {
|
|
2984
|
-
return value.result;
|
|
2985
|
-
}
|
|
2986
|
-
if ("output" in value) {
|
|
2987
|
-
return value.output;
|
|
2988
|
-
}
|
|
2989
|
-
return value;
|
|
2990
|
-
}
|
|
2991
|
-
getNestedValue(obj, path) {
|
|
2992
|
-
if (!obj) {
|
|
2993
|
-
return;
|
|
2994
|
-
}
|
|
2995
|
-
if ("input" in obj && path in obj["input"]) {
|
|
2996
|
-
return obj["input"][path];
|
|
2997
|
-
}
|
|
2998
|
-
return path.split(".").reduce((current, key) => {
|
|
2999
|
-
if (current && typeof current === "object") {
|
|
3000
|
-
return current[key];
|
|
3001
|
-
}
|
|
3002
|
-
return;
|
|
3003
|
-
}, obj);
|
|
3004
|
-
}
|
|
3005
|
-
};
|
|
3006
|
-
__legacyDecorateClassTS([
|
|
3007
|
-
TracedAs("agent.node.execute", { recordParams: true, recordResult: true, log: true })
|
|
3008
|
-
], AgentNode.prototype, "execute", null);
|
|
3009
|
-
__legacyDecorateClassTS([
|
|
3010
|
-
TracedAs("agent.node.createAgentSubSession", { recordParams: true, recordResult: true, log: true })
|
|
3011
|
-
], AgentNode.prototype, "createAgentSubSession", null);
|
|
3012
|
-
});
|
|
3013
|
-
|
|
3014
|
-
// packages/core/src/env/workflow/nodes/agent-component-adapter.ts
|
|
3015
|
-
var exports_agent_component_adapter = {};
|
|
3016
|
-
__export(exports_agent_component_adapter, {
|
|
3017
|
-
AgentComponentAdapter: () => AgentComponentAdapter
|
|
3018
|
-
});
|
|
3019
|
-
|
|
3020
|
-
class AgentComponentAdapter {
|
|
3021
|
-
agentComponent;
|
|
3022
|
-
options;
|
|
3023
|
-
_sessionComponent;
|
|
3024
|
-
agentSessionPrefix = "agent";
|
|
3025
|
-
_currentAgentSessionId;
|
|
3026
|
-
pendingSessions = new Map;
|
|
3027
|
-
runSessionToAgentSessions = new Map;
|
|
3028
|
-
constructor(agentComponent, options = {}, _sessionComponent) {
|
|
3029
|
-
this.agentComponent = agentComponent;
|
|
3030
|
-
this.options = options;
|
|
3031
|
-
this._sessionComponent = _sessionComponent;
|
|
3032
|
-
}
|
|
3033
|
-
setSessionComponent(sessionComponent) {
|
|
3034
|
-
this._sessionComponent = sessionComponent;
|
|
3035
|
-
}
|
|
3036
|
-
getCurrentAgentSessionId() {
|
|
3037
|
-
return this._currentAgentSessionId;
|
|
3038
|
-
}
|
|
3039
|
-
registerAgent(name, config) {
|
|
3040
|
-
this.agentComponent.registerAgent(name, {
|
|
3041
|
-
type: config.type || "general",
|
|
3042
|
-
model: config.model,
|
|
3043
|
-
systemPrompt: config.systemPrompt,
|
|
3044
|
-
maxIterations: config.maxIterations,
|
|
3045
|
-
allowedTools: config.allowedTools,
|
|
3046
|
-
deniedTools: config.deniedTools,
|
|
3047
|
-
timeout: config.timeout,
|
|
3048
|
-
maxErrorRetries: config.maxErrorRetries
|
|
3049
|
-
});
|
|
3050
|
-
if (config.sessionIdPrefix) {
|
|
3051
|
-
this.agentSessionPrefixes.set(name, config.sessionIdPrefix);
|
|
3052
|
-
}
|
|
3053
|
-
}
|
|
3054
|
-
async run(config, resumeOptions) {
|
|
3055
|
-
const startTime = Date.now();
|
|
3056
|
-
const nodeId = config.nodeId || "unknown";
|
|
3057
|
-
const runId = config.runId || "unknown";
|
|
3058
|
-
const workflowSessionId = config.workflowSessionId;
|
|
3059
|
-
const existingAgentSessionId = config.agentSessionId;
|
|
3060
|
-
const resumeAgentSessionId = resumeOptions?.agentSessionId;
|
|
3061
|
-
const isResume = !!resumeOptions?.userResponse || !!existingAgentSessionId || !!resumeAgentSessionId;
|
|
3062
|
-
let agentSessionId;
|
|
3063
|
-
if (isResume && (this._currentAgentSessionId || existingAgentSessionId || resumeAgentSessionId)) {
|
|
3064
|
-
agentSessionId = resumeAgentSessionId || existingAgentSessionId || this._currentAgentSessionId;
|
|
3065
|
-
if (resumeOptions?.userResponse && this._sessionComponent && agentSessionId) {
|
|
3066
|
-
try {
|
|
3067
|
-
await this._sessionComponent.addMessage(agentSessionId, {
|
|
3068
|
-
role: "user",
|
|
3069
|
-
content: resumeOptions.userResponse,
|
|
3070
|
-
metadata: {
|
|
3071
|
-
type: "user_intent",
|
|
3072
|
-
intent: "workflow.resume",
|
|
3073
|
-
workflowNodeId: nodeId
|
|
3074
|
-
}
|
|
3075
|
-
});
|
|
3076
|
-
} catch (error) {
|
|
3077
|
-
console.warn(`Failed to add user response to agent session ${agentSessionId}:`, error);
|
|
3078
|
-
}
|
|
3079
|
-
}
|
|
3080
|
-
} else {
|
|
3081
|
-
if (this._sessionComponent) {
|
|
3082
|
-
agentSessionId = `${this.agentSessionPrefix}_${runId}_${nodeId}_${Date.now()}`;
|
|
3083
|
-
try {
|
|
3084
|
-
await this._sessionComponent.create({
|
|
3085
|
-
title: `Agent Session: ${config.type} (${agentSessionId})`,
|
|
3086
|
-
metadata: {
|
|
3087
|
-
type: "agent",
|
|
3088
|
-
workflowRunId: runId,
|
|
3089
|
-
workflowNodeId: nodeId
|
|
3090
|
-
}
|
|
3091
|
-
});
|
|
3092
|
-
this._currentAgentSessionId = agentSessionId;
|
|
3093
|
-
if (workflowSessionId) {
|
|
3094
|
-
const mapping = this.runSessionToAgentSessions.get(workflowSessionId) || [];
|
|
3095
|
-
mapping.push(agentSessionId);
|
|
3096
|
-
this.runSessionToAgentSessions.set(workflowSessionId, mapping);
|
|
3097
|
-
}
|
|
3098
|
-
this.pendingSessions.set(agentSessionId, {
|
|
3099
|
-
agentSessionId,
|
|
3100
|
-
nodeId,
|
|
3101
|
-
runId,
|
|
3102
|
-
createdAt: Date.now()
|
|
3103
|
-
});
|
|
3104
|
-
} catch (error) {
|
|
3105
|
-
console.warn(`Failed to create agent session ${agentSessionId}:`, error);
|
|
3106
|
-
}
|
|
3107
|
-
}
|
|
3108
|
-
}
|
|
3109
|
-
try {
|
|
3110
|
-
const context2 = {};
|
|
3111
|
-
if (config.options?.timeout) {
|
|
3112
|
-
context2.abort = new AbortController;
|
|
3113
|
-
}
|
|
3114
|
-
if (agentSessionId) {
|
|
3115
|
-
context2.sessionId = agentSessionId;
|
|
3116
|
-
}
|
|
3117
|
-
if (config.options?.allowedTools) {
|
|
3118
|
-
context2.allowedTools = config.options.allowedTools;
|
|
3119
|
-
}
|
|
3120
|
-
if (config.options?.deniedTools) {
|
|
3121
|
-
context2.deniedTools = config.options.deniedTools;
|
|
3122
|
-
}
|
|
3123
|
-
if (config.workflowHistory) {
|
|
3124
|
-
context2.workflowHistory = config.workflowHistory;
|
|
3125
|
-
}
|
|
3126
|
-
const result = await this.agentComponent.run(config.type || "general", config.prompt, context2);
|
|
3127
|
-
if (result.error?.startsWith("__ASK_USER_ERROR__:")) {
|
|
3128
|
-
const jsonStr = result.error.substring("__ASK_USER_ERROR__:".length);
|
|
3129
|
-
const errorInfo = JSON.parse(jsonStr);
|
|
3130
|
-
throw new AskUserError(runId, errorInfo.sessionId, errorInfo.nodeId, errorInfo.nodeType || "agent", errorInfo.query);
|
|
3131
|
-
}
|
|
3132
|
-
const duration = Date.now() - startTime;
|
|
3133
|
-
if (agentSessionId) {
|
|
3134
|
-
this.pendingSessions.delete(agentSessionId);
|
|
3135
|
-
}
|
|
3136
|
-
const messages = result._messages || [];
|
|
3137
|
-
return {
|
|
3138
|
-
output: result.finalText || result.output,
|
|
3139
|
-
metadata: {
|
|
3140
|
-
duration,
|
|
3141
|
-
iterations: result.iterations,
|
|
3142
|
-
toolCalls: result.toolCalls?.length,
|
|
3143
|
-
agentSessionId
|
|
3144
|
-
},
|
|
3145
|
-
messages
|
|
3146
|
-
};
|
|
3147
|
-
} catch (error) {
|
|
3148
|
-
const isAskUserError = error instanceof Error && error.name === "AskUserError";
|
|
3149
|
-
if (isAskUserError) {
|
|
3150
|
-
throw error;
|
|
3151
|
-
}
|
|
3152
|
-
const duration = Date.now() - startTime;
|
|
3153
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3154
|
-
if (agentSessionId) {
|
|
3155
|
-
this.pendingSessions.delete(agentSessionId);
|
|
3156
|
-
}
|
|
3157
|
-
return {
|
|
3158
|
-
output: undefined,
|
|
3159
|
-
metadata: {
|
|
3160
|
-
duration,
|
|
3161
|
-
error: errorMessage,
|
|
3162
|
-
agentSessionId
|
|
3163
|
-
}
|
|
3164
|
-
};
|
|
3165
|
-
} finally {
|
|
3166
|
-
if (!isResume) {
|
|
3167
|
-
this._currentAgentSessionId = undefined;
|
|
3168
|
-
}
|
|
3169
|
-
}
|
|
3170
|
-
}
|
|
3171
|
-
async resumeAgent(agentSessionId, userResponse, config) {
|
|
3172
|
-
if (this._sessionComponent) {
|
|
3173
|
-
try {
|
|
3174
|
-
await this._sessionComponent.addMessage(agentSessionId, {
|
|
3175
|
-
role: "user",
|
|
3176
|
-
content: userResponse,
|
|
3177
|
-
metadata: {
|
|
3178
|
-
type: "user_intent",
|
|
3179
|
-
intent: "workflow.resume"
|
|
3180
|
-
}
|
|
3181
|
-
});
|
|
3182
|
-
this.pendingSessions.delete(agentSessionId);
|
|
3183
|
-
this._currentAgentSessionId = agentSessionId;
|
|
3184
|
-
} catch (error) {
|
|
3185
|
-
console.warn(`Failed to add user response to agent session ${agentSessionId}:`, error);
|
|
3186
|
-
}
|
|
3187
|
-
}
|
|
3188
|
-
config.agentSessionId = agentSessionId;
|
|
3189
|
-
return this.run(config, { userResponse });
|
|
3190
|
-
}
|
|
3191
|
-
getPendingSession(agentSessionId) {
|
|
3192
|
-
return this.pendingSessions.get(agentSessionId);
|
|
3193
|
-
}
|
|
3194
|
-
getPendingSessionsForRun(runId) {
|
|
3195
|
-
return Array.from(this.pendingSessions.values()).filter((session) => session.runId === runId);
|
|
3196
|
-
}
|
|
3197
|
-
getAgentSessionsForWorkflowSession(workflowSessionId) {
|
|
3198
|
-
return this.runSessionToAgentSessions.get(workflowSessionId) || [];
|
|
3199
|
-
}
|
|
3200
|
-
hasAgent(name) {
|
|
3201
|
-
return this.agentComponent.getAgent(name) !== undefined;
|
|
3202
|
-
}
|
|
3203
|
-
listAgents() {
|
|
3204
|
-
return this.agentComponent.listAgents().map((a) => a.name);
|
|
3205
|
-
}
|
|
3206
|
-
getAgentComponent() {
|
|
3207
|
-
return this.agentComponent;
|
|
3208
|
-
}
|
|
3209
|
-
agentSessionPrefixes = new Map;
|
|
3210
|
-
}
|
|
3211
|
-
var init_agent_component_adapter = __esm(() => {
|
|
3212
|
-
init_workflow_hil();
|
|
3213
|
-
});
|
|
3214
|
-
|
|
3215
|
-
// packages/core/src/env/workflow/nodes/workflow-node.ts
|
|
3216
|
-
class WorkflowNode {
|
|
3217
|
-
workflowRunner;
|
|
3218
|
-
type = "workflow";
|
|
3219
|
-
id;
|
|
3220
|
-
config;
|
|
3221
|
-
constructor(definition, workflowRunner) {
|
|
3222
|
-
this.workflowRunner = workflowRunner;
|
|
3223
|
-
this.id = definition.id;
|
|
3224
|
-
this.config = definition.config ?? {};
|
|
3225
|
-
}
|
|
3226
|
-
async execute(context2) {
|
|
3227
|
-
const startTime = Date.now();
|
|
3228
|
-
try {
|
|
3229
|
-
const workflowName = this.config.workflow_name;
|
|
3230
|
-
if (!workflowName) {
|
|
3231
|
-
throw new Error("workflow_name is required in config. Please specify config.workflow_name in the node definition.");
|
|
3232
|
-
}
|
|
3233
|
-
const previousOutputs = context2.previousOutputs ?? this.convertToMap(context2.nodeOutputs ?? {});
|
|
3234
|
-
const resolvedInput = this.resolveInput(this.config.input ?? {}, previousOutputs);
|
|
3235
|
-
const result = await this.workflowRunner.run(workflowName, resolvedInput);
|
|
3236
|
-
const success = result.status === "completed";
|
|
3237
|
-
return {
|
|
3238
|
-
success,
|
|
3239
|
-
output: result.output,
|
|
3240
|
-
error: success ? undefined : result.error,
|
|
3241
|
-
duration: Date.now() - startTime
|
|
3242
|
-
};
|
|
3243
|
-
} catch (error) {
|
|
3244
|
-
return {
|
|
3245
|
-
success: false,
|
|
3246
|
-
output: undefined,
|
|
3247
|
-
error: error instanceof Error ? error : new Error(String(error)),
|
|
3248
|
-
duration: Date.now() - startTime
|
|
3249
|
-
};
|
|
3250
|
-
}
|
|
3251
|
-
}
|
|
3252
|
-
convertToMap(nodeOutputs) {
|
|
3253
|
-
const map = new Map;
|
|
3254
|
-
for (const [nodeId, result] of Object.entries(nodeOutputs)) {
|
|
3255
|
-
map.set(nodeId, result.output);
|
|
3256
|
-
}
|
|
3257
|
-
return map;
|
|
3258
|
-
}
|
|
3259
|
-
resolveInput(input, previousOutputs) {
|
|
3260
|
-
const resolved = {};
|
|
3261
|
-
for (const [key, value] of Object.entries(input)) {
|
|
3262
|
-
resolved[key] = this.resolveValue(value, previousOutputs);
|
|
3263
|
-
}
|
|
3264
|
-
return resolved;
|
|
3265
|
-
}
|
|
3266
|
-
resolveValue(value, previousOutputs) {
|
|
3267
|
-
if (typeof value === "string") {
|
|
3268
|
-
return this.resolveStringTemplate(value, previousOutputs);
|
|
3269
|
-
}
|
|
3270
|
-
if (Array.isArray(value)) {
|
|
3271
|
-
return value.map((item) => this.resolveValue(item, previousOutputs));
|
|
3272
|
-
}
|
|
3273
|
-
if (value !== null && typeof value === "object") {
|
|
3274
|
-
const resolved = {};
|
|
3275
|
-
for (const [k, v] of Object.entries(value)) {
|
|
3276
|
-
resolved[k] = this.resolveValue(v, previousOutputs);
|
|
3277
|
-
}
|
|
3278
|
-
return resolved;
|
|
3279
|
-
}
|
|
3280
|
-
return value;
|
|
3281
|
-
}
|
|
3282
|
-
resolveStringTemplate(template, previousOutputs) {
|
|
3283
|
-
const templatePattern = /\{\{([^}]+)\}\}/g;
|
|
3284
|
-
return template.replace(templatePattern, (match, path) => {
|
|
3285
|
-
const trimmedPath = path.trim();
|
|
3286
|
-
const value = this.resolvePath(trimmedPath, previousOutputs);
|
|
3287
|
-
if (value !== undefined) {
|
|
3288
|
-
return this.stringifyValue(value, match);
|
|
3289
|
-
}
|
|
3290
|
-
return match;
|
|
3291
|
-
});
|
|
3292
|
-
}
|
|
3293
|
-
resolvePath(path, previousOutputs) {
|
|
3294
|
-
const segments = path.split(".");
|
|
3295
|
-
if (segments.length === 0) {
|
|
3296
|
-
return;
|
|
3297
|
-
}
|
|
3298
|
-
const nodeId = segments[0];
|
|
3299
|
-
let nodeOutput = previousOutputs.get(nodeId);
|
|
3300
|
-
if (nodeOutput === undefined) {
|
|
3301
|
-
return;
|
|
3302
|
-
}
|
|
3303
|
-
nodeOutput = this.extractFromWrapper(nodeOutput);
|
|
3304
|
-
if (segments.length === 1) {
|
|
3305
|
-
return nodeOutput;
|
|
3306
|
-
}
|
|
3307
|
-
let current = nodeOutput;
|
|
3308
|
-
let startIndex = 1;
|
|
3309
|
-
if (segments.length > 1 && (segments[1] === "output" || segments[1] === "result" || segments[1] === "metadata")) {
|
|
3310
|
-
startIndex = 2;
|
|
3311
|
-
}
|
|
3312
|
-
for (let i = startIndex;i < segments.length; i++) {
|
|
3313
|
-
if (current === null || current === undefined) {
|
|
3314
|
-
return;
|
|
3315
|
-
}
|
|
3316
|
-
current = current[segments[i]];
|
|
3317
|
-
}
|
|
3318
|
-
return current;
|
|
3319
|
-
}
|
|
3320
|
-
extractFromWrapper(value) {
|
|
3321
|
-
if (value === null || value === undefined) {
|
|
3322
|
-
return value;
|
|
3323
|
-
}
|
|
3324
|
-
if (typeof value !== "object") {
|
|
3325
|
-
return value;
|
|
3326
|
-
}
|
|
3327
|
-
if ("result" in value && "metadata" in value) {
|
|
3328
|
-
return value.result;
|
|
3329
|
-
}
|
|
3330
|
-
if ("output" in value) {
|
|
3331
|
-
return value.output;
|
|
3332
|
-
}
|
|
3333
|
-
return value;
|
|
3334
|
-
}
|
|
3335
|
-
stringifyValue(value, originalTemplate) {
|
|
3336
|
-
if (value === undefined) {
|
|
3337
|
-
return originalTemplate;
|
|
3338
|
-
}
|
|
3339
|
-
if (value === null) {
|
|
3340
|
-
return "null";
|
|
3341
|
-
}
|
|
3342
|
-
if (typeof value === "string") {
|
|
3343
|
-
return value;
|
|
3344
|
-
}
|
|
3345
|
-
return JSON.stringify(value);
|
|
3346
|
-
}
|
|
3347
|
-
}
|
|
3348
|
-
|
|
3349
|
-
// packages/core/src/env/workflow/nodes/ask-user-node.ts
|
|
3350
|
-
class AskUserNode {
|
|
3351
|
-
type = "ask_user";
|
|
3352
|
-
id;
|
|
3353
|
-
config;
|
|
3354
|
-
constructor(definition) {
|
|
3355
|
-
this.id = definition.id;
|
|
3356
|
-
this.config = definition.config || {};
|
|
3357
|
-
}
|
|
3358
|
-
async execute(context2) {
|
|
3359
|
-
const query = this.config.query || "\u786E\u8BA4\u7EE7\u7EED\u5417\uFF1F";
|
|
3360
|
-
const options = this.config.options;
|
|
3361
|
-
const fullQuery = options ? `${query} (\u9009\u9879: ${options.join(", ")})` : query;
|
|
3362
|
-
await context2.eventBus.publish(createNodeInterruptEvent(context2.runId, this.id, this.type, fullQuery));
|
|
3363
|
-
throw new AskUserError(context2.runId, context2.sessionId, this.id, this.type, query);
|
|
3364
|
-
}
|
|
3365
|
-
validateConfig(_config) {
|
|
3366
|
-
return true;
|
|
3367
|
-
}
|
|
3368
|
-
}
|
|
3369
|
-
var init_ask_user_node = __esm(() => {
|
|
3370
|
-
init_workflow_hil();
|
|
3371
|
-
});
|
|
3372
|
-
|
|
3373
|
-
// packages/core/src/env/workflow/engine/node-registry.ts
|
|
3374
|
-
class NodeRegistry {
|
|
3375
|
-
factories = new Map;
|
|
3376
|
-
toolRegistry;
|
|
3377
|
-
skillRegistry;
|
|
3378
|
-
agentRunner;
|
|
3379
|
-
workflowRunner;
|
|
3380
|
-
agentComponentAdapter;
|
|
3381
|
-
sessionComponent;
|
|
3382
|
-
constructor(options) {
|
|
3383
|
-
const {
|
|
3384
|
-
toolRegistry,
|
|
3385
|
-
skillRegistry,
|
|
3386
|
-
agentComponent,
|
|
3387
|
-
agentRunner,
|
|
3388
|
-
workflowRunner,
|
|
3389
|
-
sessionComponent
|
|
3390
|
-
} = options ?? {};
|
|
3391
|
-
this.toolRegistry = toolRegistry;
|
|
3392
|
-
this.skillRegistry = skillRegistry;
|
|
3393
|
-
this.workflowRunner = workflowRunner;
|
|
3394
|
-
this.sessionComponent = sessionComponent;
|
|
3395
|
-
if (agentRunner) {
|
|
3396
|
-
this.agentRunner = agentRunner;
|
|
3397
|
-
if (agentRunner.setSessionComponent && sessionComponent) {
|
|
3398
|
-
agentRunner.setSessionComponent(sessionComponent);
|
|
3399
|
-
}
|
|
3400
|
-
} else if (agentComponent) {
|
|
3401
|
-
this.agentComponentAdapter = new AgentComponentAdapter(agentComponent, {}, sessionComponent);
|
|
3402
|
-
this.agentRunner = this.agentComponentAdapter;
|
|
3403
|
-
}
|
|
3404
|
-
this.registerBuiltInTypes();
|
|
3405
|
-
}
|
|
3406
|
-
getAgentAdapter() {
|
|
3407
|
-
return this.agentComponentAdapter;
|
|
3408
|
-
}
|
|
3409
|
-
getAgentRunner() {
|
|
3410
|
-
return this.agentRunner;
|
|
3411
|
-
}
|
|
3412
|
-
getSessionComponent() {
|
|
3413
|
-
return this.sessionComponent;
|
|
3414
|
-
}
|
|
3415
|
-
registerBuiltInTypes() {
|
|
3416
|
-
this.factories.set("tool", (definition) => {
|
|
3417
|
-
if (!this.toolRegistry) {
|
|
3418
|
-
throw new Error("ToolRegistry is required for tool nodes");
|
|
3419
|
-
}
|
|
3420
|
-
return new ToolNode(definition, this.toolRegistry);
|
|
3421
|
-
});
|
|
3422
|
-
this.factories.set("skill", (definition) => {
|
|
3423
|
-
if (!this.skillRegistry) {
|
|
3424
|
-
throw new Error("SkillRegistry is required for skill nodes");
|
|
3425
|
-
}
|
|
3426
|
-
return new SkillNode(definition, this.skillRegistry);
|
|
3427
|
-
});
|
|
3428
|
-
this.factories.set("agent", (definition) => {
|
|
3429
|
-
if (!this.agentRunner) {
|
|
3430
|
-
throw new Error("AgentRunner is required for agent nodes");
|
|
3431
|
-
}
|
|
3432
|
-
return new AgentNode(definition, this.agentRunner);
|
|
3433
|
-
});
|
|
3434
|
-
this.factories.set("workflow", (definition) => {
|
|
3435
|
-
if (!this.workflowRunner) {
|
|
3436
|
-
throw new Error("WorkflowRunner is required for workflow nodes");
|
|
3437
|
-
}
|
|
3438
|
-
return new WorkflowNode(definition, this.workflowRunner);
|
|
3439
|
-
});
|
|
3440
|
-
this.factories.set("ask_user", (definition) => {
|
|
3441
|
-
return new AskUserNode(definition);
|
|
3442
|
-
});
|
|
3443
|
-
}
|
|
3444
|
-
register(type, factory) {
|
|
3445
|
-
this.factories.set(type, factory);
|
|
3446
|
-
}
|
|
3447
|
-
has(type) {
|
|
3448
|
-
return this.factories.has(type);
|
|
3449
|
-
}
|
|
3450
|
-
list() {
|
|
3451
|
-
return Array.from(this.factories.keys());
|
|
3452
|
-
}
|
|
3453
|
-
createNode(definition, context2) {
|
|
3454
|
-
const factory = this.factories.get(definition.type);
|
|
3455
|
-
if (!factory) {
|
|
3456
|
-
const availableTypes = this.list().join(", ");
|
|
3457
|
-
throw new Error(`Unknown node type: ${definition.type}. Available types: ${availableTypes}`);
|
|
3458
|
-
}
|
|
3459
|
-
return factory(definition, context2);
|
|
3460
|
-
}
|
|
3461
|
-
}
|
|
3462
|
-
var init_node_registry = __esm(() => {
|
|
3463
|
-
init_agent_node();
|
|
3464
|
-
init_agent_component_adapter();
|
|
3465
|
-
init_ask_user_node();
|
|
3466
|
-
});
|
|
3467
|
-
|
|
3468
|
-
// packages/core/src/env/workflow/utils/session-recovery.ts
|
|
3469
|
-
var exports_session_recovery = {};
|
|
3470
|
-
__export(exports_session_recovery, {
|
|
3471
|
-
parseNodeOutputs: () => parseNodeOutputs,
|
|
3472
|
-
inferNextNode: () => inferNextNode,
|
|
3473
|
-
hasPendingAskUser: () => hasPendingAskUser,
|
|
3474
|
-
getAgentSessionIdFromInterrupt: () => getAgentSessionIdFromInterrupt,
|
|
3475
|
-
findLastInterruptMessage: () => findLastInterruptMessage,
|
|
3476
|
-
findLastCallMessage: () => findLastCallMessage
|
|
3477
|
-
});
|
|
3478
|
-
function inferNextNode(messages, definition) {
|
|
3479
|
-
if (messages.length === 0) {
|
|
3480
|
-
return { type: "entry_node", nodeId: definition.entryNode };
|
|
3481
|
-
}
|
|
3482
|
-
const lastMessage = messages[messages.length - 1];
|
|
3483
|
-
const metadata = lastMessage.metadata;
|
|
3484
|
-
switch (metadata?.type) {
|
|
3485
|
-
case "workflow.node.call":
|
|
3486
|
-
return {
|
|
3487
|
-
type: "resume_node",
|
|
3488
|
-
nodeId: metadata.workflowNodeId,
|
|
3489
|
-
agentSessionId: metadata.agentSessionId
|
|
3490
|
-
};
|
|
3491
|
-
case "workflow.node.interrupt":
|
|
3492
|
-
return {
|
|
3493
|
-
type: "ask_user",
|
|
3494
|
-
nodeId: metadata.workflowNodeId,
|
|
3495
|
-
agentSessionId: metadata.agentSessionId
|
|
3496
|
-
};
|
|
3497
|
-
case "workflow.node.result":
|
|
3498
|
-
return getNextNodes(metadata.workflowNodeId, definition);
|
|
3499
|
-
default:
|
|
3500
|
-
const lastCall = findLastCallMessage(messages);
|
|
3501
|
-
if (lastCall) {
|
|
3502
|
-
const callMetadata = lastCall.metadata;
|
|
3503
|
-
return {
|
|
3504
|
-
type: "resume_node",
|
|
3505
|
-
nodeId: callMetadata.workflowNodeId,
|
|
3506
|
-
agentSessionId: callMetadata.agentSessionId
|
|
3507
|
-
};
|
|
3508
|
-
}
|
|
3509
|
-
return { type: "entry_node", nodeId: definition.entryNode };
|
|
3510
|
-
}
|
|
3511
|
-
}
|
|
3512
|
-
function getNextNodes(completedNodeId, definition) {
|
|
3513
|
-
if (!definition.edges) {
|
|
3514
|
-
return { type: "next_nodes", nodeIds: [] };
|
|
3515
|
-
}
|
|
3516
|
-
const nextNodeIds = definition.edges.filter((edge) => edge.from === completedNodeId).map((edge) => edge.to);
|
|
3517
|
-
return { type: "next_nodes", nodeIds: nextNodeIds };
|
|
3518
|
-
}
|
|
3519
|
-
function findLastInterruptMessage(messages) {
|
|
3520
|
-
for (let i = messages.length - 1;i >= 0; i--) {
|
|
3521
|
-
const msg = messages[i];
|
|
3522
|
-
if (msg.metadata?.type === "workflow.node.interrupt") {
|
|
3523
|
-
return msg;
|
|
3524
|
-
}
|
|
3525
|
-
}
|
|
3526
|
-
return null;
|
|
3527
|
-
}
|
|
3528
|
-
function findLastCallMessage(messages) {
|
|
3529
|
-
for (let i = messages.length - 1;i >= 0; i--) {
|
|
3530
|
-
const msg = messages[i];
|
|
3531
|
-
if (msg.metadata?.type === "workflow.node.call") {
|
|
3532
|
-
return msg;
|
|
3533
|
-
}
|
|
3534
|
-
}
|
|
3535
|
-
return null;
|
|
3536
|
-
}
|
|
3537
|
-
function parseNodeOutputs(messages) {
|
|
3538
|
-
const outputs = new Map;
|
|
3539
|
-
let lastCallNodeId = null;
|
|
3540
|
-
for (const msg of messages) {
|
|
3541
|
-
const metadata = msg.metadata;
|
|
3542
|
-
if (metadata?.type === "workflow.node.call") {
|
|
3543
|
-
lastCallNodeId = metadata.workflowNodeId;
|
|
3544
|
-
} else if (metadata?.type === "workflow.node.result" && lastCallNodeId) {
|
|
3545
|
-
try {
|
|
3546
|
-
outputs.set(lastCallNodeId, JSON.parse(msg.content));
|
|
3547
|
-
} catch {
|
|
3548
|
-
outputs.set(lastCallNodeId, msg.content);
|
|
3549
|
-
}
|
|
3550
|
-
lastCallNodeId = null;
|
|
3551
|
-
}
|
|
3552
|
-
}
|
|
3553
|
-
return outputs;
|
|
3554
|
-
}
|
|
3555
|
-
function hasPendingAskUser(messages) {
|
|
3556
|
-
if (messages.length === 0)
|
|
3557
|
-
return false;
|
|
3558
|
-
const lastMessage = messages[messages.length - 1];
|
|
3559
|
-
const metadata = lastMessage.metadata;
|
|
3560
|
-
return metadata?.type === "workflow.node.interrupt";
|
|
3561
|
-
}
|
|
3562
|
-
function getAgentSessionIdFromInterrupt(messages) {
|
|
3563
|
-
const lastInterrupt = findLastInterruptMessage(messages);
|
|
3564
|
-
if (!lastInterrupt)
|
|
3565
|
-
return null;
|
|
3566
|
-
const metadata = lastInterrupt.metadata;
|
|
3567
|
-
return metadata?.agentSessionId || null;
|
|
3568
|
-
}
|
|
3569
|
-
|
|
3570
|
-
// packages/core/src/env/workflow/engine/engine.ts
|
|
3571
|
-
import { EventEmitter } from "events";
|
|
3572
|
-
var logger, WorkflowEngine;
|
|
3573
|
-
var init_engine = __esm(() => {
|
|
3574
|
-
init_event();
|
|
3575
|
-
init_workflow_hil();
|
|
3576
|
-
init_executor();
|
|
3577
|
-
init_node_registry();
|
|
3578
|
-
init_logger();
|
|
3579
|
-
init_decorator();
|
|
3580
|
-
logger = createLogger("workflow:engine");
|
|
3581
|
-
WorkflowEngine = class WorkflowEngine extends EventEmitter {
|
|
3582
|
-
activeSessions = new Map;
|
|
3583
|
-
sessionIdCounter = 0;
|
|
3584
|
-
sessionComponent;
|
|
3585
|
-
nodeRegistry;
|
|
3586
|
-
workflowRepository;
|
|
3587
|
-
constructor(nodeRegistry, sessionComponent, workflowRepository) {
|
|
3588
|
-
super();
|
|
3589
|
-
this.nodeRegistry = nodeRegistry;
|
|
3590
|
-
this.sessionComponent = sessionComponent;
|
|
3591
|
-
this.workflowRepository = workflowRepository;
|
|
3592
|
-
}
|
|
3593
|
-
static async create(options) {
|
|
3594
|
-
const agentComponent = options.env?.getComponent("agent");
|
|
3595
|
-
const sessionComponent = options.sessionComponent;
|
|
3596
|
-
const nodeRegistry = new NodeRegistry({
|
|
3597
|
-
toolRegistry: options.toolRegistry,
|
|
3598
|
-
skillRegistry: options.skillRegistry,
|
|
3599
|
-
agentComponent,
|
|
3600
|
-
workflowRunner: options.workflowRunner,
|
|
3601
|
-
sessionComponent
|
|
3602
|
-
});
|
|
3603
|
-
return new WorkflowEngine(nodeRegistry, sessionComponent, options.workflowRepository);
|
|
3604
|
-
}
|
|
3605
|
-
generateRunId() {
|
|
3606
|
-
const random = Math.random().toString(36).substring(2, 8);
|
|
3607
|
-
return `run_${Date.now()}_${++this.sessionIdCounter}_${random}`;
|
|
3608
|
-
}
|
|
3609
|
-
getRunIdFromSessionId(sessionId) {
|
|
3610
|
-
return sessionId.replace(/^workflow_/, "");
|
|
3611
|
-
}
|
|
3612
|
-
getSessionId(runId) {
|
|
3613
|
-
return `workflow_${runId}`;
|
|
3614
|
-
}
|
|
3615
|
-
async createSession(workflow2, options) {
|
|
3616
|
-
const definition = "definition" in workflow2 ? workflow2.definition : workflow2;
|
|
3617
|
-
const workflowId = "id" in workflow2 ? workflow2.id : `inline_${definition.name}`;
|
|
3618
|
-
const workflowName = definition.name;
|
|
3619
|
-
const runId = this.generateRunId();
|
|
3620
|
-
const sessionId = this.getSessionId(runId);
|
|
3621
|
-
const metadata = {
|
|
3622
|
-
type: "workflow",
|
|
3623
|
-
workflowId,
|
|
3624
|
-
workflowName,
|
|
3625
|
-
workflowVersion: definition.version,
|
|
3626
|
-
status: "running",
|
|
3627
|
-
input: options?.input,
|
|
3628
|
-
agentSessions: []
|
|
3629
|
-
};
|
|
3630
|
-
if (this.sessionComponent) {
|
|
3631
|
-
await this.sessionComponent.create({
|
|
3632
|
-
id: sessionId,
|
|
3633
|
-
title: `Workflow: ${workflowName} (${runId})`,
|
|
3634
|
-
metadata
|
|
3635
|
-
});
|
|
3636
|
-
}
|
|
3637
|
-
logger.info(`[WorkflowEngine] Created session: ${sessionId}`);
|
|
3638
|
-
return sessionId;
|
|
3639
|
-
}
|
|
3640
|
-
async run(sessionId, options) {
|
|
3641
|
-
let session = this.sessionComponent ? await this.sessionComponent.get(sessionId) : null;
|
|
3642
|
-
let workflowDef = null;
|
|
3643
|
-
let workflowId = "";
|
|
3644
|
-
let workflowName = "";
|
|
3645
|
-
if (session) {
|
|
3646
|
-
const metadata2 = session.metadata;
|
|
3647
|
-
if (metadata2.type === "workflow" && metadata2.workflowId) {
|
|
3648
|
-
workflowDef = this.findDefinitionForWorkflow(metadata2.workflowId);
|
|
3649
|
-
workflowId = metadata2.workflowId;
|
|
3650
|
-
workflowName = metadata2.workflowName;
|
|
3651
|
-
}
|
|
3652
|
-
if (!workflowDef && metadata2.workflowName) {
|
|
3653
|
-
workflowDef = this.findDefinitionForWorkflow(metadata2.workflowName);
|
|
3654
|
-
workflowId = metadata2.workflowName;
|
|
3655
|
-
workflowName = metadata2.workflowName;
|
|
3656
|
-
}
|
|
3657
|
-
} else {
|
|
3658
|
-
if (!options?.workflowId) {
|
|
3659
|
-
throw new Error("workflowId required for new session");
|
|
3660
|
-
}
|
|
3661
|
-
workflowDef = this.findDefinitionForWorkflow(options.workflowId);
|
|
3662
|
-
if (!workflowDef) {
|
|
3663
|
-
throw new Error(`Workflow not found: ${options.workflowId}`);
|
|
3664
|
-
}
|
|
3665
|
-
workflowId = options.workflowId;
|
|
3666
|
-
workflowName = workflowDef.name;
|
|
3667
|
-
if (this.sessionComponent) {
|
|
3668
|
-
const sessionMetadata = {
|
|
3669
|
-
type: "workflow",
|
|
3670
|
-
workflowId,
|
|
3671
|
-
workflowName,
|
|
3672
|
-
workflowVersion: workflowDef.version,
|
|
3673
|
-
status: "running"
|
|
3674
|
-
};
|
|
3675
|
-
await this.sessionComponent.create({
|
|
3676
|
-
id: sessionId,
|
|
3677
|
-
title: `Workflow: ${workflowName}`,
|
|
3678
|
-
metadata: sessionMetadata
|
|
3679
|
-
});
|
|
3680
|
-
session = await this.sessionComponent.get(sessionId);
|
|
3681
|
-
}
|
|
3682
|
-
}
|
|
3683
|
-
if (!session || !workflowDef) {
|
|
3684
|
-
throw new Error(`Cannot start workflow: session or workflow not found`);
|
|
3685
|
-
}
|
|
3686
|
-
const metadata = session.metadata;
|
|
3687
|
-
if (metadata.status === "completed") {
|
|
3688
|
-
return { runId: this.getRunIdFromSessionId(sessionId), status: "completed" };
|
|
3689
|
-
}
|
|
3690
|
-
if (metadata.status === "failed") {
|
|
3691
|
-
return { runId: this.getRunIdFromSessionId(sessionId), status: "failed" };
|
|
3692
|
-
}
|
|
3693
|
-
const messages = this.sessionComponent ? await this.sessionComponent.getMessages(sessionId) : [];
|
|
3694
|
-
const { inferNextNode: inferNextNode2 } = await Promise.resolve().then(() => exports_session_recovery);
|
|
3695
|
-
const entry = workflowDef.entry;
|
|
3696
|
-
const entryNode = Array.isArray(entry) ? entry[0] : entry;
|
|
3697
|
-
const resumePoint = inferNextNode2(messages, {
|
|
3698
|
-
entryNode: entryNode !== "__default_entry__" ? entryNode : undefined,
|
|
3699
|
-
edges: undefined
|
|
3700
|
-
});
|
|
3701
|
-
const sessionState = await this.initializeSessionState(sessionId, workflowDef, workflowId, workflowName, options);
|
|
3702
|
-
this.activeSessions.set(sessionId, sessionState);
|
|
3703
|
-
return this.runWithResume(sessionId, resumePoint, options);
|
|
3704
|
-
}
|
|
3705
|
-
async initializeSessionState(sessionId, definition, workflowId, workflowName, options) {
|
|
3706
|
-
const dagManager = new DAGManager(definition);
|
|
3707
|
-
const validation = dagManager.validate();
|
|
3708
|
-
if (!validation.valid) {
|
|
3709
|
-
throw new Error(`Invalid workflow: ${validation.errors.join(", ")}`);
|
|
3710
|
-
}
|
|
3711
|
-
const parallelLimit = options?.parallelLimit ?? definition.config?.parallel_limit ?? null;
|
|
3712
|
-
const scheduler = new Scheduler(dagManager, { parallelLimit });
|
|
3713
|
-
const eventBus = new EventBus;
|
|
3714
|
-
const executorOptions = {
|
|
3715
|
-
globalTimeout: options?.timeout ?? definition.config?.timeout ?? null,
|
|
3716
|
-
globalRetry: definition.config?.retry ?? null,
|
|
3717
|
-
debug: options?.debug ?? definition.config?.debug ?? false
|
|
3718
|
-
};
|
|
3719
|
-
const executor = new Executor(this.nodeRegistry, eventBus, executorOptions, this.sessionComponent);
|
|
3720
|
-
const config = {
|
|
3721
|
-
parallelLimit,
|
|
3722
|
-
timeout: options?.timeout ?? definition.config?.timeout ?? null,
|
|
3723
|
-
debug: options?.debug ?? definition.config?.debug ?? false
|
|
3724
|
-
};
|
|
3725
|
-
const abortController = new AbortController;
|
|
3726
|
-
let resolveCompleted;
|
|
3727
|
-
let rejectCompleted;
|
|
3728
|
-
const completedPromise = new Promise((resolve, reject) => {
|
|
3729
|
-
resolveCompleted = resolve;
|
|
3730
|
-
rejectCompleted = reject;
|
|
3731
|
-
});
|
|
3732
|
-
const sessionState = {
|
|
3733
|
-
sessionId,
|
|
3734
|
-
workflowId,
|
|
3735
|
-
workflowName,
|
|
3736
|
-
status: "running",
|
|
3737
|
-
startedAt: new Date,
|
|
3738
|
-
eventBus,
|
|
3739
|
-
dagManager,
|
|
3740
|
-
scheduler,
|
|
3741
|
-
executor,
|
|
3742
|
-
nodeRegistry: this.nodeRegistry,
|
|
3743
|
-
nodeOutputs: new Map,
|
|
3744
|
-
config,
|
|
3745
|
-
abortController,
|
|
3746
|
-
completedPromise,
|
|
3747
|
-
resolveCompleted,
|
|
3748
|
-
rejectCompleted,
|
|
3749
|
-
workflowHistory: [],
|
|
3750
|
-
agentSessions: new Map
|
|
3751
|
-
};
|
|
3752
|
-
this.setupEventHandlers(sessionState);
|
|
3753
|
-
return sessionState;
|
|
3754
|
-
}
|
|
3755
|
-
async runWithResume(sessionId, resumePoint, options) {
|
|
3756
|
-
const sessionState = this.activeSessions.get(sessionId);
|
|
3757
|
-
if (!sessionState) {
|
|
3758
|
-
throw new Error(`Session not found: ${sessionId}`);
|
|
3759
|
-
}
|
|
3760
|
-
const runId = this.getRunIdFromSessionId(sessionId);
|
|
3761
|
-
await sessionState.eventBus.publish(createWorkflowEvent("workflow.started", runId, {
|
|
3762
|
-
workflow_name: sessionState.workflowName,
|
|
3763
|
-
input: options?.input
|
|
3764
|
-
}));
|
|
3765
|
-
let pendingNodeId;
|
|
3766
|
-
let agentSessionId;
|
|
3767
|
-
switch (resumePoint.type) {
|
|
3768
|
-
case "entry_node":
|
|
3769
|
-
case "next_nodes":
|
|
3770
|
-
pendingNodeId = undefined;
|
|
3771
|
-
break;
|
|
3772
|
-
case "resume_node":
|
|
3773
|
-
case "ask_user":
|
|
3774
|
-
pendingNodeId = resumePoint.nodeId;
|
|
3775
|
-
agentSessionId = resumePoint.agentSessionId;
|
|
3776
|
-
break;
|
|
3777
|
-
}
|
|
3778
|
-
const userResponse = typeof options?.input === "string" ? options.input : undefined;
|
|
3779
|
-
this.scheduleAndExecute(sessionState, {
|
|
3780
|
-
input: options?.input,
|
|
3781
|
-
pendingNodeId,
|
|
3782
|
-
agentSessionId,
|
|
3783
|
-
userResponse
|
|
3784
|
-
}).catch((error) => {
|
|
3785
|
-
logger.error(`Workflow ${sessionId} scheduling error:`, error);
|
|
3786
|
-
this.failWorkflow(sessionState, error);
|
|
3787
|
-
});
|
|
3788
|
-
if (options?.sync !== false) {
|
|
3789
|
-
return this.waitForCompletion(sessionId, options?.timeout);
|
|
3790
|
-
}
|
|
3791
|
-
return { runId, status: "running" };
|
|
3792
|
-
}
|
|
3793
|
-
async runWorkflow(workflow2, options) {
|
|
3794
|
-
const definition = "definition" in workflow2 ? workflow2.definition : workflow2;
|
|
3795
|
-
const workflowId = "id" in workflow2 ? workflow2.id : `inline_${definition.name}`;
|
|
3796
|
-
const workflowName = definition.name;
|
|
3797
|
-
const sessionId = await this.createSession(workflow2, options);
|
|
3798
|
-
const sessionState = await this.initializeSessionState(sessionId, definition, workflowId, workflowName, options);
|
|
3799
|
-
this.activeSessions.set(sessionId, sessionState);
|
|
3800
|
-
return this.runWithResume(sessionId, { type: "entry_node" }, options);
|
|
3801
|
-
}
|
|
3802
|
-
async pause(sessionId) {
|
|
3803
|
-
const sessionState = this.activeSessions.get(sessionId);
|
|
3804
|
-
if (!sessionState) {
|
|
3805
|
-
throw new Error(`Session not found: ${sessionId}`);
|
|
3806
|
-
}
|
|
3807
|
-
if (sessionState.status !== "running") {
|
|
3808
|
-
throw new Error(`Session ${sessionId} is not running (current: ${sessionState.status})`);
|
|
3809
|
-
}
|
|
3810
|
-
sessionState.status = "paused";
|
|
3811
|
-
sessionState.abortController.abort();
|
|
3812
|
-
sessionState.executor.cancelAll();
|
|
3813
|
-
if (this.sessionComponent) {
|
|
3814
|
-
const metadata = await this.getSessionMetadata(sessionId);
|
|
3815
|
-
await this.sessionComponent.update(sessionId, {
|
|
3816
|
-
metadata: { ...metadata, status: "paused" }
|
|
3817
|
-
});
|
|
3818
|
-
}
|
|
3819
|
-
await sessionState.eventBus.publish(createWorkflowEvent("workflow.paused", this.getRunIdFromSessionId(sessionId), {}));
|
|
3820
|
-
logger.info(`[WorkflowEngine] Workflow paused: ${sessionId}`);
|
|
3821
|
-
}
|
|
3822
|
-
async resume(sessionId, options) {
|
|
3823
|
-
const sessionState = this.activeSessions.get(sessionId);
|
|
3824
|
-
if (!sessionState) {
|
|
3825
|
-
logger.info(`[WorkflowEngine] Session not in memory, attempting to restore from DB: ${sessionId}`);
|
|
3826
|
-
return this.resumeFromDatabase(sessionId, options);
|
|
3827
|
-
}
|
|
3828
|
-
if (options?.response) {
|
|
3829
|
-
await this.writeNodeResume(sessionId, options.response);
|
|
3830
|
-
}
|
|
3831
|
-
if (sessionState.status === "running") {
|
|
3832
|
-
return { runId: this.getRunIdFromSessionId(sessionId), status: "running" };
|
|
3833
|
-
}
|
|
3834
|
-
if (sessionState.status !== "paused") {
|
|
3835
|
-
throw new Error(`Session ${sessionId} is not paused (current: ${sessionState.status})`);
|
|
3836
|
-
}
|
|
3837
|
-
sessionState.status = "running";
|
|
3838
|
-
sessionState.abortController = new AbortController;
|
|
3839
|
-
if (this.sessionComponent) {
|
|
3840
|
-
const metadata = await this.getSessionMetadata(sessionId);
|
|
3841
|
-
await this.sessionComponent.update(sessionId, {
|
|
3842
|
-
metadata: { ...metadata, status: "running" }
|
|
3843
|
-
});
|
|
3844
|
-
}
|
|
3845
|
-
await sessionState.eventBus.publish(createWorkflowEvent("workflow.resumed", this.getRunIdFromSessionId(sessionId), {
|
|
3846
|
-
userResponse: options?.response
|
|
3847
|
-
}));
|
|
3848
|
-
const runtimeState = await this.restoreRuntimeState(sessionId);
|
|
3849
|
-
this.scheduleAndExecute(sessionState, {
|
|
3850
|
-
pendingNodeId: runtimeState.pendingNodeId || undefined,
|
|
3851
|
-
agentSessionId: runtimeState.agentSessionId,
|
|
3852
|
-
userResponse: options?.response,
|
|
3853
|
-
restoredOutputs: runtimeState.nodeOutputs
|
|
3854
|
-
});
|
|
3855
|
-
return {
|
|
3856
|
-
runId: this.getRunIdFromSessionId(sessionId),
|
|
3857
|
-
status: "running"
|
|
3858
|
-
};
|
|
3859
|
-
}
|
|
3860
|
-
async resumeFromDatabase(sessionId, options) {
|
|
3861
|
-
const session = await this.sessionComponent?.get(sessionId);
|
|
3862
|
-
if (!session) {
|
|
3863
|
-
throw new Error(`Session not found: ${sessionId}`);
|
|
3864
|
-
}
|
|
3865
|
-
const metadata = session.metadata;
|
|
3866
|
-
if (metadata.type !== "workflow") {
|
|
3867
|
-
throw new Error(`Session is not a workflow session: ${sessionId}`);
|
|
3868
|
-
}
|
|
3869
|
-
if (metadata.status !== "paused") {
|
|
3870
|
-
throw new Error(`Workflow is not paused: ${sessionId}, status: ${metadata.status}`);
|
|
3871
|
-
}
|
|
3872
|
-
const runtimeState = await this.restoreRuntimeState(sessionId);
|
|
3873
|
-
if (!runtimeState.pendingNodeId) {
|
|
3874
|
-
throw new Error(`No pending node found in session: ${sessionId}`);
|
|
3875
|
-
}
|
|
3876
|
-
if (options?.response) {
|
|
3877
|
-
await this.writeNodeResume(sessionId, options.response);
|
|
3878
|
-
}
|
|
3879
|
-
if (this.sessionComponent) {
|
|
3880
|
-
await this.sessionComponent.update(sessionId, {
|
|
3881
|
-
metadata: { ...metadata, status: "running" }
|
|
3882
|
-
});
|
|
3883
|
-
}
|
|
3884
|
-
logger.info(`[WorkflowEngine] Resumed from database: ${sessionId}, pendingNode: ${runtimeState.pendingNodeId}`);
|
|
3885
|
-
throw new Error(`Cannot resume from database without workflow definition. Session ${sessionId} is paused at node "${runtimeState.pendingNodeId}". Please ensure the workflow is registered before resuming.`);
|
|
3886
|
-
}
|
|
3887
|
-
async restoreRuntimeState(sessionId) {
|
|
3888
|
-
const messages = this.sessionComponent ? await this.sessionComponent.getMessages(sessionId) : [];
|
|
3889
|
-
const nodeOutputs = new Map;
|
|
3890
|
-
let lastCallNodeId = null;
|
|
3891
|
-
let lastInterruptMessage = null;
|
|
3892
|
-
let agentSessionId;
|
|
3893
|
-
for (const msg of messages) {
|
|
3894
|
-
const msgMetadata = msg.metadata;
|
|
3895
|
-
if (msgMetadata?.type === "workflow.node.call") {
|
|
3896
|
-
lastCallNodeId = msgMetadata.workflowNodeId;
|
|
3897
|
-
} else if (msgMetadata?.type === "workflow.node.result") {
|
|
3898
|
-
if (lastCallNodeId) {
|
|
3899
|
-
try {
|
|
3900
|
-
nodeOutputs.set(lastCallNodeId, JSON.parse(msg.content));
|
|
3901
|
-
} catch {
|
|
3902
|
-
nodeOutputs.set(lastCallNodeId, msg.content);
|
|
3903
|
-
}
|
|
3904
|
-
}
|
|
3905
|
-
lastCallNodeId = null;
|
|
3906
|
-
} else if (msgMetadata?.type === "workflow.node.interrupt") {
|
|
3907
|
-
lastInterruptMessage = msg;
|
|
3908
|
-
lastCallNodeId = msgMetadata.workflowNodeId;
|
|
3909
|
-
agentSessionId = msgMetadata.agentSessionId;
|
|
3910
|
-
}
|
|
3911
|
-
}
|
|
3912
|
-
return {
|
|
3913
|
-
nodeOutputs,
|
|
3914
|
-
pendingNodeId: lastCallNodeId,
|
|
3915
|
-
waitingForUser: !!lastInterruptMessage,
|
|
3916
|
-
agentSessionId,
|
|
3917
|
-
lastInterruptMessage
|
|
3918
|
-
};
|
|
3919
|
-
}
|
|
3920
|
-
async writeNodeResume(sessionId, response) {
|
|
3921
|
-
if (this.sessionComponent) {
|
|
3922
|
-
await this.sessionComponent.addMessage(sessionId, {
|
|
3923
|
-
role: "workflow.node.resume",
|
|
3924
|
-
content: response,
|
|
3925
|
-
metadata: {
|
|
3926
|
-
type: "workflow.node.resume",
|
|
3927
|
-
response,
|
|
3928
|
-
timestamp: Date.now()
|
|
3929
|
-
}
|
|
3930
|
-
});
|
|
3931
|
-
}
|
|
3932
|
-
}
|
|
3933
|
-
async stop(sessionId, reason) {
|
|
3934
|
-
const sessionState = this.activeSessions.get(sessionId);
|
|
3935
|
-
if (!sessionState) {
|
|
3936
|
-
if (this.sessionComponent) {
|
|
3937
|
-
await this.sessionComponent.update(sessionId, {
|
|
3938
|
-
metadata: { status: "stopped" }
|
|
3939
|
-
});
|
|
3940
|
-
}
|
|
3941
|
-
return;
|
|
3942
|
-
}
|
|
3943
|
-
sessionState.status = "stopped";
|
|
3944
|
-
sessionState.abortController.abort();
|
|
3945
|
-
sessionState.executor.cancelAll();
|
|
3946
|
-
if (this.sessionComponent) {
|
|
3947
|
-
const metadata = await this.getSessionMetadata(sessionId);
|
|
3948
|
-
await this.sessionComponent.update(sessionId, {
|
|
3949
|
-
metadata: { ...metadata, status: "stopped" }
|
|
3950
|
-
});
|
|
3951
|
-
}
|
|
3952
|
-
await sessionState.eventBus.publish(createWorkflowEvent("workflow.stopped", this.getRunIdFromSessionId(sessionId), {
|
|
3953
|
-
reason: reason ?? "User requested stop"
|
|
3954
|
-
}));
|
|
3955
|
-
this.cleanupSession(sessionState);
|
|
3956
|
-
}
|
|
3957
|
-
getSessionStatus(sessionId) {
|
|
3958
|
-
const sessionState = this.activeSessions.get(sessionId);
|
|
3959
|
-
return sessionState?.status ?? null;
|
|
3960
|
-
}
|
|
3961
|
-
isSessionActive(sessionId) {
|
|
3962
|
-
return this.activeSessions.has(sessionId);
|
|
3963
|
-
}
|
|
3964
|
-
setupEventHandlers(sessionState) {
|
|
3965
|
-
const { sessionId, eventBus, scheduler } = sessionState;
|
|
3966
|
-
const runId = this.getRunIdFromSessionId(sessionId);
|
|
3967
|
-
eventBus.on("node.completed", async (event2) => {
|
|
3968
|
-
if (event2.type !== "node.completed")
|
|
3969
|
-
return;
|
|
3970
|
-
sessionState.nodeOutputs.set(event2.node_id, event2.output);
|
|
3971
|
-
scheduler.markCompleted(event2.node_id);
|
|
3972
|
-
if (event2.output && typeof event2.output === "object" && "workflowHistory" in event2.output) {
|
|
3973
|
-
const messages = event2.output.workflowHistory;
|
|
3974
|
-
if (Array.isArray(messages)) {
|
|
3975
|
-
sessionState.workflowHistory.push(...messages);
|
|
3976
|
-
}
|
|
3977
|
-
}
|
|
3978
|
-
this.checkAndFinalize(sessionState);
|
|
3979
|
-
});
|
|
3980
|
-
eventBus.on("node.failed", async (event2) => {
|
|
3981
|
-
if (event2.type !== "node.failed")
|
|
3982
|
-
return;
|
|
3983
|
-
scheduler.markFailed(event2.node_id);
|
|
3984
|
-
await this.failWorkflow(sessionState, new Error(event2.error.message));
|
|
3985
|
-
});
|
|
3986
|
-
eventBus.on("node.interrupt", async (event2) => {
|
|
3987
|
-
if (event2.type !== "node.interrupt")
|
|
3988
|
-
return;
|
|
3989
|
-
logger.info(`Workflow paused at node "${event2.node_id}" - ask_user pending`);
|
|
3990
|
-
sessionState.status = "paused";
|
|
3991
|
-
sessionState.abortController.abort();
|
|
3992
|
-
if (this.sessionComponent) {
|
|
3993
|
-
const metadata = await this.getSessionMetadata(sessionId);
|
|
3994
|
-
await this.sessionComponent.update(sessionId, {
|
|
3995
|
-
metadata: { ...metadata, status: "paused" }
|
|
3996
|
-
});
|
|
3997
|
-
}
|
|
3998
|
-
await eventBus.publish(createWorkflowEvent("workflow.paused", runId, {
|
|
3999
|
-
pendingNodeId: event2.node_id,
|
|
4000
|
-
query: event2.query
|
|
4001
|
-
}));
|
|
4002
|
-
await this.writeNodeInterrupt(sessionId, event2.node_id, event2.node_type, event2.query, event2.agent_session_id);
|
|
4003
|
-
sessionState.resolveCompleted({
|
|
4004
|
-
runId,
|
|
4005
|
-
status: "paused",
|
|
4006
|
-
pendingNodeId: event2.node_id,
|
|
4007
|
-
query: event2.query,
|
|
4008
|
-
agentSessionId: event2.agent_session_id
|
|
4009
|
-
});
|
|
4010
|
-
});
|
|
4011
|
-
}
|
|
4012
|
-
async writeNodeInterrupt(sessionId, nodeId, nodeType, query, agentSessionId) {
|
|
4013
|
-
if (this.sessionComponent) {
|
|
4014
|
-
await this.sessionComponent.addMessage(sessionId, {
|
|
4015
|
-
role: "workflow.node.interrupt",
|
|
4016
|
-
content: query,
|
|
4017
|
-
metadata: {
|
|
4018
|
-
type: "workflow.node.interrupt",
|
|
4019
|
-
workflowNodeId: nodeId,
|
|
4020
|
-
workflowNodeType: nodeType,
|
|
4021
|
-
query,
|
|
4022
|
-
agentSessionId,
|
|
4023
|
-
timestamp: Date.now()
|
|
4024
|
-
}
|
|
4025
|
-
});
|
|
4026
|
-
}
|
|
4027
|
-
}
|
|
4028
|
-
async scheduleAndExecute(sessionState, options) {
|
|
4029
|
-
const { scheduler, executor, eventBus, abortController, nodeOutputs } = sessionState;
|
|
4030
|
-
const { input: globalInput, pendingNodeId, agentSessionId, userResponse, restoredOutputs } = options || {};
|
|
4031
|
-
if (restoredOutputs) {
|
|
4032
|
-
for (const [nodeId, output] of restoredOutputs) {
|
|
4033
|
-
nodeOutputs.set(nodeId, output);
|
|
4034
|
-
}
|
|
4035
|
-
}
|
|
4036
|
-
const scheduleAvailableNodes = async () => {
|
|
4037
|
-
const state = scheduler.getState();
|
|
4038
|
-
const completedNodes = new Set(state.completed);
|
|
4039
|
-
const readyNodes = scheduler.getReadyNodes(completedNodes);
|
|
4040
|
-
const canStart = scheduler.canStartMore();
|
|
4041
|
-
if (readyNodes.length === 0 || !canStart) {
|
|
4042
|
-
return false;
|
|
4043
|
-
}
|
|
4044
|
-
let scheduled = 0;
|
|
4045
|
-
for (const nodeId of readyNodes) {
|
|
4046
|
-
if (!scheduler.canStartMore())
|
|
4047
|
-
break;
|
|
4048
|
-
if (scheduled >= (sessionState.config.parallelLimit ?? Infinity))
|
|
4049
|
-
break;
|
|
4050
|
-
await this.startNode(sessionState, nodeId, globalInput);
|
|
4051
|
-
scheduled++;
|
|
4052
|
-
}
|
|
4053
|
-
return true;
|
|
4054
|
-
};
|
|
4055
|
-
if (pendingNodeId) {
|
|
4056
|
-
await this.resumeNode(sessionState, pendingNodeId, {
|
|
4057
|
-
agentSessionId,
|
|
4058
|
-
userResponse
|
|
4059
|
-
});
|
|
4060
|
-
} else {
|
|
4061
|
-
await scheduleAvailableNodes();
|
|
4062
|
-
}
|
|
4063
|
-
while (sessionState.status === "running" && !abortController.signal.aborted) {
|
|
4064
|
-
const state = scheduler.getState();
|
|
4065
|
-
if (state.pending.length === 0 && state.running.length === 0) {
|
|
4066
|
-
break;
|
|
4067
|
-
}
|
|
4068
|
-
try {
|
|
4069
|
-
await this.waitForNextNodeEvent(sessionState, abortController.signal);
|
|
4070
|
-
} catch {
|
|
4071
|
-
break;
|
|
4072
|
-
}
|
|
4073
|
-
await scheduleAvailableNodes();
|
|
4074
|
-
}
|
|
4075
|
-
}
|
|
4076
|
-
waitForNextNodeEvent(sessionState, signal) {
|
|
4077
|
-
return new Promise((resolve) => {
|
|
4078
|
-
const timeoutId = setTimeout(() => {
|
|
4079
|
-
cleanup();
|
|
4080
|
-
resolve();
|
|
4081
|
-
}, 100);
|
|
4082
|
-
const cleanup = () => {
|
|
4083
|
-
clearTimeout(timeoutId);
|
|
4084
|
-
sessionState.eventBus.off("node.completed", onCompleted);
|
|
4085
|
-
sessionState.eventBus.off("node.failed", onFailed);
|
|
4086
|
-
};
|
|
4087
|
-
const onCompleted = (event2) => {
|
|
4088
|
-
if (event2.type === "node.completed") {
|
|
4089
|
-
cleanup();
|
|
4090
|
-
resolve();
|
|
4091
|
-
}
|
|
4092
|
-
};
|
|
4093
|
-
const onFailed = (event2) => {
|
|
4094
|
-
if (event2.type === "node.failed") {
|
|
4095
|
-
cleanup();
|
|
4096
|
-
resolve();
|
|
4097
|
-
}
|
|
4098
|
-
};
|
|
4099
|
-
sessionState.eventBus.on("node.completed", onCompleted);
|
|
4100
|
-
sessionState.eventBus.on("node.failed", onFailed);
|
|
4101
|
-
if (signal.aborted) {
|
|
4102
|
-
cleanup();
|
|
4103
|
-
resolve();
|
|
4104
|
-
}
|
|
4105
|
-
});
|
|
4106
|
-
}
|
|
4107
|
-
async startNode(sessionState, nodeId, input) {
|
|
4108
|
-
const { scheduler, executor, eventBus, dagManager } = sessionState;
|
|
4109
|
-
const sessionId = sessionState.sessionId;
|
|
4110
|
-
const runId = this.getRunIdFromSessionId(sessionId);
|
|
4111
|
-
scheduler.markStarted(nodeId);
|
|
4112
|
-
await eventBus.publish(createWorkflowEvent("node.scheduled", runId, {
|
|
4113
|
-
node_id: nodeId
|
|
4114
|
-
}));
|
|
4115
|
-
const nodeDef = dagManager.getNode(nodeId);
|
|
4116
|
-
if (!nodeDef) {
|
|
4117
|
-
scheduler.markFailed(nodeId);
|
|
4118
|
-
return;
|
|
4119
|
-
}
|
|
4120
|
-
await this.writeNodeCall(sessionId, nodeId, nodeDef.type, input);
|
|
4121
|
-
const context2 = this.createExecutionContext(sessionState, nodeId, input);
|
|
4122
|
-
executor.executeNode(nodeDef, context2).catch(async (error) => {
|
|
4123
|
-
if (error instanceof AskUserError) {
|
|
4124
|
-
await eventBus.publish(createNodeInterruptEvent(runId, nodeId, nodeDef.type, error.query, error.agentSessionId));
|
|
4125
|
-
return;
|
|
4126
|
-
}
|
|
4127
|
-
scheduler.markFailed(nodeId);
|
|
4128
|
-
});
|
|
4129
|
-
}
|
|
4130
|
-
async writeNodeCall(sessionId, nodeId, nodeType, input) {
|
|
4131
|
-
if (this.sessionComponent) {
|
|
4132
|
-
await this.sessionComponent.addMessage(sessionId, {
|
|
4133
|
-
role: "workflow.node.call",
|
|
4134
|
-
content: JSON.stringify({ input }),
|
|
4135
|
-
metadata: {
|
|
4136
|
-
type: "workflow.node.call",
|
|
4137
|
-
workflowNodeId: nodeId,
|
|
4138
|
-
workflowNodeType: nodeType,
|
|
4139
|
-
timestamp: Date.now()
|
|
4140
|
-
}
|
|
4141
|
-
});
|
|
4142
|
-
}
|
|
4143
|
-
}
|
|
4144
|
-
async resumeNode(sessionState, nodeId, options) {
|
|
4145
|
-
const { scheduler, executor, eventBus, dagManager } = sessionState;
|
|
4146
|
-
const sessionId = sessionState.sessionId;
|
|
4147
|
-
const runId = this.getRunIdFromSessionId(sessionId);
|
|
4148
|
-
scheduler.markStarted(nodeId);
|
|
4149
|
-
await eventBus.publish(createWorkflowEvent("node.started", runId, {
|
|
4150
|
-
node_id: nodeId,
|
|
4151
|
-
agentSessionId: options?.agentSessionId,
|
|
4152
|
-
userResponse: options?.userResponse
|
|
4153
|
-
}));
|
|
4154
|
-
const nodeDef = dagManager.getNode(nodeId);
|
|
4155
|
-
if (!nodeDef) {
|
|
4156
|
-
scheduler.markFailed(nodeId);
|
|
4157
|
-
return;
|
|
4158
|
-
}
|
|
4159
|
-
const context2 = this.createExecutionContext(sessionState, nodeId, undefined);
|
|
4160
|
-
if (options?.agentSessionId || options?.userResponse) {
|
|
4161
|
-
context2.agentSessionId = options.agentSessionId;
|
|
4162
|
-
context2.userResponse = options.userResponse;
|
|
4163
|
-
}
|
|
4164
|
-
executor.executeNode(nodeDef, context2).catch((error) => {
|
|
4165
|
-
if (error instanceof AskUserError) {
|
|
4166
|
-
const event2 = createNodeInterruptEvent(runId, nodeId, nodeDef.type, error.query, error.agentSessionId);
|
|
4167
|
-
eventBus.publish(event2);
|
|
4168
|
-
return;
|
|
4169
|
-
}
|
|
4170
|
-
scheduler.markFailed(nodeId);
|
|
4171
|
-
});
|
|
4172
|
-
}
|
|
4173
|
-
createExecutionContext(sessionState, nodeId, globalInput) {
|
|
4174
|
-
const nodeDef = sessionState.dagManager.getNode(nodeId);
|
|
4175
|
-
const runId = this.getRunIdFromSessionId(sessionState.sessionId);
|
|
4176
|
-
const deps = nodeDef.depends_on || [];
|
|
4177
|
-
const input = {};
|
|
4178
|
-
for (const depId of deps) {
|
|
4179
|
-
const depOutput = sessionState.nodeOutputs.get(depId);
|
|
4180
|
-
if (depOutput !== undefined) {
|
|
4181
|
-
input[depId] = depOutput;
|
|
4182
|
-
}
|
|
4183
|
-
}
|
|
4184
|
-
const analysis = sessionState.dagManager.analyze();
|
|
4185
|
-
if (analysis.entryNodes.includes(nodeId) && globalInput) {
|
|
4186
|
-
Object.assign(input, globalInput);
|
|
4187
|
-
}
|
|
4188
|
-
const askUser = (query) => {
|
|
4189
|
-
throw new AskUserError(runId, sessionState.sessionId, nodeId, nodeDef.type, query);
|
|
4190
|
-
};
|
|
4191
|
-
return {
|
|
4192
|
-
runId,
|
|
4193
|
-
sessionId: sessionState.sessionId,
|
|
4194
|
-
workflowName: sessionState.workflowName,
|
|
4195
|
-
nodeId,
|
|
4196
|
-
input,
|
|
4197
|
-
previousOutputs: sessionState.nodeOutputs,
|
|
4198
|
-
config: nodeDef.config ?? {},
|
|
4199
|
-
debug: sessionState.config.debug,
|
|
4200
|
-
eventBus: sessionState.eventBus,
|
|
4201
|
-
nodeOutputs: sessionState.nodeOutputs,
|
|
4202
|
-
workflowHistory: sessionState.workflowHistory,
|
|
4203
|
-
sessionComponent: this.sessionComponent,
|
|
4204
|
-
askUser
|
|
4205
|
-
};
|
|
4206
|
-
}
|
|
4207
|
-
checkAndFinalize(sessionState) {
|
|
4208
|
-
const state = sessionState.scheduler.getState();
|
|
4209
|
-
if (state.pending.length === 0 && state.running.length === 0 && state.ready.length === 0) {
|
|
4210
|
-
if (state.failed.length > 0) {
|
|
4211
|
-
this.failWorkflow(sessionState, new Error(`Nodes failed: ${state.failed.join(", ")}`));
|
|
4212
|
-
} else {
|
|
4213
|
-
this.completeWorkflow(sessionState);
|
|
4214
|
-
}
|
|
4215
|
-
}
|
|
4216
|
-
}
|
|
4217
|
-
async completeWorkflow(sessionState) {
|
|
4218
|
-
const durationMs = Date.now() - sessionState.startedAt.getTime();
|
|
4219
|
-
const sessionId = sessionState.sessionId;
|
|
4220
|
-
const runId = this.getRunIdFromSessionId(sessionId);
|
|
4221
|
-
const output = {};
|
|
4222
|
-
for (const [nodeId, nodeOutput] of sessionState.nodeOutputs) {
|
|
4223
|
-
output[nodeId] = nodeOutput;
|
|
4224
|
-
}
|
|
4225
|
-
if (this.sessionComponent) {
|
|
4226
|
-
const metadata = await this.getSessionMetadata(sessionId);
|
|
4227
|
-
await this.sessionComponent.update(sessionId, {
|
|
4228
|
-
metadata: { ...metadata, status: "completed" }
|
|
4229
|
-
});
|
|
4230
|
-
}
|
|
4231
|
-
await sessionState.eventBus.publish(createWorkflowEvent("workflow.completed", runId, {
|
|
4232
|
-
result: output,
|
|
4233
|
-
duration_ms: durationMs
|
|
4234
|
-
}), true);
|
|
4235
|
-
sessionState.resolveCompleted({
|
|
4236
|
-
runId,
|
|
4237
|
-
status: "completed",
|
|
4238
|
-
output,
|
|
4239
|
-
durationMs
|
|
4240
|
-
});
|
|
4241
|
-
this.cleanupSession(sessionState);
|
|
4242
|
-
}
|
|
4243
|
-
async failWorkflow(sessionState, error) {
|
|
4244
|
-
const durationMs = Date.now() - sessionState.startedAt.getTime();
|
|
4245
|
-
const sessionId = sessionState.sessionId;
|
|
4246
|
-
const runId = this.getRunIdFromSessionId(sessionId);
|
|
4247
|
-
sessionState.executor.cancelAll();
|
|
4248
|
-
if (this.sessionComponent) {
|
|
4249
|
-
const metadata = await this.getSessionMetadata(sessionId);
|
|
4250
|
-
await this.sessionComponent.update(sessionId, {
|
|
4251
|
-
metadata: { ...metadata, status: "failed" }
|
|
4252
|
-
});
|
|
4253
|
-
}
|
|
4254
|
-
await sessionState.eventBus.publish(createWorkflowEvent("workflow.failed", runId, {
|
|
4255
|
-
error: { message: error.message, stack: error.stack },
|
|
4256
|
-
failed_at: new Date().toISOString()
|
|
4257
|
-
}), true);
|
|
4258
|
-
sessionState.resolveCompleted({
|
|
4259
|
-
runId,
|
|
4260
|
-
status: "failed",
|
|
4261
|
-
error: error.message,
|
|
4262
|
-
durationMs
|
|
4263
|
-
});
|
|
4264
|
-
this.cleanupSession(sessionState);
|
|
4265
|
-
}
|
|
4266
|
-
cleanupSession(sessionState) {
|
|
4267
|
-
sessionState.eventBus.clear();
|
|
4268
|
-
this.activeSessions.delete(sessionState.sessionId);
|
|
4269
|
-
}
|
|
4270
|
-
async waitForCompletion(sessionId, timeout) {
|
|
4271
|
-
const sessionState = this.activeSessions.get(sessionId);
|
|
4272
|
-
if (!sessionState) {
|
|
4273
|
-
throw new Error(`Session not found: ${sessionId}`);
|
|
4274
|
-
}
|
|
4275
|
-
const timeoutMs = timeout ?? 300000;
|
|
4276
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
4277
|
-
setTimeout(() => {
|
|
4278
|
-
reject(new Error(`Workflow execution timeout: ${timeoutMs}ms`));
|
|
4279
|
-
}, timeoutMs);
|
|
4280
|
-
});
|
|
4281
|
-
return Promise.race([
|
|
4282
|
-
sessionState.completedPromise,
|
|
4283
|
-
timeoutPromise
|
|
4284
|
-
]);
|
|
4285
|
-
}
|
|
4286
|
-
async getSessionMetadata(sessionId) {
|
|
4287
|
-
if (!this.sessionComponent) {
|
|
4288
|
-
return { type: "workflow", workflowId: "", workflowName: "", status: "running" };
|
|
4289
|
-
}
|
|
4290
|
-
const session = await this.sessionComponent.get(sessionId);
|
|
4291
|
-
return session?.metadata || { type: "workflow", workflowId: "", workflowName: "", status: "running" };
|
|
4292
|
-
}
|
|
4293
|
-
findDefinitionForWorkflow(workflowIdOrName) {
|
|
4294
|
-
if (!this.workflowRepository) {
|
|
4295
|
-
return null;
|
|
4296
|
-
}
|
|
4297
|
-
let workflow2 = this.workflowRepository.getById(workflowIdOrName);
|
|
4298
|
-
if (workflow2)
|
|
4299
|
-
return workflow2.definition;
|
|
4300
|
-
workflow2 = this.workflowRepository.getByName(workflowIdOrName);
|
|
4301
|
-
if (workflow2)
|
|
4302
|
-
return workflow2.definition;
|
|
4303
|
-
return null;
|
|
4304
|
-
}
|
|
4305
|
-
};
|
|
4306
|
-
__legacyDecorateClassTS([
|
|
4307
|
-
TracedAs("workflow.engine.createSession", { recordParams: true, recordResult: true, log: true })
|
|
4308
|
-
], WorkflowEngine.prototype, "createSession", null);
|
|
4309
|
-
__legacyDecorateClassTS([
|
|
4310
|
-
TracedAs("workflow.engine.run", { recordParams: true, recordResult: true, log: true })
|
|
4311
|
-
], WorkflowEngine.prototype, "run", null);
|
|
4312
|
-
__legacyDecorateClassTS([
|
|
4313
|
-
TracedAs("workflow.engine.runWorkflow", { recordParams: true, recordResult: true, log: true })
|
|
4314
|
-
], WorkflowEngine.prototype, "runWorkflow", null);
|
|
4315
|
-
__legacyDecorateClassTS([
|
|
4316
|
-
TracedAs("workflow.engine.pause", { recordParams: true, recordResult: true, log: true })
|
|
4317
|
-
], WorkflowEngine.prototype, "pause", null);
|
|
4318
|
-
__legacyDecorateClassTS([
|
|
4319
|
-
TracedAs("workflow.engine.resume", { recordParams: true, recordResult: true, log: true })
|
|
4320
|
-
], WorkflowEngine.prototype, "resume", null);
|
|
4321
|
-
__legacyDecorateClassTS([
|
|
4322
|
-
TracedAs("workflow.engine.resumeFromDatabase", { recordParams: true, recordResult: true, log: true })
|
|
4323
|
-
], WorkflowEngine.prototype, "resumeFromDatabase", null);
|
|
4324
|
-
__legacyDecorateClassTS([
|
|
4325
|
-
TracedAs("workflow.engine.restoreRuntimeState", { recordParams: true, recordResult: true, log: true })
|
|
4326
|
-
], WorkflowEngine.prototype, "restoreRuntimeState", null);
|
|
4327
|
-
__legacyDecorateClassTS([
|
|
4328
|
-
TracedAs("workflow.engine.writeNodeResume", { recordParams: true, recordResult: true, log: true })
|
|
4329
|
-
], WorkflowEngine.prototype, "writeNodeResume", null);
|
|
4330
|
-
__legacyDecorateClassTS([
|
|
4331
|
-
TracedAs("workflow.engine.stop", { recordParams: true, recordResult: true, log: true })
|
|
4332
|
-
], WorkflowEngine.prototype, "stop", null);
|
|
4333
|
-
__legacyDecorateClassTS([
|
|
4334
|
-
TracedAs("workflow.engine.writeNodeInterrupt", { recordParams: true, recordResult: true, log: true }),
|
|
4335
|
-
TracedAs("workflow.engine.writeNodeInterrupt", { recordParams: true, recordResult: true, log: true })
|
|
4336
|
-
], WorkflowEngine.prototype, "writeNodeInterrupt", null);
|
|
4337
|
-
__legacyDecorateClassTS([
|
|
4338
|
-
TracedAs("workflow.engine.scheduleAndExecute", { recordParams: true, recordResult: true, log: true }),
|
|
4339
|
-
TracedAs("workflow.engine.scheduleAndExecute", { recordParams: true, recordResult: true, log: true })
|
|
4340
|
-
], WorkflowEngine.prototype, "scheduleAndExecute", null);
|
|
4341
|
-
__legacyDecorateClassTS([
|
|
4342
|
-
TracedAs("workflow.engine.waitForNextNodeEvent", { recordParams: true, recordResult: true, log: true })
|
|
4343
|
-
], WorkflowEngine.prototype, "waitForNextNodeEvent", null);
|
|
4344
|
-
__legacyDecorateClassTS([
|
|
4345
|
-
TracedAs("workflow.engine.startNode", { recordParams: true, recordResult: true, log: true }),
|
|
4346
|
-
TracedAs("workflow.engine.startNode", { recordParams: true, recordResult: true, log: true })
|
|
4347
|
-
], WorkflowEngine.prototype, "startNode", null);
|
|
4348
|
-
__legacyDecorateClassTS([
|
|
4349
|
-
TracedAs("workflow.engine.writeNodeCall", { recordParams: true, recordResult: true, log: true }),
|
|
4350
|
-
TracedAs("workflow.engine.writeNodeCall", { recordParams: true, recordResult: true, log: true })
|
|
4351
|
-
], WorkflowEngine.prototype, "writeNodeCall", null);
|
|
4352
|
-
__legacyDecorateClassTS([
|
|
4353
|
-
TracedAs("workflow.engine.resumeNode", { recordParams: true, recordResult: true, log: true }),
|
|
4354
|
-
TracedAs("workflow.engine.resumeNode", { recordParams: true, recordResult: true, log: true })
|
|
4355
|
-
], WorkflowEngine.prototype, "resumeNode", null);
|
|
4356
|
-
__legacyDecorateClassTS([
|
|
4357
|
-
TracedAs("workflow.engine.checkAndFinalize", { recordParams: true, recordResult: true, log: true })
|
|
4358
|
-
], WorkflowEngine.prototype, "checkAndFinalize", null);
|
|
4359
|
-
__legacyDecorateClassTS([
|
|
4360
|
-
TracedAs("workflow.engine.completeWorkflow", { recordParams: true, recordResult: true, log: true })
|
|
4361
|
-
], WorkflowEngine.prototype, "completeWorkflow", null);
|
|
4362
|
-
__legacyDecorateClassTS([
|
|
4363
|
-
TracedAs("workflow.engine.failWorkflow", { recordParams: true, recordResult: true, log: true })
|
|
4364
|
-
], WorkflowEngine.prototype, "failWorkflow", null);
|
|
4365
|
-
});
|
|
4366
|
-
|
|
4367
|
-
// packages/core/src/env/workflow/engine/index.ts
|
|
4368
|
-
var exports_engine = {};
|
|
4369
|
-
__export(exports_engine, {
|
|
4370
|
-
WorkflowEngine: () => WorkflowEngine,
|
|
4371
|
-
Scheduler: () => Scheduler,
|
|
4372
|
-
NodeRegistry: () => NodeRegistry,
|
|
4373
|
-
Executor: () => Executor,
|
|
4374
|
-
EventBus: () => EventBus,
|
|
4375
|
-
DAGManager: () => DAGManager
|
|
4376
|
-
});
|
|
4377
|
-
var init_engine2 = __esm(() => {
|
|
4378
|
-
init_executor();
|
|
4379
|
-
init_engine();
|
|
4380
|
-
init_node_registry();
|
|
4381
|
-
});
|
|
4382
|
-
init_engine2();
|
|
4383
|
-
|
|
4384
|
-
export {
|
|
4385
|
-
WorkflowEngine,
|
|
4386
|
-
Scheduler,
|
|
4387
|
-
NodeRegistry,
|
|
4388
|
-
Executor,
|
|
4389
|
-
EventBus,
|
|
4390
|
-
DAGManager
|
|
4391
|
-
};
|