simple-agents-wasm 0.2.28 → 0.2.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/index.d.ts +4 -1
- package/index.js +472 -4
- package/package.json +1 -1
- package/pkg/simple_agents_wasm.js +9 -1
- package/pkg/simple_agents_wasm_bg.wasm +0 -0
- package/rust/Cargo.toml +1 -1
- package/rust/src/lib.rs +810 -24
package/README.md
CHANGED
|
@@ -47,5 +47,8 @@ console.log(result.content);
|
|
|
47
47
|
- Browser mode still depends on provider CORS support.
|
|
48
48
|
- `healed_json` and `schema` completion modes are not supported yet.
|
|
49
49
|
- `runWorkflowYaml(workflowPath, ...)` is not supported in browser runtime.
|
|
50
|
-
- `runWorkflowYamlString(...)` supports string-based workflow execution
|
|
50
|
+
- `runWorkflowYamlString(...)` supports string-based workflow execution for:
|
|
51
|
+
- step workflows (`steps` DSL)
|
|
52
|
+
- graph workflows (`entry_node` + `nodes` + `edges`) with `llm_call`, `switch`, and `custom_worker`.
|
|
53
|
+
- Graph `custom_worker` nodes call `workflowOptions.functions[handler]` and throw a runtime error when the handler is missing.
|
|
51
54
|
- Use `hasRustBackend()` to check whether Rust wasm backend was loaded.
|
package/index.d.ts
CHANGED
|
@@ -105,7 +105,10 @@ export interface WorkflowRunOptions {
|
|
|
105
105
|
trace?: Record<string, unknown>;
|
|
106
106
|
functions?: Record<
|
|
107
107
|
string,
|
|
108
|
-
(
|
|
108
|
+
(
|
|
109
|
+
args: Record<string, unknown>,
|
|
110
|
+
context: Record<string, unknown>
|
|
111
|
+
) => unknown | Promise<unknown>
|
|
109
112
|
>;
|
|
110
113
|
}
|
|
111
114
|
|
package/index.js
CHANGED
|
@@ -127,13 +127,343 @@ function parseWorkflow(yamlText) {
|
|
|
127
127
|
throw configError("workflow YAML must parse to an object");
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
if (!Array.isArray(parsed.steps)) {
|
|
131
|
-
throw configError(
|
|
130
|
+
if (!Array.isArray(parsed.steps) && !isGraphWorkflow(parsed)) {
|
|
131
|
+
throw configError(
|
|
132
|
+
"workflow YAML must contain either a steps array or graph fields (entry_node + nodes)"
|
|
133
|
+
);
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
return parsed;
|
|
135
137
|
}
|
|
136
138
|
|
|
139
|
+
function isGraphWorkflow(doc) {
|
|
140
|
+
return (
|
|
141
|
+
doc &&
|
|
142
|
+
typeof doc === "object" &&
|
|
143
|
+
typeof doc.entry_node === "string" &&
|
|
144
|
+
Array.isArray(doc.nodes)
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function getPathValue(source, path) {
|
|
149
|
+
if (!source || typeof source !== "object") {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const normalized = String(path).trim().replace(/^\$\./, "");
|
|
154
|
+
const tokens = normalized.split(".").filter((token) => token.length > 0);
|
|
155
|
+
let current = source;
|
|
156
|
+
for (const token of tokens) {
|
|
157
|
+
if (!current || typeof current !== "object") {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
current = current[token];
|
|
161
|
+
}
|
|
162
|
+
return current;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function interpolatePathTemplate(template, context) {
|
|
166
|
+
if (typeof template !== "string") {
|
|
167
|
+
return "";
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return template.replace(/{{\s*([^}]+)\s*}}/g, (_, token) => {
|
|
171
|
+
const resolved = getPathValue(context, token);
|
|
172
|
+
if (resolved === null || resolved === undefined) {
|
|
173
|
+
return "";
|
|
174
|
+
}
|
|
175
|
+
if (typeof resolved === "string") {
|
|
176
|
+
return resolved;
|
|
177
|
+
}
|
|
178
|
+
return JSON.stringify(resolved);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function interpolatePathValue(value, context) {
|
|
183
|
+
if (typeof value === "string") {
|
|
184
|
+
return value.replace(/{{\s*([^}]+)\s*}}/g, (_, token) => {
|
|
185
|
+
const resolved = getPathValue(context, token);
|
|
186
|
+
if (resolved === null || resolved === undefined) {
|
|
187
|
+
return "";
|
|
188
|
+
}
|
|
189
|
+
if (typeof resolved === "string") {
|
|
190
|
+
return resolved;
|
|
191
|
+
}
|
|
192
|
+
return JSON.stringify(resolved);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (Array.isArray(value)) {
|
|
197
|
+
return value.map((entry) => interpolatePathValue(entry, context));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (value !== null && value !== undefined && typeof value === "object") {
|
|
201
|
+
const output = {};
|
|
202
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
203
|
+
output[key] = interpolatePathValue(nested, context);
|
|
204
|
+
}
|
|
205
|
+
return output;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return value;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function maybeParseJson(text) {
|
|
212
|
+
if (typeof text !== "string") {
|
|
213
|
+
return text;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
return JSON.parse(text);
|
|
218
|
+
} catch {
|
|
219
|
+
const start = text.indexOf("{");
|
|
220
|
+
const end = text.lastIndexOf("}");
|
|
221
|
+
if (start !== -1 && end !== -1 && end > start) {
|
|
222
|
+
const candidate = text.slice(start, end + 1);
|
|
223
|
+
try {
|
|
224
|
+
return JSON.parse(candidate);
|
|
225
|
+
} catch {
|
|
226
|
+
return text;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return text;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function matchesJsonSchemaType(expectedType, value) {
|
|
234
|
+
if (expectedType === "null") {
|
|
235
|
+
return value === null;
|
|
236
|
+
}
|
|
237
|
+
if (expectedType === "array") {
|
|
238
|
+
return Array.isArray(value);
|
|
239
|
+
}
|
|
240
|
+
if (expectedType === "object") {
|
|
241
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
242
|
+
}
|
|
243
|
+
if (expectedType === "integer") {
|
|
244
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
245
|
+
}
|
|
246
|
+
return typeof value === expectedType;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function jsonValueType(value) {
|
|
250
|
+
if (value === null) {
|
|
251
|
+
return "null";
|
|
252
|
+
}
|
|
253
|
+
if (Array.isArray(value)) {
|
|
254
|
+
return "array";
|
|
255
|
+
}
|
|
256
|
+
return typeof value;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function equalJsonValue(left, right) {
|
|
260
|
+
if (left === right) {
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
if (
|
|
264
|
+
left === null ||
|
|
265
|
+
right === null ||
|
|
266
|
+
left === undefined ||
|
|
267
|
+
right === undefined ||
|
|
268
|
+
typeof left !== "object" ||
|
|
269
|
+
typeof right !== "object"
|
|
270
|
+
) {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
276
|
+
} catch {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function schemaValidationError(schema, value, path = "$") {
|
|
282
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (Array.isArray(schema.anyOf) && schema.anyOf.length > 0) {
|
|
287
|
+
const anyOfErrors = schema.anyOf
|
|
288
|
+
.map((nested) => schemaValidationError(nested, value, path))
|
|
289
|
+
.filter((entry) => typeof entry === "string");
|
|
290
|
+
if (anyOfErrors.length === schema.anyOf.length) {
|
|
291
|
+
return `${path} did not satisfy anyOf`;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0) {
|
|
296
|
+
let matched = 0;
|
|
297
|
+
for (const nested of schema.oneOf) {
|
|
298
|
+
if (schemaValidationError(nested, value, path) === null) {
|
|
299
|
+
matched += 1;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (matched !== 1) {
|
|
303
|
+
return `${path} must satisfy exactly one oneOf schema`;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (Array.isArray(schema.allOf) && schema.allOf.length > 0) {
|
|
308
|
+
for (const nested of schema.allOf) {
|
|
309
|
+
const error = schemaValidationError(nested, value, path);
|
|
310
|
+
if (error !== null) {
|
|
311
|
+
return error;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (Array.isArray(schema.enum) && schema.enum.length > 0) {
|
|
317
|
+
const matched = schema.enum.some((candidate) => equalJsonValue(candidate, value));
|
|
318
|
+
if (!matched) {
|
|
319
|
+
return `${path} must be one of enum values`;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (schema.type !== undefined) {
|
|
324
|
+
const expectedTypes = Array.isArray(schema.type) ? schema.type : [schema.type];
|
|
325
|
+
const matchedType = expectedTypes.some((expectedType) => {
|
|
326
|
+
return typeof expectedType === "string" && matchesJsonSchemaType(expectedType, value);
|
|
327
|
+
});
|
|
328
|
+
if (!matchedType) {
|
|
329
|
+
return `${path} expected type ${expectedTypes.join(" | ")}, got ${jsonValueType(value)}`;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (typeof value === "string") {
|
|
334
|
+
if (typeof schema.minLength === "number" && value.length < schema.minLength) {
|
|
335
|
+
return `${path} must have minLength ${schema.minLength}`;
|
|
336
|
+
}
|
|
337
|
+
if (typeof schema.maxLength === "number" && value.length > schema.maxLength) {
|
|
338
|
+
return `${path} must have maxLength ${schema.maxLength}`;
|
|
339
|
+
}
|
|
340
|
+
if (typeof schema.pattern === "string") {
|
|
341
|
+
const pattern = new RegExp(schema.pattern);
|
|
342
|
+
if (!pattern.test(value)) {
|
|
343
|
+
return `${path} must match pattern ${schema.pattern}`;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (typeof value === "number") {
|
|
349
|
+
if (typeof schema.minimum === "number" && value < schema.minimum) {
|
|
350
|
+
return `${path} must be >= ${schema.minimum}`;
|
|
351
|
+
}
|
|
352
|
+
if (typeof schema.maximum === "number" && value > schema.maximum) {
|
|
353
|
+
return `${path} must be <= ${schema.maximum}`;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (Array.isArray(value)) {
|
|
358
|
+
if (typeof schema.minItems === "number" && value.length < schema.minItems) {
|
|
359
|
+
return `${path} must have at least ${schema.minItems} items`;
|
|
360
|
+
}
|
|
361
|
+
if (typeof schema.maxItems === "number" && value.length > schema.maxItems) {
|
|
362
|
+
return `${path} must have at most ${schema.maxItems} items`;
|
|
363
|
+
}
|
|
364
|
+
if (schema.items !== undefined) {
|
|
365
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
366
|
+
const error = schemaValidationError(schema.items, value[index], `${path}[${index}]`);
|
|
367
|
+
if (error !== null) {
|
|
368
|
+
return error;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const isObjectValue = value !== null && typeof value === "object" && !Array.isArray(value);
|
|
375
|
+
if (isObjectValue) {
|
|
376
|
+
const properties =
|
|
377
|
+
schema.properties && typeof schema.properties === "object" && !Array.isArray(schema.properties)
|
|
378
|
+
? schema.properties
|
|
379
|
+
: {};
|
|
380
|
+
|
|
381
|
+
if (Array.isArray(schema.required)) {
|
|
382
|
+
for (const key of schema.required) {
|
|
383
|
+
if (typeof key !== "string") {
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
if (!(key in value)) {
|
|
387
|
+
return `${path}.${key} is required`;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
for (const [key, propertySchema] of Object.entries(properties)) {
|
|
393
|
+
if (!(key in value)) {
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
const error = schemaValidationError(propertySchema, value[key], `${path}.${key}`);
|
|
397
|
+
if (error !== null) {
|
|
398
|
+
return error;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const knownKeys = new Set(Object.keys(properties));
|
|
403
|
+
if (schema.additionalProperties === false) {
|
|
404
|
+
for (const key of Object.keys(value)) {
|
|
405
|
+
if (!knownKeys.has(key)) {
|
|
406
|
+
return `${path}.${key} is not allowed`;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
} else if (
|
|
410
|
+
schema.additionalProperties !== undefined &&
|
|
411
|
+
schema.additionalProperties !== true
|
|
412
|
+
) {
|
|
413
|
+
for (const key of Object.keys(value)) {
|
|
414
|
+
if (knownKeys.has(key)) {
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
const error = schemaValidationError(
|
|
418
|
+
schema.additionalProperties,
|
|
419
|
+
value[key],
|
|
420
|
+
`${path}.${key}`
|
|
421
|
+
);
|
|
422
|
+
if (error !== null) {
|
|
423
|
+
return error;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function llmOutputSchema(node) {
|
|
433
|
+
const schema = node?.config?.output_schema;
|
|
434
|
+
if (schema && typeof schema === "object" && !Array.isArray(schema)) {
|
|
435
|
+
return schema;
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
type: "object",
|
|
439
|
+
additionalProperties: true
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function normalizeSseChunk(chunk) {
|
|
444
|
+
return chunk.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function evaluateSwitchCondition(condition, context) {
|
|
448
|
+
if (typeof condition !== "string") {
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const eq = condition.match(/^\$\.([A-Za-z0-9_.]+)\s*==\s*"([\s\S]*)"$/);
|
|
453
|
+
if (eq) {
|
|
454
|
+
const left = getPathValue(context, eq[1]);
|
|
455
|
+
return String(left ?? "") === eq[2];
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const ne = condition.match(/^\$\.([A-Za-z0-9_.]+)\s*!=\s*"([\s\S]*)"$/);
|
|
459
|
+
if (ne) {
|
|
460
|
+
const left = getPathValue(context, ne[1]);
|
|
461
|
+
return String(left ?? "") !== ne[2];
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
|
|
137
467
|
function parseSseEventBlock(block) {
|
|
138
468
|
const lines = block.split("\n");
|
|
139
469
|
const dataLines = [];
|
|
@@ -174,7 +504,7 @@ async function* iterateSse(response) {
|
|
|
174
504
|
break;
|
|
175
505
|
}
|
|
176
506
|
|
|
177
|
-
buffer += decoder.decode(value, { stream: true });
|
|
507
|
+
buffer += normalizeSseChunk(decoder.decode(value, { stream: true }));
|
|
178
508
|
let delimiterIndex = buffer.indexOf("\n\n");
|
|
179
509
|
while (delimiterIndex !== -1) {
|
|
180
510
|
const block = buffer.slice(0, delimiterIndex).trim();
|
|
@@ -186,6 +516,8 @@ async function* iterateSse(response) {
|
|
|
186
516
|
}
|
|
187
517
|
}
|
|
188
518
|
|
|
519
|
+
buffer += normalizeSseChunk(decoder.decode());
|
|
520
|
+
|
|
189
521
|
const trailing = buffer.trim();
|
|
190
522
|
if (trailing.length > 0) {
|
|
191
523
|
yield trailing;
|
|
@@ -468,6 +800,142 @@ class BrowserJsClient {
|
|
|
468
800
|
? workflowOptions.functions
|
|
469
801
|
: {};
|
|
470
802
|
|
|
803
|
+
if (isGraphWorkflow(doc)) {
|
|
804
|
+
const nodeById = new Map();
|
|
805
|
+
for (const node of doc.nodes) {
|
|
806
|
+
if (!node || typeof node !== "object" || typeof node.id !== "string") {
|
|
807
|
+
throw configError("workflow node is invalid or missing id");
|
|
808
|
+
}
|
|
809
|
+
nodeById.set(node.id, node);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
const edgeMap = new Map();
|
|
813
|
+
if (Array.isArray(doc.edges)) {
|
|
814
|
+
for (const edge of doc.edges) {
|
|
815
|
+
if (!edge || typeof edge.from !== "string" || typeof edge.to !== "string") {
|
|
816
|
+
continue;
|
|
817
|
+
}
|
|
818
|
+
const existing = edgeMap.get(edge.from) ?? [];
|
|
819
|
+
existing.push(edge.to);
|
|
820
|
+
edgeMap.set(edge.from, existing);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
const graphContext = {
|
|
825
|
+
input: workflowInput,
|
|
826
|
+
nodes: {}
|
|
827
|
+
};
|
|
828
|
+
|
|
829
|
+
let pointer = doc.entry_node;
|
|
830
|
+
let output;
|
|
831
|
+
let iterations = 0;
|
|
832
|
+
|
|
833
|
+
while (typeof pointer === "string" && pointer.length > 0) {
|
|
834
|
+
iterations += 1;
|
|
835
|
+
if (iterations > 1000) {
|
|
836
|
+
throw runtimeError("workflow exceeded maximum step iterations");
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
const node = nodeById.get(pointer);
|
|
840
|
+
if (!node) {
|
|
841
|
+
throw configError(`workflow references unknown node '${pointer}'`);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
const nodeType = node.node_type ?? {};
|
|
845
|
+
const nodeTypeName = Object.keys(nodeType)[0] ?? "unknown";
|
|
846
|
+
events.push({ stepId: node.id, stepType: nodeTypeName, status: "started" });
|
|
847
|
+
|
|
848
|
+
if (nodeType.llm_call) {
|
|
849
|
+
const llm = nodeType.llm_call;
|
|
850
|
+
const model = llm.model ?? doc.model ?? workflowInput.model;
|
|
851
|
+
if (typeof model !== "string" || model.trim().length === 0) {
|
|
852
|
+
throw configError(`llm_call node '${node.id}' requires node_type.llm_call.model`);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
const prompt = interpolatePathTemplate(node.config?.prompt ?? "", graphContext);
|
|
856
|
+
let promptOrMessages = prompt;
|
|
857
|
+
if (llm.messages_path === "input.messages") {
|
|
858
|
+
const source = getPathValue(graphContext, llm.messages_path);
|
|
859
|
+
const history = Array.isArray(source)
|
|
860
|
+
? source
|
|
861
|
+
.filter((message) => {
|
|
862
|
+
return (
|
|
863
|
+
message &&
|
|
864
|
+
typeof message === "object" &&
|
|
865
|
+
typeof message.role === "string" &&
|
|
866
|
+
typeof message.content === "string"
|
|
867
|
+
);
|
|
868
|
+
})
|
|
869
|
+
.map((message) => ({ role: message.role, content: message.content }))
|
|
870
|
+
: [];
|
|
871
|
+
if (llm.append_prompt_as_user !== false) {
|
|
872
|
+
history.push({ role: "user", content: prompt });
|
|
873
|
+
}
|
|
874
|
+
promptOrMessages = history;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
const completion = await this.complete(model, promptOrMessages, {
|
|
878
|
+
temperature: llm.temperature
|
|
879
|
+
});
|
|
880
|
+
const parsedOutput = maybeParseJson(completion.content ?? "");
|
|
881
|
+
const validationError = schemaValidationError(llmOutputSchema(node), parsedOutput);
|
|
882
|
+
if (validationError !== null) {
|
|
883
|
+
throw runtimeError(
|
|
884
|
+
`llm_call node '${node.id}' output failed schema validation: ${validationError}`
|
|
885
|
+
);
|
|
886
|
+
}
|
|
887
|
+
graphContext.nodes[node.id] = {
|
|
888
|
+
output: parsedOutput,
|
|
889
|
+
raw: completion.content ?? ""
|
|
890
|
+
};
|
|
891
|
+
output = parsedOutput;
|
|
892
|
+
|
|
893
|
+
const nextTargets = edgeMap.get(node.id) ?? [];
|
|
894
|
+
pointer = nextTargets[0] ?? "";
|
|
895
|
+
} else if (nodeType.switch) {
|
|
896
|
+
const switchSpec = nodeType.switch;
|
|
897
|
+
const branches = Array.isArray(switchSpec.branches) ? switchSpec.branches : [];
|
|
898
|
+
const matched = branches.find((branch) =>
|
|
899
|
+
evaluateSwitchCondition(branch?.condition, graphContext)
|
|
900
|
+
);
|
|
901
|
+
pointer = matched?.target ?? switchSpec.default ?? "";
|
|
902
|
+
} else if (nodeType.custom_worker) {
|
|
903
|
+
const handler = nodeType.custom_worker.handler ?? "custom_worker";
|
|
904
|
+
const fn = functions[handler];
|
|
905
|
+
if (typeof fn !== "function") {
|
|
906
|
+
throw runtimeError(
|
|
907
|
+
`custom_worker node '${node.id}' requires workflowOptions.functions['${handler}']`
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
const workerOutput = await fn(
|
|
911
|
+
{
|
|
912
|
+
handler,
|
|
913
|
+
payload: interpolatePathValue(node.config?.payload ?? null, graphContext),
|
|
914
|
+
nodeId: node.id
|
|
915
|
+
},
|
|
916
|
+
graphContext
|
|
917
|
+
);
|
|
918
|
+
graphContext.nodes[node.id] = {
|
|
919
|
+
output: workerOutput
|
|
920
|
+
};
|
|
921
|
+
output = workerOutput;
|
|
922
|
+
const nextTargets = edgeMap.get(node.id) ?? [];
|
|
923
|
+
pointer = nextTargets[0] ?? "";
|
|
924
|
+
} else {
|
|
925
|
+
throw configError(`unsupported node_type in simple-agents-wasm graph workflow`);
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
events.push({ stepId: node.id, stepType: nodeTypeName, status: "completed" });
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
return {
|
|
932
|
+
status: "ok",
|
|
933
|
+
context: graphContext,
|
|
934
|
+
output,
|
|
935
|
+
events
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
|
|
471
939
|
const indexById = new Map();
|
|
472
940
|
doc.steps.forEach((step, index) => {
|
|
473
941
|
if (!step || typeof step !== "object") {
|
|
@@ -530,7 +998,7 @@ class BrowserJsClient {
|
|
|
530
998
|
}
|
|
531
999
|
|
|
532
1000
|
const args = interpolate(step.args ?? {}, context);
|
|
533
|
-
context[step.id] = fn(args, context);
|
|
1001
|
+
context[step.id] = await fn(args, context);
|
|
534
1002
|
} else if (step.type === "output") {
|
|
535
1003
|
output = interpolate(step.text ?? step.value ?? "", context);
|
|
536
1004
|
context[step.id] = output;
|
package/package.json
CHANGED
|
@@ -138,6 +138,10 @@ function __wbg_get_imports() {
|
|
|
138
138
|
const ret = typeof(arg0) === 'function';
|
|
139
139
|
return ret;
|
|
140
140
|
},
|
|
141
|
+
__wbg___wbindgen_is_null_0b605fc6b167c56f: function(arg0) {
|
|
142
|
+
const ret = arg0 === null;
|
|
143
|
+
return ret;
|
|
144
|
+
},
|
|
141
145
|
__wbg___wbindgen_is_object_781bc9f159099513: function(arg0) {
|
|
142
146
|
const val = arg0;
|
|
143
147
|
const ret = typeof(val) === 'object' && val !== null;
|
|
@@ -191,6 +195,10 @@ function __wbg_get_imports() {
|
|
|
191
195
|
const ret = arg0.call(arg1);
|
|
192
196
|
return ret;
|
|
193
197
|
}, arguments); },
|
|
198
|
+
__wbg_construct_526a6dedb187eba9: function() { return handleError(function (arg0, arg1) {
|
|
199
|
+
const ret = Reflect.construct(arg0, arg1);
|
|
200
|
+
return ret;
|
|
201
|
+
}, arguments); },
|
|
194
202
|
__wbg_done_08ce71ee07e3bd17: function(arg0) {
|
|
195
203
|
const ret = arg0.done;
|
|
196
204
|
return ret;
|
|
@@ -386,7 +394,7 @@ function __wbg_get_imports() {
|
|
|
386
394
|
return ret;
|
|
387
395
|
},
|
|
388
396
|
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
|
389
|
-
// Cast intrinsic for `Closure(Closure { dtor_idx:
|
|
397
|
+
// Cast intrinsic for `Closure(Closure { dtor_idx: 106, function: Function { arguments: [Externref], shim_idx: 107, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
390
398
|
const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__h5b569a9b0c99a6ce, wasm_bindgen__convert__closures_____invoke__h26e23bd7929d5711);
|
|
391
399
|
return ret;
|
|
392
400
|
},
|
|
Binary file
|