@graphrefly/graphrefly 0.10.0 → 0.12.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-QTZSBQGJ.js → chunk-4F2ZFD5L.js} +19 -1
- package/dist/chunk-4F2ZFD5L.js.map +1 -0
- package/dist/{chunk-LR2CLSEF.js → chunk-6OLNYOGU.js} +2 -3
- package/dist/chunk-6OLNYOGU.js.map +1 -0
- package/dist/{chunk-TZLX4KIT.js → chunk-BRPCN2HJ.js} +46 -17
- package/dist/chunk-BRPCN2HJ.js.map +1 -0
- package/dist/{chunk-A2AJJOSJ.js → chunk-IXTW3BIO.js} +3 -3
- package/dist/{chunk-XCZPGOVP.js → chunk-JYRHO63K.js} +3 -3
- package/dist/{chunk-UCW3VWMN.js → chunk-NULSP7U4.js} +4 -4
- package/dist/{chunk-WYI7YW54.js → chunk-VQWLA6XQ.js} +3 -3
- package/dist/{chunk-YWTP2XRJ.js → chunk-X732W3QA.js} +2 -2
- package/dist/{chunk-E7OH6ZAZ.js → chunk-XWMTVV2D.js} +62 -3
- package/dist/chunk-XWMTVV2D.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 +52 -14
- 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 +5 -5
- 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-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-CiAqgfFg.d.ts} +17 -13
- package/dist/{index-a5gHmH5b.d.ts → index-CthwPnHQ.d.cts} +17 -13
- 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 +1084 -118
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +422 -22
- package/dist/index.d.ts +422 -22
- package/dist/index.js +988 -120
- 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-TZLX4KIT.js.map +0 -1
- /package/dist/{chunk-A2AJJOSJ.js.map → chunk-IXTW3BIO.js.map} +0 -0
- /package/dist/{chunk-XCZPGOVP.js.map → chunk-JYRHO63K.js.map} +0 -0
- /package/dist/{chunk-UCW3VWMN.js.map → chunk-NULSP7U4.js.map} +0 -0
- /package/dist/{chunk-WYI7YW54.js.map → chunk-VQWLA6XQ.js.map} +0 -0
- /package/dist/{chunk-YWTP2XRJ.js.map → chunk-X732W3QA.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -64,7 +64,6 @@ import {
|
|
|
64
64
|
fromSyslog,
|
|
65
65
|
fromWebSocket,
|
|
66
66
|
fromWebhook,
|
|
67
|
-
gate,
|
|
68
67
|
interval,
|
|
69
68
|
last,
|
|
70
69
|
linear,
|
|
@@ -126,6 +125,7 @@ import {
|
|
|
126
125
|
toWebSocket,
|
|
127
126
|
tokenBucket,
|
|
128
127
|
tokenTracker,
|
|
128
|
+
valve,
|
|
129
129
|
verifiable,
|
|
130
130
|
window,
|
|
131
131
|
windowCount,
|
|
@@ -137,14 +137,24 @@ import {
|
|
|
137
137
|
workerBridge,
|
|
138
138
|
workerSelf,
|
|
139
139
|
zip
|
|
140
|
-
} from "./chunk-
|
|
140
|
+
} from "./chunk-BRPCN2HJ.js";
|
|
141
141
|
import {
|
|
142
142
|
cqrs_exports,
|
|
143
143
|
nestjs_exports
|
|
144
|
-
} from "./chunk-
|
|
144
|
+
} from "./chunk-NULSP7U4.js";
|
|
145
145
|
import {
|
|
146
|
+
DEFAULT_DOWN,
|
|
147
|
+
bridge,
|
|
146
148
|
core_exports
|
|
147
|
-
} from "./chunk-
|
|
149
|
+
} from "./chunk-XWMTVV2D.js";
|
|
150
|
+
import {
|
|
151
|
+
JsonCodec,
|
|
152
|
+
createDagCborCodec,
|
|
153
|
+
createDagCborZstdCodec,
|
|
154
|
+
graph_exports,
|
|
155
|
+
negotiateCodec,
|
|
156
|
+
replayWAL
|
|
157
|
+
} from "./chunk-IXTW3BIO.js";
|
|
148
158
|
import {
|
|
149
159
|
cached,
|
|
150
160
|
createWatermarkController,
|
|
@@ -177,34 +187,27 @@ import {
|
|
|
177
187
|
toArray,
|
|
178
188
|
toMessages$,
|
|
179
189
|
toObservable
|
|
180
|
-
} from "./chunk-
|
|
190
|
+
} from "./chunk-X732W3QA.js";
|
|
181
191
|
import {
|
|
182
192
|
ResettableTimer
|
|
183
193
|
} from "./chunk-WZ2Z2CRV.js";
|
|
184
|
-
import {
|
|
185
|
-
JsonCodec,
|
|
186
|
-
createDagCborCodec,
|
|
187
|
-
createDagCborZstdCodec,
|
|
188
|
-
graph_exports,
|
|
189
|
-
negotiateCodec,
|
|
190
|
-
replayWAL
|
|
191
|
-
} from "./chunk-A2AJJOSJ.js";
|
|
192
194
|
import {
|
|
193
195
|
analyzeAndMeasure,
|
|
194
196
|
computeLineBreaks,
|
|
195
197
|
reactive_layout_exports
|
|
196
|
-
} from "./chunk-
|
|
198
|
+
} from "./chunk-JYRHO63K.js";
|
|
197
199
|
import {
|
|
198
200
|
GRAPH_META_SEGMENT,
|
|
199
201
|
Graph,
|
|
200
202
|
reachable
|
|
201
|
-
} from "./chunk-
|
|
203
|
+
} from "./chunk-VQWLA6XQ.js";
|
|
202
204
|
import {
|
|
203
205
|
describeNode,
|
|
204
206
|
metaSnapshot,
|
|
205
207
|
resolveDescribeFields
|
|
206
|
-
} from "./chunk-
|
|
208
|
+
} from "./chunk-6OLNYOGU.js";
|
|
207
209
|
import {
|
|
210
|
+
CLEANUP_RESULT,
|
|
208
211
|
COMPLETE,
|
|
209
212
|
DATA,
|
|
210
213
|
DEFAULT_ACTOR,
|
|
@@ -221,6 +224,7 @@ import {
|
|
|
221
224
|
accessHintForGuard,
|
|
222
225
|
advanceVersion,
|
|
223
226
|
batch,
|
|
227
|
+
cleanupResult,
|
|
224
228
|
createVersioning,
|
|
225
229
|
defaultHash,
|
|
226
230
|
derived,
|
|
@@ -245,7 +249,7 @@ import {
|
|
|
245
249
|
propagatesToMeta,
|
|
246
250
|
state,
|
|
247
251
|
wallClockNs
|
|
248
|
-
} from "./chunk-
|
|
252
|
+
} from "./chunk-4F2ZFD5L.js";
|
|
249
253
|
|
|
250
254
|
// src/compat/index.ts
|
|
251
255
|
var compat_exports = {};
|
|
@@ -1045,6 +1049,7 @@ __export(patterns_exports, {
|
|
|
1045
1049
|
ai: () => ai_exports,
|
|
1046
1050
|
cqrs: () => cqrs_exports,
|
|
1047
1051
|
demoShell: () => demo_shell_exports,
|
|
1052
|
+
domainTemplates: () => domain_templates_exports,
|
|
1048
1053
|
graphspec: () => graphspec_exports,
|
|
1049
1054
|
layout: () => reactive_layout_exports,
|
|
1050
1055
|
memory: () => memory_exports,
|
|
@@ -1070,6 +1075,7 @@ __export(ai_exports, {
|
|
|
1070
1075
|
knobsAsTools: () => knobsAsTools,
|
|
1071
1076
|
llmConsolidator: () => llmConsolidator,
|
|
1072
1077
|
llmExtractor: () => llmExtractor,
|
|
1078
|
+
promptNode: () => promptNode,
|
|
1073
1079
|
suggestStrategy: () => suggestStrategy,
|
|
1074
1080
|
systemPromptBuilder: () => systemPromptBuilder,
|
|
1075
1081
|
toolRegistry: () => toolRegistry,
|
|
@@ -1585,6 +1591,75 @@ function fromLLMStream(adapter, messages, opts) {
|
|
|
1585
1591
|
}
|
|
1586
1592
|
};
|
|
1587
1593
|
}
|
|
1594
|
+
function extractContent(resp) {
|
|
1595
|
+
if (resp != null && typeof resp === "object" && "content" in resp) {
|
|
1596
|
+
return String(resp.content);
|
|
1597
|
+
}
|
|
1598
|
+
if (typeof resp === "string") return resp;
|
|
1599
|
+
return String(resp);
|
|
1600
|
+
}
|
|
1601
|
+
function promptNode(adapter, deps, prompt, opts) {
|
|
1602
|
+
const format = opts?.format ?? "text";
|
|
1603
|
+
const retries = opts?.retries ?? 0;
|
|
1604
|
+
const useCache = opts?.cache ?? false;
|
|
1605
|
+
const cache2 = useCache ? /* @__PURE__ */ new Map() : null;
|
|
1606
|
+
const messagesNode = derived(
|
|
1607
|
+
deps,
|
|
1608
|
+
(values) => {
|
|
1609
|
+
const text = typeof prompt === "string" ? prompt : prompt(...values);
|
|
1610
|
+
const msgs = [];
|
|
1611
|
+
if (opts?.systemPrompt) msgs.push({ role: "system", content: opts.systemPrompt });
|
|
1612
|
+
msgs.push({ role: "user", content: text });
|
|
1613
|
+
return msgs;
|
|
1614
|
+
},
|
|
1615
|
+
{
|
|
1616
|
+
name: opts?.name ? `${opts.name}::messages` : "prompt_node::messages",
|
|
1617
|
+
meta: aiMeta("prompt_node")
|
|
1618
|
+
}
|
|
1619
|
+
);
|
|
1620
|
+
const result = switchMap(messagesNode, (msgs) => {
|
|
1621
|
+
if (!msgs || msgs.length === 0) {
|
|
1622
|
+
return state(null);
|
|
1623
|
+
}
|
|
1624
|
+
const cacheKey = useCache ? JSON.stringify(msgs.map((m) => [m.role, m.content])) : "";
|
|
1625
|
+
if (cache2?.has(cacheKey)) {
|
|
1626
|
+
return state(cache2.get(cacheKey));
|
|
1627
|
+
}
|
|
1628
|
+
async function attempt(remaining) {
|
|
1629
|
+
try {
|
|
1630
|
+
const resp = await new Promise((resolve, reject) => {
|
|
1631
|
+
const input = adapter.invoke(msgs, {
|
|
1632
|
+
model: opts?.model,
|
|
1633
|
+
temperature: opts?.temperature,
|
|
1634
|
+
maxTokens: opts?.maxTokens,
|
|
1635
|
+
systemPrompt: opts?.systemPrompt
|
|
1636
|
+
});
|
|
1637
|
+
if (input && typeof input.then === "function") {
|
|
1638
|
+
input.then(resolve, reject);
|
|
1639
|
+
} else if (input && typeof input.get === "function") {
|
|
1640
|
+
resolve(input.get());
|
|
1641
|
+
} else {
|
|
1642
|
+
resolve(input);
|
|
1643
|
+
}
|
|
1644
|
+
});
|
|
1645
|
+
const content = extractContent(resp);
|
|
1646
|
+
let parsed;
|
|
1647
|
+
if (format === "json") {
|
|
1648
|
+
parsed = JSON.parse(stripFences(content));
|
|
1649
|
+
} else {
|
|
1650
|
+
parsed = content;
|
|
1651
|
+
}
|
|
1652
|
+
cache2?.set(cacheKey, parsed);
|
|
1653
|
+
return parsed;
|
|
1654
|
+
} catch (err) {
|
|
1655
|
+
if (remaining > 0) return attempt(remaining - 1);
|
|
1656
|
+
throw err;
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
return attempt(retries);
|
|
1660
|
+
});
|
|
1661
|
+
return result;
|
|
1662
|
+
}
|
|
1588
1663
|
var ChatStreamGraph = class extends Graph {
|
|
1589
1664
|
_log;
|
|
1590
1665
|
_keepaliveSubs = [];
|
|
@@ -2458,7 +2533,7 @@ function gaugesAsContext(graph, actor, options) {
|
|
|
2458
2533
|
const ungrouped = [];
|
|
2459
2534
|
for (const entry of entries) {
|
|
2460
2535
|
const node2 = described.nodes[entry.path];
|
|
2461
|
-
const tags =
|
|
2536
|
+
const tags = node2.meta?.tags;
|
|
2462
2537
|
if (tags && tags.length > 0) {
|
|
2463
2538
|
const tag = tags[0];
|
|
2464
2539
|
let group = tagGroups.get(tag);
|
|
@@ -3025,15 +3100,13 @@ function demoShell(opts) {
|
|
|
3025
3100
|
};
|
|
3026
3101
|
}
|
|
3027
3102
|
|
|
3028
|
-
// src/patterns/
|
|
3029
|
-
var
|
|
3030
|
-
__export(
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
specDiff: () => specDiff,
|
|
3036
|
-
validateSpec: () => validateSpec
|
|
3103
|
+
// src/patterns/domain-templates.ts
|
|
3104
|
+
var domain_templates_exports = {};
|
|
3105
|
+
__export(domain_templates_exports, {
|
|
3106
|
+
contentModerationGraph: () => contentModerationGraph,
|
|
3107
|
+
dataQualityGraph: () => dataQualityGraph,
|
|
3108
|
+
issueTrackerGraph: () => issueTrackerGraph,
|
|
3109
|
+
observabilityGraph: () => observabilityGraph
|
|
3037
3110
|
});
|
|
3038
3111
|
|
|
3039
3112
|
// src/patterns/reduction.ts
|
|
@@ -3052,6 +3125,10 @@ function baseMeta(kind, meta) {
|
|
|
3052
3125
|
...meta ?? {}
|
|
3053
3126
|
};
|
|
3054
3127
|
}
|
|
3128
|
+
function keepalive2(n) {
|
|
3129
|
+
return n.subscribe(() => {
|
|
3130
|
+
});
|
|
3131
|
+
}
|
|
3055
3132
|
function stratify(name, source, rules, opts) {
|
|
3056
3133
|
const g = new Graph(name, opts);
|
|
3057
3134
|
g.add("source", source);
|
|
@@ -3066,18 +3143,27 @@ function stratify(name, source, rules, opts) {
|
|
|
3066
3143
|
}
|
|
3067
3144
|
function _addBranch(graph, source, rulesNode, rule) {
|
|
3068
3145
|
const branchName = `branch/${rule.name}`;
|
|
3146
|
+
const _noValue = /* @__PURE__ */ Symbol("noValue");
|
|
3147
|
+
let sourceDirty = false;
|
|
3148
|
+
let rulesDirty = false;
|
|
3149
|
+
let sourcePhase2 = false;
|
|
3150
|
+
let sourceValue = _noValue;
|
|
3069
3151
|
let pendingDirty = false;
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
if (t === DATA) {
|
|
3077
|
-
const value = msg[1];
|
|
3152
|
+
function resolve(actions) {
|
|
3153
|
+
if (sourcePhase2) {
|
|
3154
|
+
sourcePhase2 = false;
|
|
3155
|
+
const value = sourceValue;
|
|
3156
|
+
sourceValue = _noValue;
|
|
3157
|
+
if (value !== _noValue) {
|
|
3078
3158
|
const currentRules = rulesNode.get();
|
|
3079
3159
|
const currentRule = currentRules.find((r) => r.name === rule.name);
|
|
3080
|
-
|
|
3160
|
+
let matches = false;
|
|
3161
|
+
try {
|
|
3162
|
+
matches = currentRule?.classify(value) ?? false;
|
|
3163
|
+
} catch {
|
|
3164
|
+
matches = false;
|
|
3165
|
+
}
|
|
3166
|
+
if (matches) {
|
|
3081
3167
|
pendingDirty = false;
|
|
3082
3168
|
actions.emit(value);
|
|
3083
3169
|
} else {
|
|
@@ -3086,28 +3172,57 @@ function _addBranch(graph, source, rulesNode, rule) {
|
|
|
3086
3172
|
actions.down([[DIRTY], [RESOLVED]]);
|
|
3087
3173
|
}
|
|
3088
3174
|
}
|
|
3089
|
-
|
|
3090
|
-
}
|
|
3091
|
-
if (t === DIRTY) {
|
|
3092
|
-
pendingDirty = true;
|
|
3093
|
-
return true;
|
|
3094
|
-
}
|
|
3095
|
-
if (t === RESOLVED) {
|
|
3175
|
+
} else {
|
|
3096
3176
|
if (pendingDirty) {
|
|
3097
3177
|
pendingDirty = false;
|
|
3098
3178
|
actions.down([[DIRTY], [RESOLVED]]);
|
|
3099
3179
|
} else {
|
|
3100
3180
|
actions.down([[RESOLVED]]);
|
|
3101
3181
|
}
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
}
|
|
3185
|
+
const filterNode = node([source, rulesNode], () => void 0, {
|
|
3186
|
+
describeKind: "operator",
|
|
3187
|
+
meta: baseMeta("stratify_branch", { branch: rule.name }),
|
|
3188
|
+
onMessage(msg, depIndex, actions) {
|
|
3189
|
+
const t = msg[0];
|
|
3190
|
+
if (t === DIRTY) {
|
|
3191
|
+
if (depIndex === 0) {
|
|
3192
|
+
sourceDirty = true;
|
|
3193
|
+
pendingDirty = true;
|
|
3194
|
+
} else {
|
|
3195
|
+
rulesDirty = true;
|
|
3196
|
+
}
|
|
3102
3197
|
return true;
|
|
3103
3198
|
}
|
|
3104
|
-
if (t ===
|
|
3199
|
+
if (t === DATA || t === RESOLVED) {
|
|
3200
|
+
if (depIndex === 0) {
|
|
3201
|
+
sourceDirty = false;
|
|
3202
|
+
sourcePhase2 = true;
|
|
3203
|
+
sourceValue = t === DATA ? msg[1] : _noValue;
|
|
3204
|
+
} else {
|
|
3205
|
+
rulesDirty = false;
|
|
3206
|
+
}
|
|
3207
|
+
if (sourceDirty || rulesDirty) return true;
|
|
3208
|
+
resolve(actions);
|
|
3209
|
+
return true;
|
|
3210
|
+
}
|
|
3211
|
+
if (t === COMPLETE || t === ERROR || t === TEARDOWN) {
|
|
3212
|
+
sourceDirty = false;
|
|
3213
|
+
rulesDirty = false;
|
|
3214
|
+
sourcePhase2 = false;
|
|
3215
|
+
sourceValue = _noValue;
|
|
3105
3216
|
pendingDirty = false;
|
|
3106
|
-
|
|
3217
|
+
if (depIndex === 0) {
|
|
3218
|
+
actions.down([msg]);
|
|
3219
|
+
}
|
|
3107
3220
|
return true;
|
|
3108
3221
|
}
|
|
3222
|
+
if (depIndex === 1) return true;
|
|
3109
3223
|
return false;
|
|
3110
|
-
}
|
|
3224
|
+
},
|
|
3225
|
+
completeWhenDepsComplete: false
|
|
3111
3226
|
});
|
|
3112
3227
|
graph.add(branchName, filterNode);
|
|
3113
3228
|
graph.connect("source", branchName);
|
|
@@ -3143,20 +3258,14 @@ function funnel(name, sources, stages, opts) {
|
|
|
3143
3258
|
const prevNode = g.resolve(prevOutputPath);
|
|
3144
3259
|
const stageInputPath = `${stage.name}::input`;
|
|
3145
3260
|
const stageInput = g.resolve(stageInputPath);
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
stageInput.down([[DATA, msg[1]]]);
|
|
3151
|
-
} else if (t === DIRTY) {
|
|
3152
|
-
stageInput.down([[DIRTY]]);
|
|
3153
|
-
} else if (t === RESOLVED) {
|
|
3154
|
-
stageInput.down([[RESOLVED]]);
|
|
3155
|
-
} else if (t === COMPLETE || t === ERROR) {
|
|
3156
|
-
stageInput.down([msg]);
|
|
3157
|
-
}
|
|
3158
|
-
}
|
|
3261
|
+
const bridgeName = `__bridge_${prevOutputPath}\u2192${stage.name}_input`;
|
|
3262
|
+
const br = bridge(prevNode, stageInput, {
|
|
3263
|
+
name: bridgeName,
|
|
3264
|
+
down: DEFAULT_DOWN.filter((t) => t !== TEARDOWN)
|
|
3159
3265
|
});
|
|
3266
|
+
g.add(bridgeName, br);
|
|
3267
|
+
g.connect(prevOutputPath, bridgeName);
|
|
3268
|
+
keepalive2(br);
|
|
3160
3269
|
prevOutputPath = `${stage.name}::output`;
|
|
3161
3270
|
}
|
|
3162
3271
|
return g;
|
|
@@ -3174,38 +3283,41 @@ function feedback(graph, condition, reentry, opts) {
|
|
|
3174
3283
|
graph.add(counterName, counter);
|
|
3175
3284
|
const condNode = graph.resolve(condition);
|
|
3176
3285
|
const reentryNode = graph.resolve(reentry);
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3286
|
+
const feedbackEffectName = `__feedback_effect_${condition}`;
|
|
3287
|
+
const feedbackEffect = node([condNode], void 0, {
|
|
3288
|
+
name: feedbackEffectName,
|
|
3289
|
+
describeKind: "effect",
|
|
3290
|
+
meta: {
|
|
3291
|
+
...baseMeta("feedback_effect", {
|
|
3292
|
+
feedbackFrom: condition,
|
|
3293
|
+
feedbackTo: reentry
|
|
3294
|
+
}),
|
|
3295
|
+
_internal: true
|
|
3296
|
+
},
|
|
3297
|
+
onMessage(msg, _depIndex, _actions) {
|
|
3298
|
+
const t = msg[0];
|
|
3299
|
+
if (t === DATA) {
|
|
3188
3300
|
const currentCount = counter.get();
|
|
3189
|
-
if (currentCount >= maxIter)
|
|
3301
|
+
if (currentCount >= maxIter) return true;
|
|
3190
3302
|
const condValue = msg[1];
|
|
3191
|
-
if (condValue == null)
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
safeUnsub();
|
|
3303
|
+
if (condValue == null) return true;
|
|
3304
|
+
batch(() => {
|
|
3305
|
+
counter.down([[DATA, currentCount + 1]]);
|
|
3306
|
+
reentryNode.down([[DATA, condValue]]);
|
|
3307
|
+
});
|
|
3308
|
+
return true;
|
|
3198
3309
|
}
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
if (msg[0] === COMPLETE || msg[0] === ERROR) {
|
|
3204
|
-
safeUnsub();
|
|
3205
|
-
return;
|
|
3310
|
+
if (t === COMPLETE || t === ERROR) {
|
|
3311
|
+
const terminal = t === ERROR && msg.length > 1 ? [ERROR, msg[1]] : [t];
|
|
3312
|
+
counter.down([terminal]);
|
|
3313
|
+
return true;
|
|
3206
3314
|
}
|
|
3315
|
+
return false;
|
|
3207
3316
|
}
|
|
3208
3317
|
});
|
|
3318
|
+
graph.add(feedbackEffectName, feedbackEffect);
|
|
3319
|
+
graph.connect(condition, feedbackEffectName);
|
|
3320
|
+
keepalive2(feedbackEffect);
|
|
3209
3321
|
return graph;
|
|
3210
3322
|
}
|
|
3211
3323
|
function budgetGate(source, constraints, opts) {
|
|
@@ -3221,7 +3333,8 @@ function budgetGate(source, constraints, opts) {
|
|
|
3221
3333
|
}
|
|
3222
3334
|
function flushBuffer(actions) {
|
|
3223
3335
|
while (buffer2.length > 0 && checkBudget()) {
|
|
3224
|
-
const item = buffer2
|
|
3336
|
+
const item = buffer2[0];
|
|
3337
|
+
buffer2 = buffer2.slice(1);
|
|
3225
3338
|
actions.emit(item);
|
|
3226
3339
|
}
|
|
3227
3340
|
if (buffer2.length === 0 && pendingResolved) {
|
|
@@ -3339,7 +3452,600 @@ function scorer(sources, weights, opts) {
|
|
|
3339
3452
|
);
|
|
3340
3453
|
}
|
|
3341
3454
|
|
|
3455
|
+
// src/patterns/domain-templates.ts
|
|
3456
|
+
function keepalive3(n) {
|
|
3457
|
+
return n.subscribe(() => {
|
|
3458
|
+
});
|
|
3459
|
+
}
|
|
3460
|
+
function baseMeta2(kind, extra) {
|
|
3461
|
+
return { domain_template: true, template_type: kind, ...extra ?? {} };
|
|
3462
|
+
}
|
|
3463
|
+
function observabilityGraph(name, opts) {
|
|
3464
|
+
const g = new Graph(name, opts);
|
|
3465
|
+
g.add("source", opts.source);
|
|
3466
|
+
const defaultBranches = [
|
|
3467
|
+
{ name: "errors", classify: (v) => isTagged(v, "error") },
|
|
3468
|
+
{ name: "traces", classify: (v) => isTagged(v, "trace") },
|
|
3469
|
+
{ name: "metrics", classify: (v) => isTagged(v, "metric") }
|
|
3470
|
+
];
|
|
3471
|
+
const branches = opts.branches ?? defaultBranches;
|
|
3472
|
+
const rules = branches.map((b) => ({
|
|
3473
|
+
name: b.name,
|
|
3474
|
+
classify: b.classify
|
|
3475
|
+
}));
|
|
3476
|
+
const strat = stratify("stratify", opts.source, rules);
|
|
3477
|
+
g.mount("stratify", strat);
|
|
3478
|
+
const branchNodes = branches.map((b) => {
|
|
3479
|
+
try {
|
|
3480
|
+
return g.resolve(`stratify::branch/${b.name}`);
|
|
3481
|
+
} catch {
|
|
3482
|
+
return state(null);
|
|
3483
|
+
}
|
|
3484
|
+
});
|
|
3485
|
+
const correlateFn = opts.correlate ?? ((vals) => vals);
|
|
3486
|
+
const correlateNode = derived(
|
|
3487
|
+
branchNodes,
|
|
3488
|
+
(vals) => correlateFn(vals),
|
|
3489
|
+
{
|
|
3490
|
+
meta: baseMeta2("observability", { stage: "correlate" })
|
|
3491
|
+
}
|
|
3492
|
+
);
|
|
3493
|
+
g.add("correlate", correlateNode);
|
|
3494
|
+
for (const b of branches) {
|
|
3495
|
+
try {
|
|
3496
|
+
g.connect(`stratify::branch/${b.name}`, "correlate");
|
|
3497
|
+
} catch {
|
|
3498
|
+
}
|
|
3499
|
+
}
|
|
3500
|
+
const sloCheckFn = opts.sloCheck ?? (() => ({ pass: true }));
|
|
3501
|
+
const sloValue = derived([correlateNode], (vals) => vals[0], {
|
|
3502
|
+
meta: baseMeta2("observability", { stage: "slo_value" })
|
|
3503
|
+
});
|
|
3504
|
+
const sloVerified = derived([sloValue], (vals) => sloCheckFn(vals[0]), {
|
|
3505
|
+
meta: baseMeta2("observability", { stage: "slo_verified" })
|
|
3506
|
+
});
|
|
3507
|
+
g.add("slo_value", sloValue);
|
|
3508
|
+
g.add("slo_verified", sloVerified);
|
|
3509
|
+
g.connect("correlate", "slo_value");
|
|
3510
|
+
g.connect("slo_value", "slo_verified");
|
|
3511
|
+
const weightValues = opts.weights ?? branches.map(() => 1);
|
|
3512
|
+
const signalNodes = branchNodes.map(
|
|
3513
|
+
(bn) => derived([bn], (vals) => vals[0] != null ? 1 : 0)
|
|
3514
|
+
);
|
|
3515
|
+
const weightNodes = weightValues.map((w) => state(w));
|
|
3516
|
+
for (let i = 0; i < signalNodes.length; i++) {
|
|
3517
|
+
g.add(`__signal_${i}`, signalNodes[i]);
|
|
3518
|
+
g.add(`__weight_${i}`, weightNodes[i]);
|
|
3519
|
+
}
|
|
3520
|
+
const alerts = scorer(
|
|
3521
|
+
signalNodes,
|
|
3522
|
+
weightNodes
|
|
3523
|
+
);
|
|
3524
|
+
g.add("alerts", alerts);
|
|
3525
|
+
const output = derived(
|
|
3526
|
+
[alerts, sloVerified],
|
|
3527
|
+
(vals) => ({
|
|
3528
|
+
scored: vals[0],
|
|
3529
|
+
slo: vals[1]
|
|
3530
|
+
}),
|
|
3531
|
+
{
|
|
3532
|
+
meta: baseMeta2("observability", { stage: "output" })
|
|
3533
|
+
}
|
|
3534
|
+
);
|
|
3535
|
+
g.add("output", output);
|
|
3536
|
+
g.connect("alerts", "output");
|
|
3537
|
+
g.connect("slo_verified", "output");
|
|
3538
|
+
const fbReentry = state(null, {
|
|
3539
|
+
meta: baseMeta2("observability", { stage: "feedback_reentry" })
|
|
3540
|
+
});
|
|
3541
|
+
g.add("feedback_reentry", fbReentry);
|
|
3542
|
+
const fbCondition = derived(
|
|
3543
|
+
[sloVerified],
|
|
3544
|
+
(vals) => {
|
|
3545
|
+
const result = vals[0];
|
|
3546
|
+
if (result && result.pass === false) return result;
|
|
3547
|
+
return null;
|
|
3548
|
+
},
|
|
3549
|
+
{
|
|
3550
|
+
meta: baseMeta2("observability", { stage: "feedback_condition" })
|
|
3551
|
+
}
|
|
3552
|
+
);
|
|
3553
|
+
g.add("feedback_condition", fbCondition);
|
|
3554
|
+
g.connect("slo_verified", "feedback_condition");
|
|
3555
|
+
feedback(g, "feedback_condition", "feedback_reentry", {
|
|
3556
|
+
maxIterations: opts.maxFeedbackIterations ?? 5
|
|
3557
|
+
});
|
|
3558
|
+
return g;
|
|
3559
|
+
}
|
|
3560
|
+
function issueTrackerGraph(name, opts) {
|
|
3561
|
+
const g = new Graph(name, opts);
|
|
3562
|
+
g.add("source", opts.source);
|
|
3563
|
+
let _issueCounter = 0;
|
|
3564
|
+
const defaultExtract = (raw) => ({
|
|
3565
|
+
id: `issue-${++_issueCounter}`,
|
|
3566
|
+
title: String(raw),
|
|
3567
|
+
severity: 1,
|
|
3568
|
+
source: "unknown",
|
|
3569
|
+
raw
|
|
3570
|
+
});
|
|
3571
|
+
const extractFn = opts.extract ?? defaultExtract;
|
|
3572
|
+
const extractNode = derived([opts.source], (vals) => extractFn(vals[0]), {
|
|
3573
|
+
meta: baseMeta2("issue_tracker", { stage: "extract" })
|
|
3574
|
+
});
|
|
3575
|
+
g.add("extract", extractNode);
|
|
3576
|
+
g.connect("source", "extract");
|
|
3577
|
+
const verifyFn = opts.verify ?? (() => ({ valid: true }));
|
|
3578
|
+
const verifyNode = derived(
|
|
3579
|
+
[extractNode],
|
|
3580
|
+
(vals) => {
|
|
3581
|
+
const issue = vals[0];
|
|
3582
|
+
return { issue, verification: verifyFn(issue) };
|
|
3583
|
+
},
|
|
3584
|
+
{
|
|
3585
|
+
meta: baseMeta2("issue_tracker", { stage: "verify" })
|
|
3586
|
+
}
|
|
3587
|
+
);
|
|
3588
|
+
g.add("verify", verifyNode);
|
|
3589
|
+
g.connect("extract", "verify");
|
|
3590
|
+
const knownPatterns = state([], {
|
|
3591
|
+
meta: baseMeta2("issue_tracker", { stage: "known_patterns" })
|
|
3592
|
+
});
|
|
3593
|
+
g.add("known_patterns", knownPatterns);
|
|
3594
|
+
const detectFn = opts.detectRegression ?? (() => ({ regression: false }));
|
|
3595
|
+
const regressionNode = derived(
|
|
3596
|
+
[extractNode, knownPatterns],
|
|
3597
|
+
(vals) => {
|
|
3598
|
+
const issue = vals[0];
|
|
3599
|
+
const known = vals[1];
|
|
3600
|
+
return { issue, regression: detectFn(issue, known) };
|
|
3601
|
+
},
|
|
3602
|
+
{ meta: baseMeta2("issue_tracker", { stage: "regression" }) }
|
|
3603
|
+
);
|
|
3604
|
+
g.add("regression", regressionNode);
|
|
3605
|
+
g.connect("extract", "regression");
|
|
3606
|
+
g.connect("known_patterns", "regression");
|
|
3607
|
+
const severitySignal = derived([extractNode], (vals) => {
|
|
3608
|
+
const issue = vals[0];
|
|
3609
|
+
return issue?.severity ?? 0;
|
|
3610
|
+
});
|
|
3611
|
+
const regressionSignal = derived([regressionNode], (vals) => {
|
|
3612
|
+
const r = vals[0];
|
|
3613
|
+
return r?.regression ? 2 : 0;
|
|
3614
|
+
});
|
|
3615
|
+
g.add("__severity_signal", severitySignal);
|
|
3616
|
+
g.add("__regression_signal", regressionSignal);
|
|
3617
|
+
const severityWeight = state(1);
|
|
3618
|
+
const regressionWeight = state(1.5);
|
|
3619
|
+
g.add("__severity_weight", severityWeight);
|
|
3620
|
+
g.add("__regression_weight", regressionWeight);
|
|
3621
|
+
const priority = scorer([severitySignal, regressionSignal], [severityWeight, regressionWeight]);
|
|
3622
|
+
g.add("priority", priority);
|
|
3623
|
+
const output = derived(
|
|
3624
|
+
[verifyNode, regressionNode, priority],
|
|
3625
|
+
(vals) => ({
|
|
3626
|
+
verified: vals[0],
|
|
3627
|
+
regression: vals[1],
|
|
3628
|
+
priority: vals[2]
|
|
3629
|
+
}),
|
|
3630
|
+
{ meta: baseMeta2("issue_tracker", { stage: "output" }) }
|
|
3631
|
+
);
|
|
3632
|
+
g.add("output", output);
|
|
3633
|
+
g.connect("verify", "output");
|
|
3634
|
+
g.connect("regression", "output");
|
|
3635
|
+
g.connect("priority", "output");
|
|
3636
|
+
const fbReentry = state(null, {
|
|
3637
|
+
meta: baseMeta2("issue_tracker", { stage: "feedback_reentry" })
|
|
3638
|
+
});
|
|
3639
|
+
g.add("feedback_reentry", fbReentry);
|
|
3640
|
+
const fbCondition = derived(
|
|
3641
|
+
[verifyNode],
|
|
3642
|
+
(vals) => {
|
|
3643
|
+
const result = vals[0];
|
|
3644
|
+
if (result) {
|
|
3645
|
+
const v = result.verification;
|
|
3646
|
+
if (v && v.valid === false) return result;
|
|
3647
|
+
}
|
|
3648
|
+
return null;
|
|
3649
|
+
},
|
|
3650
|
+
{
|
|
3651
|
+
meta: baseMeta2("issue_tracker", { stage: "feedback_condition" })
|
|
3652
|
+
}
|
|
3653
|
+
);
|
|
3654
|
+
g.add("feedback_condition", fbCondition);
|
|
3655
|
+
g.connect("verify", "feedback_condition");
|
|
3656
|
+
feedback(g, "feedback_condition", "feedback_reentry", {
|
|
3657
|
+
maxIterations: opts.maxFeedbackIterations ?? 3
|
|
3658
|
+
});
|
|
3659
|
+
return g;
|
|
3660
|
+
}
|
|
3661
|
+
function contentModerationGraph(name, opts) {
|
|
3662
|
+
const g = new Graph(name, opts);
|
|
3663
|
+
g.add("source", opts.source);
|
|
3664
|
+
const defaultClassify = (content) => ({
|
|
3665
|
+
label: "review",
|
|
3666
|
+
confidence: 0.5,
|
|
3667
|
+
original: content
|
|
3668
|
+
});
|
|
3669
|
+
const classifyFn = opts.classify ?? defaultClassify;
|
|
3670
|
+
const classifyNode = derived([opts.source], (vals) => classifyFn(vals[0]), {
|
|
3671
|
+
meta: baseMeta2("content_moderation", { stage: "classify" })
|
|
3672
|
+
});
|
|
3673
|
+
g.add("classify", classifyNode);
|
|
3674
|
+
g.connect("source", "classify");
|
|
3675
|
+
const strat = stratify("stratify", classifyNode, [
|
|
3676
|
+
{ name: "safe", classify: (v) => v.label === "safe" },
|
|
3677
|
+
{ name: "review", classify: (v) => v.label === "review" },
|
|
3678
|
+
{ name: "block", classify: (v) => v.label === "block" }
|
|
3679
|
+
]);
|
|
3680
|
+
g.mount("stratify", strat);
|
|
3681
|
+
const reviewLog = reactiveLog([], {
|
|
3682
|
+
name: "review_queue",
|
|
3683
|
+
maxSize: opts.maxQueueSize
|
|
3684
|
+
});
|
|
3685
|
+
g.add("review_queue", reviewLog.entries);
|
|
3686
|
+
let reviewBranch;
|
|
3687
|
+
try {
|
|
3688
|
+
reviewBranch = g.resolve("stratify::branch/review");
|
|
3689
|
+
} catch {
|
|
3690
|
+
reviewBranch = state(null);
|
|
3691
|
+
g.add("__review_fallback", reviewBranch);
|
|
3692
|
+
}
|
|
3693
|
+
const reviewAccumulator = effect([reviewBranch], (vals) => {
|
|
3694
|
+
const item = vals[0];
|
|
3695
|
+
if (item) {
|
|
3696
|
+
reviewLog.append(item);
|
|
3697
|
+
}
|
|
3698
|
+
});
|
|
3699
|
+
g.add("__review_accumulator", reviewAccumulator);
|
|
3700
|
+
keepalive3(reviewAccumulator);
|
|
3701
|
+
try {
|
|
3702
|
+
g.connect("stratify::branch/review", "__review_accumulator");
|
|
3703
|
+
} catch {
|
|
3704
|
+
}
|
|
3705
|
+
const policy2 = state(
|
|
3706
|
+
{},
|
|
3707
|
+
{
|
|
3708
|
+
meta: baseMeta2("content_moderation", {
|
|
3709
|
+
stage: "policy",
|
|
3710
|
+
access: "both",
|
|
3711
|
+
description: "Moderation policy rules \u2014 updated via feedback"
|
|
3712
|
+
})
|
|
3713
|
+
}
|
|
3714
|
+
);
|
|
3715
|
+
g.add("policy", policy2);
|
|
3716
|
+
const weights = opts.weights ?? [0.1, 1, 2];
|
|
3717
|
+
const confidenceSignal = derived([classifyNode], (vals) => {
|
|
3718
|
+
const r = vals[0];
|
|
3719
|
+
return r?.confidence ?? 0;
|
|
3720
|
+
});
|
|
3721
|
+
const severitySignal = derived([classifyNode], (vals) => {
|
|
3722
|
+
const r = vals[0];
|
|
3723
|
+
if (!r) return 0;
|
|
3724
|
+
return r.label === "block" ? weights[2] : r.label === "review" ? weights[1] : weights[0];
|
|
3725
|
+
});
|
|
3726
|
+
g.add("__confidence_signal", confidenceSignal);
|
|
3727
|
+
g.add("__severity_signal", severitySignal);
|
|
3728
|
+
const wConfidence = state(1);
|
|
3729
|
+
const wSeverity = state(1);
|
|
3730
|
+
g.add("__w_confidence", wConfidence);
|
|
3731
|
+
g.add("__w_severity", wSeverity);
|
|
3732
|
+
const priority = scorer([confidenceSignal, severitySignal], [wConfidence, wSeverity]);
|
|
3733
|
+
g.add("priority", priority);
|
|
3734
|
+
const output = derived(
|
|
3735
|
+
[classifyNode, priority],
|
|
3736
|
+
(vals) => ({
|
|
3737
|
+
classification: vals[0],
|
|
3738
|
+
priority: vals[1]
|
|
3739
|
+
}),
|
|
3740
|
+
{ meta: baseMeta2("content_moderation", { stage: "output" }) }
|
|
3741
|
+
);
|
|
3742
|
+
g.add("output", output);
|
|
3743
|
+
g.connect("classify", "output");
|
|
3744
|
+
g.connect("priority", "output");
|
|
3745
|
+
const fbCondition = derived(
|
|
3746
|
+
[reviewLog.entries, policy2],
|
|
3747
|
+
(vals) => {
|
|
3748
|
+
const snap = vals[0];
|
|
3749
|
+
const entries = snap?.value?.entries;
|
|
3750
|
+
if (entries && entries.length > 0) {
|
|
3751
|
+
const latest = entries[entries.length - 1];
|
|
3752
|
+
if (latest && latest.falsePositive) {
|
|
3753
|
+
return latest;
|
|
3754
|
+
}
|
|
3755
|
+
}
|
|
3756
|
+
return null;
|
|
3757
|
+
},
|
|
3758
|
+
{
|
|
3759
|
+
meta: baseMeta2("content_moderation", { stage: "feedback_condition" })
|
|
3760
|
+
}
|
|
3761
|
+
);
|
|
3762
|
+
g.add("feedback_condition", fbCondition);
|
|
3763
|
+
feedback(g, "feedback_condition", "policy", {
|
|
3764
|
+
maxIterations: opts.maxFeedbackIterations ?? 5
|
|
3765
|
+
});
|
|
3766
|
+
return g;
|
|
3767
|
+
}
|
|
3768
|
+
function dataQualityGraph(name, opts) {
|
|
3769
|
+
const g = new Graph(name, opts);
|
|
3770
|
+
g.add("source", opts.source);
|
|
3771
|
+
const validateFn = opts.validate ?? ((record) => ({
|
|
3772
|
+
valid: true,
|
|
3773
|
+
errors: [],
|
|
3774
|
+
record
|
|
3775
|
+
}));
|
|
3776
|
+
const validateNode = derived(
|
|
3777
|
+
[opts.source],
|
|
3778
|
+
(vals) => vals[0] != null ? validateFn(vals[0]) : void 0,
|
|
3779
|
+
{ meta: baseMeta2("data_quality", { stage: "validate" }) }
|
|
3780
|
+
);
|
|
3781
|
+
g.add("validate", validateNode);
|
|
3782
|
+
g.connect("source", "validate");
|
|
3783
|
+
const detectAnomalyFn = opts.detectAnomaly ?? ((record) => ({
|
|
3784
|
+
anomaly: false,
|
|
3785
|
+
score: 0,
|
|
3786
|
+
record
|
|
3787
|
+
}));
|
|
3788
|
+
const anomalyNode = derived(
|
|
3789
|
+
[opts.source],
|
|
3790
|
+
(vals) => vals[0] != null ? detectAnomalyFn(vals[0]) : void 0,
|
|
3791
|
+
{ meta: baseMeta2("data_quality", { stage: "anomaly" }) }
|
|
3792
|
+
);
|
|
3793
|
+
g.add("anomaly", anomalyNode);
|
|
3794
|
+
g.connect("source", "anomaly");
|
|
3795
|
+
const baseline = state(null, {
|
|
3796
|
+
meta: baseMeta2("data_quality", {
|
|
3797
|
+
stage: "baseline",
|
|
3798
|
+
description: "Rolling baseline for drift detection"
|
|
3799
|
+
})
|
|
3800
|
+
});
|
|
3801
|
+
g.add("baseline", baseline);
|
|
3802
|
+
const baselineUpdater = effect([validateNode], (vals) => {
|
|
3803
|
+
const result = vals[0];
|
|
3804
|
+
if (result?.valid) {
|
|
3805
|
+
batch(() => {
|
|
3806
|
+
baseline.down([[DATA, result.record]]);
|
|
3807
|
+
});
|
|
3808
|
+
}
|
|
3809
|
+
});
|
|
3810
|
+
g.add("__baseline_updater", baselineUpdater);
|
|
3811
|
+
g.connect("validate", "__baseline_updater");
|
|
3812
|
+
keepalive3(baselineUpdater);
|
|
3813
|
+
const detectDriftFn = opts.detectDrift ?? (() => ({ drift: false }));
|
|
3814
|
+
const driftNode = derived(
|
|
3815
|
+
[opts.source, baseline],
|
|
3816
|
+
(vals) => detectDriftFn(vals[0], vals[1]),
|
|
3817
|
+
{ meta: baseMeta2("data_quality", { stage: "drift" }) }
|
|
3818
|
+
);
|
|
3819
|
+
g.add("drift", driftNode);
|
|
3820
|
+
g.connect("source", "drift");
|
|
3821
|
+
g.connect("baseline", "drift");
|
|
3822
|
+
const suggestFn = opts.suggest ?? (() => null);
|
|
3823
|
+
const remediateNode = derived(
|
|
3824
|
+
[validateNode, anomalyNode],
|
|
3825
|
+
(vals) => suggestFn({
|
|
3826
|
+
validation: vals[0],
|
|
3827
|
+
anomaly: vals[1]
|
|
3828
|
+
}),
|
|
3829
|
+
{ meta: baseMeta2("data_quality", { stage: "remediate" }) }
|
|
3830
|
+
);
|
|
3831
|
+
g.add("remediate", remediateNode);
|
|
3832
|
+
g.connect("validate", "remediate");
|
|
3833
|
+
g.connect("anomaly", "remediate");
|
|
3834
|
+
const output = derived(
|
|
3835
|
+
[validateNode, anomalyNode, driftNode, remediateNode],
|
|
3836
|
+
(vals) => ({
|
|
3837
|
+
validation: vals[0],
|
|
3838
|
+
anomaly: vals[1],
|
|
3839
|
+
drift: vals[2],
|
|
3840
|
+
remediation: vals[3]
|
|
3841
|
+
}),
|
|
3842
|
+
{ meta: baseMeta2("data_quality", { stage: "output" }) }
|
|
3843
|
+
);
|
|
3844
|
+
g.add("output", output);
|
|
3845
|
+
g.connect("validate", "output");
|
|
3846
|
+
g.connect("anomaly", "output");
|
|
3847
|
+
g.connect("drift", "output");
|
|
3848
|
+
g.connect("remediate", "output");
|
|
3849
|
+
const validationRules = state([], {
|
|
3850
|
+
meta: baseMeta2("data_quality", { stage: "validation_rules" })
|
|
3851
|
+
});
|
|
3852
|
+
g.add("validation_rules", validationRules);
|
|
3853
|
+
const fbCondition = derived(
|
|
3854
|
+
[anomalyNode],
|
|
3855
|
+
(vals) => {
|
|
3856
|
+
const a = vals[0];
|
|
3857
|
+
if (a?.anomaly) return a;
|
|
3858
|
+
return null;
|
|
3859
|
+
},
|
|
3860
|
+
{
|
|
3861
|
+
meta: baseMeta2("data_quality", { stage: "feedback_condition" })
|
|
3862
|
+
}
|
|
3863
|
+
);
|
|
3864
|
+
g.add("feedback_condition", fbCondition);
|
|
3865
|
+
g.connect("anomaly", "feedback_condition");
|
|
3866
|
+
feedback(g, "feedback_condition", "validation_rules", {
|
|
3867
|
+
maxIterations: opts.maxFeedbackIterations ?? 3
|
|
3868
|
+
});
|
|
3869
|
+
return g;
|
|
3870
|
+
}
|
|
3871
|
+
function isTagged(value, tag) {
|
|
3872
|
+
if (value == null || typeof value !== "object") return false;
|
|
3873
|
+
const v = value;
|
|
3874
|
+
return v.type === tag || v.kind === tag;
|
|
3875
|
+
}
|
|
3876
|
+
|
|
3342
3877
|
// src/patterns/graphspec.ts
|
|
3878
|
+
var graphspec_exports = {};
|
|
3879
|
+
__export(graphspec_exports, {
|
|
3880
|
+
compileSpec: () => compileSpec,
|
|
3881
|
+
decompileGraph: () => decompileGraph,
|
|
3882
|
+
extractFnFactory: () => extractFnFactory,
|
|
3883
|
+
extractSourceFactory: () => extractSourceFactory,
|
|
3884
|
+
generateCatalogPrompt: () => generateCatalogPrompt,
|
|
3885
|
+
isRichFnEntry: () => isRichFnEntry,
|
|
3886
|
+
isRichSourceEntry: () => isRichSourceEntry,
|
|
3887
|
+
llmCompose: () => llmCompose,
|
|
3888
|
+
llmRefine: () => llmRefine,
|
|
3889
|
+
specDiff: () => specDiff,
|
|
3890
|
+
validateSpec: () => validateSpec,
|
|
3891
|
+
validateSpecAgainstCatalog: () => validateSpecAgainstCatalog
|
|
3892
|
+
});
|
|
3893
|
+
function isRichFnEntry(entry) {
|
|
3894
|
+
return typeof entry === "object" && entry !== null && "factory" in entry;
|
|
3895
|
+
}
|
|
3896
|
+
function isRichSourceEntry(entry) {
|
|
3897
|
+
return typeof entry === "object" && entry !== null && "factory" in entry;
|
|
3898
|
+
}
|
|
3899
|
+
function extractFnFactory(entry) {
|
|
3900
|
+
return isRichFnEntry(entry) ? entry.factory : entry;
|
|
3901
|
+
}
|
|
3902
|
+
function extractSourceFactory(entry) {
|
|
3903
|
+
return isRichSourceEntry(entry) ? entry.factory : entry;
|
|
3904
|
+
}
|
|
3905
|
+
function generateCatalogPrompt(catalog) {
|
|
3906
|
+
const sections = [];
|
|
3907
|
+
if (catalog.fns) {
|
|
3908
|
+
const groups = /* @__PURE__ */ new Map();
|
|
3909
|
+
for (const [name, entry] of Object.entries(catalog.fns)) {
|
|
3910
|
+
const tag = isRichFnEntry(entry) ? entry.tags?.[0] ?? "Other" : "Other";
|
|
3911
|
+
if (!groups.has(tag)) groups.set(tag, []);
|
|
3912
|
+
groups.get(tag).push(formatFnEntry(name, entry));
|
|
3913
|
+
}
|
|
3914
|
+
for (const [tag, lines] of groups) {
|
|
3915
|
+
sections.push(`${tag}:
|
|
3916
|
+
${lines.join("\n")}`);
|
|
3917
|
+
}
|
|
3918
|
+
}
|
|
3919
|
+
if (catalog.sources) {
|
|
3920
|
+
const lines = [];
|
|
3921
|
+
for (const [name, entry] of Object.entries(catalog.sources)) {
|
|
3922
|
+
lines.push(formatSourceEntry(name, entry));
|
|
3923
|
+
}
|
|
3924
|
+
if (lines.length > 0) {
|
|
3925
|
+
sections.push(`Sources:
|
|
3926
|
+
${lines.join("\n")}`);
|
|
3927
|
+
}
|
|
3928
|
+
}
|
|
3929
|
+
return sections.join("\n\n");
|
|
3930
|
+
}
|
|
3931
|
+
function formatFnEntry(name, entry) {
|
|
3932
|
+
if (!isRichFnEntry(entry)) return `- ${name}`;
|
|
3933
|
+
let line = `- ${name}: ${entry.description}`;
|
|
3934
|
+
if (entry.configSchema) {
|
|
3935
|
+
const fields = Object.entries(entry.configSchema).map(([k, v]) => {
|
|
3936
|
+
let desc = `${k}: ${v.type}`;
|
|
3937
|
+
if (v.enum) desc += ` (${v.enum.join("|")})`;
|
|
3938
|
+
if (v.required === false) desc += "?";
|
|
3939
|
+
return desc;
|
|
3940
|
+
});
|
|
3941
|
+
line += `. Config: { ${fields.join(", ")} }`;
|
|
3942
|
+
}
|
|
3943
|
+
return line;
|
|
3944
|
+
}
|
|
3945
|
+
function formatSourceEntry(name, entry) {
|
|
3946
|
+
if (!isRichSourceEntry(entry)) return `- ${name}`;
|
|
3947
|
+
let line = `- ${name}: ${entry.description}`;
|
|
3948
|
+
if (entry.configSchema) {
|
|
3949
|
+
const fields = Object.entries(entry.configSchema).map(([k, v]) => {
|
|
3950
|
+
let desc = `${k}: ${v.type}`;
|
|
3951
|
+
if (v.required === false) desc += "?";
|
|
3952
|
+
return desc;
|
|
3953
|
+
});
|
|
3954
|
+
line += `. Config: { ${fields.join(", ")} }`;
|
|
3955
|
+
}
|
|
3956
|
+
return line;
|
|
3957
|
+
}
|
|
3958
|
+
function validateSpecAgainstCatalog(spec, catalog) {
|
|
3959
|
+
const errors = [];
|
|
3960
|
+
const fnNames = new Set(Object.keys(catalog.fns ?? {}));
|
|
3961
|
+
const sourceNames = new Set(Object.keys(catalog.sources ?? {}));
|
|
3962
|
+
for (const [nodeName, nodeRaw] of Object.entries(spec.nodes)) {
|
|
3963
|
+
if (nodeRaw.type === "template") continue;
|
|
3964
|
+
const node2 = nodeRaw;
|
|
3965
|
+
if (node2.fn && fnNames.size > 0 && !fnNames.has(node2.fn)) {
|
|
3966
|
+
if (sourceNames.has(node2.fn)) {
|
|
3967
|
+
errors.push(
|
|
3968
|
+
`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(", ")}`
|
|
3969
|
+
);
|
|
3970
|
+
} else {
|
|
3971
|
+
const suggestion = findClosest(node2.fn, fnNames);
|
|
3972
|
+
errors.push(
|
|
3973
|
+
`Node "${nodeName}": fn "${node2.fn}" not found in catalog` + (suggestion ? `. Did you mean "${suggestion}"?` : "")
|
|
3974
|
+
);
|
|
3975
|
+
}
|
|
3976
|
+
}
|
|
3977
|
+
if (node2.source && sourceNames.size > 0 && !sourceNames.has(node2.source)) {
|
|
3978
|
+
if (fnNames.has(node2.source)) {
|
|
3979
|
+
errors.push(
|
|
3980
|
+
`Node "${nodeName}": source "${node2.source}" is a function, not a source. Use it as fn instead, or use a source from: ${[...sourceNames].join(", ")}`
|
|
3981
|
+
);
|
|
3982
|
+
} else {
|
|
3983
|
+
const suggestion = findClosest(node2.source, sourceNames);
|
|
3984
|
+
errors.push(
|
|
3985
|
+
`Node "${nodeName}": source "${node2.source}" not found in catalog` + (suggestion ? `. Did you mean "${suggestion}"?` : "")
|
|
3986
|
+
);
|
|
3987
|
+
}
|
|
3988
|
+
}
|
|
3989
|
+
if (node2.fn && node2.config && catalog.fns?.[node2.fn]) {
|
|
3990
|
+
const entry = catalog.fns[node2.fn];
|
|
3991
|
+
if (isRichFnEntry(entry) && entry.configSchema) {
|
|
3992
|
+
for (const [field, schema] of Object.entries(entry.configSchema)) {
|
|
3993
|
+
if (schema.required !== false && !(field in node2.config)) {
|
|
3994
|
+
errors.push(`Node "${nodeName}": config missing required field "${field}"`);
|
|
3995
|
+
}
|
|
3996
|
+
if (field in node2.config && schema.enum) {
|
|
3997
|
+
const val = node2.config[field];
|
|
3998
|
+
if (!schema.enum.includes(val)) {
|
|
3999
|
+
errors.push(
|
|
4000
|
+
`Node "${nodeName}": config.${field} = ${JSON.stringify(val)}, expected one of: ${schema.enum.join(", ")}`
|
|
4001
|
+
);
|
|
4002
|
+
}
|
|
4003
|
+
}
|
|
4004
|
+
}
|
|
4005
|
+
}
|
|
4006
|
+
}
|
|
4007
|
+
}
|
|
4008
|
+
if (spec.templates) {
|
|
4009
|
+
for (const [tName, template] of Object.entries(spec.templates)) {
|
|
4010
|
+
for (const [nodeName, node2] of Object.entries(template.nodes)) {
|
|
4011
|
+
if (node2.fn && fnNames.size > 0 && !fnNames.has(node2.fn)) {
|
|
4012
|
+
const suggestion = findClosest(node2.fn, fnNames);
|
|
4013
|
+
errors.push(
|
|
4014
|
+
`Template "${tName}" node "${nodeName}": fn "${node2.fn}" not found in catalog` + (suggestion ? `. Did you mean "${suggestion}"?` : "")
|
|
4015
|
+
);
|
|
4016
|
+
}
|
|
4017
|
+
}
|
|
4018
|
+
}
|
|
4019
|
+
}
|
|
4020
|
+
return { valid: errors.length === 0, errors };
|
|
4021
|
+
}
|
|
4022
|
+
function findClosest(input, candidates) {
|
|
4023
|
+
let best = null;
|
|
4024
|
+
let bestDist = Infinity;
|
|
4025
|
+
const lower = input.toLowerCase();
|
|
4026
|
+
for (const c of candidates) {
|
|
4027
|
+
const dist = levenshtein(lower, c.toLowerCase());
|
|
4028
|
+
if (dist < bestDist && dist <= Math.max(3, Math.floor(input.length / 2))) {
|
|
4029
|
+
bestDist = dist;
|
|
4030
|
+
best = c;
|
|
4031
|
+
}
|
|
4032
|
+
}
|
|
4033
|
+
return best;
|
|
4034
|
+
}
|
|
4035
|
+
function levenshtein(a, b) {
|
|
4036
|
+
const m = a.length;
|
|
4037
|
+
const n = b.length;
|
|
4038
|
+
const dp = Array.from(
|
|
4039
|
+
{ length: m + 1 },
|
|
4040
|
+
(_, i) => Array.from({ length: n + 1 }, (_2, j) => i === 0 ? j : j === 0 ? i : 0)
|
|
4041
|
+
);
|
|
4042
|
+
for (let i = 1; i <= m; i++) {
|
|
4043
|
+
for (let j = 1; j <= n; j++) {
|
|
4044
|
+
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]);
|
|
4045
|
+
}
|
|
4046
|
+
}
|
|
4047
|
+
return dp[m][n];
|
|
4048
|
+
}
|
|
3343
4049
|
var VALID_NODE_TYPES2 = /* @__PURE__ */ new Set([
|
|
3344
4050
|
"state",
|
|
3345
4051
|
"producer",
|
|
@@ -3516,6 +4222,21 @@ ${validation.errors.join("\n")}`);
|
|
|
3516
4222
|
const catalog = opts?.catalog ?? {};
|
|
3517
4223
|
const g = new Graph(spec.name);
|
|
3518
4224
|
const templates = spec.templates ?? {};
|
|
4225
|
+
const catalogValidation = validateSpecAgainstCatalog(spec, catalog);
|
|
4226
|
+
if (!catalogValidation.valid) {
|
|
4227
|
+
throw new Error(
|
|
4228
|
+
`compileSpec: catalog validation errors:
|
|
4229
|
+
${catalogValidation.errors.join("\n")}`
|
|
4230
|
+
);
|
|
4231
|
+
}
|
|
4232
|
+
const resolveFn = (fnName) => {
|
|
4233
|
+
const entry = catalog.fns?.[fnName];
|
|
4234
|
+
return entry ? extractFnFactory(entry) : void 0;
|
|
4235
|
+
};
|
|
4236
|
+
const resolveSource = (sourceName) => {
|
|
4237
|
+
const entry = catalog.sources?.[sourceName];
|
|
4238
|
+
return entry ? extractSourceFactory(entry) : void 0;
|
|
4239
|
+
};
|
|
3519
4240
|
const created = /* @__PURE__ */ new Map();
|
|
3520
4241
|
const deferred = [];
|
|
3521
4242
|
for (const [name, raw] of Object.entries(spec.nodes)) {
|
|
@@ -3529,8 +4250,8 @@ ${validation.errors.join("\n")}`);
|
|
|
3529
4250
|
g.add(name, nd);
|
|
3530
4251
|
created.set(name, nd);
|
|
3531
4252
|
} else if (n.type === "producer") {
|
|
3532
|
-
const sourceFactory = n.source ?
|
|
3533
|
-
const fnFactory = n.fn ?
|
|
4253
|
+
const sourceFactory = n.source ? resolveSource(n.source) : void 0;
|
|
4254
|
+
const fnFactory = n.fn ? resolveFn(n.fn) : void 0;
|
|
3534
4255
|
if (sourceFactory) {
|
|
3535
4256
|
const nd = sourceFactory(n.config ?? {});
|
|
3536
4257
|
g.add(name, nd);
|
|
@@ -3560,7 +4281,7 @@ ${validation.errors.join("\n")}`);
|
|
|
3560
4281
|
const deps = n.deps ?? [];
|
|
3561
4282
|
if (!deps.every((dep) => created.has(dep))) continue;
|
|
3562
4283
|
const resolvedDeps = deps.map((dep) => created.get(dep));
|
|
3563
|
-
const fnFactory = n.fn ?
|
|
4284
|
+
const fnFactory = n.fn ? resolveFn(n.fn) : void 0;
|
|
3564
4285
|
let nd;
|
|
3565
4286
|
if (fnFactory) {
|
|
3566
4287
|
nd = fnFactory(resolvedDeps, n.config ?? {});
|
|
@@ -3603,8 +4324,8 @@ ${validation.errors.join("\n")}`);
|
|
|
3603
4324
|
sub.add(nName, nd);
|
|
3604
4325
|
subCreated.set(nName, nd);
|
|
3605
4326
|
} else if (nSpec.type === "producer") {
|
|
3606
|
-
const sourceFactory = nSpec.source ?
|
|
3607
|
-
const fnFactory = nSpec.fn ?
|
|
4327
|
+
const sourceFactory = nSpec.source ? resolveSource(nSpec.source) : void 0;
|
|
4328
|
+
const fnFactory = nSpec.fn ? resolveFn(nSpec.fn) : void 0;
|
|
3608
4329
|
if (sourceFactory) {
|
|
3609
4330
|
const nd = sourceFactory(nSpec.config ?? {});
|
|
3610
4331
|
sub.add(nName, nd);
|
|
@@ -3635,7 +4356,7 @@ ${validation.errors.join("\n")}`);
|
|
|
3635
4356
|
const allReady = deps.every((dep) => subCreated.has(dep) || created.has(dep));
|
|
3636
4357
|
if (!allReady) continue;
|
|
3637
4358
|
const resolvedDeps = deps.map((dep) => subCreated.get(dep) ?? created.get(dep));
|
|
3638
|
-
const fnFactory = nSpec.fn ?
|
|
4359
|
+
const fnFactory = nSpec.fn ? resolveFn(nSpec.fn) : void 0;
|
|
3639
4360
|
let nd;
|
|
3640
4361
|
if (fnFactory) {
|
|
3641
4362
|
nd = fnFactory(resolvedDeps, nSpec.config ?? {});
|
|
@@ -3696,14 +4417,15 @@ var INTERNAL_META_KEYS = /* @__PURE__ */ new Set([
|
|
|
3696
4417
|
"_templateName",
|
|
3697
4418
|
"_templateBind",
|
|
3698
4419
|
"feedbackFrom",
|
|
3699
|
-
"feedbackTo"
|
|
4420
|
+
"feedbackTo",
|
|
4421
|
+
"_internal"
|
|
3700
4422
|
]);
|
|
3701
4423
|
function decompileGraph(graph) {
|
|
3702
4424
|
const desc = graph.describe({ detail: "standard" });
|
|
3703
4425
|
const nodes = {};
|
|
3704
4426
|
const feedbackEdges = [];
|
|
3705
4427
|
const metaSegment = `::${GRAPH_META_SEGMENT}::`;
|
|
3706
|
-
const feedbackCounterPattern = /^__feedback_(.+)$/;
|
|
4428
|
+
const feedbackCounterPattern = /^__feedback_(?!effect_)(.+)$/;
|
|
3707
4429
|
const feedbackConditions = /* @__PURE__ */ new Set();
|
|
3708
4430
|
for (const path of Object.keys(desc.nodes)) {
|
|
3709
4431
|
if (path.includes(metaSegment)) continue;
|
|
@@ -3723,6 +4445,9 @@ function decompileGraph(graph) {
|
|
|
3723
4445
|
for (const [path, nodeDesc] of Object.entries(desc.nodes)) {
|
|
3724
4446
|
if (path.includes(metaSegment)) continue;
|
|
3725
4447
|
if (feedbackCounterPattern.test(path)) continue;
|
|
4448
|
+
if (nodeDesc.meta?._internal) continue;
|
|
4449
|
+
if (path.startsWith("__feedback_effect_")) continue;
|
|
4450
|
+
if (path.startsWith("__bridge_")) continue;
|
|
3726
4451
|
if (path.includes("::")) continue;
|
|
3727
4452
|
const specNode = {
|
|
3728
4453
|
type: nodeDesc.type
|
|
@@ -4055,11 +4780,12 @@ function stripFences2(text) {
|
|
|
4055
4780
|
}
|
|
4056
4781
|
async function llmCompose(problem, adapter, opts) {
|
|
4057
4782
|
let systemPrompt = LLM_COMPOSE_SYSTEM_PROMPT;
|
|
4058
|
-
|
|
4783
|
+
const catalogPrompt = opts?.catalogDescription ?? (opts?.catalog ? generateCatalogPrompt(opts.catalog) : void 0);
|
|
4784
|
+
if (catalogPrompt) {
|
|
4059
4785
|
systemPrompt += `
|
|
4060
4786
|
|
|
4061
|
-
Available catalog:
|
|
4062
|
-
${
|
|
4787
|
+
Available catalog (use ONLY these names):
|
|
4788
|
+
${catalogPrompt}`;
|
|
4063
4789
|
}
|
|
4064
4790
|
if (opts?.systemPromptExtra) {
|
|
4065
4791
|
systemPrompt += `
|
|
@@ -4091,7 +4817,30 @@ ${opts.systemPromptExtra}`;
|
|
|
4091
4817
|
throw new Error(`llmCompose: invalid GraphSpec:
|
|
4092
4818
|
${validation.errors.join("\n")}`);
|
|
4093
4819
|
}
|
|
4094
|
-
|
|
4820
|
+
let spec = parsed;
|
|
4821
|
+
if (opts?.catalog) {
|
|
4822
|
+
const maxRefine = opts.maxAutoRefine ?? 0;
|
|
4823
|
+
for (let attempt = 0; attempt <= maxRefine; attempt++) {
|
|
4824
|
+
const catalogValidation = validateSpecAgainstCatalog(spec, opts.catalog);
|
|
4825
|
+
if (catalogValidation.valid) break;
|
|
4826
|
+
if (attempt === maxRefine) {
|
|
4827
|
+
throw new Error(
|
|
4828
|
+
`llmCompose: catalog validation failed after ${maxRefine} refine attempts:
|
|
4829
|
+
${catalogValidation.errors.join("\n")}`
|
|
4830
|
+
);
|
|
4831
|
+
}
|
|
4832
|
+
spec = await llmRefine(
|
|
4833
|
+
spec,
|
|
4834
|
+
`Fix these catalog errors:
|
|
4835
|
+
${catalogValidation.errors.join("\n")}
|
|
4836
|
+
|
|
4837
|
+
Use ONLY functions and sources from the catalog.`,
|
|
4838
|
+
adapter,
|
|
4839
|
+
{ ...opts, catalogDescription: catalogPrompt }
|
|
4840
|
+
);
|
|
4841
|
+
}
|
|
4842
|
+
}
|
|
4843
|
+
return spec;
|
|
4095
4844
|
}
|
|
4096
4845
|
async function llmRefine(currentSpec, feedback2, adapter, opts) {
|
|
4097
4846
|
let systemPrompt = LLM_COMPOSE_SYSTEM_PROMPT;
|
|
@@ -4163,7 +4912,7 @@ function requireNonNegativeInt(value, label) {
|
|
|
4163
4912
|
}
|
|
4164
4913
|
return value;
|
|
4165
4914
|
}
|
|
4166
|
-
function
|
|
4915
|
+
function keepalive4(n) {
|
|
4167
4916
|
return n.subscribe(() => {
|
|
4168
4917
|
});
|
|
4169
4918
|
}
|
|
@@ -4199,7 +4948,7 @@ var TopicGraph = class extends Graph {
|
|
|
4199
4948
|
);
|
|
4200
4949
|
this.add("latest", this.latest);
|
|
4201
4950
|
this.connect("events", "latest");
|
|
4202
|
-
this._keepaliveDisposers.push(
|
|
4951
|
+
this._keepaliveDisposers.push(keepalive4(this.latest));
|
|
4203
4952
|
}
|
|
4204
4953
|
destroy() {
|
|
4205
4954
|
for (const dispose of this._keepaliveDisposers) dispose();
|
|
@@ -4255,8 +5004,8 @@ var SubscriptionGraph = class extends Graph {
|
|
|
4255
5004
|
this.connect("topic::events", "source");
|
|
4256
5005
|
this.connect("source", "available");
|
|
4257
5006
|
this.connect("cursor", "available");
|
|
4258
|
-
this._keepaliveDisposers.push(
|
|
4259
|
-
this._keepaliveDisposers.push(
|
|
5007
|
+
this._keepaliveDisposers.push(keepalive4(this.source));
|
|
5008
|
+
this._keepaliveDisposers.push(keepalive4(this.available));
|
|
4260
5009
|
}
|
|
4261
5010
|
destroy() {
|
|
4262
5011
|
for (const dispose of this._keepaliveDisposers) dispose();
|
|
@@ -4308,7 +5057,7 @@ var JobQueueGraph = class extends Graph {
|
|
|
4308
5057
|
);
|
|
4309
5058
|
this.add("depth", this.depth);
|
|
4310
5059
|
this.connect("pending", "depth");
|
|
4311
|
-
this._keepaliveDisposers.push(
|
|
5060
|
+
this._keepaliveDisposers.push(keepalive4(this.depth));
|
|
4312
5061
|
}
|
|
4313
5062
|
destroy() {
|
|
4314
5063
|
for (const dispose of this._keepaliveDisposers) dispose();
|
|
@@ -4408,7 +5157,7 @@ var JobFlowGraph = class extends Graph {
|
|
|
4408
5157
|
);
|
|
4409
5158
|
this.add("completedCount", this.completedCount);
|
|
4410
5159
|
this.connect("completed", "completedCount");
|
|
4411
|
-
this._keepaliveDisposers.push(
|
|
5160
|
+
this._keepaliveDisposers.push(keepalive4(this.completedCount));
|
|
4412
5161
|
const maxPerPump = Math.max(
|
|
4413
5162
|
1,
|
|
4414
5163
|
requireNonNegativeInt(opts.maxPerPump ?? DEFAULT_MAX_PER_PUMP, "job flow maxPerPump")
|
|
@@ -4448,7 +5197,7 @@ var JobFlowGraph = class extends Graph {
|
|
|
4448
5197
|
);
|
|
4449
5198
|
this.add(`pump_${stage}`, pump);
|
|
4450
5199
|
this.connect(`${stage}::pending`, `pump_${stage}`);
|
|
4451
|
-
this._keepaliveDisposers.push(
|
|
5200
|
+
this._keepaliveDisposers.push(keepalive4(pump));
|
|
4452
5201
|
}
|
|
4453
5202
|
}
|
|
4454
5203
|
destroy() {
|
|
@@ -4520,7 +5269,7 @@ var TopicBridgeGraph = class extends Graph {
|
|
|
4520
5269
|
);
|
|
4521
5270
|
this.add("pump", pump);
|
|
4522
5271
|
this.connect("subscription::available", "pump");
|
|
4523
|
-
this._keepaliveDisposers.push(
|
|
5272
|
+
this._keepaliveDisposers.push(keepalive4(pump));
|
|
4524
5273
|
}
|
|
4525
5274
|
destroy() {
|
|
4526
5275
|
for (const dispose of this._keepaliveDisposers) dispose();
|
|
@@ -4550,7 +5299,7 @@ __export(orchestration_exports, {
|
|
|
4550
5299
|
approval: () => approval,
|
|
4551
5300
|
branch: () => branch,
|
|
4552
5301
|
forEach: () => forEach2,
|
|
4553
|
-
gate: () =>
|
|
5302
|
+
gate: () => gate,
|
|
4554
5303
|
join: () => join,
|
|
4555
5304
|
loop: () => loop,
|
|
4556
5305
|
onFailure: () => onFailure,
|
|
@@ -4558,6 +5307,7 @@ __export(orchestration_exports, {
|
|
|
4558
5307
|
sensor: () => sensor,
|
|
4559
5308
|
subPipeline: () => subPipeline,
|
|
4560
5309
|
task: () => task,
|
|
5310
|
+
valve: () => valve2,
|
|
4561
5311
|
wait: () => wait
|
|
4562
5312
|
});
|
|
4563
5313
|
function resolveDep(graph, dep) {
|
|
@@ -4590,7 +5340,7 @@ function registerStep(graph, name, step, depPaths) {
|
|
|
4590
5340
|
graph.connect(path, name);
|
|
4591
5341
|
}
|
|
4592
5342
|
}
|
|
4593
|
-
function
|
|
5343
|
+
function baseMeta3(kind, meta) {
|
|
4594
5344
|
return {
|
|
4595
5345
|
orchestration: true,
|
|
4596
5346
|
orchestration_type: kind,
|
|
@@ -4628,7 +5378,7 @@ function task(graph, name, run, opts) {
|
|
|
4628
5378
|
...nodeOpts,
|
|
4629
5379
|
name,
|
|
4630
5380
|
describeKind: "derived",
|
|
4631
|
-
meta:
|
|
5381
|
+
meta: baseMeta3("task", opts?.meta)
|
|
4632
5382
|
}
|
|
4633
5383
|
);
|
|
4634
5384
|
registerStep(
|
|
@@ -4651,13 +5401,13 @@ function branch(graph, name, source, predicate, opts) {
|
|
|
4651
5401
|
...opts,
|
|
4652
5402
|
name,
|
|
4653
5403
|
describeKind: "derived",
|
|
4654
|
-
meta:
|
|
5404
|
+
meta: baseMeta3("branch", opts?.meta)
|
|
4655
5405
|
}
|
|
4656
5406
|
);
|
|
4657
5407
|
registerStep(graph, name, step, src.path ? [src.path] : []);
|
|
4658
5408
|
return step;
|
|
4659
5409
|
}
|
|
4660
|
-
function
|
|
5410
|
+
function valve2(graph, name, source, control, opts) {
|
|
4661
5411
|
const src = resolveDep(graph, source);
|
|
4662
5412
|
const ctrl = resolveDep(graph, control);
|
|
4663
5413
|
const step = node(
|
|
@@ -4674,7 +5424,7 @@ function gate2(graph, name, source, control, opts) {
|
|
|
4674
5424
|
...opts,
|
|
4675
5425
|
name,
|
|
4676
5426
|
describeKind: "operator",
|
|
4677
|
-
meta:
|
|
5427
|
+
meta: baseMeta3("valve", opts?.meta)
|
|
4678
5428
|
}
|
|
4679
5429
|
);
|
|
4680
5430
|
registerStep(
|
|
@@ -4702,7 +5452,7 @@ function approval(graph, name, source, approver, opts) {
|
|
|
4702
5452
|
...opts,
|
|
4703
5453
|
name,
|
|
4704
5454
|
describeKind: "operator",
|
|
4705
|
-
meta:
|
|
5455
|
+
meta: baseMeta3("approval", opts?.meta)
|
|
4706
5456
|
}
|
|
4707
5457
|
);
|
|
4708
5458
|
registerStep(
|
|
@@ -4713,6 +5463,119 @@ function approval(graph, name, source, approver, opts) {
|
|
|
4713
5463
|
);
|
|
4714
5464
|
return step;
|
|
4715
5465
|
}
|
|
5466
|
+
function gate(graph, name, source, opts) {
|
|
5467
|
+
const maxPending = opts?.maxPending ?? Infinity;
|
|
5468
|
+
if (maxPending < 1 && maxPending !== Infinity) {
|
|
5469
|
+
throw new RangeError("gate: maxPending must be >= 1");
|
|
5470
|
+
}
|
|
5471
|
+
const startOpen = opts?.startOpen ?? false;
|
|
5472
|
+
const src = resolveDep(graph, source);
|
|
5473
|
+
const pendingNode = state([], { name: "pending", equals: () => false });
|
|
5474
|
+
const isOpenNode = state(startOpen, { name: "isOpen" });
|
|
5475
|
+
const countNode = node([pendingNode], ([arr]) => arr.length, {
|
|
5476
|
+
name: "count",
|
|
5477
|
+
describeKind: "derived"
|
|
5478
|
+
});
|
|
5479
|
+
let queue = [];
|
|
5480
|
+
let torn = false;
|
|
5481
|
+
function syncPending() {
|
|
5482
|
+
pendingNode.down([[DATA, [...queue]]]);
|
|
5483
|
+
}
|
|
5484
|
+
function enqueue(value) {
|
|
5485
|
+
queue.push(value);
|
|
5486
|
+
if (queue.length > maxPending) queue.shift();
|
|
5487
|
+
syncPending();
|
|
5488
|
+
}
|
|
5489
|
+
function dequeue(n) {
|
|
5490
|
+
const items = queue.splice(0, n);
|
|
5491
|
+
syncPending();
|
|
5492
|
+
return items;
|
|
5493
|
+
}
|
|
5494
|
+
function guardTorn(method) {
|
|
5495
|
+
if (torn) throw new Error(`gate: ${method}() called after gate was torn down`);
|
|
5496
|
+
}
|
|
5497
|
+
const output = node([src.node], () => void 0, {
|
|
5498
|
+
name,
|
|
5499
|
+
describeKind: "operator",
|
|
5500
|
+
meta: baseMeta3("gate", opts?.meta),
|
|
5501
|
+
onMessage(msg, _depIndex, actions) {
|
|
5502
|
+
if (msg[0] === DATA) {
|
|
5503
|
+
if (isOpenNode.get()) {
|
|
5504
|
+
actions.emit(msg[1]);
|
|
5505
|
+
} else {
|
|
5506
|
+
enqueue(msg[1]);
|
|
5507
|
+
actions.down([[RESOLVED]]);
|
|
5508
|
+
}
|
|
5509
|
+
return true;
|
|
5510
|
+
}
|
|
5511
|
+
if (msg[0] === TEARDOWN) {
|
|
5512
|
+
torn = true;
|
|
5513
|
+
queue = [];
|
|
5514
|
+
syncPending();
|
|
5515
|
+
actions.down([msg]);
|
|
5516
|
+
return true;
|
|
5517
|
+
}
|
|
5518
|
+
if (msg[0] === COMPLETE || msg[0] === ERROR) {
|
|
5519
|
+
torn = true;
|
|
5520
|
+
queue = [];
|
|
5521
|
+
syncPending();
|
|
5522
|
+
actions.down([msg]);
|
|
5523
|
+
return true;
|
|
5524
|
+
}
|
|
5525
|
+
actions.down([msg]);
|
|
5526
|
+
return true;
|
|
5527
|
+
}
|
|
5528
|
+
});
|
|
5529
|
+
const controller = {
|
|
5530
|
+
node: output,
|
|
5531
|
+
pending: pendingNode,
|
|
5532
|
+
count: countNode,
|
|
5533
|
+
isOpen: isOpenNode,
|
|
5534
|
+
approve(count = 1) {
|
|
5535
|
+
guardTorn("approve");
|
|
5536
|
+
const items = dequeue(count);
|
|
5537
|
+
for (const item of items) {
|
|
5538
|
+
if (torn) break;
|
|
5539
|
+
output.down([[DATA, item]]);
|
|
5540
|
+
}
|
|
5541
|
+
},
|
|
5542
|
+
reject(count = 1) {
|
|
5543
|
+
guardTorn("reject");
|
|
5544
|
+
dequeue(count);
|
|
5545
|
+
},
|
|
5546
|
+
modify(fn, count = 1) {
|
|
5547
|
+
guardTorn("modify");
|
|
5548
|
+
const snapshot = [...queue];
|
|
5549
|
+
const items = dequeue(count);
|
|
5550
|
+
for (let i = 0; i < items.length; i++) {
|
|
5551
|
+
if (torn) break;
|
|
5552
|
+
output.down([[DATA, fn(items[i], i, snapshot)]]);
|
|
5553
|
+
}
|
|
5554
|
+
},
|
|
5555
|
+
open() {
|
|
5556
|
+
guardTorn("open");
|
|
5557
|
+
isOpenNode.down([[DATA, true]]);
|
|
5558
|
+
const items = dequeue(queue.length);
|
|
5559
|
+
for (const item of items) {
|
|
5560
|
+
if (torn) break;
|
|
5561
|
+
output.down([[DATA, item]]);
|
|
5562
|
+
}
|
|
5563
|
+
},
|
|
5564
|
+
close() {
|
|
5565
|
+
guardTorn("close");
|
|
5566
|
+
isOpenNode.down([[DATA, false]]);
|
|
5567
|
+
}
|
|
5568
|
+
};
|
|
5569
|
+
countNode.subscribe(() => void 0);
|
|
5570
|
+
registerStep(graph, name, output, src.path ? [src.path] : []);
|
|
5571
|
+
const internal = new Graph(`${name}_state`);
|
|
5572
|
+
internal.add("pending", pendingNode);
|
|
5573
|
+
internal.add("isOpen", isOpenNode);
|
|
5574
|
+
internal.add("count", countNode);
|
|
5575
|
+
internal.connect("pending", "count");
|
|
5576
|
+
graph.mount(`${name}_state`, internal);
|
|
5577
|
+
return controller;
|
|
5578
|
+
}
|
|
4716
5579
|
function forEach2(graph, name, source, run, opts) {
|
|
4717
5580
|
const src = resolveDep(graph, source);
|
|
4718
5581
|
let terminated = false;
|
|
@@ -4721,7 +5584,7 @@ function forEach2(graph, name, source, run, opts) {
|
|
|
4721
5584
|
name,
|
|
4722
5585
|
describeKind: "effect",
|
|
4723
5586
|
completeWhenDepsComplete: false,
|
|
4724
|
-
meta:
|
|
5587
|
+
meta: baseMeta3("forEach", opts?.meta),
|
|
4725
5588
|
onMessage(msg, depIndex, actions) {
|
|
4726
5589
|
if (terminated) return true;
|
|
4727
5590
|
if (depIndex !== 0) {
|
|
@@ -4756,7 +5619,7 @@ function join(graph, name, deps, opts) {
|
|
|
4756
5619
|
...opts,
|
|
4757
5620
|
name,
|
|
4758
5621
|
describeKind: "derived",
|
|
4759
|
-
meta:
|
|
5622
|
+
meta: baseMeta3("join", opts?.meta)
|
|
4760
5623
|
}
|
|
4761
5624
|
);
|
|
4762
5625
|
registerStep(
|
|
@@ -4787,7 +5650,7 @@ function loop(graph, name, source, iterate, opts) {
|
|
|
4787
5650
|
...opts,
|
|
4788
5651
|
name,
|
|
4789
5652
|
describeKind: "derived",
|
|
4790
|
-
meta:
|
|
5653
|
+
meta: baseMeta3("loop", opts?.meta)
|
|
4791
5654
|
}
|
|
4792
5655
|
);
|
|
4793
5656
|
registerStep(
|
|
@@ -4812,7 +5675,7 @@ function sensor(graph, name, initial, opts) {
|
|
|
4812
5675
|
name,
|
|
4813
5676
|
initial,
|
|
4814
5677
|
describeKind: "producer",
|
|
4815
|
-
meta:
|
|
5678
|
+
meta: baseMeta3("sensor", opts?.meta)
|
|
4816
5679
|
});
|
|
4817
5680
|
registerStep(graph, name, source, []);
|
|
4818
5681
|
return {
|
|
@@ -4850,7 +5713,7 @@ function wait(graph, name, source, ms, opts) {
|
|
|
4850
5713
|
initial: src.node.get(),
|
|
4851
5714
|
describeKind: "operator",
|
|
4852
5715
|
completeWhenDepsComplete: false,
|
|
4853
|
-
meta:
|
|
5716
|
+
meta: baseMeta3("wait", opts?.meta),
|
|
4854
5717
|
onMessage(msg, depIndex, actions) {
|
|
4855
5718
|
if (terminated) return true;
|
|
4856
5719
|
if (depIndex !== 0) {
|
|
@@ -4900,7 +5763,7 @@ function onFailure(graph, name, source, recover, opts) {
|
|
|
4900
5763
|
name,
|
|
4901
5764
|
describeKind: "operator",
|
|
4902
5765
|
completeWhenDepsComplete: false,
|
|
4903
|
-
meta:
|
|
5766
|
+
meta: baseMeta3("onFailure", opts?.meta),
|
|
4904
5767
|
onMessage(msg, _depIndex, actions) {
|
|
4905
5768
|
if (terminated) return true;
|
|
4906
5769
|
if (msg[0] === ERROR) {
|
|
@@ -4924,10 +5787,12 @@ function onFailure(graph, name, source, recover, opts) {
|
|
|
4924
5787
|
// src/index.ts
|
|
4925
5788
|
var version = "0.0.0";
|
|
4926
5789
|
export {
|
|
5790
|
+
CLEANUP_RESULT,
|
|
4927
5791
|
COMPLETE,
|
|
4928
5792
|
CircuitOpenError,
|
|
4929
5793
|
DATA,
|
|
4930
5794
|
DEFAULT_ACTOR,
|
|
5795
|
+
DEFAULT_DOWN,
|
|
4931
5796
|
DIRTY,
|
|
4932
5797
|
DictCheckpointAdapter,
|
|
4933
5798
|
DynamicNodeImpl,
|
|
@@ -4953,6 +5818,7 @@ export {
|
|
|
4953
5818
|
ai_exports as ai,
|
|
4954
5819
|
audit,
|
|
4955
5820
|
batch,
|
|
5821
|
+
bridge,
|
|
4956
5822
|
buffer,
|
|
4957
5823
|
bufferCount,
|
|
4958
5824
|
bufferTime,
|
|
@@ -4964,6 +5830,7 @@ export {
|
|
|
4964
5830
|
checkpointToRedis,
|
|
4965
5831
|
checkpointToS3,
|
|
4966
5832
|
circuitBreaker,
|
|
5833
|
+
cleanupResult,
|
|
4967
5834
|
combine,
|
|
4968
5835
|
combineLatest,
|
|
4969
5836
|
compat_exports as compat,
|
|
@@ -4988,6 +5855,7 @@ export {
|
|
|
4988
5855
|
deserializeError,
|
|
4989
5856
|
distill,
|
|
4990
5857
|
distinctUntilChanged,
|
|
5858
|
+
domain_templates_exports as domainTemplates,
|
|
4991
5859
|
dynamicNode,
|
|
4992
5860
|
effect,
|
|
4993
5861
|
elementAt,
|
|
@@ -5036,7 +5904,6 @@ export {
|
|
|
5036
5904
|
fromTimer,
|
|
5037
5905
|
fromWebSocket,
|
|
5038
5906
|
fromWebhook,
|
|
5039
|
-
gate,
|
|
5040
5907
|
globToRegExp,
|
|
5041
5908
|
graph_exports as graph,
|
|
5042
5909
|
graphspec_exports as graphspec,
|
|
@@ -5152,6 +6019,7 @@ export {
|
|
|
5152
6019
|
toWebSocket,
|
|
5153
6020
|
tokenBucket,
|
|
5154
6021
|
tokenTracker,
|
|
6022
|
+
valve,
|
|
5155
6023
|
verifiable,
|
|
5156
6024
|
version,
|
|
5157
6025
|
vue_exports as vue,
|