@darkhorseprojects/circuitry 0.2.32 → 0.2.33
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/index.js +100 -8
- package/dist/node.js +100 -8
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -519,6 +519,96 @@ ${contextSection}`
|
|
|
519
519
|
].filter(Boolean).join("\n\n");
|
|
520
520
|
};
|
|
521
521
|
var collectImages = (contextInputs) => contextInputs.filter((item) => item.kind === "image" && item.image).map((item) => item.image);
|
|
522
|
+
var stripJsonFence = (output) => {
|
|
523
|
+
const trimmed = output.trim();
|
|
524
|
+
const fenced = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
|
|
525
|
+
return fenced ? fenced[1].trim() : trimmed;
|
|
526
|
+
};
|
|
527
|
+
var parseExpectedOutput = (nodeId, output) => {
|
|
528
|
+
try {
|
|
529
|
+
return JSON.parse(stripJsonFence(output));
|
|
530
|
+
} catch (error) {
|
|
531
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
532
|
+
throw new Error(`Node ${nodeId} output does not match expect: output is not valid JSON (${detail})`);
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
var isFieldObject = (schema) => !!schema && typeof schema === "object" && !Array.isArray(schema) && typeof schema.type === "string";
|
|
536
|
+
var describeExpectedType = (schema) => Array.isArray(schema) ? "list" : typeof schema === "string" ? schema : isFieldObject(schema) ? schema.type : "dict";
|
|
537
|
+
var matchesPrimitiveType = (value, type) => {
|
|
538
|
+
switch (type) {
|
|
539
|
+
case "str":
|
|
540
|
+
return typeof value === "string";
|
|
541
|
+
case "int":
|
|
542
|
+
return Number.isInteger(value);
|
|
543
|
+
case "float":
|
|
544
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
545
|
+
case "bool":
|
|
546
|
+
return typeof value === "boolean";
|
|
547
|
+
case "list":
|
|
548
|
+
return Array.isArray(value);
|
|
549
|
+
case "dict":
|
|
550
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
551
|
+
default:
|
|
552
|
+
return true;
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
var validateExpectValue = (value, schema, path, errors) => {
|
|
556
|
+
if (typeof schema === "string") {
|
|
557
|
+
if (!matchesPrimitiveType(value, schema)) {
|
|
558
|
+
errors.push(`${path} expected ${schema}, got ${Array.isArray(value) ? "list" : typeof value}`);
|
|
559
|
+
}
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
if (Array.isArray(schema)) {
|
|
563
|
+
if (!Array.isArray(value)) {
|
|
564
|
+
errors.push(`${path} expected list, got ${typeof value}`);
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
if (schema.length > 0) {
|
|
568
|
+
value.forEach((item, index) => validateExpectValue(item, schema[0], `${path}[${index}]`, errors));
|
|
569
|
+
}
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
if (isFieldObject(schema)) {
|
|
573
|
+
if (schema.optional && value === void 0) return;
|
|
574
|
+
if (!matchesPrimitiveType(value, schema.type)) {
|
|
575
|
+
errors.push(`${path} expected ${schema.type}, got ${Array.isArray(value) ? "list" : typeof value}`);
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
if (schema.contains && typeof value === "string" && !value.includes(schema.contains)) {
|
|
579
|
+
errors.push(`${path} must include string: ${schema.contains}`);
|
|
580
|
+
}
|
|
581
|
+
if (schema.type === "list" && schema.items && Array.isArray(value)) {
|
|
582
|
+
value.forEach((item, index) => validateExpectValue(item, schema.items, `${path}[${index}]`, errors));
|
|
583
|
+
}
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
if (schema && typeof schema === "object") {
|
|
587
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
588
|
+
errors.push(`${path} expected dict, got ${Array.isArray(value) ? "list" : typeof value}`);
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
for (const [key, childSchema] of Object.entries(schema)) {
|
|
592
|
+
const childOptional = isFieldObject(childSchema) && childSchema.optional;
|
|
593
|
+
const childValue = value[key];
|
|
594
|
+
if (childValue === void 0 && !childOptional) {
|
|
595
|
+
errors.push(`${path}.${key} is missing required field of type ${describeExpectedType(childSchema)}`);
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
validateExpectValue(childValue, childSchema, `${path}.${key}`, errors);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
var assertExpectedOutput = (node, output) => {
|
|
603
|
+
if (!node.expect) return;
|
|
604
|
+
const parsed = parseExpectedOutput(node.id, output);
|
|
605
|
+
const errors = [];
|
|
606
|
+
validateExpectValue(parsed, node.expect, node.id, errors);
|
|
607
|
+
if (errors.length) {
|
|
608
|
+
throw new Error(`Node ${node.id} output does not match expect:
|
|
609
|
+
${errors.join("\n")}`);
|
|
610
|
+
}
|
|
611
|
+
};
|
|
522
612
|
var executeCircuitryNode = async ({
|
|
523
613
|
graph,
|
|
524
614
|
item,
|
|
@@ -542,8 +632,9 @@ var executeCircuitryNode = async ({
|
|
|
542
632
|
};
|
|
543
633
|
}
|
|
544
634
|
const agent = item.node.agent || {};
|
|
635
|
+
let result;
|
|
545
636
|
try {
|
|
546
|
-
|
|
637
|
+
result = await executeNode({
|
|
547
638
|
nodeId: item.id,
|
|
548
639
|
model: (agent.model === "inherit" ? void 0 : agent.model) || (defaultModel === "inherit" ? void 0 : defaultModel) || "inherit",
|
|
549
640
|
tools: agent.tools || [],
|
|
@@ -556,13 +647,6 @@ var executeCircuitryNode = async ({
|
|
|
556
647
|
images: collectImages(contextInputs),
|
|
557
648
|
prompt: composeCircuitryPrompt(graph, item.node, inputPayload, contextInputs)
|
|
558
649
|
});
|
|
559
|
-
onNodeComplete?.(item.id, { output: result.output });
|
|
560
|
-
return {
|
|
561
|
-
nodeId: item.id,
|
|
562
|
-
fallbackCycle,
|
|
563
|
-
inputNodeIds: inputPayload.map((input) => input.nodeId),
|
|
564
|
-
output: result.output
|
|
565
|
-
};
|
|
566
650
|
} catch (error) {
|
|
567
651
|
const message = error instanceof Error ? error.message : String(error);
|
|
568
652
|
onNodeComplete?.(item.id, { error: message });
|
|
@@ -574,6 +658,14 @@ var executeCircuitryNode = async ({
|
|
|
574
658
|
error: message
|
|
575
659
|
};
|
|
576
660
|
}
|
|
661
|
+
assertExpectedOutput(item.node, result.output);
|
|
662
|
+
onNodeComplete?.(item.id, { output: result.output });
|
|
663
|
+
return {
|
|
664
|
+
nodeId: item.id,
|
|
665
|
+
fallbackCycle,
|
|
666
|
+
inputNodeIds: inputPayload.map((input) => input.nodeId),
|
|
667
|
+
output: result.output
|
|
668
|
+
};
|
|
577
669
|
};
|
|
578
670
|
var runCircuitryGraphExecution = async ({
|
|
579
671
|
graph,
|
package/dist/node.js
CHANGED
|
@@ -441,6 +441,96 @@ ${contextSection}`
|
|
|
441
441
|
].filter(Boolean).join("\n\n");
|
|
442
442
|
};
|
|
443
443
|
var collectImages = (contextInputs) => contextInputs.filter((item) => item.kind === "image" && item.image).map((item) => item.image);
|
|
444
|
+
var stripJsonFence = (output) => {
|
|
445
|
+
const trimmed = output.trim();
|
|
446
|
+
const fenced = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
|
|
447
|
+
return fenced ? fenced[1].trim() : trimmed;
|
|
448
|
+
};
|
|
449
|
+
var parseExpectedOutput = (nodeId, output) => {
|
|
450
|
+
try {
|
|
451
|
+
return JSON.parse(stripJsonFence(output));
|
|
452
|
+
} catch (error) {
|
|
453
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
454
|
+
throw new Error(`Node ${nodeId} output does not match expect: output is not valid JSON (${detail})`);
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
var isFieldObject = (schema) => !!schema && typeof schema === "object" && !Array.isArray(schema) && typeof schema.type === "string";
|
|
458
|
+
var describeExpectedType = (schema) => Array.isArray(schema) ? "list" : typeof schema === "string" ? schema : isFieldObject(schema) ? schema.type : "dict";
|
|
459
|
+
var matchesPrimitiveType = (value, type) => {
|
|
460
|
+
switch (type) {
|
|
461
|
+
case "str":
|
|
462
|
+
return typeof value === "string";
|
|
463
|
+
case "int":
|
|
464
|
+
return Number.isInteger(value);
|
|
465
|
+
case "float":
|
|
466
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
467
|
+
case "bool":
|
|
468
|
+
return typeof value === "boolean";
|
|
469
|
+
case "list":
|
|
470
|
+
return Array.isArray(value);
|
|
471
|
+
case "dict":
|
|
472
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
473
|
+
default:
|
|
474
|
+
return true;
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
var validateExpectValue = (value, schema, path2, errors) => {
|
|
478
|
+
if (typeof schema === "string") {
|
|
479
|
+
if (!matchesPrimitiveType(value, schema)) {
|
|
480
|
+
errors.push(`${path2} expected ${schema}, got ${Array.isArray(value) ? "list" : typeof value}`);
|
|
481
|
+
}
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
if (Array.isArray(schema)) {
|
|
485
|
+
if (!Array.isArray(value)) {
|
|
486
|
+
errors.push(`${path2} expected list, got ${typeof value}`);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
if (schema.length > 0) {
|
|
490
|
+
value.forEach((item, index) => validateExpectValue(item, schema[0], `${path2}[${index}]`, errors));
|
|
491
|
+
}
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (isFieldObject(schema)) {
|
|
495
|
+
if (schema.optional && value === void 0) return;
|
|
496
|
+
if (!matchesPrimitiveType(value, schema.type)) {
|
|
497
|
+
errors.push(`${path2} expected ${schema.type}, got ${Array.isArray(value) ? "list" : typeof value}`);
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
if (schema.contains && typeof value === "string" && !value.includes(schema.contains)) {
|
|
501
|
+
errors.push(`${path2} must include string: ${schema.contains}`);
|
|
502
|
+
}
|
|
503
|
+
if (schema.type === "list" && schema.items && Array.isArray(value)) {
|
|
504
|
+
value.forEach((item, index) => validateExpectValue(item, schema.items, `${path2}[${index}]`, errors));
|
|
505
|
+
}
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
if (schema && typeof schema === "object") {
|
|
509
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
510
|
+
errors.push(`${path2} expected dict, got ${Array.isArray(value) ? "list" : typeof value}`);
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
for (const [key, childSchema] of Object.entries(schema)) {
|
|
514
|
+
const childOptional = isFieldObject(childSchema) && childSchema.optional;
|
|
515
|
+
const childValue = value[key];
|
|
516
|
+
if (childValue === void 0 && !childOptional) {
|
|
517
|
+
errors.push(`${path2}.${key} is missing required field of type ${describeExpectedType(childSchema)}`);
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
validateExpectValue(childValue, childSchema, `${path2}.${key}`, errors);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
var assertExpectedOutput = (node, output) => {
|
|
525
|
+
if (!node.expect) return;
|
|
526
|
+
const parsed = parseExpectedOutput(node.id, output);
|
|
527
|
+
const errors = [];
|
|
528
|
+
validateExpectValue(parsed, node.expect, node.id, errors);
|
|
529
|
+
if (errors.length) {
|
|
530
|
+
throw new Error(`Node ${node.id} output does not match expect:
|
|
531
|
+
${errors.join("\n")}`);
|
|
532
|
+
}
|
|
533
|
+
};
|
|
444
534
|
var executeCircuitryNode = async ({
|
|
445
535
|
graph,
|
|
446
536
|
item,
|
|
@@ -464,8 +554,9 @@ var executeCircuitryNode = async ({
|
|
|
464
554
|
};
|
|
465
555
|
}
|
|
466
556
|
const agent = item.node.agent || {};
|
|
557
|
+
let result;
|
|
467
558
|
try {
|
|
468
|
-
|
|
559
|
+
result = await executeNode({
|
|
469
560
|
nodeId: item.id,
|
|
470
561
|
model: (agent.model === "inherit" ? void 0 : agent.model) || (defaultModel === "inherit" ? void 0 : defaultModel) || "inherit",
|
|
471
562
|
tools: agent.tools || [],
|
|
@@ -478,13 +569,6 @@ var executeCircuitryNode = async ({
|
|
|
478
569
|
images: collectImages(contextInputs),
|
|
479
570
|
prompt: composeCircuitryPrompt(graph, item.node, inputPayload, contextInputs)
|
|
480
571
|
});
|
|
481
|
-
onNodeComplete?.(item.id, { output: result.output });
|
|
482
|
-
return {
|
|
483
|
-
nodeId: item.id,
|
|
484
|
-
fallbackCycle,
|
|
485
|
-
inputNodeIds: inputPayload.map((input) => input.nodeId),
|
|
486
|
-
output: result.output
|
|
487
|
-
};
|
|
488
572
|
} catch (error) {
|
|
489
573
|
const message = error instanceof Error ? error.message : String(error);
|
|
490
574
|
onNodeComplete?.(item.id, { error: message });
|
|
@@ -496,6 +580,14 @@ var executeCircuitryNode = async ({
|
|
|
496
580
|
error: message
|
|
497
581
|
};
|
|
498
582
|
}
|
|
583
|
+
assertExpectedOutput(item.node, result.output);
|
|
584
|
+
onNodeComplete?.(item.id, { output: result.output });
|
|
585
|
+
return {
|
|
586
|
+
nodeId: item.id,
|
|
587
|
+
fallbackCycle,
|
|
588
|
+
inputNodeIds: inputPayload.map((input) => input.nodeId),
|
|
589
|
+
output: result.output
|
|
590
|
+
};
|
|
499
591
|
};
|
|
500
592
|
var runCircuitryGraphExecution = async ({
|
|
501
593
|
graph,
|