@graphrefly/graphrefly 0.9.0 → 0.11.0
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/{chunk-WYI7YW54.js → chunk-2OTXEZQO.js} +3 -3
- package/dist/{chunk-TZLX4KIT.js → chunk-2VHNCFGG.js} +3 -3
- package/dist/{chunk-XCZPGOVP.js → chunk-3WACHRHV.js} +3 -3
- package/dist/{chunk-YWTP2XRJ.js → chunk-5WXTWOD7.js} +2 -2
- package/dist/{chunk-E7OH6ZAZ.js → chunk-FMVFRP7L.js} +62 -3
- package/dist/chunk-FMVFRP7L.js.map +1 -0
- package/dist/{chunk-LR2CLSEF.js → chunk-OHUECHWY.js} +2 -3
- package/dist/chunk-OHUECHWY.js.map +1 -0
- package/dist/{chunk-UCW3VWMN.js → chunk-PZCDQD2U.js} +4 -4
- package/dist/{chunk-A2AJJOSJ.js → chunk-U5HFZGAQ.js} +3 -3
- package/dist/{chunk-QTZSBQGJ.js → chunk-UG2QZMRN.js} +18 -1
- package/dist/chunk-UG2QZMRN.js.map +1 -0
- package/dist/compat/nestjs/index.cjs +10 -1
- package/dist/compat/nestjs/index.cjs.map +1 -1
- package/dist/compat/nestjs/index.d.cts +4 -4
- package/dist/compat/nestjs/index.d.ts +4 -4
- package/dist/compat/nestjs/index.js +7 -7
- package/dist/core/index.cjs +74 -1
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +12 -3
- package/dist/extra/index.cjs +10 -0
- package/dist/extra/index.cjs.map +1 -1
- package/dist/extra/index.d.cts +4 -4
- package/dist/extra/index.d.ts +4 -4
- package/dist/extra/index.js +3 -3
- package/dist/graph/index.cjs +10 -1
- package/dist/graph/index.cjs.map +1 -1
- package/dist/graph/index.d.cts +3 -3
- package/dist/graph/index.d.ts +3 -3
- package/dist/graph/index.js +4 -4
- package/dist/{graph-DqTICAY2.d.cts → graph-BE10ujU9.d.cts} +1 -1
- package/dist/{graph-X9uwnD_z.d.ts → graph-DXT95WZ3.d.ts} +1 -1
- package/dist/{index-DLO8wnYU.d.ts → index-53cDGX7F.d.ts} +3 -3
- package/dist/{index-DMv1Etbi.d.ts → index-B10Q0sQB.d.ts} +2 -2
- package/dist/{index-a5gHmH5b.d.ts → index-Bbgvinsi.d.ts} +3 -3
- package/dist/{index-BPCeYDS4.d.ts → index-C0_7g9sj.d.ts} +1 -1
- package/dist/{index-3U0WxdD-.d.cts → index-CCvzN5GB.d.cts} +2 -2
- package/dist/{index-BP1t_38S.d.cts → index-DpZozxaJ.d.cts} +3 -3
- package/dist/{index-BVG5pjin.d.ts → index-Dzdm20sx.d.ts} +88 -3
- package/dist/{index-BYEgosAX.d.cts → index-QfbXNW1N.d.cts} +88 -3
- package/dist/{index-BYa2YMat.d.cts → index-aBZ2RoP0.d.cts} +3 -3
- package/dist/{index-DbwgQ4Cw.d.cts → index-nRulwTr-.d.cts} +1 -1
- package/dist/index.cjs +2009 -406
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +559 -14
- package/dist/index.d.ts +559 -14
- package/dist/index.js +1938 -406
- package/dist/index.js.map +1 -1
- package/dist/{meta-BJEU8fYz.d.cts → meta-BcuDhtwu.d.cts} +33 -1
- package/dist/{meta-BJEU8fYz.d.ts → meta-BcuDhtwu.d.ts} +33 -1
- package/dist/patterns/reactive-layout/index.cjs +10 -1
- package/dist/patterns/reactive-layout/index.cjs.map +1 -1
- package/dist/patterns/reactive-layout/index.d.cts +3 -3
- package/dist/patterns/reactive-layout/index.d.ts +3 -3
- package/dist/patterns/reactive-layout/index.js +4 -4
- package/dist/{reactive-log-RhgIog2Z.d.ts → reactive-log-Cu0VdqkT.d.ts} +2 -2
- package/dist/{reactive-log-BfX6bOSZ.d.cts → reactive-log-OULQssZg.d.cts} +2 -2
- package/package.json +7 -2
- package/dist/chunk-E7OH6ZAZ.js.map +0 -1
- package/dist/chunk-LR2CLSEF.js.map +0 -1
- package/dist/chunk-QTZSBQGJ.js.map +0 -1
- /package/dist/{chunk-WYI7YW54.js.map → chunk-2OTXEZQO.js.map} +0 -0
- /package/dist/{chunk-TZLX4KIT.js.map → chunk-2VHNCFGG.js.map} +0 -0
- /package/dist/{chunk-XCZPGOVP.js.map → chunk-3WACHRHV.js.map} +0 -0
- /package/dist/{chunk-YWTP2XRJ.js.map → chunk-5WXTWOD7.js.map} +0 -0
- /package/dist/{chunk-UCW3VWMN.js.map → chunk-PZCDQD2U.js.map} +0 -0
- /package/dist/{chunk-A2AJJOSJ.js.map → chunk-U5HFZGAQ.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -65,10 +65,12 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
|
|
|
65
65
|
// src/index.ts
|
|
66
66
|
var index_exports = {};
|
|
67
67
|
__export(index_exports, {
|
|
68
|
+
CLEANUP_RESULT: () => CLEANUP_RESULT,
|
|
68
69
|
COMPLETE: () => COMPLETE,
|
|
69
70
|
CircuitOpenError: () => CircuitOpenError,
|
|
70
71
|
DATA: () => DATA,
|
|
71
72
|
DEFAULT_ACTOR: () => DEFAULT_ACTOR,
|
|
73
|
+
DEFAULT_DOWN: () => DEFAULT_DOWN,
|
|
72
74
|
DIRTY: () => DIRTY,
|
|
73
75
|
DictCheckpointAdapter: () => DictCheckpointAdapter,
|
|
74
76
|
DynamicNodeImpl: () => DynamicNodeImpl,
|
|
@@ -94,6 +96,7 @@ __export(index_exports, {
|
|
|
94
96
|
ai: () => ai_exports,
|
|
95
97
|
audit: () => audit,
|
|
96
98
|
batch: () => batch,
|
|
99
|
+
bridge: () => bridge,
|
|
97
100
|
buffer: () => buffer,
|
|
98
101
|
bufferCount: () => bufferCount,
|
|
99
102
|
bufferTime: () => bufferTime,
|
|
@@ -105,6 +108,7 @@ __export(index_exports, {
|
|
|
105
108
|
checkpointToRedis: () => checkpointToRedis,
|
|
106
109
|
checkpointToS3: () => checkpointToS3,
|
|
107
110
|
circuitBreaker: () => circuitBreaker,
|
|
111
|
+
cleanupResult: () => cleanupResult,
|
|
108
112
|
combine: () => combine,
|
|
109
113
|
combineLatest: () => combineLatest,
|
|
110
114
|
compat: () => compat_exports,
|
|
@@ -129,6 +133,7 @@ __export(index_exports, {
|
|
|
129
133
|
deserializeError: () => deserializeError,
|
|
130
134
|
distill: () => distill,
|
|
131
135
|
distinctUntilChanged: () => distinctUntilChanged,
|
|
136
|
+
domainTemplates: () => domain_templates_exports,
|
|
132
137
|
dynamicNode: () => dynamicNode,
|
|
133
138
|
effect: () => effect,
|
|
134
139
|
elementAt: () => elementAt,
|
|
@@ -180,6 +185,7 @@ __export(index_exports, {
|
|
|
180
185
|
gate: () => gate,
|
|
181
186
|
globToRegExp: () => globToRegExp,
|
|
182
187
|
graph: () => graph_exports,
|
|
188
|
+
graphspec: () => graphspec_exports,
|
|
183
189
|
interval: () => interval,
|
|
184
190
|
isBatching: () => isBatching,
|
|
185
191
|
isKnownMessageType: () => isKnownMessageType,
|
|
@@ -728,6 +734,7 @@ function isV1(info) {
|
|
|
728
734
|
|
|
729
735
|
// src/core/node.ts
|
|
730
736
|
var NO_VALUE = /* @__PURE__ */ Symbol.for("graphrefly/NO_VALUE");
|
|
737
|
+
var CLEANUP_RESULT = /* @__PURE__ */ Symbol.for("graphrefly/CLEANUP_RESULT");
|
|
731
738
|
function createIntBitSet() {
|
|
732
739
|
let bits = 0;
|
|
733
740
|
return {
|
|
@@ -790,6 +797,12 @@ function createBitSet(size) {
|
|
|
790
797
|
}
|
|
791
798
|
var isNodeArray = (value) => Array.isArray(value);
|
|
792
799
|
var isNodeOptions = (value) => typeof value === "object" && value != null && !Array.isArray(value);
|
|
800
|
+
function cleanupResult(cleanup, ...args) {
|
|
801
|
+
const r = { [CLEANUP_RESULT]: true, cleanup };
|
|
802
|
+
if (args.length > 0) r.value = args[0];
|
|
803
|
+
return r;
|
|
804
|
+
}
|
|
805
|
+
var isCleanupResult = (value) => typeof value === "object" && value !== null && CLEANUP_RESULT in value;
|
|
793
806
|
var isCleanupFn = (value) => typeof value === "function";
|
|
794
807
|
var statusAfterMessage = (status, msg) => {
|
|
795
808
|
const t = msg[0];
|
|
@@ -1205,6 +1218,14 @@ var NodeImpl = class {
|
|
|
1205
1218
|
this._lastDepValues = depValues;
|
|
1206
1219
|
this._inspectorHook?.({ kind: "run", depValues });
|
|
1207
1220
|
const out = this._fn(depValues, this._actions);
|
|
1221
|
+
if (isCleanupResult(out)) {
|
|
1222
|
+
this._cleanup = out.cleanup;
|
|
1223
|
+
if (this._manualEmitUsed) return;
|
|
1224
|
+
if ("value" in out) {
|
|
1225
|
+
this._emitAutoValue(out.value);
|
|
1226
|
+
}
|
|
1227
|
+
return;
|
|
1228
|
+
}
|
|
1208
1229
|
if (isCleanupFn(out)) {
|
|
1209
1230
|
this._cleanup = out;
|
|
1210
1231
|
return;
|
|
@@ -3543,7 +3564,6 @@ function resolveDescribeFields(detail, fields) {
|
|
|
3543
3564
|
case "full":
|
|
3544
3565
|
return null;
|
|
3545
3566
|
// null = include everything
|
|
3546
|
-
case "minimal":
|
|
3547
3567
|
default:
|
|
3548
3568
|
return /* @__PURE__ */ new Set(["type", "deps"]);
|
|
3549
3569
|
}
|
|
@@ -5518,9 +5538,11 @@ __export(cqrs_exports, {
|
|
|
5518
5538
|
// src/core/index.ts
|
|
5519
5539
|
var core_exports = {};
|
|
5520
5540
|
__export(core_exports, {
|
|
5541
|
+
CLEANUP_RESULT: () => CLEANUP_RESULT,
|
|
5521
5542
|
COMPLETE: () => COMPLETE,
|
|
5522
5543
|
DATA: () => DATA,
|
|
5523
5544
|
DEFAULT_ACTOR: () => DEFAULT_ACTOR,
|
|
5545
|
+
DEFAULT_DOWN: () => DEFAULT_DOWN,
|
|
5524
5546
|
DIRTY: () => DIRTY,
|
|
5525
5547
|
DynamicNodeImpl: () => DynamicNodeImpl,
|
|
5526
5548
|
ERROR: () => ERROR,
|
|
@@ -5534,6 +5556,8 @@ __export(core_exports, {
|
|
|
5534
5556
|
accessHintForGuard: () => accessHintForGuard,
|
|
5535
5557
|
advanceVersion: () => advanceVersion,
|
|
5536
5558
|
batch: () => batch,
|
|
5559
|
+
bridge: () => bridge,
|
|
5560
|
+
cleanupResult: () => cleanupResult,
|
|
5537
5561
|
createVersioning: () => createVersioning,
|
|
5538
5562
|
defaultHash: () => defaultHash,
|
|
5539
5563
|
derived: () => derived,
|
|
@@ -5563,6 +5587,57 @@ __export(core_exports, {
|
|
|
5563
5587
|
wallClockNs: () => wallClockNs
|
|
5564
5588
|
});
|
|
5565
5589
|
|
|
5590
|
+
// src/core/bridge.ts
|
|
5591
|
+
var DEFAULT_DOWN = [
|
|
5592
|
+
DATA,
|
|
5593
|
+
DIRTY,
|
|
5594
|
+
RESOLVED,
|
|
5595
|
+
COMPLETE,
|
|
5596
|
+
ERROR,
|
|
5597
|
+
TEARDOWN,
|
|
5598
|
+
PAUSE,
|
|
5599
|
+
RESUME,
|
|
5600
|
+
INVALIDATE
|
|
5601
|
+
];
|
|
5602
|
+
var STANDARD_TYPES = /* @__PURE__ */ new Set([
|
|
5603
|
+
DATA,
|
|
5604
|
+
DIRTY,
|
|
5605
|
+
RESOLVED,
|
|
5606
|
+
COMPLETE,
|
|
5607
|
+
ERROR,
|
|
5608
|
+
TEARDOWN,
|
|
5609
|
+
PAUSE,
|
|
5610
|
+
RESUME,
|
|
5611
|
+
INVALIDATE
|
|
5612
|
+
]);
|
|
5613
|
+
function bridge(from, to, opts) {
|
|
5614
|
+
const allowedDown = new Set(opts?.down ?? DEFAULT_DOWN);
|
|
5615
|
+
const onMessage = (msg, _depIndex, _actions) => {
|
|
5616
|
+
const type = msg[0];
|
|
5617
|
+
if (!STANDARD_TYPES.has(type)) {
|
|
5618
|
+
to.down([msg]);
|
|
5619
|
+
return true;
|
|
5620
|
+
}
|
|
5621
|
+
if (type === COMPLETE || type === ERROR) {
|
|
5622
|
+
if (allowedDown.has(type)) {
|
|
5623
|
+
to.down([msg]);
|
|
5624
|
+
}
|
|
5625
|
+
return false;
|
|
5626
|
+
}
|
|
5627
|
+
if (!allowedDown.has(type)) {
|
|
5628
|
+
return true;
|
|
5629
|
+
}
|
|
5630
|
+
to.down([msg]);
|
|
5631
|
+
return true;
|
|
5632
|
+
};
|
|
5633
|
+
return node([from], void 0, {
|
|
5634
|
+
name: opts?.name,
|
|
5635
|
+
describeKind: "effect",
|
|
5636
|
+
onMessage,
|
|
5637
|
+
meta: { _internal: true }
|
|
5638
|
+
});
|
|
5639
|
+
}
|
|
5640
|
+
|
|
5566
5641
|
// src/core/timer.ts
|
|
5567
5642
|
var ResettableTimer = class {
|
|
5568
5643
|
_timer;
|
|
@@ -12862,6 +12937,8 @@ __export(patterns_exports, {
|
|
|
12862
12937
|
ai: () => ai_exports,
|
|
12863
12938
|
cqrs: () => cqrs_exports,
|
|
12864
12939
|
demoShell: () => demo_shell_exports,
|
|
12940
|
+
domainTemplates: () => domain_templates_exports,
|
|
12941
|
+
graphspec: () => graphspec_exports,
|
|
12865
12942
|
layout: () => reactive_layout_exports,
|
|
12866
12943
|
memory: () => memory_exports,
|
|
12867
12944
|
messaging: () => messaging_exports,
|
|
@@ -14274,7 +14351,7 @@ function gaugesAsContext(graph, actor, options) {
|
|
|
14274
14351
|
const ungrouped = [];
|
|
14275
14352
|
for (const entry of entries) {
|
|
14276
14353
|
const node2 = described.nodes[entry.path];
|
|
14277
|
-
const tags =
|
|
14354
|
+
const tags = node2.meta?.tags;
|
|
14278
14355
|
if (tags && tags.length > 0) {
|
|
14279
14356
|
const tag = tags[0];
|
|
14280
14357
|
let group = tagGroups.get(tag);
|
|
@@ -15417,135 +15494,1926 @@ function demoShell(opts) {
|
|
|
15417
15494
|
};
|
|
15418
15495
|
}
|
|
15419
15496
|
|
|
15420
|
-
// src/patterns/
|
|
15421
|
-
var
|
|
15422
|
-
__export(
|
|
15423
|
-
|
|
15424
|
-
|
|
15425
|
-
|
|
15426
|
-
|
|
15427
|
-
TopicGraph: () => TopicGraph,
|
|
15428
|
-
jobFlow: () => jobFlow,
|
|
15429
|
-
jobQueue: () => jobQueue,
|
|
15430
|
-
subscription: () => subscription,
|
|
15431
|
-
topic: () => topic,
|
|
15432
|
-
topicBridge: () => topicBridge
|
|
15497
|
+
// src/patterns/domain-templates.ts
|
|
15498
|
+
var domain_templates_exports = {};
|
|
15499
|
+
__export(domain_templates_exports, {
|
|
15500
|
+
contentModerationGraph: () => contentModerationGraph,
|
|
15501
|
+
dataQualityGraph: () => dataQualityGraph,
|
|
15502
|
+
issueTrackerGraph: () => issueTrackerGraph,
|
|
15503
|
+
observabilityGraph: () => observabilityGraph
|
|
15433
15504
|
});
|
|
15434
|
-
|
|
15435
|
-
|
|
15436
|
-
|
|
15437
|
-
|
|
15438
|
-
|
|
15439
|
-
|
|
15505
|
+
|
|
15506
|
+
// src/patterns/reduction.ts
|
|
15507
|
+
var reduction_exports = {};
|
|
15508
|
+
__export(reduction_exports, {
|
|
15509
|
+
budgetGate: () => budgetGate,
|
|
15510
|
+
feedback: () => feedback,
|
|
15511
|
+
funnel: () => funnel,
|
|
15512
|
+
scorer: () => scorer,
|
|
15513
|
+
stratify: () => stratify
|
|
15514
|
+
});
|
|
15515
|
+
function baseMeta(kind, meta) {
|
|
15516
|
+
return {
|
|
15517
|
+
reduction: true,
|
|
15518
|
+
reduction_type: kind,
|
|
15519
|
+
...meta ?? {}
|
|
15520
|
+
};
|
|
15440
15521
|
}
|
|
15441
15522
|
function keepalive4(n) {
|
|
15442
15523
|
return n.subscribe(() => {
|
|
15443
15524
|
});
|
|
15444
15525
|
}
|
|
15445
|
-
function
|
|
15446
|
-
|
|
15447
|
-
|
|
15448
|
-
|
|
15449
|
-
|
|
15450
|
-
};
|
|
15526
|
+
function stratify(name, source, rules, opts) {
|
|
15527
|
+
const g = new Graph(name, opts);
|
|
15528
|
+
g.add("source", source);
|
|
15529
|
+
const rulesNode = state(rules, {
|
|
15530
|
+
meta: baseMeta("stratify_rules")
|
|
15531
|
+
});
|
|
15532
|
+
g.add("rules", rulesNode);
|
|
15533
|
+
for (const rule of rules) {
|
|
15534
|
+
_addBranch(g, source, rulesNode, rule);
|
|
15535
|
+
}
|
|
15536
|
+
return g;
|
|
15451
15537
|
}
|
|
15452
|
-
|
|
15453
|
-
|
|
15454
|
-
|
|
15455
|
-
|
|
15456
|
-
|
|
15457
|
-
|
|
15458
|
-
|
|
15459
|
-
|
|
15460
|
-
|
|
15461
|
-
|
|
15462
|
-
|
|
15463
|
-
|
|
15464
|
-
|
|
15465
|
-
|
|
15466
|
-
|
|
15467
|
-
|
|
15468
|
-
|
|
15469
|
-
|
|
15470
|
-
|
|
15471
|
-
|
|
15472
|
-
|
|
15538
|
+
function _addBranch(graph, source, rulesNode, rule) {
|
|
15539
|
+
const branchName = `branch/${rule.name}`;
|
|
15540
|
+
const _noValue = /* @__PURE__ */ Symbol("noValue");
|
|
15541
|
+
let sourceDirty = false;
|
|
15542
|
+
let rulesDirty = false;
|
|
15543
|
+
let sourcePhase2 = false;
|
|
15544
|
+
let sourceValue = _noValue;
|
|
15545
|
+
let pendingDirty = false;
|
|
15546
|
+
function resolve(actions) {
|
|
15547
|
+
if (sourcePhase2) {
|
|
15548
|
+
sourcePhase2 = false;
|
|
15549
|
+
const value = sourceValue;
|
|
15550
|
+
sourceValue = _noValue;
|
|
15551
|
+
if (value !== _noValue) {
|
|
15552
|
+
const currentRules = rulesNode.get();
|
|
15553
|
+
const currentRule = currentRules.find((r) => r.name === rule.name);
|
|
15554
|
+
let matches = false;
|
|
15555
|
+
try {
|
|
15556
|
+
matches = currentRule?.classify(value) ?? false;
|
|
15557
|
+
} catch {
|
|
15558
|
+
matches = false;
|
|
15559
|
+
}
|
|
15560
|
+
if (matches) {
|
|
15561
|
+
pendingDirty = false;
|
|
15562
|
+
actions.emit(value);
|
|
15563
|
+
} else {
|
|
15564
|
+
if (pendingDirty) {
|
|
15565
|
+
pendingDirty = false;
|
|
15566
|
+
actions.down([[DIRTY], [RESOLVED]]);
|
|
15567
|
+
}
|
|
15568
|
+
}
|
|
15569
|
+
} else {
|
|
15570
|
+
if (pendingDirty) {
|
|
15571
|
+
pendingDirty = false;
|
|
15572
|
+
actions.down([[DIRTY], [RESOLVED]]);
|
|
15573
|
+
} else {
|
|
15574
|
+
actions.down([[RESOLVED]]);
|
|
15575
|
+
}
|
|
15473
15576
|
}
|
|
15474
|
-
|
|
15475
|
-
this.add("latest", this.latest);
|
|
15476
|
-
this.connect("events", "latest");
|
|
15477
|
-
this._keepaliveDisposers.push(keepalive4(this.latest));
|
|
15478
|
-
}
|
|
15479
|
-
destroy() {
|
|
15480
|
-
for (const dispose of this._keepaliveDisposers) dispose();
|
|
15481
|
-
this._keepaliveDisposers.length = 0;
|
|
15482
|
-
super.destroy();
|
|
15483
|
-
}
|
|
15484
|
-
publish(value) {
|
|
15485
|
-
this._log.append(value);
|
|
15486
|
-
}
|
|
15487
|
-
retained() {
|
|
15488
|
-
const snapshot = this.events.get();
|
|
15489
|
-
return snapshot.value.entries;
|
|
15577
|
+
}
|
|
15490
15578
|
}
|
|
15491
|
-
|
|
15492
|
-
|
|
15493
|
-
|
|
15494
|
-
|
|
15495
|
-
|
|
15496
|
-
|
|
15497
|
-
|
|
15498
|
-
|
|
15499
|
-
|
|
15500
|
-
|
|
15501
|
-
|
|
15502
|
-
|
|
15503
|
-
|
|
15504
|
-
describeKind: "derived",
|
|
15505
|
-
meta: messagingMeta("subscription_source"),
|
|
15506
|
-
initial: topicEvents.get()
|
|
15507
|
-
});
|
|
15508
|
-
this.add("source", this.source);
|
|
15509
|
-
this.cursor = state(initialCursor, {
|
|
15510
|
-
name: "cursor",
|
|
15511
|
-
describeKind: "state",
|
|
15512
|
-
meta: messagingMeta("subscription_cursor")
|
|
15513
|
-
});
|
|
15514
|
-
this.add("cursor", this.cursor);
|
|
15515
|
-
this.available = derived(
|
|
15516
|
-
[this.source, this.cursor],
|
|
15517
|
-
([sourceSnapshot, cursor]) => {
|
|
15518
|
-
const entries = sourceSnapshot.value.entries;
|
|
15519
|
-
const start = Math.max(0, Math.trunc(cursor ?? 0));
|
|
15520
|
-
return entries.slice(start);
|
|
15521
|
-
},
|
|
15522
|
-
{
|
|
15523
|
-
name: "available",
|
|
15524
|
-
describeKind: "derived",
|
|
15525
|
-
meta: messagingMeta("subscription_available"),
|
|
15526
|
-
initial: []
|
|
15579
|
+
const filterNode = node([source, rulesNode], () => void 0, {
|
|
15580
|
+
describeKind: "operator",
|
|
15581
|
+
meta: baseMeta("stratify_branch", { branch: rule.name }),
|
|
15582
|
+
onMessage(msg, depIndex, actions) {
|
|
15583
|
+
const t = msg[0];
|
|
15584
|
+
if (t === DIRTY) {
|
|
15585
|
+
if (depIndex === 0) {
|
|
15586
|
+
sourceDirty = true;
|
|
15587
|
+
pendingDirty = true;
|
|
15588
|
+
} else {
|
|
15589
|
+
rulesDirty = true;
|
|
15590
|
+
}
|
|
15591
|
+
return true;
|
|
15527
15592
|
}
|
|
15528
|
-
|
|
15529
|
-
|
|
15530
|
-
|
|
15531
|
-
|
|
15532
|
-
|
|
15533
|
-
|
|
15534
|
-
|
|
15535
|
-
|
|
15536
|
-
|
|
15537
|
-
|
|
15538
|
-
|
|
15539
|
-
|
|
15593
|
+
if (t === DATA || t === RESOLVED) {
|
|
15594
|
+
if (depIndex === 0) {
|
|
15595
|
+
sourceDirty = false;
|
|
15596
|
+
sourcePhase2 = true;
|
|
15597
|
+
sourceValue = t === DATA ? msg[1] : _noValue;
|
|
15598
|
+
} else {
|
|
15599
|
+
rulesDirty = false;
|
|
15600
|
+
}
|
|
15601
|
+
if (sourceDirty || rulesDirty) return true;
|
|
15602
|
+
resolve(actions);
|
|
15603
|
+
return true;
|
|
15604
|
+
}
|
|
15605
|
+
if (t === COMPLETE || t === ERROR || t === TEARDOWN) {
|
|
15606
|
+
sourceDirty = false;
|
|
15607
|
+
rulesDirty = false;
|
|
15608
|
+
sourcePhase2 = false;
|
|
15609
|
+
sourceValue = _noValue;
|
|
15610
|
+
pendingDirty = false;
|
|
15611
|
+
if (depIndex === 0) {
|
|
15612
|
+
actions.down([msg]);
|
|
15613
|
+
}
|
|
15614
|
+
return true;
|
|
15615
|
+
}
|
|
15616
|
+
if (depIndex === 1) return true;
|
|
15617
|
+
return false;
|
|
15618
|
+
},
|
|
15619
|
+
completeWhenDepsComplete: false
|
|
15620
|
+
});
|
|
15621
|
+
graph.add(branchName, filterNode);
|
|
15622
|
+
graph.connect("source", branchName);
|
|
15623
|
+
if (rule.ops) {
|
|
15624
|
+
const transformed = rule.ops(filterNode);
|
|
15625
|
+
const transformedName = `branch/${rule.name}/out`;
|
|
15626
|
+
graph.add(transformedName, transformed);
|
|
15627
|
+
graph.connect(branchName, transformedName);
|
|
15540
15628
|
}
|
|
15541
|
-
|
|
15542
|
-
|
|
15543
|
-
|
|
15544
|
-
|
|
15545
|
-
|
|
15546
|
-
|
|
15547
|
-
|
|
15548
|
-
|
|
15629
|
+
}
|
|
15630
|
+
function funnel(name, sources, stages, opts) {
|
|
15631
|
+
if (sources.length === 0) throw new RangeError("funnel requires at least one source");
|
|
15632
|
+
if (stages.length === 0) throw new RangeError("funnel requires at least one stage");
|
|
15633
|
+
const g = new Graph(name, opts);
|
|
15634
|
+
const merged = sources.length === 1 ? sources[0] : merge(...sources);
|
|
15635
|
+
g.add("merged", merged);
|
|
15636
|
+
let prevOutputPath = "merged";
|
|
15637
|
+
for (let i = 0; i < stages.length; i++) {
|
|
15638
|
+
const stage = stages[i];
|
|
15639
|
+
const sub = new Graph(stage.name);
|
|
15640
|
+
stage.build(sub);
|
|
15641
|
+
try {
|
|
15642
|
+
sub.resolve("input");
|
|
15643
|
+
} catch {
|
|
15644
|
+
throw new Error(`funnel stage "${stage.name}" must define an "input" node`);
|
|
15645
|
+
}
|
|
15646
|
+
try {
|
|
15647
|
+
sub.resolve("output");
|
|
15648
|
+
} catch {
|
|
15649
|
+
throw new Error(`funnel stage "${stage.name}" must define an "output" node`);
|
|
15650
|
+
}
|
|
15651
|
+
g.mount(stage.name, sub);
|
|
15652
|
+
const prevNode = g.resolve(prevOutputPath);
|
|
15653
|
+
const stageInputPath = `${stage.name}::input`;
|
|
15654
|
+
const stageInput = g.resolve(stageInputPath);
|
|
15655
|
+
const bridgeName = `__bridge_${prevOutputPath}\u2192${stage.name}_input`;
|
|
15656
|
+
const br = bridge(prevNode, stageInput, {
|
|
15657
|
+
name: bridgeName,
|
|
15658
|
+
down: DEFAULT_DOWN.filter((t) => t !== TEARDOWN)
|
|
15659
|
+
});
|
|
15660
|
+
g.add(bridgeName, br);
|
|
15661
|
+
g.connect(prevOutputPath, bridgeName);
|
|
15662
|
+
keepalive4(br);
|
|
15663
|
+
prevOutputPath = `${stage.name}::output`;
|
|
15664
|
+
}
|
|
15665
|
+
return g;
|
|
15666
|
+
}
|
|
15667
|
+
function feedback(graph, condition, reentry, opts) {
|
|
15668
|
+
const maxIter = opts?.maxIterations ?? 10;
|
|
15669
|
+
const counterName = `__feedback_${condition}`;
|
|
15670
|
+
const counter = state(0, {
|
|
15671
|
+
meta: baseMeta("feedback_counter", {
|
|
15672
|
+
maxIterations: maxIter,
|
|
15673
|
+
feedbackFrom: condition,
|
|
15674
|
+
feedbackTo: reentry
|
|
15675
|
+
})
|
|
15676
|
+
});
|
|
15677
|
+
graph.add(counterName, counter);
|
|
15678
|
+
const condNode = graph.resolve(condition);
|
|
15679
|
+
const reentryNode = graph.resolve(reentry);
|
|
15680
|
+
const feedbackEffectName = `__feedback_effect_${condition}`;
|
|
15681
|
+
const feedbackEffect = node([condNode], void 0, {
|
|
15682
|
+
name: feedbackEffectName,
|
|
15683
|
+
describeKind: "effect",
|
|
15684
|
+
meta: {
|
|
15685
|
+
...baseMeta("feedback_effect", {
|
|
15686
|
+
feedbackFrom: condition,
|
|
15687
|
+
feedbackTo: reentry
|
|
15688
|
+
}),
|
|
15689
|
+
_internal: true
|
|
15690
|
+
},
|
|
15691
|
+
onMessage(msg, _depIndex, _actions) {
|
|
15692
|
+
const t = msg[0];
|
|
15693
|
+
if (t === DATA) {
|
|
15694
|
+
const currentCount = counter.get();
|
|
15695
|
+
if (currentCount >= maxIter) return true;
|
|
15696
|
+
const condValue = msg[1];
|
|
15697
|
+
if (condValue == null) return true;
|
|
15698
|
+
batch(() => {
|
|
15699
|
+
counter.down([[DATA, currentCount + 1]]);
|
|
15700
|
+
reentryNode.down([[DATA, condValue]]);
|
|
15701
|
+
});
|
|
15702
|
+
return true;
|
|
15703
|
+
}
|
|
15704
|
+
if (t === COMPLETE || t === ERROR) {
|
|
15705
|
+
const terminal = t === ERROR && msg.length > 1 ? [ERROR, msg[1]] : [t];
|
|
15706
|
+
counter.down([terminal]);
|
|
15707
|
+
return true;
|
|
15708
|
+
}
|
|
15709
|
+
return false;
|
|
15710
|
+
}
|
|
15711
|
+
});
|
|
15712
|
+
graph.add(feedbackEffectName, feedbackEffect);
|
|
15713
|
+
graph.connect(condition, feedbackEffectName);
|
|
15714
|
+
keepalive4(feedbackEffect);
|
|
15715
|
+
return graph;
|
|
15716
|
+
}
|
|
15717
|
+
function budgetGate(source, constraints, opts) {
|
|
15718
|
+
if (constraints.length === 0) throw new RangeError("budgetGate requires at least one constraint");
|
|
15719
|
+
const constraintNodes = constraints.map((c) => c.node);
|
|
15720
|
+
const allDeps = [source, ...constraintNodes];
|
|
15721
|
+
let buffer2 = [];
|
|
15722
|
+
let paused = false;
|
|
15723
|
+
let pendingResolved = false;
|
|
15724
|
+
const lockId = /* @__PURE__ */ Symbol("budget-gate");
|
|
15725
|
+
function checkBudget() {
|
|
15726
|
+
return constraints.every((c) => c.check(c.node.get()));
|
|
15727
|
+
}
|
|
15728
|
+
function flushBuffer(actions) {
|
|
15729
|
+
while (buffer2.length > 0 && checkBudget()) {
|
|
15730
|
+
const item = buffer2[0];
|
|
15731
|
+
buffer2 = buffer2.slice(1);
|
|
15732
|
+
actions.emit(item);
|
|
15733
|
+
}
|
|
15734
|
+
if (buffer2.length === 0 && pendingResolved) {
|
|
15735
|
+
pendingResolved = false;
|
|
15736
|
+
actions.down([[RESOLVED]]);
|
|
15737
|
+
}
|
|
15738
|
+
}
|
|
15739
|
+
return node(allDeps, () => void 0, {
|
|
15740
|
+
...opts,
|
|
15741
|
+
describeKind: "operator",
|
|
15742
|
+
meta: baseMeta("budget_gate", opts?.meta),
|
|
15743
|
+
onMessage(msg, depIndex, actions) {
|
|
15744
|
+
const t = msg[0];
|
|
15745
|
+
if (depIndex === 0) {
|
|
15746
|
+
if (t === DATA) {
|
|
15747
|
+
if (checkBudget() && buffer2.length === 0) {
|
|
15748
|
+
actions.emit(msg[1]);
|
|
15749
|
+
} else {
|
|
15750
|
+
buffer2.push(msg[1]);
|
|
15751
|
+
if (!paused) {
|
|
15752
|
+
paused = true;
|
|
15753
|
+
actions.up([[PAUSE, lockId]]);
|
|
15754
|
+
}
|
|
15755
|
+
}
|
|
15756
|
+
return true;
|
|
15757
|
+
}
|
|
15758
|
+
if (t === DIRTY) {
|
|
15759
|
+
actions.down([[DIRTY]]);
|
|
15760
|
+
return true;
|
|
15761
|
+
}
|
|
15762
|
+
if (t === RESOLVED) {
|
|
15763
|
+
if (buffer2.length === 0) {
|
|
15764
|
+
actions.down([[RESOLVED]]);
|
|
15765
|
+
} else {
|
|
15766
|
+
pendingResolved = true;
|
|
15767
|
+
}
|
|
15768
|
+
return true;
|
|
15769
|
+
}
|
|
15770
|
+
if (t === COMPLETE || t === ERROR) {
|
|
15771
|
+
for (const item of buffer2) {
|
|
15772
|
+
actions.emit(item);
|
|
15773
|
+
}
|
|
15774
|
+
buffer2 = [];
|
|
15775
|
+
pendingResolved = false;
|
|
15776
|
+
if (paused) {
|
|
15777
|
+
paused = false;
|
|
15778
|
+
actions.up([[RESUME, lockId]]);
|
|
15779
|
+
}
|
|
15780
|
+
actions.down([msg]);
|
|
15781
|
+
return true;
|
|
15782
|
+
}
|
|
15783
|
+
return false;
|
|
15784
|
+
}
|
|
15785
|
+
if (t === DATA || t === RESOLVED) {
|
|
15786
|
+
if (checkBudget() && buffer2.length > 0) {
|
|
15787
|
+
flushBuffer(actions);
|
|
15788
|
+
if (buffer2.length === 0 && paused) {
|
|
15789
|
+
paused = false;
|
|
15790
|
+
actions.up([[RESUME, lockId]]);
|
|
15791
|
+
}
|
|
15792
|
+
} else if (!checkBudget() && !paused && buffer2.length > 0) {
|
|
15793
|
+
paused = true;
|
|
15794
|
+
actions.up([[PAUSE, lockId]]);
|
|
15795
|
+
}
|
|
15796
|
+
return true;
|
|
15797
|
+
}
|
|
15798
|
+
if (t === DIRTY) {
|
|
15799
|
+
return true;
|
|
15800
|
+
}
|
|
15801
|
+
if (t === ERROR) {
|
|
15802
|
+
actions.down([msg]);
|
|
15803
|
+
return true;
|
|
15804
|
+
}
|
|
15805
|
+
if (t === COMPLETE) {
|
|
15806
|
+
return true;
|
|
15807
|
+
}
|
|
15808
|
+
return false;
|
|
15809
|
+
}
|
|
15810
|
+
});
|
|
15811
|
+
}
|
|
15812
|
+
function scorer(sources, weights, opts) {
|
|
15813
|
+
if (sources.length === 0) throw new RangeError("scorer requires at least one source");
|
|
15814
|
+
if (sources.length !== weights.length) {
|
|
15815
|
+
throw new RangeError("scorer requires the same number of sources and weights");
|
|
15816
|
+
}
|
|
15817
|
+
const allDeps = [...sources, ...weights];
|
|
15818
|
+
const n = sources.length;
|
|
15819
|
+
const scoreFns = opts?.scoreFns;
|
|
15820
|
+
return derived(
|
|
15821
|
+
allDeps,
|
|
15822
|
+
(vals) => {
|
|
15823
|
+
const signals = vals.slice(0, n);
|
|
15824
|
+
const weightValues = vals.slice(n);
|
|
15825
|
+
const breakdown = [];
|
|
15826
|
+
let totalScore = 0;
|
|
15827
|
+
for (let i = 0; i < n; i++) {
|
|
15828
|
+
const sig = signals[i] ?? 0;
|
|
15829
|
+
const wt = weightValues[i] ?? 0;
|
|
15830
|
+
const rawScore = scoreFns?.[i] ? scoreFns[i](sig) : sig;
|
|
15831
|
+
const weighted = rawScore * wt;
|
|
15832
|
+
breakdown.push(weighted);
|
|
15833
|
+
totalScore += weighted;
|
|
15834
|
+
}
|
|
15835
|
+
return {
|
|
15836
|
+
value: signals,
|
|
15837
|
+
score: totalScore,
|
|
15838
|
+
breakdown
|
|
15839
|
+
};
|
|
15840
|
+
},
|
|
15841
|
+
{
|
|
15842
|
+
...opts,
|
|
15843
|
+
describeKind: "derived",
|
|
15844
|
+
meta: baseMeta("scorer", opts?.meta)
|
|
15845
|
+
}
|
|
15846
|
+
);
|
|
15847
|
+
}
|
|
15848
|
+
|
|
15849
|
+
// src/patterns/domain-templates.ts
|
|
15850
|
+
function keepalive5(n) {
|
|
15851
|
+
return n.subscribe(() => {
|
|
15852
|
+
});
|
|
15853
|
+
}
|
|
15854
|
+
function baseMeta2(kind, extra) {
|
|
15855
|
+
return { domain_template: true, template_type: kind, ...extra ?? {} };
|
|
15856
|
+
}
|
|
15857
|
+
function observabilityGraph(name, opts) {
|
|
15858
|
+
const g = new Graph(name, opts);
|
|
15859
|
+
g.add("source", opts.source);
|
|
15860
|
+
const defaultBranches = [
|
|
15861
|
+
{ name: "errors", classify: (v) => isTagged(v, "error") },
|
|
15862
|
+
{ name: "traces", classify: (v) => isTagged(v, "trace") },
|
|
15863
|
+
{ name: "metrics", classify: (v) => isTagged(v, "metric") }
|
|
15864
|
+
];
|
|
15865
|
+
const branches = opts.branches ?? defaultBranches;
|
|
15866
|
+
const rules = branches.map((b) => ({
|
|
15867
|
+
name: b.name,
|
|
15868
|
+
classify: b.classify
|
|
15869
|
+
}));
|
|
15870
|
+
const strat = stratify("stratify", opts.source, rules);
|
|
15871
|
+
g.mount("stratify", strat);
|
|
15872
|
+
const branchNodes = branches.map((b) => {
|
|
15873
|
+
try {
|
|
15874
|
+
return g.resolve(`stratify::branch/${b.name}`);
|
|
15875
|
+
} catch {
|
|
15876
|
+
return state(null);
|
|
15877
|
+
}
|
|
15878
|
+
});
|
|
15879
|
+
const correlateFn = opts.correlate ?? ((vals) => vals);
|
|
15880
|
+
const correlateNode = derived(
|
|
15881
|
+
branchNodes,
|
|
15882
|
+
(vals) => correlateFn(vals),
|
|
15883
|
+
{
|
|
15884
|
+
meta: baseMeta2("observability", { stage: "correlate" })
|
|
15885
|
+
}
|
|
15886
|
+
);
|
|
15887
|
+
g.add("correlate", correlateNode);
|
|
15888
|
+
for (const b of branches) {
|
|
15889
|
+
try {
|
|
15890
|
+
g.connect(`stratify::branch/${b.name}`, "correlate");
|
|
15891
|
+
} catch {
|
|
15892
|
+
}
|
|
15893
|
+
}
|
|
15894
|
+
const sloCheckFn = opts.sloCheck ?? (() => ({ pass: true }));
|
|
15895
|
+
const sloValue = derived([correlateNode], (vals) => vals[0], {
|
|
15896
|
+
meta: baseMeta2("observability", { stage: "slo_value" })
|
|
15897
|
+
});
|
|
15898
|
+
const sloVerified = derived([sloValue], (vals) => sloCheckFn(vals[0]), {
|
|
15899
|
+
meta: baseMeta2("observability", { stage: "slo_verified" })
|
|
15900
|
+
});
|
|
15901
|
+
g.add("slo_value", sloValue);
|
|
15902
|
+
g.add("slo_verified", sloVerified);
|
|
15903
|
+
g.connect("correlate", "slo_value");
|
|
15904
|
+
g.connect("slo_value", "slo_verified");
|
|
15905
|
+
const weightValues = opts.weights ?? branches.map(() => 1);
|
|
15906
|
+
const signalNodes = branchNodes.map(
|
|
15907
|
+
(bn) => derived([bn], (vals) => vals[0] != null ? 1 : 0)
|
|
15908
|
+
);
|
|
15909
|
+
const weightNodes = weightValues.map((w) => state(w));
|
|
15910
|
+
for (let i = 0; i < signalNodes.length; i++) {
|
|
15911
|
+
g.add(`__signal_${i}`, signalNodes[i]);
|
|
15912
|
+
g.add(`__weight_${i}`, weightNodes[i]);
|
|
15913
|
+
}
|
|
15914
|
+
const alerts = scorer(
|
|
15915
|
+
signalNodes,
|
|
15916
|
+
weightNodes
|
|
15917
|
+
);
|
|
15918
|
+
g.add("alerts", alerts);
|
|
15919
|
+
const output = derived(
|
|
15920
|
+
[alerts, sloVerified],
|
|
15921
|
+
(vals) => ({
|
|
15922
|
+
scored: vals[0],
|
|
15923
|
+
slo: vals[1]
|
|
15924
|
+
}),
|
|
15925
|
+
{
|
|
15926
|
+
meta: baseMeta2("observability", { stage: "output" })
|
|
15927
|
+
}
|
|
15928
|
+
);
|
|
15929
|
+
g.add("output", output);
|
|
15930
|
+
g.connect("alerts", "output");
|
|
15931
|
+
g.connect("slo_verified", "output");
|
|
15932
|
+
const fbReentry = state(null, {
|
|
15933
|
+
meta: baseMeta2("observability", { stage: "feedback_reentry" })
|
|
15934
|
+
});
|
|
15935
|
+
g.add("feedback_reentry", fbReentry);
|
|
15936
|
+
const fbCondition = derived(
|
|
15937
|
+
[sloVerified],
|
|
15938
|
+
(vals) => {
|
|
15939
|
+
const result = vals[0];
|
|
15940
|
+
if (result && result.pass === false) return result;
|
|
15941
|
+
return null;
|
|
15942
|
+
},
|
|
15943
|
+
{
|
|
15944
|
+
meta: baseMeta2("observability", { stage: "feedback_condition" })
|
|
15945
|
+
}
|
|
15946
|
+
);
|
|
15947
|
+
g.add("feedback_condition", fbCondition);
|
|
15948
|
+
g.connect("slo_verified", "feedback_condition");
|
|
15949
|
+
feedback(g, "feedback_condition", "feedback_reentry", {
|
|
15950
|
+
maxIterations: opts.maxFeedbackIterations ?? 5
|
|
15951
|
+
});
|
|
15952
|
+
return g;
|
|
15953
|
+
}
|
|
15954
|
+
function issueTrackerGraph(name, opts) {
|
|
15955
|
+
const g = new Graph(name, opts);
|
|
15956
|
+
g.add("source", opts.source);
|
|
15957
|
+
let _issueCounter = 0;
|
|
15958
|
+
const defaultExtract = (raw) => ({
|
|
15959
|
+
id: `issue-${++_issueCounter}`,
|
|
15960
|
+
title: String(raw),
|
|
15961
|
+
severity: 1,
|
|
15962
|
+
source: "unknown",
|
|
15963
|
+
raw
|
|
15964
|
+
});
|
|
15965
|
+
const extractFn = opts.extract ?? defaultExtract;
|
|
15966
|
+
const extractNode = derived([opts.source], (vals) => extractFn(vals[0]), {
|
|
15967
|
+
meta: baseMeta2("issue_tracker", { stage: "extract" })
|
|
15968
|
+
});
|
|
15969
|
+
g.add("extract", extractNode);
|
|
15970
|
+
g.connect("source", "extract");
|
|
15971
|
+
const verifyFn = opts.verify ?? (() => ({ valid: true }));
|
|
15972
|
+
const verifyNode = derived(
|
|
15973
|
+
[extractNode],
|
|
15974
|
+
(vals) => {
|
|
15975
|
+
const issue = vals[0];
|
|
15976
|
+
return { issue, verification: verifyFn(issue) };
|
|
15977
|
+
},
|
|
15978
|
+
{
|
|
15979
|
+
meta: baseMeta2("issue_tracker", { stage: "verify" })
|
|
15980
|
+
}
|
|
15981
|
+
);
|
|
15982
|
+
g.add("verify", verifyNode);
|
|
15983
|
+
g.connect("extract", "verify");
|
|
15984
|
+
const knownPatterns = state([], {
|
|
15985
|
+
meta: baseMeta2("issue_tracker", { stage: "known_patterns" })
|
|
15986
|
+
});
|
|
15987
|
+
g.add("known_patterns", knownPatterns);
|
|
15988
|
+
const detectFn = opts.detectRegression ?? (() => ({ regression: false }));
|
|
15989
|
+
const regressionNode = derived(
|
|
15990
|
+
[extractNode, knownPatterns],
|
|
15991
|
+
(vals) => {
|
|
15992
|
+
const issue = vals[0];
|
|
15993
|
+
const known = vals[1];
|
|
15994
|
+
return { issue, regression: detectFn(issue, known) };
|
|
15995
|
+
},
|
|
15996
|
+
{ meta: baseMeta2("issue_tracker", { stage: "regression" }) }
|
|
15997
|
+
);
|
|
15998
|
+
g.add("regression", regressionNode);
|
|
15999
|
+
g.connect("extract", "regression");
|
|
16000
|
+
g.connect("known_patterns", "regression");
|
|
16001
|
+
const severitySignal = derived([extractNode], (vals) => {
|
|
16002
|
+
const issue = vals[0];
|
|
16003
|
+
return issue?.severity ?? 0;
|
|
16004
|
+
});
|
|
16005
|
+
const regressionSignal = derived([regressionNode], (vals) => {
|
|
16006
|
+
const r = vals[0];
|
|
16007
|
+
return r?.regression ? 2 : 0;
|
|
16008
|
+
});
|
|
16009
|
+
g.add("__severity_signal", severitySignal);
|
|
16010
|
+
g.add("__regression_signal", regressionSignal);
|
|
16011
|
+
const severityWeight = state(1);
|
|
16012
|
+
const regressionWeight = state(1.5);
|
|
16013
|
+
g.add("__severity_weight", severityWeight);
|
|
16014
|
+
g.add("__regression_weight", regressionWeight);
|
|
16015
|
+
const priority = scorer([severitySignal, regressionSignal], [severityWeight, regressionWeight]);
|
|
16016
|
+
g.add("priority", priority);
|
|
16017
|
+
const output = derived(
|
|
16018
|
+
[verifyNode, regressionNode, priority],
|
|
16019
|
+
(vals) => ({
|
|
16020
|
+
verified: vals[0],
|
|
16021
|
+
regression: vals[1],
|
|
16022
|
+
priority: vals[2]
|
|
16023
|
+
}),
|
|
16024
|
+
{ meta: baseMeta2("issue_tracker", { stage: "output" }) }
|
|
16025
|
+
);
|
|
16026
|
+
g.add("output", output);
|
|
16027
|
+
g.connect("verify", "output");
|
|
16028
|
+
g.connect("regression", "output");
|
|
16029
|
+
g.connect("priority", "output");
|
|
16030
|
+
const fbReentry = state(null, {
|
|
16031
|
+
meta: baseMeta2("issue_tracker", { stage: "feedback_reentry" })
|
|
16032
|
+
});
|
|
16033
|
+
g.add("feedback_reentry", fbReentry);
|
|
16034
|
+
const fbCondition = derived(
|
|
16035
|
+
[verifyNode],
|
|
16036
|
+
(vals) => {
|
|
16037
|
+
const result = vals[0];
|
|
16038
|
+
if (result) {
|
|
16039
|
+
const v = result.verification;
|
|
16040
|
+
if (v && v.valid === false) return result;
|
|
16041
|
+
}
|
|
16042
|
+
return null;
|
|
16043
|
+
},
|
|
16044
|
+
{
|
|
16045
|
+
meta: baseMeta2("issue_tracker", { stage: "feedback_condition" })
|
|
16046
|
+
}
|
|
16047
|
+
);
|
|
16048
|
+
g.add("feedback_condition", fbCondition);
|
|
16049
|
+
g.connect("verify", "feedback_condition");
|
|
16050
|
+
feedback(g, "feedback_condition", "feedback_reentry", {
|
|
16051
|
+
maxIterations: opts.maxFeedbackIterations ?? 3
|
|
16052
|
+
});
|
|
16053
|
+
return g;
|
|
16054
|
+
}
|
|
16055
|
+
function contentModerationGraph(name, opts) {
|
|
16056
|
+
const g = new Graph(name, opts);
|
|
16057
|
+
g.add("source", opts.source);
|
|
16058
|
+
const defaultClassify = (content) => ({
|
|
16059
|
+
label: "review",
|
|
16060
|
+
confidence: 0.5,
|
|
16061
|
+
original: content
|
|
16062
|
+
});
|
|
16063
|
+
const classifyFn = opts.classify ?? defaultClassify;
|
|
16064
|
+
const classifyNode = derived([opts.source], (vals) => classifyFn(vals[0]), {
|
|
16065
|
+
meta: baseMeta2("content_moderation", { stage: "classify" })
|
|
16066
|
+
});
|
|
16067
|
+
g.add("classify", classifyNode);
|
|
16068
|
+
g.connect("source", "classify");
|
|
16069
|
+
const strat = stratify("stratify", classifyNode, [
|
|
16070
|
+
{ name: "safe", classify: (v) => v.label === "safe" },
|
|
16071
|
+
{ name: "review", classify: (v) => v.label === "review" },
|
|
16072
|
+
{ name: "block", classify: (v) => v.label === "block" }
|
|
16073
|
+
]);
|
|
16074
|
+
g.mount("stratify", strat);
|
|
16075
|
+
const reviewLog = reactiveLog([], {
|
|
16076
|
+
name: "review_queue",
|
|
16077
|
+
maxSize: opts.maxQueueSize
|
|
16078
|
+
});
|
|
16079
|
+
g.add("review_queue", reviewLog.entries);
|
|
16080
|
+
let reviewBranch;
|
|
16081
|
+
try {
|
|
16082
|
+
reviewBranch = g.resolve("stratify::branch/review");
|
|
16083
|
+
} catch {
|
|
16084
|
+
reviewBranch = state(null);
|
|
16085
|
+
g.add("__review_fallback", reviewBranch);
|
|
16086
|
+
}
|
|
16087
|
+
const reviewAccumulator = effect([reviewBranch], (vals) => {
|
|
16088
|
+
const item = vals[0];
|
|
16089
|
+
if (item) {
|
|
16090
|
+
reviewLog.append(item);
|
|
16091
|
+
}
|
|
16092
|
+
});
|
|
16093
|
+
g.add("__review_accumulator", reviewAccumulator);
|
|
16094
|
+
keepalive5(reviewAccumulator);
|
|
16095
|
+
try {
|
|
16096
|
+
g.connect("stratify::branch/review", "__review_accumulator");
|
|
16097
|
+
} catch {
|
|
16098
|
+
}
|
|
16099
|
+
const policy2 = state(
|
|
16100
|
+
{},
|
|
16101
|
+
{
|
|
16102
|
+
meta: baseMeta2("content_moderation", {
|
|
16103
|
+
stage: "policy",
|
|
16104
|
+
access: "both",
|
|
16105
|
+
description: "Moderation policy rules \u2014 updated via feedback"
|
|
16106
|
+
})
|
|
16107
|
+
}
|
|
16108
|
+
);
|
|
16109
|
+
g.add("policy", policy2);
|
|
16110
|
+
const weights = opts.weights ?? [0.1, 1, 2];
|
|
16111
|
+
const confidenceSignal = derived([classifyNode], (vals) => {
|
|
16112
|
+
const r = vals[0];
|
|
16113
|
+
return r?.confidence ?? 0;
|
|
16114
|
+
});
|
|
16115
|
+
const severitySignal = derived([classifyNode], (vals) => {
|
|
16116
|
+
const r = vals[0];
|
|
16117
|
+
if (!r) return 0;
|
|
16118
|
+
return r.label === "block" ? weights[2] : r.label === "review" ? weights[1] : weights[0];
|
|
16119
|
+
});
|
|
16120
|
+
g.add("__confidence_signal", confidenceSignal);
|
|
16121
|
+
g.add("__severity_signal", severitySignal);
|
|
16122
|
+
const wConfidence = state(1);
|
|
16123
|
+
const wSeverity = state(1);
|
|
16124
|
+
g.add("__w_confidence", wConfidence);
|
|
16125
|
+
g.add("__w_severity", wSeverity);
|
|
16126
|
+
const priority = scorer([confidenceSignal, severitySignal], [wConfidence, wSeverity]);
|
|
16127
|
+
g.add("priority", priority);
|
|
16128
|
+
const output = derived(
|
|
16129
|
+
[classifyNode, priority],
|
|
16130
|
+
(vals) => ({
|
|
16131
|
+
classification: vals[0],
|
|
16132
|
+
priority: vals[1]
|
|
16133
|
+
}),
|
|
16134
|
+
{ meta: baseMeta2("content_moderation", { stage: "output" }) }
|
|
16135
|
+
);
|
|
16136
|
+
g.add("output", output);
|
|
16137
|
+
g.connect("classify", "output");
|
|
16138
|
+
g.connect("priority", "output");
|
|
16139
|
+
const fbCondition = derived(
|
|
16140
|
+
[reviewLog.entries, policy2],
|
|
16141
|
+
(vals) => {
|
|
16142
|
+
const snap = vals[0];
|
|
16143
|
+
const entries = snap?.value?.entries;
|
|
16144
|
+
if (entries && entries.length > 0) {
|
|
16145
|
+
const latest = entries[entries.length - 1];
|
|
16146
|
+
if (latest && latest.falsePositive) {
|
|
16147
|
+
return latest;
|
|
16148
|
+
}
|
|
16149
|
+
}
|
|
16150
|
+
return null;
|
|
16151
|
+
},
|
|
16152
|
+
{
|
|
16153
|
+
meta: baseMeta2("content_moderation", { stage: "feedback_condition" })
|
|
16154
|
+
}
|
|
16155
|
+
);
|
|
16156
|
+
g.add("feedback_condition", fbCondition);
|
|
16157
|
+
feedback(g, "feedback_condition", "policy", {
|
|
16158
|
+
maxIterations: opts.maxFeedbackIterations ?? 5
|
|
16159
|
+
});
|
|
16160
|
+
return g;
|
|
16161
|
+
}
|
|
16162
|
+
function dataQualityGraph(name, opts) {
|
|
16163
|
+
const g = new Graph(name, opts);
|
|
16164
|
+
g.add("source", opts.source);
|
|
16165
|
+
const validateFn = opts.validate ?? ((record) => ({
|
|
16166
|
+
valid: true,
|
|
16167
|
+
errors: [],
|
|
16168
|
+
record
|
|
16169
|
+
}));
|
|
16170
|
+
const validateNode = derived(
|
|
16171
|
+
[opts.source],
|
|
16172
|
+
(vals) => vals[0] != null ? validateFn(vals[0]) : void 0,
|
|
16173
|
+
{ meta: baseMeta2("data_quality", { stage: "validate" }) }
|
|
16174
|
+
);
|
|
16175
|
+
g.add("validate", validateNode);
|
|
16176
|
+
g.connect("source", "validate");
|
|
16177
|
+
const detectAnomalyFn = opts.detectAnomaly ?? ((record) => ({
|
|
16178
|
+
anomaly: false,
|
|
16179
|
+
score: 0,
|
|
16180
|
+
record
|
|
16181
|
+
}));
|
|
16182
|
+
const anomalyNode = derived(
|
|
16183
|
+
[opts.source],
|
|
16184
|
+
(vals) => vals[0] != null ? detectAnomalyFn(vals[0]) : void 0,
|
|
16185
|
+
{ meta: baseMeta2("data_quality", { stage: "anomaly" }) }
|
|
16186
|
+
);
|
|
16187
|
+
g.add("anomaly", anomalyNode);
|
|
16188
|
+
g.connect("source", "anomaly");
|
|
16189
|
+
const baseline = state(null, {
|
|
16190
|
+
meta: baseMeta2("data_quality", {
|
|
16191
|
+
stage: "baseline",
|
|
16192
|
+
description: "Rolling baseline for drift detection"
|
|
16193
|
+
})
|
|
16194
|
+
});
|
|
16195
|
+
g.add("baseline", baseline);
|
|
16196
|
+
const baselineUpdater = effect([validateNode], (vals) => {
|
|
16197
|
+
const result = vals[0];
|
|
16198
|
+
if (result?.valid) {
|
|
16199
|
+
batch(() => {
|
|
16200
|
+
baseline.down([[DATA, result.record]]);
|
|
16201
|
+
});
|
|
16202
|
+
}
|
|
16203
|
+
});
|
|
16204
|
+
g.add("__baseline_updater", baselineUpdater);
|
|
16205
|
+
g.connect("validate", "__baseline_updater");
|
|
16206
|
+
keepalive5(baselineUpdater);
|
|
16207
|
+
const detectDriftFn = opts.detectDrift ?? (() => ({ drift: false }));
|
|
16208
|
+
const driftNode = derived(
|
|
16209
|
+
[opts.source, baseline],
|
|
16210
|
+
(vals) => detectDriftFn(vals[0], vals[1]),
|
|
16211
|
+
{ meta: baseMeta2("data_quality", { stage: "drift" }) }
|
|
16212
|
+
);
|
|
16213
|
+
g.add("drift", driftNode);
|
|
16214
|
+
g.connect("source", "drift");
|
|
16215
|
+
g.connect("baseline", "drift");
|
|
16216
|
+
const suggestFn = opts.suggest ?? (() => null);
|
|
16217
|
+
const remediateNode = derived(
|
|
16218
|
+
[validateNode, anomalyNode],
|
|
16219
|
+
(vals) => suggestFn({
|
|
16220
|
+
validation: vals[0],
|
|
16221
|
+
anomaly: vals[1]
|
|
16222
|
+
}),
|
|
16223
|
+
{ meta: baseMeta2("data_quality", { stage: "remediate" }) }
|
|
16224
|
+
);
|
|
16225
|
+
g.add("remediate", remediateNode);
|
|
16226
|
+
g.connect("validate", "remediate");
|
|
16227
|
+
g.connect("anomaly", "remediate");
|
|
16228
|
+
const output = derived(
|
|
16229
|
+
[validateNode, anomalyNode, driftNode, remediateNode],
|
|
16230
|
+
(vals) => ({
|
|
16231
|
+
validation: vals[0],
|
|
16232
|
+
anomaly: vals[1],
|
|
16233
|
+
drift: vals[2],
|
|
16234
|
+
remediation: vals[3]
|
|
16235
|
+
}),
|
|
16236
|
+
{ meta: baseMeta2("data_quality", { stage: "output" }) }
|
|
16237
|
+
);
|
|
16238
|
+
g.add("output", output);
|
|
16239
|
+
g.connect("validate", "output");
|
|
16240
|
+
g.connect("anomaly", "output");
|
|
16241
|
+
g.connect("drift", "output");
|
|
16242
|
+
g.connect("remediate", "output");
|
|
16243
|
+
const validationRules = state([], {
|
|
16244
|
+
meta: baseMeta2("data_quality", { stage: "validation_rules" })
|
|
16245
|
+
});
|
|
16246
|
+
g.add("validation_rules", validationRules);
|
|
16247
|
+
const fbCondition = derived(
|
|
16248
|
+
[anomalyNode],
|
|
16249
|
+
(vals) => {
|
|
16250
|
+
const a = vals[0];
|
|
16251
|
+
if (a?.anomaly) return a;
|
|
16252
|
+
return null;
|
|
16253
|
+
},
|
|
16254
|
+
{
|
|
16255
|
+
meta: baseMeta2("data_quality", { stage: "feedback_condition" })
|
|
16256
|
+
}
|
|
16257
|
+
);
|
|
16258
|
+
g.add("feedback_condition", fbCondition);
|
|
16259
|
+
g.connect("anomaly", "feedback_condition");
|
|
16260
|
+
feedback(g, "feedback_condition", "validation_rules", {
|
|
16261
|
+
maxIterations: opts.maxFeedbackIterations ?? 3
|
|
16262
|
+
});
|
|
16263
|
+
return g;
|
|
16264
|
+
}
|
|
16265
|
+
function isTagged(value, tag) {
|
|
16266
|
+
if (value == null || typeof value !== "object") return false;
|
|
16267
|
+
const v = value;
|
|
16268
|
+
return v.type === tag || v.kind === tag;
|
|
16269
|
+
}
|
|
16270
|
+
|
|
16271
|
+
// src/patterns/graphspec.ts
|
|
16272
|
+
var graphspec_exports = {};
|
|
16273
|
+
__export(graphspec_exports, {
|
|
16274
|
+
compileSpec: () => compileSpec,
|
|
16275
|
+
decompileGraph: () => decompileGraph,
|
|
16276
|
+
extractFnFactory: () => extractFnFactory,
|
|
16277
|
+
extractSourceFactory: () => extractSourceFactory,
|
|
16278
|
+
generateCatalogPrompt: () => generateCatalogPrompt,
|
|
16279
|
+
isRichFnEntry: () => isRichFnEntry,
|
|
16280
|
+
isRichSourceEntry: () => isRichSourceEntry,
|
|
16281
|
+
llmCompose: () => llmCompose,
|
|
16282
|
+
llmRefine: () => llmRefine,
|
|
16283
|
+
specDiff: () => specDiff,
|
|
16284
|
+
validateSpec: () => validateSpec,
|
|
16285
|
+
validateSpecAgainstCatalog: () => validateSpecAgainstCatalog
|
|
16286
|
+
});
|
|
16287
|
+
function isRichFnEntry(entry) {
|
|
16288
|
+
return typeof entry === "object" && entry !== null && "factory" in entry;
|
|
16289
|
+
}
|
|
16290
|
+
function isRichSourceEntry(entry) {
|
|
16291
|
+
return typeof entry === "object" && entry !== null && "factory" in entry;
|
|
16292
|
+
}
|
|
16293
|
+
function extractFnFactory(entry) {
|
|
16294
|
+
return isRichFnEntry(entry) ? entry.factory : entry;
|
|
16295
|
+
}
|
|
16296
|
+
function extractSourceFactory(entry) {
|
|
16297
|
+
return isRichSourceEntry(entry) ? entry.factory : entry;
|
|
16298
|
+
}
|
|
16299
|
+
function generateCatalogPrompt(catalog) {
|
|
16300
|
+
const sections = [];
|
|
16301
|
+
if (catalog.fns) {
|
|
16302
|
+
const groups = /* @__PURE__ */ new Map();
|
|
16303
|
+
for (const [name, entry] of Object.entries(catalog.fns)) {
|
|
16304
|
+
const tag = isRichFnEntry(entry) ? entry.tags?.[0] ?? "Other" : "Other";
|
|
16305
|
+
if (!groups.has(tag)) groups.set(tag, []);
|
|
16306
|
+
groups.get(tag).push(formatFnEntry(name, entry));
|
|
16307
|
+
}
|
|
16308
|
+
for (const [tag, lines] of groups) {
|
|
16309
|
+
sections.push(`${tag}:
|
|
16310
|
+
${lines.join("\n")}`);
|
|
16311
|
+
}
|
|
16312
|
+
}
|
|
16313
|
+
if (catalog.sources) {
|
|
16314
|
+
const lines = [];
|
|
16315
|
+
for (const [name, entry] of Object.entries(catalog.sources)) {
|
|
16316
|
+
lines.push(formatSourceEntry(name, entry));
|
|
16317
|
+
}
|
|
16318
|
+
if (lines.length > 0) {
|
|
16319
|
+
sections.push(`Sources:
|
|
16320
|
+
${lines.join("\n")}`);
|
|
16321
|
+
}
|
|
16322
|
+
}
|
|
16323
|
+
return sections.join("\n\n");
|
|
16324
|
+
}
|
|
16325
|
+
function formatFnEntry(name, entry) {
|
|
16326
|
+
if (!isRichFnEntry(entry)) return `- ${name}`;
|
|
16327
|
+
let line = `- ${name}: ${entry.description}`;
|
|
16328
|
+
if (entry.configSchema) {
|
|
16329
|
+
const fields = Object.entries(entry.configSchema).map(([k, v]) => {
|
|
16330
|
+
let desc = `${k}: ${v.type}`;
|
|
16331
|
+
if (v.enum) desc += ` (${v.enum.join("|")})`;
|
|
16332
|
+
if (v.required === false) desc += "?";
|
|
16333
|
+
return desc;
|
|
16334
|
+
});
|
|
16335
|
+
line += `. Config: { ${fields.join(", ")} }`;
|
|
16336
|
+
}
|
|
16337
|
+
return line;
|
|
16338
|
+
}
|
|
16339
|
+
function formatSourceEntry(name, entry) {
|
|
16340
|
+
if (!isRichSourceEntry(entry)) return `- ${name}`;
|
|
16341
|
+
let line = `- ${name}: ${entry.description}`;
|
|
16342
|
+
if (entry.configSchema) {
|
|
16343
|
+
const fields = Object.entries(entry.configSchema).map(([k, v]) => {
|
|
16344
|
+
let desc = `${k}: ${v.type}`;
|
|
16345
|
+
if (v.required === false) desc += "?";
|
|
16346
|
+
return desc;
|
|
16347
|
+
});
|
|
16348
|
+
line += `. Config: { ${fields.join(", ")} }`;
|
|
16349
|
+
}
|
|
16350
|
+
return line;
|
|
16351
|
+
}
|
|
16352
|
+
function validateSpecAgainstCatalog(spec, catalog) {
|
|
16353
|
+
const errors = [];
|
|
16354
|
+
const fnNames = new Set(Object.keys(catalog.fns ?? {}));
|
|
16355
|
+
const sourceNames = new Set(Object.keys(catalog.sources ?? {}));
|
|
16356
|
+
for (const [nodeName, nodeRaw] of Object.entries(spec.nodes)) {
|
|
16357
|
+
if (nodeRaw.type === "template") continue;
|
|
16358
|
+
const node2 = nodeRaw;
|
|
16359
|
+
if (node2.fn && fnNames.size > 0 && !fnNames.has(node2.fn)) {
|
|
16360
|
+
if (sourceNames.has(node2.fn)) {
|
|
16361
|
+
errors.push(
|
|
16362
|
+
`Node "${nodeName}": fn "${node2.fn}" is a source, not a function. Use it as a producer source instead, or use a function from: ${[...fnNames].join(", ")}`
|
|
16363
|
+
);
|
|
16364
|
+
} else {
|
|
16365
|
+
const suggestion = findClosest(node2.fn, fnNames);
|
|
16366
|
+
errors.push(
|
|
16367
|
+
`Node "${nodeName}": fn "${node2.fn}" not found in catalog` + (suggestion ? `. Did you mean "${suggestion}"?` : "")
|
|
16368
|
+
);
|
|
16369
|
+
}
|
|
16370
|
+
}
|
|
16371
|
+
if (node2.source && sourceNames.size > 0 && !sourceNames.has(node2.source)) {
|
|
16372
|
+
if (fnNames.has(node2.source)) {
|
|
16373
|
+
errors.push(
|
|
16374
|
+
`Node "${nodeName}": source "${node2.source}" is a function, not a source. Use it as fn instead, or use a source from: ${[...sourceNames].join(", ")}`
|
|
16375
|
+
);
|
|
16376
|
+
} else {
|
|
16377
|
+
const suggestion = findClosest(node2.source, sourceNames);
|
|
16378
|
+
errors.push(
|
|
16379
|
+
`Node "${nodeName}": source "${node2.source}" not found in catalog` + (suggestion ? `. Did you mean "${suggestion}"?` : "")
|
|
16380
|
+
);
|
|
16381
|
+
}
|
|
16382
|
+
}
|
|
16383
|
+
if (node2.fn && node2.config && catalog.fns?.[node2.fn]) {
|
|
16384
|
+
const entry = catalog.fns[node2.fn];
|
|
16385
|
+
if (isRichFnEntry(entry) && entry.configSchema) {
|
|
16386
|
+
for (const [field, schema] of Object.entries(entry.configSchema)) {
|
|
16387
|
+
if (schema.required !== false && !(field in node2.config)) {
|
|
16388
|
+
errors.push(`Node "${nodeName}": config missing required field "${field}"`);
|
|
16389
|
+
}
|
|
16390
|
+
if (field in node2.config && schema.enum) {
|
|
16391
|
+
const val = node2.config[field];
|
|
16392
|
+
if (!schema.enum.includes(val)) {
|
|
16393
|
+
errors.push(
|
|
16394
|
+
`Node "${nodeName}": config.${field} = ${JSON.stringify(val)}, expected one of: ${schema.enum.join(", ")}`
|
|
16395
|
+
);
|
|
16396
|
+
}
|
|
16397
|
+
}
|
|
16398
|
+
}
|
|
16399
|
+
}
|
|
16400
|
+
}
|
|
16401
|
+
}
|
|
16402
|
+
if (spec.templates) {
|
|
16403
|
+
for (const [tName, template] of Object.entries(spec.templates)) {
|
|
16404
|
+
for (const [nodeName, node2] of Object.entries(template.nodes)) {
|
|
16405
|
+
if (node2.fn && fnNames.size > 0 && !fnNames.has(node2.fn)) {
|
|
16406
|
+
const suggestion = findClosest(node2.fn, fnNames);
|
|
16407
|
+
errors.push(
|
|
16408
|
+
`Template "${tName}" node "${nodeName}": fn "${node2.fn}" not found in catalog` + (suggestion ? `. Did you mean "${suggestion}"?` : "")
|
|
16409
|
+
);
|
|
16410
|
+
}
|
|
16411
|
+
}
|
|
16412
|
+
}
|
|
16413
|
+
}
|
|
16414
|
+
return { valid: errors.length === 0, errors };
|
|
16415
|
+
}
|
|
16416
|
+
function findClosest(input, candidates) {
|
|
16417
|
+
let best = null;
|
|
16418
|
+
let bestDist = Infinity;
|
|
16419
|
+
const lower = input.toLowerCase();
|
|
16420
|
+
for (const c of candidates) {
|
|
16421
|
+
const dist = levenshtein(lower, c.toLowerCase());
|
|
16422
|
+
if (dist < bestDist && dist <= Math.max(3, Math.floor(input.length / 2))) {
|
|
16423
|
+
bestDist = dist;
|
|
16424
|
+
best = c;
|
|
16425
|
+
}
|
|
16426
|
+
}
|
|
16427
|
+
return best;
|
|
16428
|
+
}
|
|
16429
|
+
function levenshtein(a, b) {
|
|
16430
|
+
const m = a.length;
|
|
16431
|
+
const n = b.length;
|
|
16432
|
+
const dp = Array.from(
|
|
16433
|
+
{ length: m + 1 },
|
|
16434
|
+
(_, i) => Array.from({ length: n + 1 }, (_2, j) => i === 0 ? j : j === 0 ? i : 0)
|
|
16435
|
+
);
|
|
16436
|
+
for (let i = 1; i <= m; i++) {
|
|
16437
|
+
for (let j = 1; j <= n; j++) {
|
|
16438
|
+
dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
16439
|
+
}
|
|
16440
|
+
}
|
|
16441
|
+
return dp[m][n];
|
|
16442
|
+
}
|
|
16443
|
+
var VALID_NODE_TYPES2 = /* @__PURE__ */ new Set([
|
|
16444
|
+
"state",
|
|
16445
|
+
"producer",
|
|
16446
|
+
"derived",
|
|
16447
|
+
"effect",
|
|
16448
|
+
"operator",
|
|
16449
|
+
"template"
|
|
16450
|
+
]);
|
|
16451
|
+
var INNER_NODE_TYPES = /* @__PURE__ */ new Set(["state", "producer", "derived", "effect", "operator"]);
|
|
16452
|
+
function validateSpec(spec) {
|
|
16453
|
+
const errors = [];
|
|
16454
|
+
if (spec == null || typeof spec !== "object") {
|
|
16455
|
+
return { valid: false, errors: ["GraphSpec must be a non-null object"] };
|
|
16456
|
+
}
|
|
16457
|
+
const s = spec;
|
|
16458
|
+
if (typeof s.name !== "string" || s.name.length === 0) {
|
|
16459
|
+
errors.push("Missing or empty 'name' field");
|
|
16460
|
+
}
|
|
16461
|
+
if (s.nodes == null || typeof s.nodes !== "object" || Array.isArray(s.nodes)) {
|
|
16462
|
+
errors.push("Missing or invalid 'nodes' field (must be an object)");
|
|
16463
|
+
return { valid: false, errors };
|
|
16464
|
+
}
|
|
16465
|
+
const nodeNames = new Set(Object.keys(s.nodes));
|
|
16466
|
+
const nodeTypes = /* @__PURE__ */ new Map();
|
|
16467
|
+
const templateDefs = /* @__PURE__ */ new Map();
|
|
16468
|
+
if (s.templates != null && typeof s.templates === "object" && !Array.isArray(s.templates)) {
|
|
16469
|
+
for (const [tName, tRaw] of Object.entries(s.templates)) {
|
|
16470
|
+
if (tRaw != null && typeof tRaw === "object") {
|
|
16471
|
+
const t = tRaw;
|
|
16472
|
+
templateDefs.set(tName, {
|
|
16473
|
+
params: Array.isArray(t.params) ? t.params : []
|
|
16474
|
+
});
|
|
16475
|
+
}
|
|
16476
|
+
}
|
|
16477
|
+
}
|
|
16478
|
+
if (s.templates != null) {
|
|
16479
|
+
if (typeof s.templates !== "object" || Array.isArray(s.templates)) {
|
|
16480
|
+
errors.push("'templates' must be an object");
|
|
16481
|
+
} else {
|
|
16482
|
+
for (const [tName, tRaw] of Object.entries(s.templates)) {
|
|
16483
|
+
if (tRaw == null || typeof tRaw !== "object") {
|
|
16484
|
+
errors.push(`Template "${tName}": must be an object`);
|
|
16485
|
+
continue;
|
|
16486
|
+
}
|
|
16487
|
+
const t = tRaw;
|
|
16488
|
+
if (!Array.isArray(t.params)) {
|
|
16489
|
+
errors.push(`Template "${tName}": missing 'params' array`);
|
|
16490
|
+
}
|
|
16491
|
+
if (t.nodes == null || typeof t.nodes !== "object" || Array.isArray(t.nodes)) {
|
|
16492
|
+
errors.push(`Template "${tName}": missing or invalid 'nodes' object`);
|
|
16493
|
+
} else {
|
|
16494
|
+
const paramSet = new Set(Array.isArray(t.params) ? t.params : []);
|
|
16495
|
+
const innerNames = new Set(Object.keys(t.nodes));
|
|
16496
|
+
for (const [nName, nRaw] of Object.entries(t.nodes)) {
|
|
16497
|
+
if (nRaw == null || typeof nRaw !== "object") {
|
|
16498
|
+
errors.push(`Template "${tName}" node "${nName}": must be an object`);
|
|
16499
|
+
continue;
|
|
16500
|
+
}
|
|
16501
|
+
const n = nRaw;
|
|
16502
|
+
if (typeof n.type !== "string" || !INNER_NODE_TYPES.has(n.type)) {
|
|
16503
|
+
errors.push(`Template "${tName}" node "${nName}": invalid type`);
|
|
16504
|
+
}
|
|
16505
|
+
if (Array.isArray(n.deps)) {
|
|
16506
|
+
for (const dep of n.deps) {
|
|
16507
|
+
if (!innerNames.has(dep) && !paramSet.has(dep)) {
|
|
16508
|
+
errors.push(
|
|
16509
|
+
`Template "${tName}" node "${nName}": dep "${dep}" is not an inner node or param`
|
|
16510
|
+
);
|
|
16511
|
+
}
|
|
16512
|
+
}
|
|
16513
|
+
}
|
|
16514
|
+
}
|
|
16515
|
+
if (typeof t.output !== "string") {
|
|
16516
|
+
errors.push(`Template "${tName}": missing 'output' string`);
|
|
16517
|
+
} else if (!t.nodes[t.output]) {
|
|
16518
|
+
errors.push(`Template "${tName}": output "${t.output}" is not a declared node`);
|
|
16519
|
+
}
|
|
16520
|
+
}
|
|
16521
|
+
}
|
|
16522
|
+
}
|
|
16523
|
+
}
|
|
16524
|
+
for (const [name, raw] of Object.entries(s.nodes)) {
|
|
16525
|
+
if (raw == null || typeof raw !== "object") {
|
|
16526
|
+
errors.push(`Node "${name}": must be an object`);
|
|
16527
|
+
continue;
|
|
16528
|
+
}
|
|
16529
|
+
const n = raw;
|
|
16530
|
+
if (typeof n.type !== "string" || !VALID_NODE_TYPES2.has(n.type)) {
|
|
16531
|
+
errors.push(
|
|
16532
|
+
`Node "${name}": invalid type "${String(n.type)}" (expected: ${[...VALID_NODE_TYPES2].join(", ")})`
|
|
16533
|
+
);
|
|
16534
|
+
continue;
|
|
16535
|
+
}
|
|
16536
|
+
nodeTypes.set(name, n.type);
|
|
16537
|
+
if (n.type === "template") {
|
|
16538
|
+
if (typeof n.template !== "string" || !templateDefs.has(n.template)) {
|
|
16539
|
+
errors.push(`Node "${name}": template "${String(n.template)}" not found in templates`);
|
|
16540
|
+
} else {
|
|
16541
|
+
if (n.bind == null || typeof n.bind !== "object" || Array.isArray(n.bind)) {
|
|
16542
|
+
errors.push(`Node "${name}": template ref requires 'bind' object`);
|
|
16543
|
+
} else {
|
|
16544
|
+
const tmpl = templateDefs.get(n.template);
|
|
16545
|
+
const bind = n.bind;
|
|
16546
|
+
for (const param of tmpl.params) {
|
|
16547
|
+
if (!(param in bind)) {
|
|
16548
|
+
errors.push(
|
|
16549
|
+
`Node "${name}": template param "${param}" is not bound (template "${n.template}")`
|
|
16550
|
+
);
|
|
16551
|
+
}
|
|
16552
|
+
}
|
|
16553
|
+
for (const [, target] of Object.entries(bind)) {
|
|
16554
|
+
if (typeof target === "string" && !nodeNames.has(target)) {
|
|
16555
|
+
errors.push(
|
|
16556
|
+
`Node "${name}": bind target "${target}" does not reference an existing node`
|
|
16557
|
+
);
|
|
16558
|
+
}
|
|
16559
|
+
}
|
|
16560
|
+
}
|
|
16561
|
+
}
|
|
16562
|
+
} else {
|
|
16563
|
+
if (Array.isArray(n.deps)) {
|
|
16564
|
+
for (const dep of n.deps) {
|
|
16565
|
+
if (dep === name) {
|
|
16566
|
+
errors.push(`Node "${name}": self-referencing dep`);
|
|
16567
|
+
} else if (!nodeNames.has(dep)) {
|
|
16568
|
+
errors.push(`Node "${name}": dep "${dep}" does not reference an existing node`);
|
|
16569
|
+
}
|
|
16570
|
+
}
|
|
16571
|
+
}
|
|
16572
|
+
if ((n.type === "derived" || n.type === "effect" || n.type === "operator") && !Array.isArray(n.deps)) {
|
|
16573
|
+
errors.push(`Node "${name}": ${n.type} node should have a 'deps' array`);
|
|
16574
|
+
}
|
|
16575
|
+
}
|
|
16576
|
+
}
|
|
16577
|
+
if (s.feedback != null) {
|
|
16578
|
+
if (!Array.isArray(s.feedback)) {
|
|
16579
|
+
errors.push("'feedback' must be an array");
|
|
16580
|
+
} else {
|
|
16581
|
+
for (let i = 0; i < s.feedback.length; i++) {
|
|
16582
|
+
const edge = s.feedback[i];
|
|
16583
|
+
if (edge == null || typeof edge !== "object") {
|
|
16584
|
+
errors.push(`Feedback [${i}]: must be an object`);
|
|
16585
|
+
continue;
|
|
16586
|
+
}
|
|
16587
|
+
const e = edge;
|
|
16588
|
+
if (typeof e.from !== "string" || !nodeNames.has(e.from)) {
|
|
16589
|
+
errors.push(
|
|
16590
|
+
`Feedback [${i}]: 'from' "${String(e.from)}" does not reference an existing node`
|
|
16591
|
+
);
|
|
16592
|
+
}
|
|
16593
|
+
if (typeof e.from === "string" && e.from === e.to) {
|
|
16594
|
+
errors.push(`Feedback [${i}]: 'from' and 'to' must be different nodes`);
|
|
16595
|
+
}
|
|
16596
|
+
if (typeof e.to !== "string" || !nodeNames.has(e.to)) {
|
|
16597
|
+
errors.push(
|
|
16598
|
+
`Feedback [${i}]: 'to' "${String(e.to)}" does not reference an existing node`
|
|
16599
|
+
);
|
|
16600
|
+
} else if (typeof e.to === "string" && nodeTypes.get(e.to) !== "state") {
|
|
16601
|
+
errors.push(
|
|
16602
|
+
`Feedback [${i}]: 'to' node "${e.to}" must be a state node (got "${nodeTypes.get(e.to) ?? "unknown"}")`
|
|
16603
|
+
);
|
|
16604
|
+
}
|
|
16605
|
+
}
|
|
16606
|
+
}
|
|
16607
|
+
}
|
|
16608
|
+
return { valid: errors.length === 0, errors };
|
|
16609
|
+
}
|
|
16610
|
+
function compileSpec(spec, opts) {
|
|
16611
|
+
const validation = validateSpec(spec);
|
|
16612
|
+
if (!validation.valid) {
|
|
16613
|
+
throw new Error(`compileSpec: invalid GraphSpec:
|
|
16614
|
+
${validation.errors.join("\n")}`);
|
|
16615
|
+
}
|
|
16616
|
+
const catalog = opts?.catalog ?? {};
|
|
16617
|
+
const g = new Graph(spec.name);
|
|
16618
|
+
const templates = spec.templates ?? {};
|
|
16619
|
+
const catalogValidation = validateSpecAgainstCatalog(spec, catalog);
|
|
16620
|
+
if (!catalogValidation.valid) {
|
|
16621
|
+
throw new Error(
|
|
16622
|
+
`compileSpec: catalog validation errors:
|
|
16623
|
+
${catalogValidation.errors.join("\n")}`
|
|
16624
|
+
);
|
|
16625
|
+
}
|
|
16626
|
+
const resolveFn = (fnName) => {
|
|
16627
|
+
const entry = catalog.fns?.[fnName];
|
|
16628
|
+
return entry ? extractFnFactory(entry) : void 0;
|
|
16629
|
+
};
|
|
16630
|
+
const resolveSource = (sourceName) => {
|
|
16631
|
+
const entry = catalog.sources?.[sourceName];
|
|
16632
|
+
return entry ? extractSourceFactory(entry) : void 0;
|
|
16633
|
+
};
|
|
16634
|
+
const created = /* @__PURE__ */ new Map();
|
|
16635
|
+
const deferred = [];
|
|
16636
|
+
for (const [name, raw] of Object.entries(spec.nodes)) {
|
|
16637
|
+
if (raw.type === "template") continue;
|
|
16638
|
+
const n = raw;
|
|
16639
|
+
if (n.type === "state") {
|
|
16640
|
+
const nd = state(n.initial, {
|
|
16641
|
+
name,
|
|
16642
|
+
meta: n.meta ? { ...n.meta } : void 0
|
|
16643
|
+
});
|
|
16644
|
+
g.add(name, nd);
|
|
16645
|
+
created.set(name, nd);
|
|
16646
|
+
} else if (n.type === "producer") {
|
|
16647
|
+
const sourceFactory = n.source ? resolveSource(n.source) : void 0;
|
|
16648
|
+
const fnFactory = n.fn ? resolveFn(n.fn) : void 0;
|
|
16649
|
+
if (sourceFactory) {
|
|
16650
|
+
const nd = sourceFactory(n.config ?? {});
|
|
16651
|
+
g.add(name, nd);
|
|
16652
|
+
created.set(name, nd);
|
|
16653
|
+
} else if (fnFactory) {
|
|
16654
|
+
const nd = fnFactory([], n.config ?? {});
|
|
16655
|
+
g.add(name, nd);
|
|
16656
|
+
created.set(name, nd);
|
|
16657
|
+
} else {
|
|
16658
|
+
const nd = producer(() => {
|
|
16659
|
+
}, {
|
|
16660
|
+
name,
|
|
16661
|
+
meta: { ...n.meta, _specFn: n.fn, _specSource: n.source }
|
|
16662
|
+
});
|
|
16663
|
+
g.add(name, nd);
|
|
16664
|
+
created.set(name, nd);
|
|
16665
|
+
}
|
|
16666
|
+
} else {
|
|
16667
|
+
deferred.push([name, n]);
|
|
16668
|
+
}
|
|
16669
|
+
}
|
|
16670
|
+
let progressed = true;
|
|
16671
|
+
const pending = new Map(deferred);
|
|
16672
|
+
while (pending.size > 0 && progressed) {
|
|
16673
|
+
progressed = false;
|
|
16674
|
+
for (const [name, n] of [...pending.entries()]) {
|
|
16675
|
+
const deps = n.deps ?? [];
|
|
16676
|
+
if (!deps.every((dep) => created.has(dep))) continue;
|
|
16677
|
+
const resolvedDeps = deps.map((dep) => created.get(dep));
|
|
16678
|
+
const fnFactory = n.fn ? resolveFn(n.fn) : void 0;
|
|
16679
|
+
let nd;
|
|
16680
|
+
if (fnFactory) {
|
|
16681
|
+
nd = fnFactory(resolvedDeps, n.config ?? {});
|
|
16682
|
+
} else if (n.type === "effect") {
|
|
16683
|
+
nd = effect(resolvedDeps, () => {
|
|
16684
|
+
});
|
|
16685
|
+
} else {
|
|
16686
|
+
nd = derived(resolvedDeps, (vals) => vals[0]);
|
|
16687
|
+
}
|
|
16688
|
+
g.add(name, nd);
|
|
16689
|
+
created.set(name, nd);
|
|
16690
|
+
pending.delete(name);
|
|
16691
|
+
progressed = true;
|
|
16692
|
+
}
|
|
16693
|
+
}
|
|
16694
|
+
if (pending.size > 0) {
|
|
16695
|
+
const unresolved = [...pending.keys()].sort().join(", ");
|
|
16696
|
+
throw new Error(`compileSpec: unresolvable deps for nodes: ${unresolved}`);
|
|
16697
|
+
}
|
|
16698
|
+
for (const [name, raw] of Object.entries(spec.nodes)) {
|
|
16699
|
+
if (raw.type !== "template") continue;
|
|
16700
|
+
const ref = raw;
|
|
16701
|
+
const tmpl = templates[ref.template];
|
|
16702
|
+
const sub = new Graph(name);
|
|
16703
|
+
const subCreated = /* @__PURE__ */ new Map();
|
|
16704
|
+
const subDeferred = [];
|
|
16705
|
+
for (const [nName, nSpec] of Object.entries(tmpl.nodes)) {
|
|
16706
|
+
const resolvedDeps = (nSpec.deps ?? []).map((dep) => {
|
|
16707
|
+
if (dep.startsWith("$") && ref.bind[dep]) {
|
|
16708
|
+
return ref.bind[dep];
|
|
16709
|
+
}
|
|
16710
|
+
return dep;
|
|
16711
|
+
});
|
|
16712
|
+
const specWithResolvedDeps = { ...nSpec, deps: resolvedDeps };
|
|
16713
|
+
if (nSpec.type === "state") {
|
|
16714
|
+
const nd = state(nSpec.initial, {
|
|
16715
|
+
name: nName,
|
|
16716
|
+
meta: nSpec.meta ? { ...nSpec.meta } : void 0
|
|
16717
|
+
});
|
|
16718
|
+
sub.add(nName, nd);
|
|
16719
|
+
subCreated.set(nName, nd);
|
|
16720
|
+
} else if (nSpec.type === "producer") {
|
|
16721
|
+
const sourceFactory = nSpec.source ? resolveSource(nSpec.source) : void 0;
|
|
16722
|
+
const fnFactory = nSpec.fn ? resolveFn(nSpec.fn) : void 0;
|
|
16723
|
+
if (sourceFactory) {
|
|
16724
|
+
const nd = sourceFactory(nSpec.config ?? {});
|
|
16725
|
+
sub.add(nName, nd);
|
|
16726
|
+
subCreated.set(nName, nd);
|
|
16727
|
+
} else if (fnFactory) {
|
|
16728
|
+
const nd = fnFactory([], nSpec.config ?? {});
|
|
16729
|
+
sub.add(nName, nd);
|
|
16730
|
+
subCreated.set(nName, nd);
|
|
16731
|
+
} else {
|
|
16732
|
+
const nd = producer(() => {
|
|
16733
|
+
}, {
|
|
16734
|
+
name: nName,
|
|
16735
|
+
meta: { ...nSpec.meta, _specFn: nSpec.fn, _specSource: nSpec.source }
|
|
16736
|
+
});
|
|
16737
|
+
sub.add(nName, nd);
|
|
16738
|
+
subCreated.set(nName, nd);
|
|
16739
|
+
}
|
|
16740
|
+
} else {
|
|
16741
|
+
subDeferred.push([nName, specWithResolvedDeps]);
|
|
16742
|
+
}
|
|
16743
|
+
}
|
|
16744
|
+
let subProgressed = true;
|
|
16745
|
+
const subPending = new Map(subDeferred);
|
|
16746
|
+
while (subPending.size > 0 && subProgressed) {
|
|
16747
|
+
subProgressed = false;
|
|
16748
|
+
for (const [nName, nSpec] of [...subPending.entries()]) {
|
|
16749
|
+
const deps = nSpec.deps ?? [];
|
|
16750
|
+
const allReady = deps.every((dep) => subCreated.has(dep) || created.has(dep));
|
|
16751
|
+
if (!allReady) continue;
|
|
16752
|
+
const resolvedDeps = deps.map((dep) => subCreated.get(dep) ?? created.get(dep));
|
|
16753
|
+
const fnFactory = nSpec.fn ? resolveFn(nSpec.fn) : void 0;
|
|
16754
|
+
let nd;
|
|
16755
|
+
if (fnFactory) {
|
|
16756
|
+
nd = fnFactory(resolvedDeps, nSpec.config ?? {});
|
|
16757
|
+
} else if (nSpec.type === "effect") {
|
|
16758
|
+
nd = effect(resolvedDeps, () => {
|
|
16759
|
+
});
|
|
16760
|
+
} else {
|
|
16761
|
+
nd = derived(resolvedDeps, (vals) => vals[0]);
|
|
16762
|
+
}
|
|
16763
|
+
sub.add(nName, nd);
|
|
16764
|
+
subCreated.set(nName, nd);
|
|
16765
|
+
subPending.delete(nName);
|
|
16766
|
+
subProgressed = true;
|
|
16767
|
+
}
|
|
16768
|
+
}
|
|
16769
|
+
if (subPending.size > 0) {
|
|
16770
|
+
const unresolved = [...subPending.keys()].sort().join(", ");
|
|
16771
|
+
throw new Error(
|
|
16772
|
+
`compileSpec: template "${ref.template}" has unresolvable deps: ${unresolved}`
|
|
16773
|
+
);
|
|
16774
|
+
}
|
|
16775
|
+
g.mount(name, sub);
|
|
16776
|
+
const outputPath = `${name}::${tmpl.output}`;
|
|
16777
|
+
created.set(name, g.resolve(outputPath));
|
|
16778
|
+
try {
|
|
16779
|
+
const outputNode = g.resolve(outputPath);
|
|
16780
|
+
outputNode.meta._templateName?.down([[DATA, ref.template]]);
|
|
16781
|
+
outputNode.meta._templateBind?.down([[DATA, ref.bind]]);
|
|
16782
|
+
} catch {
|
|
16783
|
+
}
|
|
16784
|
+
}
|
|
16785
|
+
for (const [name, raw] of Object.entries(spec.nodes)) {
|
|
16786
|
+
if (raw.type === "template") continue;
|
|
16787
|
+
const n = raw;
|
|
16788
|
+
for (const dep of n.deps ?? []) {
|
|
16789
|
+
try {
|
|
16790
|
+
g.connect(dep, name);
|
|
16791
|
+
} catch (err) {
|
|
16792
|
+
const msg = err instanceof Error ? err.message : "";
|
|
16793
|
+
if (!msg.includes("constructor deps") && !msg.includes("already")) {
|
|
16794
|
+
throw err;
|
|
16795
|
+
}
|
|
16796
|
+
}
|
|
16797
|
+
}
|
|
16798
|
+
}
|
|
16799
|
+
for (const fb of spec.feedback ?? []) {
|
|
16800
|
+
feedback(g, fb.from, fb.to, {
|
|
16801
|
+
maxIterations: fb.maxIterations
|
|
16802
|
+
});
|
|
16803
|
+
}
|
|
16804
|
+
return g;
|
|
16805
|
+
}
|
|
16806
|
+
var INTERNAL_META_KEYS = /* @__PURE__ */ new Set([
|
|
16807
|
+
"reduction",
|
|
16808
|
+
"reduction_type",
|
|
16809
|
+
"_specFn",
|
|
16810
|
+
"_specSource",
|
|
16811
|
+
"_templateName",
|
|
16812
|
+
"_templateBind",
|
|
16813
|
+
"feedbackFrom",
|
|
16814
|
+
"feedbackTo",
|
|
16815
|
+
"_internal"
|
|
16816
|
+
]);
|
|
16817
|
+
function decompileGraph(graph) {
|
|
16818
|
+
const desc = graph.describe({ detail: "standard" });
|
|
16819
|
+
const nodes = {};
|
|
16820
|
+
const feedbackEdges = [];
|
|
16821
|
+
const metaSegment = `::${GRAPH_META_SEGMENT}::`;
|
|
16822
|
+
const feedbackCounterPattern = /^__feedback_(?!effect_)(.+)$/;
|
|
16823
|
+
const feedbackConditions = /* @__PURE__ */ new Set();
|
|
16824
|
+
for (const path of Object.keys(desc.nodes)) {
|
|
16825
|
+
if (path.includes(metaSegment)) continue;
|
|
16826
|
+
const match = feedbackCounterPattern.exec(path);
|
|
16827
|
+
if (match) {
|
|
16828
|
+
feedbackConditions.add(match[1]);
|
|
16829
|
+
const meta = desc.nodes[path]?.meta;
|
|
16830
|
+
if (meta?.feedbackFrom && meta?.feedbackTo) {
|
|
16831
|
+
feedbackEdges.push({
|
|
16832
|
+
from: meta.feedbackFrom,
|
|
16833
|
+
to: meta.feedbackTo,
|
|
16834
|
+
...meta.maxIterations ? { maxIterations: meta.maxIterations } : {}
|
|
16835
|
+
});
|
|
16836
|
+
}
|
|
16837
|
+
}
|
|
16838
|
+
}
|
|
16839
|
+
for (const [path, nodeDesc] of Object.entries(desc.nodes)) {
|
|
16840
|
+
if (path.includes(metaSegment)) continue;
|
|
16841
|
+
if (feedbackCounterPattern.test(path)) continue;
|
|
16842
|
+
if (nodeDesc.meta?._internal) continue;
|
|
16843
|
+
if (path.startsWith("__feedback_effect_")) continue;
|
|
16844
|
+
if (path.startsWith("__bridge_")) continue;
|
|
16845
|
+
if (path.includes("::")) continue;
|
|
16846
|
+
const specNode = {
|
|
16847
|
+
type: nodeDesc.type
|
|
16848
|
+
};
|
|
16849
|
+
if (nodeDesc.deps.length > 0) {
|
|
16850
|
+
specNode.deps = nodeDesc.deps.filter((d) => !d.includes("::"));
|
|
16851
|
+
}
|
|
16852
|
+
if (nodeDesc.type === "state" && nodeDesc.value !== void 0) {
|
|
16853
|
+
specNode.initial = nodeDesc.value;
|
|
16854
|
+
}
|
|
16855
|
+
if (nodeDesc.meta && Object.keys(nodeDesc.meta).length > 0) {
|
|
16856
|
+
const meta = {};
|
|
16857
|
+
for (const [k, v] of Object.entries(nodeDesc.meta)) {
|
|
16858
|
+
if (!INTERNAL_META_KEYS.has(k)) meta[k] = v;
|
|
16859
|
+
}
|
|
16860
|
+
if (Object.keys(meta).length > 0) {
|
|
16861
|
+
specNode.meta = meta;
|
|
16862
|
+
}
|
|
16863
|
+
}
|
|
16864
|
+
nodes[path] = specNode;
|
|
16865
|
+
}
|
|
16866
|
+
const templates = {};
|
|
16867
|
+
const templateRefs = {};
|
|
16868
|
+
const metaDetectedSubgraphs = /* @__PURE__ */ new Set();
|
|
16869
|
+
for (const subName of desc.subgraphs) {
|
|
16870
|
+
const prefix = `${subName}::`;
|
|
16871
|
+
for (const [path, nodeDesc] of Object.entries(desc.nodes)) {
|
|
16872
|
+
if (!path.startsWith(prefix)) continue;
|
|
16873
|
+
if (path.includes(metaSegment)) continue;
|
|
16874
|
+
const meta = nodeDesc.meta;
|
|
16875
|
+
if (meta?._templateName && meta?._templateBind) {
|
|
16876
|
+
const templateName = meta._templateName;
|
|
16877
|
+
const bind = meta._templateBind;
|
|
16878
|
+
if (!templates[templateName]) {
|
|
16879
|
+
const tmplNodes = {};
|
|
16880
|
+
const tmplInnerNames = /* @__PURE__ */ new Set();
|
|
16881
|
+
const tmplPrefix = `${subName}::`;
|
|
16882
|
+
for (const [p, nd] of Object.entries(desc.nodes)) {
|
|
16883
|
+
if (!p.startsWith(tmplPrefix) || p.includes(metaSegment)) continue;
|
|
16884
|
+
const localName = p.slice(tmplPrefix.length);
|
|
16885
|
+
if (localName.includes("::")) continue;
|
|
16886
|
+
tmplInnerNames.add(localName);
|
|
16887
|
+
tmplNodes[localName] = {
|
|
16888
|
+
type: nd.type,
|
|
16889
|
+
...nd.deps.length > 0 ? {
|
|
16890
|
+
deps: nd.deps.map(
|
|
16891
|
+
(d) => d.startsWith(tmplPrefix) ? d.slice(tmplPrefix.length) : d
|
|
16892
|
+
)
|
|
16893
|
+
} : {}
|
|
16894
|
+
};
|
|
16895
|
+
}
|
|
16896
|
+
const tmplParams = [];
|
|
16897
|
+
const tmplParamMap = /* @__PURE__ */ new Map();
|
|
16898
|
+
for (const n of Object.values(tmplNodes)) {
|
|
16899
|
+
for (const dep of n.deps ?? []) {
|
|
16900
|
+
if (!tmplInnerNames.has(dep) && !tmplParamMap.has(dep)) {
|
|
16901
|
+
const param = `$${dep}`;
|
|
16902
|
+
tmplParams.push(param);
|
|
16903
|
+
tmplParamMap.set(dep, param);
|
|
16904
|
+
}
|
|
16905
|
+
}
|
|
16906
|
+
}
|
|
16907
|
+
for (const n of Object.values(tmplNodes)) {
|
|
16908
|
+
if (n.deps) n.deps = n.deps.map((d) => tmplParamMap.get(d) ?? d);
|
|
16909
|
+
}
|
|
16910
|
+
const depended = /* @__PURE__ */ new Set();
|
|
16911
|
+
for (const n of Object.values(tmplNodes)) {
|
|
16912
|
+
for (const dep of n.deps ?? []) {
|
|
16913
|
+
if (tmplInnerNames.has(dep)) depended.add(dep);
|
|
16914
|
+
}
|
|
16915
|
+
}
|
|
16916
|
+
const outputCandidates = [...tmplInnerNames].filter((n) => !depended.has(n));
|
|
16917
|
+
const tmplOutput = outputCandidates[0] ?? [...tmplInnerNames].pop();
|
|
16918
|
+
templates[templateName] = { params: tmplParams, nodes: tmplNodes, output: tmplOutput };
|
|
16919
|
+
}
|
|
16920
|
+
delete nodes[subName];
|
|
16921
|
+
templateRefs[subName] = { type: "template", template: templateName, bind };
|
|
16922
|
+
metaDetectedSubgraphs.add(subName);
|
|
16923
|
+
break;
|
|
16924
|
+
}
|
|
16925
|
+
}
|
|
16926
|
+
}
|
|
16927
|
+
const structureMap = /* @__PURE__ */ new Map();
|
|
16928
|
+
for (const subName of desc.subgraphs) {
|
|
16929
|
+
if (metaDetectedSubgraphs.has(subName)) continue;
|
|
16930
|
+
const subNodes = {};
|
|
16931
|
+
const prefix = `${subName}::`;
|
|
16932
|
+
for (const [path, nodeDesc] of Object.entries(desc.nodes)) {
|
|
16933
|
+
if (path.includes(metaSegment)) continue;
|
|
16934
|
+
if (!path.startsWith(prefix)) continue;
|
|
16935
|
+
const localName = path.slice(prefix.length);
|
|
16936
|
+
if (localName.includes("::")) continue;
|
|
16937
|
+
subNodes[localName] = {
|
|
16938
|
+
type: nodeDesc.type,
|
|
16939
|
+
...nodeDesc.deps.length > 0 ? {
|
|
16940
|
+
deps: nodeDesc.deps.map((d) => d.startsWith(prefix) ? d.slice(prefix.length) : d)
|
|
16941
|
+
} : {}
|
|
16942
|
+
};
|
|
16943
|
+
}
|
|
16944
|
+
const fingerprint = JSON.stringify(
|
|
16945
|
+
Object.fromEntries(
|
|
16946
|
+
Object.entries(subNodes).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => [k, { type: v.type, deps: v.deps ?? [] }])
|
|
16947
|
+
)
|
|
16948
|
+
);
|
|
16949
|
+
if (!structureMap.has(fingerprint)) {
|
|
16950
|
+
structureMap.set(fingerprint, []);
|
|
16951
|
+
}
|
|
16952
|
+
structureMap.get(fingerprint).push({ name: subName, nodes: subNodes });
|
|
16953
|
+
}
|
|
16954
|
+
for (const [, group] of structureMap) {
|
|
16955
|
+
if (group.length < 2) continue;
|
|
16956
|
+
const templateName = `${group[0].name}_template`;
|
|
16957
|
+
const refNodes = group[0].nodes;
|
|
16958
|
+
const innerNames = new Set(Object.keys(refNodes));
|
|
16959
|
+
const params = [];
|
|
16960
|
+
const baseParamMap = /* @__PURE__ */ new Map();
|
|
16961
|
+
for (const n of Object.values(refNodes)) {
|
|
16962
|
+
for (const dep of n.deps ?? []) {
|
|
16963
|
+
if (!innerNames.has(dep) && !baseParamMap.has(dep)) {
|
|
16964
|
+
const param = `$${dep}`;
|
|
16965
|
+
params.push(param);
|
|
16966
|
+
baseParamMap.set(dep, param);
|
|
16967
|
+
}
|
|
16968
|
+
}
|
|
16969
|
+
}
|
|
16970
|
+
const depended = /* @__PURE__ */ new Set();
|
|
16971
|
+
for (const n of Object.values(refNodes)) {
|
|
16972
|
+
for (const dep of n.deps ?? []) {
|
|
16973
|
+
if (innerNames.has(dep)) depended.add(dep);
|
|
16974
|
+
}
|
|
16975
|
+
}
|
|
16976
|
+
const outputCandidates = [...innerNames].filter((n) => !depended.has(n));
|
|
16977
|
+
const output = outputCandidates[0] ?? [...innerNames].pop();
|
|
16978
|
+
const tmplNodes = {};
|
|
16979
|
+
for (const [nName, nSpec] of Object.entries(refNodes)) {
|
|
16980
|
+
tmplNodes[nName] = {
|
|
16981
|
+
...nSpec,
|
|
16982
|
+
deps: nSpec.deps?.map((d) => baseParamMap.get(d) ?? d)
|
|
16983
|
+
};
|
|
16984
|
+
}
|
|
16985
|
+
templates[templateName] = { params, nodes: tmplNodes, output };
|
|
16986
|
+
for (const member of group) {
|
|
16987
|
+
delete nodes[member.name];
|
|
16988
|
+
const memberBind = {};
|
|
16989
|
+
const memberInnerNames = new Set(Object.keys(member.nodes));
|
|
16990
|
+
for (const n of Object.values(member.nodes)) {
|
|
16991
|
+
for (const dep of n.deps ?? []) {
|
|
16992
|
+
if (!memberInnerNames.has(dep)) {
|
|
16993
|
+
const param = baseParamMap.get(dep) ?? `$${dep}`;
|
|
16994
|
+
memberBind[param] = dep;
|
|
16995
|
+
}
|
|
16996
|
+
}
|
|
16997
|
+
}
|
|
16998
|
+
templateRefs[member.name] = {
|
|
16999
|
+
type: "template",
|
|
17000
|
+
template: templateName,
|
|
17001
|
+
bind: memberBind
|
|
17002
|
+
};
|
|
17003
|
+
}
|
|
17004
|
+
}
|
|
17005
|
+
const allNodes = {
|
|
17006
|
+
...nodes,
|
|
17007
|
+
...templateRefs
|
|
17008
|
+
};
|
|
17009
|
+
const result = { name: desc.name, nodes: allNodes };
|
|
17010
|
+
if (Object.keys(templates).length > 0) result.templates = templates;
|
|
17011
|
+
if (feedbackEdges.length > 0) result.feedback = feedbackEdges;
|
|
17012
|
+
return result;
|
|
17013
|
+
}
|
|
17014
|
+
function specDiff(specA, specB) {
|
|
17015
|
+
const entries = [];
|
|
17016
|
+
if (specA.name !== specB.name) {
|
|
17017
|
+
entries.push({
|
|
17018
|
+
type: "changed",
|
|
17019
|
+
path: "name",
|
|
17020
|
+
detail: `"${specA.name}" \u2192 "${specB.name}"`
|
|
17021
|
+
});
|
|
17022
|
+
}
|
|
17023
|
+
const nodesA = new Set(Object.keys(specA.nodes));
|
|
17024
|
+
const nodesB = new Set(Object.keys(specB.nodes));
|
|
17025
|
+
for (const name of nodesB) {
|
|
17026
|
+
if (!nodesA.has(name)) {
|
|
17027
|
+
const n = specB.nodes[name];
|
|
17028
|
+
entries.push({
|
|
17029
|
+
type: "added",
|
|
17030
|
+
path: `nodes.${name}`,
|
|
17031
|
+
detail: `type: ${n.type}`
|
|
17032
|
+
});
|
|
17033
|
+
}
|
|
17034
|
+
}
|
|
17035
|
+
for (const name of nodesA) {
|
|
17036
|
+
if (!nodesB.has(name)) {
|
|
17037
|
+
entries.push({ type: "removed", path: `nodes.${name}` });
|
|
17038
|
+
}
|
|
17039
|
+
}
|
|
17040
|
+
for (const name of nodesA) {
|
|
17041
|
+
if (!nodesB.has(name)) continue;
|
|
17042
|
+
const a = specA.nodes[name];
|
|
17043
|
+
const b = specB.nodes[name];
|
|
17044
|
+
if (JSON.stringify(a) !== JSON.stringify(b)) {
|
|
17045
|
+
const details = [];
|
|
17046
|
+
if (a.type !== b.type) details.push(`type: ${a.type} \u2192 ${b.type}`);
|
|
17047
|
+
if (JSON.stringify(a.deps) !== JSON.stringify(b.deps)) {
|
|
17048
|
+
details.push("deps changed");
|
|
17049
|
+
}
|
|
17050
|
+
if (a.fn !== b.fn) {
|
|
17051
|
+
details.push(`fn: ${a.fn} \u2192 ${b.fn}`);
|
|
17052
|
+
}
|
|
17053
|
+
if (JSON.stringify(a.config) !== JSON.stringify(b.config)) {
|
|
17054
|
+
details.push("config changed");
|
|
17055
|
+
}
|
|
17056
|
+
entries.push({
|
|
17057
|
+
type: "changed",
|
|
17058
|
+
path: `nodes.${name}`,
|
|
17059
|
+
detail: details.join("; ") || "modified"
|
|
17060
|
+
});
|
|
17061
|
+
}
|
|
17062
|
+
}
|
|
17063
|
+
const tmplA = specA.templates ?? {};
|
|
17064
|
+
const tmplB = specB.templates ?? {};
|
|
17065
|
+
const tmplNamesA = new Set(Object.keys(tmplA));
|
|
17066
|
+
const tmplNamesB = new Set(Object.keys(tmplB));
|
|
17067
|
+
for (const name of tmplNamesB) {
|
|
17068
|
+
if (!tmplNamesA.has(name)) {
|
|
17069
|
+
entries.push({ type: "added", path: `templates.${name}` });
|
|
17070
|
+
}
|
|
17071
|
+
}
|
|
17072
|
+
for (const name of tmplNamesA) {
|
|
17073
|
+
if (!tmplNamesB.has(name)) {
|
|
17074
|
+
entries.push({ type: "removed", path: `templates.${name}` });
|
|
17075
|
+
}
|
|
17076
|
+
}
|
|
17077
|
+
for (const name of tmplNamesA) {
|
|
17078
|
+
if (!tmplNamesB.has(name)) continue;
|
|
17079
|
+
if (JSON.stringify(tmplA[name]) !== JSON.stringify(tmplB[name])) {
|
|
17080
|
+
entries.push({
|
|
17081
|
+
type: "changed",
|
|
17082
|
+
path: `templates.${name}`,
|
|
17083
|
+
detail: "template definition changed"
|
|
17084
|
+
});
|
|
17085
|
+
}
|
|
17086
|
+
}
|
|
17087
|
+
const fbA = specA.feedback ?? [];
|
|
17088
|
+
const fbB = specB.feedback ?? [];
|
|
17089
|
+
const fbKeyA = new Set(fbA.map((e) => `${e.from}->${e.to}`));
|
|
17090
|
+
const fbKeyB = new Set(fbB.map((e) => `${e.from}->${e.to}`));
|
|
17091
|
+
for (const fb of fbB) {
|
|
17092
|
+
const key = `${fb.from}->${fb.to}`;
|
|
17093
|
+
if (!fbKeyA.has(key)) {
|
|
17094
|
+
entries.push({
|
|
17095
|
+
type: "added",
|
|
17096
|
+
path: `feedback.${key}`,
|
|
17097
|
+
detail: `maxIterations: ${fb.maxIterations ?? 10}`
|
|
17098
|
+
});
|
|
17099
|
+
}
|
|
17100
|
+
}
|
|
17101
|
+
for (const fb of fbA) {
|
|
17102
|
+
const key = `${fb.from}->${fb.to}`;
|
|
17103
|
+
if (!fbKeyB.has(key)) {
|
|
17104
|
+
entries.push({ type: "removed", path: `feedback.${key}` });
|
|
17105
|
+
}
|
|
17106
|
+
}
|
|
17107
|
+
for (const fb of fbA) {
|
|
17108
|
+
const key = `${fb.from}->${fb.to}`;
|
|
17109
|
+
const counterpart = fbB.find((b) => b.from === fb.from && b.to === fb.to);
|
|
17110
|
+
if (counterpart && JSON.stringify(fb) !== JSON.stringify(counterpart)) {
|
|
17111
|
+
entries.push({
|
|
17112
|
+
type: "changed",
|
|
17113
|
+
path: `feedback.${key}`,
|
|
17114
|
+
detail: `maxIterations: ${fb.maxIterations ?? 10} \u2192 ${counterpart.maxIterations ?? 10}`
|
|
17115
|
+
});
|
|
17116
|
+
}
|
|
17117
|
+
}
|
|
17118
|
+
const added = entries.filter((e) => e.type === "added").length;
|
|
17119
|
+
const removed = entries.filter((e) => e.type === "removed").length;
|
|
17120
|
+
const changed = entries.filter((e) => e.type === "changed").length;
|
|
17121
|
+
const parts = [];
|
|
17122
|
+
if (added) parts.push(`${added} added`);
|
|
17123
|
+
if (removed) parts.push(`${removed} removed`);
|
|
17124
|
+
if (changed) parts.push(`${changed} changed`);
|
|
17125
|
+
const summary = parts.length > 0 ? parts.join(", ") : "no changes";
|
|
17126
|
+
return { entries, summary };
|
|
17127
|
+
}
|
|
17128
|
+
var LLM_COMPOSE_SYSTEM_PROMPT = `You are a graph architect for GraphReFly, a reactive graph protocol.
|
|
17129
|
+
|
|
17130
|
+
Given a natural-language description, produce a JSON GraphSpec with this structure:
|
|
17131
|
+
|
|
17132
|
+
{
|
|
17133
|
+
"name": "<graph_name>",
|
|
17134
|
+
"nodes": {
|
|
17135
|
+
"<node_name>": {
|
|
17136
|
+
"type": "state" | "derived" | "producer" | "effect" | "operator",
|
|
17137
|
+
"deps": ["<dep_node_name>", ...],
|
|
17138
|
+
"fn": "<catalog_function_name>",
|
|
17139
|
+
"source": "<catalog_source_name>",
|
|
17140
|
+
"config": { ... },
|
|
17141
|
+
"initial": <value>,
|
|
17142
|
+
"meta": { "description": "<purpose>" }
|
|
17143
|
+
},
|
|
17144
|
+
"<template_instance>": {
|
|
17145
|
+
"type": "template",
|
|
17146
|
+
"template": "<template_name>",
|
|
17147
|
+
"bind": { "$param": "node_name" }
|
|
17148
|
+
}
|
|
17149
|
+
},
|
|
17150
|
+
"templates": {
|
|
17151
|
+
"<template_name>": {
|
|
17152
|
+
"params": ["$param1", "$param2"],
|
|
17153
|
+
"nodes": { ... },
|
|
17154
|
+
"output": "<output_node>"
|
|
17155
|
+
}
|
|
17156
|
+
},
|
|
17157
|
+
"feedback": [
|
|
17158
|
+
{ "from": "<condition_node>", "to": "<state_node>", "maxIterations": 10 }
|
|
17159
|
+
]
|
|
17160
|
+
}
|
|
17161
|
+
|
|
17162
|
+
Rules:
|
|
17163
|
+
- "state" nodes hold user/LLM-writable values (knobs). Use "initial" for default values.
|
|
17164
|
+
- "derived" nodes compute from deps using a named "fn".
|
|
17165
|
+
- "effect" nodes produce side effects from deps.
|
|
17166
|
+
- "producer" nodes generate values from a named "source".
|
|
17167
|
+
- Use "templates" when the same subgraph pattern repeats (e.g., per-source resilience).
|
|
17168
|
+
- Use "feedback" for bounded cycles where a derived value writes back to a state node.
|
|
17169
|
+
- meta.description is required for every node.
|
|
17170
|
+
- Return ONLY valid JSON, no markdown fences or commentary.`;
|
|
17171
|
+
function stripFences2(text) {
|
|
17172
|
+
const match = text.match(/^```(?:json)?\s*([\s\S]*?)\s*```[\s\S]*$/);
|
|
17173
|
+
return match ? match[1] : text;
|
|
17174
|
+
}
|
|
17175
|
+
async function llmCompose(problem, adapter, opts) {
|
|
17176
|
+
let systemPrompt = LLM_COMPOSE_SYSTEM_PROMPT;
|
|
17177
|
+
const catalogPrompt = opts?.catalogDescription ?? (opts?.catalog ? generateCatalogPrompt(opts.catalog) : void 0);
|
|
17178
|
+
if (catalogPrompt) {
|
|
17179
|
+
systemPrompt += `
|
|
17180
|
+
|
|
17181
|
+
Available catalog (use ONLY these names):
|
|
17182
|
+
${catalogPrompt}`;
|
|
17183
|
+
}
|
|
17184
|
+
if (opts?.systemPromptExtra) {
|
|
17185
|
+
systemPrompt += `
|
|
17186
|
+
|
|
17187
|
+
${opts.systemPromptExtra}`;
|
|
17188
|
+
}
|
|
17189
|
+
const messages = [
|
|
17190
|
+
{ role: "system", content: systemPrompt },
|
|
17191
|
+
{ role: "user", content: problem }
|
|
17192
|
+
];
|
|
17193
|
+
const rawResult = adapter.invoke(messages, {
|
|
17194
|
+
model: opts?.model,
|
|
17195
|
+
temperature: opts?.temperature ?? 0,
|
|
17196
|
+
maxTokens: opts?.maxTokens
|
|
17197
|
+
});
|
|
17198
|
+
const response = await rawResult;
|
|
17199
|
+
let content = response.content.trim();
|
|
17200
|
+
if (content.startsWith("```")) {
|
|
17201
|
+
content = stripFences2(content);
|
|
17202
|
+
}
|
|
17203
|
+
let parsed;
|
|
17204
|
+
try {
|
|
17205
|
+
parsed = JSON.parse(content);
|
|
17206
|
+
} catch {
|
|
17207
|
+
throw new Error(`llmCompose: LLM response is not valid JSON: ${content.slice(0, 200)}`);
|
|
17208
|
+
}
|
|
17209
|
+
const validation = validateSpec(parsed);
|
|
17210
|
+
if (!validation.valid) {
|
|
17211
|
+
throw new Error(`llmCompose: invalid GraphSpec:
|
|
17212
|
+
${validation.errors.join("\n")}`);
|
|
17213
|
+
}
|
|
17214
|
+
let spec = parsed;
|
|
17215
|
+
if (opts?.catalog) {
|
|
17216
|
+
const maxRefine = opts.maxAutoRefine ?? 0;
|
|
17217
|
+
for (let attempt = 0; attempt <= maxRefine; attempt++) {
|
|
17218
|
+
const catalogValidation = validateSpecAgainstCatalog(spec, opts.catalog);
|
|
17219
|
+
if (catalogValidation.valid) break;
|
|
17220
|
+
if (attempt === maxRefine) {
|
|
17221
|
+
throw new Error(
|
|
17222
|
+
`llmCompose: catalog validation failed after ${maxRefine} refine attempts:
|
|
17223
|
+
${catalogValidation.errors.join("\n")}`
|
|
17224
|
+
);
|
|
17225
|
+
}
|
|
17226
|
+
spec = await llmRefine(
|
|
17227
|
+
spec,
|
|
17228
|
+
`Fix these catalog errors:
|
|
17229
|
+
${catalogValidation.errors.join("\n")}
|
|
17230
|
+
|
|
17231
|
+
Use ONLY functions and sources from the catalog.`,
|
|
17232
|
+
adapter,
|
|
17233
|
+
{ ...opts, catalogDescription: catalogPrompt }
|
|
17234
|
+
);
|
|
17235
|
+
}
|
|
17236
|
+
}
|
|
17237
|
+
return spec;
|
|
17238
|
+
}
|
|
17239
|
+
async function llmRefine(currentSpec, feedback2, adapter, opts) {
|
|
17240
|
+
let systemPrompt = LLM_COMPOSE_SYSTEM_PROMPT;
|
|
17241
|
+
if (opts?.catalogDescription) {
|
|
17242
|
+
systemPrompt += `
|
|
17243
|
+
|
|
17244
|
+
Available catalog:
|
|
17245
|
+
${opts.catalogDescription}`;
|
|
17246
|
+
}
|
|
17247
|
+
if (opts?.systemPromptExtra) {
|
|
17248
|
+
systemPrompt += `
|
|
17249
|
+
|
|
17250
|
+
${opts.systemPromptExtra}`;
|
|
17251
|
+
}
|
|
17252
|
+
const messages = [
|
|
17253
|
+
{ role: "system", content: systemPrompt },
|
|
17254
|
+
{
|
|
17255
|
+
role: "user",
|
|
17256
|
+
content: `Current GraphSpec:
|
|
17257
|
+
${JSON.stringify(currentSpec, null, 2)}
|
|
17258
|
+
|
|
17259
|
+
Modification request: ${feedback2}
|
|
17260
|
+
|
|
17261
|
+
Return the complete modified GraphSpec as JSON.`
|
|
17262
|
+
}
|
|
17263
|
+
];
|
|
17264
|
+
const rawResult = adapter.invoke(messages, {
|
|
17265
|
+
model: opts?.model,
|
|
17266
|
+
temperature: opts?.temperature ?? 0,
|
|
17267
|
+
maxTokens: opts?.maxTokens
|
|
17268
|
+
});
|
|
17269
|
+
const response = await rawResult;
|
|
17270
|
+
let content = response.content.trim();
|
|
17271
|
+
if (content.startsWith("```")) {
|
|
17272
|
+
content = stripFences2(content);
|
|
17273
|
+
}
|
|
17274
|
+
let parsed;
|
|
17275
|
+
try {
|
|
17276
|
+
parsed = JSON.parse(content);
|
|
17277
|
+
} catch {
|
|
17278
|
+
throw new Error(`llmRefine: LLM response is not valid JSON: ${content.slice(0, 200)}`);
|
|
17279
|
+
}
|
|
17280
|
+
const validation = validateSpec(parsed);
|
|
17281
|
+
if (!validation.valid) {
|
|
17282
|
+
throw new Error(`llmRefine: invalid GraphSpec:
|
|
17283
|
+
${validation.errors.join("\n")}`);
|
|
17284
|
+
}
|
|
17285
|
+
return parsed;
|
|
17286
|
+
}
|
|
17287
|
+
|
|
17288
|
+
// src/patterns/messaging.ts
|
|
17289
|
+
var messaging_exports = {};
|
|
17290
|
+
__export(messaging_exports, {
|
|
17291
|
+
JobFlowGraph: () => JobFlowGraph,
|
|
17292
|
+
JobQueueGraph: () => JobQueueGraph,
|
|
17293
|
+
SubscriptionGraph: () => SubscriptionGraph,
|
|
17294
|
+
TopicBridgeGraph: () => TopicBridgeGraph,
|
|
17295
|
+
TopicGraph: () => TopicGraph,
|
|
17296
|
+
jobFlow: () => jobFlow,
|
|
17297
|
+
jobQueue: () => jobQueue,
|
|
17298
|
+
subscription: () => subscription,
|
|
17299
|
+
topic: () => topic,
|
|
17300
|
+
topicBridge: () => topicBridge
|
|
17301
|
+
});
|
|
17302
|
+
var DEFAULT_MAX_PER_PUMP = 2147483647;
|
|
17303
|
+
function requireNonNegativeInt(value, label) {
|
|
17304
|
+
if (!Number.isFinite(value) || !Number.isInteger(value) || value < 0) {
|
|
17305
|
+
throw new Error(`${label} must be a non-negative integer`);
|
|
17306
|
+
}
|
|
17307
|
+
return value;
|
|
17308
|
+
}
|
|
17309
|
+
function keepalive6(n) {
|
|
17310
|
+
return n.subscribe(() => {
|
|
17311
|
+
});
|
|
17312
|
+
}
|
|
17313
|
+
function messagingMeta(kind, extra) {
|
|
17314
|
+
return {
|
|
17315
|
+
messaging: true,
|
|
17316
|
+
messaging_type: kind,
|
|
17317
|
+
...extra ?? {}
|
|
17318
|
+
};
|
|
17319
|
+
}
|
|
17320
|
+
var TopicGraph = class extends Graph {
|
|
17321
|
+
_log;
|
|
17322
|
+
_keepaliveDisposers = [];
|
|
17323
|
+
events;
|
|
17324
|
+
latest;
|
|
17325
|
+
constructor(name, opts = {}) {
|
|
17326
|
+
super(name, opts.graph);
|
|
17327
|
+
this._log = reactiveLog([], { name: "events", maxSize: opts.retainedLimit });
|
|
17328
|
+
this.events = this._log.entries;
|
|
17329
|
+
this.add("events", this.events);
|
|
17330
|
+
this.latest = derived(
|
|
17331
|
+
[this.events],
|
|
17332
|
+
([snapshot]) => {
|
|
17333
|
+
const entries = snapshot.value.entries;
|
|
17334
|
+
return entries.length === 0 ? void 0 : entries[entries.length - 1];
|
|
17335
|
+
},
|
|
17336
|
+
{
|
|
17337
|
+
name: "latest",
|
|
17338
|
+
describeKind: "derived",
|
|
17339
|
+
meta: messagingMeta("topic_latest"),
|
|
17340
|
+
initial: void 0
|
|
17341
|
+
}
|
|
17342
|
+
);
|
|
17343
|
+
this.add("latest", this.latest);
|
|
17344
|
+
this.connect("events", "latest");
|
|
17345
|
+
this._keepaliveDisposers.push(keepalive6(this.latest));
|
|
17346
|
+
}
|
|
17347
|
+
destroy() {
|
|
17348
|
+
for (const dispose of this._keepaliveDisposers) dispose();
|
|
17349
|
+
this._keepaliveDisposers.length = 0;
|
|
17350
|
+
super.destroy();
|
|
17351
|
+
}
|
|
17352
|
+
publish(value) {
|
|
17353
|
+
this._log.append(value);
|
|
17354
|
+
}
|
|
17355
|
+
retained() {
|
|
17356
|
+
const snapshot = this.events.get();
|
|
17357
|
+
return snapshot.value.entries;
|
|
17358
|
+
}
|
|
17359
|
+
};
|
|
17360
|
+
var SubscriptionGraph = class extends Graph {
|
|
17361
|
+
_keepaliveDisposers = [];
|
|
17362
|
+
source;
|
|
17363
|
+
cursor;
|
|
17364
|
+
available;
|
|
17365
|
+
constructor(name, topicGraph, opts = {}) {
|
|
17366
|
+
super(name, opts.graph);
|
|
17367
|
+
const initialCursor = requireNonNegativeInt(opts.cursor ?? 0, "subscription cursor");
|
|
17368
|
+
this.mount("topic", topicGraph);
|
|
17369
|
+
const topicEvents = topicGraph.events;
|
|
17370
|
+
this.source = derived([topicEvents], ([snapshot]) => snapshot, {
|
|
17371
|
+
name: "source",
|
|
17372
|
+
describeKind: "derived",
|
|
17373
|
+
meta: messagingMeta("subscription_source"),
|
|
17374
|
+
initial: topicEvents.get()
|
|
17375
|
+
});
|
|
17376
|
+
this.add("source", this.source);
|
|
17377
|
+
this.cursor = state(initialCursor, {
|
|
17378
|
+
name: "cursor",
|
|
17379
|
+
describeKind: "state",
|
|
17380
|
+
meta: messagingMeta("subscription_cursor")
|
|
17381
|
+
});
|
|
17382
|
+
this.add("cursor", this.cursor);
|
|
17383
|
+
this.available = derived(
|
|
17384
|
+
[this.source, this.cursor],
|
|
17385
|
+
([sourceSnapshot, cursor]) => {
|
|
17386
|
+
const entries = sourceSnapshot.value.entries;
|
|
17387
|
+
const start = Math.max(0, Math.trunc(cursor ?? 0));
|
|
17388
|
+
return entries.slice(start);
|
|
17389
|
+
},
|
|
17390
|
+
{
|
|
17391
|
+
name: "available",
|
|
17392
|
+
describeKind: "derived",
|
|
17393
|
+
meta: messagingMeta("subscription_available"),
|
|
17394
|
+
initial: []
|
|
17395
|
+
}
|
|
17396
|
+
);
|
|
17397
|
+
this.add("available", this.available);
|
|
17398
|
+
this.connect("topic::events", "source");
|
|
17399
|
+
this.connect("source", "available");
|
|
17400
|
+
this.connect("cursor", "available");
|
|
17401
|
+
this._keepaliveDisposers.push(keepalive6(this.source));
|
|
17402
|
+
this._keepaliveDisposers.push(keepalive6(this.available));
|
|
17403
|
+
}
|
|
17404
|
+
destroy() {
|
|
17405
|
+
for (const dispose of this._keepaliveDisposers) dispose();
|
|
17406
|
+
this._keepaliveDisposers.length = 0;
|
|
17407
|
+
super.destroy();
|
|
17408
|
+
}
|
|
17409
|
+
ack(count) {
|
|
17410
|
+
const available = this.available.get();
|
|
17411
|
+
const requested = count === void 0 ? available.length : requireNonNegativeInt(count, "subscription ack count");
|
|
17412
|
+
const step = Math.min(requested, available.length);
|
|
17413
|
+
if (step <= 0) return this.cursor.get();
|
|
17414
|
+
const next = this.cursor.get() + step;
|
|
17415
|
+
this.cursor.down([[DATA, next]]);
|
|
17416
|
+
return next;
|
|
15549
17417
|
}
|
|
15550
17418
|
pull(limit, opts = {}) {
|
|
15551
17419
|
const available = this.available.get();
|
|
@@ -15583,7 +17451,7 @@ var JobQueueGraph = class extends Graph {
|
|
|
15583
17451
|
);
|
|
15584
17452
|
this.add("depth", this.depth);
|
|
15585
17453
|
this.connect("pending", "depth");
|
|
15586
|
-
this._keepaliveDisposers.push(
|
|
17454
|
+
this._keepaliveDisposers.push(keepalive6(this.depth));
|
|
15587
17455
|
}
|
|
15588
17456
|
destroy() {
|
|
15589
17457
|
for (const dispose of this._keepaliveDisposers) dispose();
|
|
@@ -15683,7 +17551,7 @@ var JobFlowGraph = class extends Graph {
|
|
|
15683
17551
|
);
|
|
15684
17552
|
this.add("completedCount", this.completedCount);
|
|
15685
17553
|
this.connect("completed", "completedCount");
|
|
15686
|
-
this._keepaliveDisposers.push(
|
|
17554
|
+
this._keepaliveDisposers.push(keepalive6(this.completedCount));
|
|
15687
17555
|
const maxPerPump = Math.max(
|
|
15688
17556
|
1,
|
|
15689
17557
|
requireNonNegativeInt(opts.maxPerPump ?? DEFAULT_MAX_PER_PUMP, "job flow maxPerPump")
|
|
@@ -15723,7 +17591,7 @@ var JobFlowGraph = class extends Graph {
|
|
|
15723
17591
|
);
|
|
15724
17592
|
this.add(`pump_${stage}`, pump);
|
|
15725
17593
|
this.connect(`${stage}::pending`, `pump_${stage}`);
|
|
15726
|
-
this._keepaliveDisposers.push(
|
|
17594
|
+
this._keepaliveDisposers.push(keepalive6(pump));
|
|
15727
17595
|
}
|
|
15728
17596
|
}
|
|
15729
17597
|
destroy() {
|
|
@@ -15795,7 +17663,7 @@ var TopicBridgeGraph = class extends Graph {
|
|
|
15795
17663
|
);
|
|
15796
17664
|
this.add("pump", pump);
|
|
15797
17665
|
this.connect("subscription::available", "pump");
|
|
15798
|
-
this._keepaliveDisposers.push(
|
|
17666
|
+
this._keepaliveDisposers.push(keepalive6(pump));
|
|
15799
17667
|
}
|
|
15800
17668
|
destroy() {
|
|
15801
17669
|
for (const dispose of this._keepaliveDisposers) dispose();
|
|
@@ -15865,7 +17733,7 @@ function registerStep(graph, name, step, depPaths) {
|
|
|
15865
17733
|
graph.connect(path, name);
|
|
15866
17734
|
}
|
|
15867
17735
|
}
|
|
15868
|
-
function
|
|
17736
|
+
function baseMeta3(kind, meta) {
|
|
15869
17737
|
return {
|
|
15870
17738
|
orchestration: true,
|
|
15871
17739
|
orchestration_type: kind,
|
|
@@ -15903,7 +17771,7 @@ function task(graph, name, run, opts) {
|
|
|
15903
17771
|
...nodeOpts,
|
|
15904
17772
|
name,
|
|
15905
17773
|
describeKind: "derived",
|
|
15906
|
-
meta:
|
|
17774
|
+
meta: baseMeta3("task", opts?.meta)
|
|
15907
17775
|
}
|
|
15908
17776
|
);
|
|
15909
17777
|
registerStep(
|
|
@@ -15926,7 +17794,7 @@ function branch(graph, name, source, predicate, opts) {
|
|
|
15926
17794
|
...opts,
|
|
15927
17795
|
name,
|
|
15928
17796
|
describeKind: "derived",
|
|
15929
|
-
meta:
|
|
17797
|
+
meta: baseMeta3("branch", opts?.meta)
|
|
15930
17798
|
}
|
|
15931
17799
|
);
|
|
15932
17800
|
registerStep(graph, name, step, src.path ? [src.path] : []);
|
|
@@ -15949,7 +17817,7 @@ function gate2(graph, name, source, control, opts) {
|
|
|
15949
17817
|
...opts,
|
|
15950
17818
|
name,
|
|
15951
17819
|
describeKind: "operator",
|
|
15952
|
-
meta:
|
|
17820
|
+
meta: baseMeta3("gate", opts?.meta)
|
|
15953
17821
|
}
|
|
15954
17822
|
);
|
|
15955
17823
|
registerStep(
|
|
@@ -15977,7 +17845,7 @@ function approval(graph, name, source, approver, opts) {
|
|
|
15977
17845
|
...opts,
|
|
15978
17846
|
name,
|
|
15979
17847
|
describeKind: "operator",
|
|
15980
|
-
meta:
|
|
17848
|
+
meta: baseMeta3("approval", opts?.meta)
|
|
15981
17849
|
}
|
|
15982
17850
|
);
|
|
15983
17851
|
registerStep(
|
|
@@ -15996,7 +17864,7 @@ function forEach2(graph, name, source, run, opts) {
|
|
|
15996
17864
|
name,
|
|
15997
17865
|
describeKind: "effect",
|
|
15998
17866
|
completeWhenDepsComplete: false,
|
|
15999
|
-
meta:
|
|
17867
|
+
meta: baseMeta3("forEach", opts?.meta),
|
|
16000
17868
|
onMessage(msg, depIndex, actions) {
|
|
16001
17869
|
if (terminated) return true;
|
|
16002
17870
|
if (depIndex !== 0) {
|
|
@@ -16031,7 +17899,7 @@ function join2(graph, name, deps, opts) {
|
|
|
16031
17899
|
...opts,
|
|
16032
17900
|
name,
|
|
16033
17901
|
describeKind: "derived",
|
|
16034
|
-
meta:
|
|
17902
|
+
meta: baseMeta3("join", opts?.meta)
|
|
16035
17903
|
}
|
|
16036
17904
|
);
|
|
16037
17905
|
registerStep(
|
|
@@ -16062,7 +17930,7 @@ function loop(graph, name, source, iterate, opts) {
|
|
|
16062
17930
|
...opts,
|
|
16063
17931
|
name,
|
|
16064
17932
|
describeKind: "derived",
|
|
16065
|
-
meta:
|
|
17933
|
+
meta: baseMeta3("loop", opts?.meta)
|
|
16066
17934
|
}
|
|
16067
17935
|
);
|
|
16068
17936
|
registerStep(
|
|
@@ -16087,7 +17955,7 @@ function sensor(graph, name, initial, opts) {
|
|
|
16087
17955
|
name,
|
|
16088
17956
|
initial,
|
|
16089
17957
|
describeKind: "producer",
|
|
16090
|
-
meta:
|
|
17958
|
+
meta: baseMeta3("sensor", opts?.meta)
|
|
16091
17959
|
});
|
|
16092
17960
|
registerStep(graph, name, source, []);
|
|
16093
17961
|
return {
|
|
@@ -16125,7 +17993,7 @@ function wait(graph, name, source, ms, opts) {
|
|
|
16125
17993
|
initial: src.node.get(),
|
|
16126
17994
|
describeKind: "operator",
|
|
16127
17995
|
completeWhenDepsComplete: false,
|
|
16128
|
-
meta:
|
|
17996
|
+
meta: baseMeta3("wait", opts?.meta),
|
|
16129
17997
|
onMessage(msg, depIndex, actions) {
|
|
16130
17998
|
if (terminated) return true;
|
|
16131
17999
|
if (depIndex !== 0) {
|
|
@@ -16175,7 +18043,7 @@ function onFailure(graph, name, source, recover, opts) {
|
|
|
16175
18043
|
name,
|
|
16176
18044
|
describeKind: "operator",
|
|
16177
18045
|
completeWhenDepsComplete: false,
|
|
16178
|
-
meta:
|
|
18046
|
+
meta: baseMeta3("onFailure", opts?.meta),
|
|
16179
18047
|
onMessage(msg, _depIndex, actions) {
|
|
16180
18048
|
if (terminated) return true;
|
|
16181
18049
|
if (msg[0] === ERROR) {
|
|
@@ -16686,285 +18554,16 @@ function reactiveBlockLayout(opts) {
|
|
|
16686
18554
|
};
|
|
16687
18555
|
}
|
|
16688
18556
|
|
|
16689
|
-
// src/patterns/reduction.ts
|
|
16690
|
-
var reduction_exports = {};
|
|
16691
|
-
__export(reduction_exports, {
|
|
16692
|
-
budgetGate: () => budgetGate,
|
|
16693
|
-
feedback: () => feedback,
|
|
16694
|
-
funnel: () => funnel,
|
|
16695
|
-
scorer: () => scorer,
|
|
16696
|
-
stratify: () => stratify
|
|
16697
|
-
});
|
|
16698
|
-
function baseMeta2(kind, meta) {
|
|
16699
|
-
return {
|
|
16700
|
-
reduction: true,
|
|
16701
|
-
reduction_type: kind,
|
|
16702
|
-
...meta ?? {}
|
|
16703
|
-
};
|
|
16704
|
-
}
|
|
16705
|
-
function stratify(name, source, rules, opts) {
|
|
16706
|
-
const g = new Graph(name, opts);
|
|
16707
|
-
g.add("source", source);
|
|
16708
|
-
const rulesNode = state(rules, {
|
|
16709
|
-
meta: baseMeta2("stratify_rules")
|
|
16710
|
-
});
|
|
16711
|
-
g.add("rules", rulesNode);
|
|
16712
|
-
for (const rule of rules) {
|
|
16713
|
-
_addBranch(g, source, rulesNode, rule);
|
|
16714
|
-
}
|
|
16715
|
-
return g;
|
|
16716
|
-
}
|
|
16717
|
-
function _addBranch(graph, source, rulesNode, rule) {
|
|
16718
|
-
const branchName = `branch/${rule.name}`;
|
|
16719
|
-
let pendingDirty = false;
|
|
16720
|
-
const filterNode = node([source, rulesNode], () => void 0, {
|
|
16721
|
-
describeKind: "operator",
|
|
16722
|
-
meta: baseMeta2("stratify_branch", { branch: rule.name }),
|
|
16723
|
-
onMessage(msg, depIndex, actions) {
|
|
16724
|
-
if (depIndex !== 0) return false;
|
|
16725
|
-
const t = msg[0];
|
|
16726
|
-
if (t === DATA) {
|
|
16727
|
-
const value = msg[1];
|
|
16728
|
-
const currentRules = rulesNode.get();
|
|
16729
|
-
const currentRule = currentRules.find((r) => r.name === rule.name);
|
|
16730
|
-
if (currentRule && currentRule.classify(value)) {
|
|
16731
|
-
pendingDirty = false;
|
|
16732
|
-
actions.emit(value);
|
|
16733
|
-
} else {
|
|
16734
|
-
if (pendingDirty) {
|
|
16735
|
-
pendingDirty = false;
|
|
16736
|
-
actions.down([[DIRTY], [RESOLVED]]);
|
|
16737
|
-
}
|
|
16738
|
-
}
|
|
16739
|
-
return true;
|
|
16740
|
-
}
|
|
16741
|
-
if (t === DIRTY) {
|
|
16742
|
-
pendingDirty = true;
|
|
16743
|
-
return true;
|
|
16744
|
-
}
|
|
16745
|
-
if (t === RESOLVED) {
|
|
16746
|
-
if (pendingDirty) {
|
|
16747
|
-
pendingDirty = false;
|
|
16748
|
-
actions.down([[DIRTY], [RESOLVED]]);
|
|
16749
|
-
} else {
|
|
16750
|
-
actions.down([[RESOLVED]]);
|
|
16751
|
-
}
|
|
16752
|
-
return true;
|
|
16753
|
-
}
|
|
16754
|
-
if (t === COMPLETE || t === ERROR) {
|
|
16755
|
-
pendingDirty = false;
|
|
16756
|
-
actions.down([msg]);
|
|
16757
|
-
return true;
|
|
16758
|
-
}
|
|
16759
|
-
return false;
|
|
16760
|
-
}
|
|
16761
|
-
});
|
|
16762
|
-
graph.add(branchName, filterNode);
|
|
16763
|
-
graph.connect("source", branchName);
|
|
16764
|
-
if (rule.ops) {
|
|
16765
|
-
const transformed = rule.ops(filterNode);
|
|
16766
|
-
const transformedName = `branch/${rule.name}/out`;
|
|
16767
|
-
graph.add(transformedName, transformed);
|
|
16768
|
-
graph.connect(branchName, transformedName);
|
|
16769
|
-
}
|
|
16770
|
-
}
|
|
16771
|
-
function funnel(name, sources, stages, opts) {
|
|
16772
|
-
if (sources.length === 0) throw new RangeError("funnel requires at least one source");
|
|
16773
|
-
if (stages.length === 0) throw new RangeError("funnel requires at least one stage");
|
|
16774
|
-
const g = new Graph(name, opts);
|
|
16775
|
-
const merged = sources.length === 1 ? sources[0] : merge(...sources);
|
|
16776
|
-
g.add("merged", merged);
|
|
16777
|
-
let prevOutputPath = "merged";
|
|
16778
|
-
for (let i = 0; i < stages.length; i++) {
|
|
16779
|
-
const stage = stages[i];
|
|
16780
|
-
const sub = new Graph(stage.name);
|
|
16781
|
-
stage.build(sub);
|
|
16782
|
-
try {
|
|
16783
|
-
sub.resolve("input");
|
|
16784
|
-
} catch {
|
|
16785
|
-
throw new Error(`funnel stage "${stage.name}" must define an "input" node`);
|
|
16786
|
-
}
|
|
16787
|
-
try {
|
|
16788
|
-
sub.resolve("output");
|
|
16789
|
-
} catch {
|
|
16790
|
-
throw new Error(`funnel stage "${stage.name}" must define an "output" node`);
|
|
16791
|
-
}
|
|
16792
|
-
g.mount(stage.name, sub);
|
|
16793
|
-
const prevNode = g.resolve(prevOutputPath);
|
|
16794
|
-
const stageInputPath = `${stage.name}::input`;
|
|
16795
|
-
const stageInput = g.resolve(stageInputPath);
|
|
16796
|
-
prevNode.subscribe((msgs) => {
|
|
16797
|
-
for (const msg of msgs) {
|
|
16798
|
-
const t = msg[0];
|
|
16799
|
-
if (t === DATA) {
|
|
16800
|
-
stageInput.down([[DATA, msg[1]]]);
|
|
16801
|
-
} else if (t === DIRTY) {
|
|
16802
|
-
stageInput.down([[DIRTY]]);
|
|
16803
|
-
} else if (t === RESOLVED) {
|
|
16804
|
-
stageInput.down([[RESOLVED]]);
|
|
16805
|
-
} else if (t === COMPLETE || t === ERROR) {
|
|
16806
|
-
stageInput.down([msg]);
|
|
16807
|
-
}
|
|
16808
|
-
}
|
|
16809
|
-
});
|
|
16810
|
-
prevOutputPath = `${stage.name}::output`;
|
|
16811
|
-
}
|
|
16812
|
-
return g;
|
|
16813
|
-
}
|
|
16814
|
-
function feedback(graph, condition, reentry, opts) {
|
|
16815
|
-
const maxIter = opts?.maxIterations ?? 10;
|
|
16816
|
-
const counterName = `__feedback_${condition}`;
|
|
16817
|
-
const counter = state(0, {
|
|
16818
|
-
meta: baseMeta2("feedback_counter", { maxIterations: maxIter })
|
|
16819
|
-
});
|
|
16820
|
-
graph.add(counterName, counter);
|
|
16821
|
-
const condNode = graph.resolve(condition);
|
|
16822
|
-
const reentryNode = graph.resolve(reentry);
|
|
16823
|
-
condNode.subscribe((msgs) => {
|
|
16824
|
-
for (const msg of msgs) {
|
|
16825
|
-
if (msg[0] === DATA) {
|
|
16826
|
-
const currentCount = counter.get();
|
|
16827
|
-
if (currentCount >= maxIter) continue;
|
|
16828
|
-
const condValue = msg[1];
|
|
16829
|
-
if (condValue == null) continue;
|
|
16830
|
-
counter.down([[DATA, currentCount + 1]]);
|
|
16831
|
-
reentryNode.down([[DATA, condValue]]);
|
|
16832
|
-
}
|
|
16833
|
-
}
|
|
16834
|
-
});
|
|
16835
|
-
return graph;
|
|
16836
|
-
}
|
|
16837
|
-
function budgetGate(source, constraints, opts) {
|
|
16838
|
-
if (constraints.length === 0) throw new RangeError("budgetGate requires at least one constraint");
|
|
16839
|
-
const constraintNodes = constraints.map((c) => c.node);
|
|
16840
|
-
const allDeps = [source, ...constraintNodes];
|
|
16841
|
-
let buffer2 = [];
|
|
16842
|
-
let paused = false;
|
|
16843
|
-
const lockId = /* @__PURE__ */ Symbol("budget-gate");
|
|
16844
|
-
function checkBudget() {
|
|
16845
|
-
return constraints.every((c) => c.check(c.node.get()));
|
|
16846
|
-
}
|
|
16847
|
-
function flushBuffer(actions) {
|
|
16848
|
-
while (buffer2.length > 0 && checkBudget()) {
|
|
16849
|
-
const item = buffer2.shift();
|
|
16850
|
-
actions.emit(item);
|
|
16851
|
-
}
|
|
16852
|
-
}
|
|
16853
|
-
return node(allDeps, () => void 0, {
|
|
16854
|
-
...opts,
|
|
16855
|
-
describeKind: "operator",
|
|
16856
|
-
meta: baseMeta2("budget_gate", opts?.meta),
|
|
16857
|
-
onMessage(msg, depIndex, actions) {
|
|
16858
|
-
const t = msg[0];
|
|
16859
|
-
if (depIndex === 0) {
|
|
16860
|
-
if (t === DATA) {
|
|
16861
|
-
if (checkBudget() && buffer2.length === 0) {
|
|
16862
|
-
actions.emit(msg[1]);
|
|
16863
|
-
} else {
|
|
16864
|
-
buffer2.push(msg[1]);
|
|
16865
|
-
if (!paused) {
|
|
16866
|
-
paused = true;
|
|
16867
|
-
actions.up([[PAUSE, lockId]]);
|
|
16868
|
-
}
|
|
16869
|
-
}
|
|
16870
|
-
return true;
|
|
16871
|
-
}
|
|
16872
|
-
if (t === DIRTY) {
|
|
16873
|
-
actions.down([[DIRTY]]);
|
|
16874
|
-
return true;
|
|
16875
|
-
}
|
|
16876
|
-
if (t === RESOLVED) {
|
|
16877
|
-
if (buffer2.length === 0) {
|
|
16878
|
-
actions.down([[RESOLVED]]);
|
|
16879
|
-
}
|
|
16880
|
-
return true;
|
|
16881
|
-
}
|
|
16882
|
-
if (t === COMPLETE || t === ERROR) {
|
|
16883
|
-
for (const item of buffer2) {
|
|
16884
|
-
actions.emit(item);
|
|
16885
|
-
}
|
|
16886
|
-
buffer2 = [];
|
|
16887
|
-
if (paused) {
|
|
16888
|
-
paused = false;
|
|
16889
|
-
actions.up([[RESUME, lockId]]);
|
|
16890
|
-
}
|
|
16891
|
-
actions.down([msg]);
|
|
16892
|
-
return true;
|
|
16893
|
-
}
|
|
16894
|
-
return false;
|
|
16895
|
-
}
|
|
16896
|
-
if (t === DATA || t === RESOLVED) {
|
|
16897
|
-
if (checkBudget() && buffer2.length > 0) {
|
|
16898
|
-
flushBuffer(actions);
|
|
16899
|
-
if (buffer2.length === 0 && paused) {
|
|
16900
|
-
paused = false;
|
|
16901
|
-
actions.up([[RESUME, lockId]]);
|
|
16902
|
-
}
|
|
16903
|
-
} else if (!checkBudget() && !paused && buffer2.length > 0) {
|
|
16904
|
-
paused = true;
|
|
16905
|
-
actions.up([[PAUSE, lockId]]);
|
|
16906
|
-
}
|
|
16907
|
-
return true;
|
|
16908
|
-
}
|
|
16909
|
-
if (t === DIRTY) {
|
|
16910
|
-
return true;
|
|
16911
|
-
}
|
|
16912
|
-
if (t === ERROR) {
|
|
16913
|
-
actions.down([msg]);
|
|
16914
|
-
return true;
|
|
16915
|
-
}
|
|
16916
|
-
if (t === COMPLETE) {
|
|
16917
|
-
return true;
|
|
16918
|
-
}
|
|
16919
|
-
return false;
|
|
16920
|
-
}
|
|
16921
|
-
});
|
|
16922
|
-
}
|
|
16923
|
-
function scorer(sources, weights, opts) {
|
|
16924
|
-
if (sources.length === 0) throw new RangeError("scorer requires at least one source");
|
|
16925
|
-
if (sources.length !== weights.length) {
|
|
16926
|
-
throw new RangeError("scorer requires the same number of sources and weights");
|
|
16927
|
-
}
|
|
16928
|
-
const allDeps = [...sources, ...weights];
|
|
16929
|
-
const n = sources.length;
|
|
16930
|
-
const scoreFns = opts?.scoreFns;
|
|
16931
|
-
return derived(
|
|
16932
|
-
allDeps,
|
|
16933
|
-
(vals) => {
|
|
16934
|
-
const signals = vals.slice(0, n);
|
|
16935
|
-
const weightValues = vals.slice(n);
|
|
16936
|
-
const breakdown = [];
|
|
16937
|
-
let totalScore = 0;
|
|
16938
|
-
for (let i = 0; i < n; i++) {
|
|
16939
|
-
const sig = signals[i] ?? 0;
|
|
16940
|
-
const wt = weightValues[i] ?? 0;
|
|
16941
|
-
const rawScore = scoreFns?.[i] ? scoreFns[i](sig) : sig;
|
|
16942
|
-
const weighted = rawScore * wt;
|
|
16943
|
-
breakdown.push(weighted);
|
|
16944
|
-
totalScore += weighted;
|
|
16945
|
-
}
|
|
16946
|
-
return {
|
|
16947
|
-
value: signals,
|
|
16948
|
-
score: totalScore,
|
|
16949
|
-
breakdown
|
|
16950
|
-
};
|
|
16951
|
-
},
|
|
16952
|
-
{
|
|
16953
|
-
...opts,
|
|
16954
|
-
describeKind: "derived",
|
|
16955
|
-
meta: baseMeta2("scorer", opts?.meta)
|
|
16956
|
-
}
|
|
16957
|
-
);
|
|
16958
|
-
}
|
|
16959
|
-
|
|
16960
18557
|
// src/index.ts
|
|
16961
18558
|
var version = "0.0.0";
|
|
16962
18559
|
// Annotate the CommonJS export names for ESM import in node:
|
|
16963
18560
|
0 && (module.exports = {
|
|
18561
|
+
CLEANUP_RESULT,
|
|
16964
18562
|
COMPLETE,
|
|
16965
18563
|
CircuitOpenError,
|
|
16966
18564
|
DATA,
|
|
16967
18565
|
DEFAULT_ACTOR,
|
|
18566
|
+
DEFAULT_DOWN,
|
|
16968
18567
|
DIRTY,
|
|
16969
18568
|
DictCheckpointAdapter,
|
|
16970
18569
|
DynamicNodeImpl,
|
|
@@ -16990,6 +18589,7 @@ var version = "0.0.0";
|
|
|
16990
18589
|
ai,
|
|
16991
18590
|
audit,
|
|
16992
18591
|
batch,
|
|
18592
|
+
bridge,
|
|
16993
18593
|
buffer,
|
|
16994
18594
|
bufferCount,
|
|
16995
18595
|
bufferTime,
|
|
@@ -17001,6 +18601,7 @@ var version = "0.0.0";
|
|
|
17001
18601
|
checkpointToRedis,
|
|
17002
18602
|
checkpointToS3,
|
|
17003
18603
|
circuitBreaker,
|
|
18604
|
+
cleanupResult,
|
|
17004
18605
|
combine,
|
|
17005
18606
|
combineLatest,
|
|
17006
18607
|
compat,
|
|
@@ -17025,6 +18626,7 @@ var version = "0.0.0";
|
|
|
17025
18626
|
deserializeError,
|
|
17026
18627
|
distill,
|
|
17027
18628
|
distinctUntilChanged,
|
|
18629
|
+
domainTemplates,
|
|
17028
18630
|
dynamicNode,
|
|
17029
18631
|
effect,
|
|
17030
18632
|
elementAt,
|
|
@@ -17076,6 +18678,7 @@ var version = "0.0.0";
|
|
|
17076
18678
|
gate,
|
|
17077
18679
|
globToRegExp,
|
|
17078
18680
|
graph,
|
|
18681
|
+
graphspec,
|
|
17079
18682
|
interval,
|
|
17080
18683
|
isBatching,
|
|
17081
18684
|
isKnownMessageType,
|