@graphrefly/graphrefly 0.26.0 → 0.27.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.
Files changed (150) hide show
  1. package/dist/ai-CaR_912Q.d.cts +1033 -0
  2. package/dist/ai-WlRltJV7.d.ts +1033 -0
  3. package/dist/audit-ClmqGOCx.d.cts +245 -0
  4. package/dist/audit-DRlSzBu9.d.ts +245 -0
  5. package/dist/{chunk-JYXEWPH4.js → chunk-APFNLIRG.js} +2 -2
  6. package/dist/chunk-AT5LKYNL.js +395 -0
  7. package/dist/chunk-AT5LKYNL.js.map +1 -0
  8. package/dist/{chunk-AMCG74RZ.js → chunk-BQ6RQQFF.js} +215 -2128
  9. package/dist/chunk-BQ6RQQFF.js.map +1 -0
  10. package/dist/{chunk-IZYUSJC7.js → chunk-DST5DKZS.js} +6 -4
  11. package/dist/{chunk-IZYUSJC7.js.map → chunk-DST5DKZS.js.map} +1 -1
  12. package/dist/{chunk-LCE3GF5P.js → chunk-GTE6PWRZ.js} +2 -2
  13. package/dist/{chunk-RB6QPHJ7.js → chunk-J2VBW3DZ.js} +2 -93
  14. package/dist/chunk-J2VBW3DZ.js.map +1 -0
  15. package/dist/{chunk-FQMKGR6L.js → chunk-JWBCY4NC.js} +3 -3
  16. package/dist/chunk-K2AUJHVP.js +2251 -0
  17. package/dist/chunk-K2AUJHVP.js.map +1 -0
  18. package/dist/chunk-NC6S43JJ.js +456 -0
  19. package/dist/chunk-NC6S43JJ.js.map +1 -0
  20. package/dist/chunk-OFVJBJXR.js +98 -0
  21. package/dist/chunk-OFVJBJXR.js.map +1 -0
  22. package/dist/{chunk-6LDQFTYS.js → chunk-OU5CQKNW.js} +2 -2
  23. package/dist/{chunk-THTWHNU4.js → chunk-PF7GRZMW.js} +5 -5
  24. package/dist/chunk-RNHBMHKA.js +1665 -0
  25. package/dist/chunk-RNHBMHKA.js.map +1 -0
  26. package/dist/{chunk-SN4YWWYO.js → chunk-WBZOVTYK.js} +11 -11
  27. package/dist/chunk-WKNUIZOY.js +354 -0
  28. package/dist/chunk-WKNUIZOY.js.map +1 -0
  29. package/dist/{chunk-ZQMEI34O.js → chunk-X3VMZYBT.js} +3 -3
  30. package/dist/chunk-X5R3GL6H.js +525 -0
  31. package/dist/chunk-X5R3GL6H.js.map +1 -0
  32. package/dist/compat/index.d.cts +14 -14
  33. package/dist/compat/index.d.ts +14 -14
  34. package/dist/compat/index.js +17 -16
  35. package/dist/compat/jotai/index.d.cts +2 -2
  36. package/dist/compat/jotai/index.d.ts +2 -2
  37. package/dist/compat/nanostores/index.d.cts +2 -2
  38. package/dist/compat/nanostores/index.d.ts +2 -2
  39. package/dist/compat/nestjs/index.d.cts +6 -6
  40. package/dist/compat/nestjs/index.d.ts +6 -6
  41. package/dist/compat/nestjs/index.js +7 -6
  42. package/dist/compat/react/index.d.cts +2 -2
  43. package/dist/compat/react/index.d.ts +2 -2
  44. package/dist/compat/solid/index.d.cts +2 -2
  45. package/dist/compat/solid/index.d.ts +2 -2
  46. package/dist/compat/svelte/index.d.cts +2 -2
  47. package/dist/compat/svelte/index.d.ts +2 -2
  48. package/dist/compat/vue/index.d.cts +2 -2
  49. package/dist/compat/vue/index.d.ts +2 -2
  50. package/dist/compat/zustand/index.d.cts +5 -5
  51. package/dist/compat/zustand/index.d.ts +5 -5
  52. package/dist/compat/zustand/index.js +3 -3
  53. package/dist/composite-C7PcQvcs.d.cts +303 -0
  54. package/dist/composite-aUCvjZVR.d.ts +303 -0
  55. package/dist/core/index.d.cts +4 -3
  56. package/dist/core/index.d.ts +4 -3
  57. package/dist/{demo-shell-DEp-nMTl.d.ts → demo-shell-BDkOptd6.d.ts} +2 -2
  58. package/dist/{demo-shell-26p5fVxn.d.cts → demo-shell-Crid1WdR.d.cts} +2 -2
  59. package/dist/extra/index.d.cts +5 -4
  60. package/dist/extra/index.d.ts +5 -4
  61. package/dist/extra/index.js +68 -62
  62. package/dist/extra/sources.d.cts +1 -1
  63. package/dist/extra/sources.d.ts +1 -1
  64. package/dist/graph/index.d.cts +5 -5
  65. package/dist/graph/index.d.ts +5 -5
  66. package/dist/graph/index.js +3 -3
  67. package/dist/{graph-DQ69XU0g.d.ts → graph-CCwGKLCm.d.ts} +4 -4
  68. package/dist/{graph-6tZ5jEzr.d.cts → graph-DNCrvZSn.d.cts} +4 -4
  69. package/dist/{index-qldRdbQw.d.ts → index-3lsddbbS.d.ts} +1 -1
  70. package/dist/{index-Bxb5ZYc9.d.cts → index-B1tloyhO.d.cts} +1 -1
  71. package/dist/{index-eJ6T_qGM.d.ts → index-B6D3QNSA.d.ts} +2 -2
  72. package/dist/{index-B4MP_8V_.d.cts → index-B6EhDnjH.d.cts} +1 -1
  73. package/dist/{index-CmnuOibw.d.ts → index-B9B7_HEY.d.ts} +1 -1
  74. package/dist/{index-BeIdBfcb.d.cts → index-BHlKbUwO.d.cts} +16 -315
  75. package/dist/{index-CuYwdKO-.d.ts → index-BPVt8kqc.d.ts} +3 -3
  76. package/dist/index-BaSM3aYt.d.ts +195 -0
  77. package/dist/{index-BjI6ty9z.d.ts → index-BuEoe-Qu.d.ts} +9 -9
  78. package/dist/{index-DdD5MVDL.d.ts → index-BwfLUNw4.d.ts} +16 -315
  79. package/dist/{index-QBpffFW-.d.cts → index-ByQxazQJ.d.cts} +1 -1
  80. package/dist/{index-xdGjv0nO.d.ts → index-C0svESO4.d.ts} +1 -1
  81. package/dist/{index-BW1z3BN9.d.ts → index-C8oil6M6.d.ts} +3 -3
  82. package/dist/{index-C8mdwMXc.d.cts → index-CI3DprxP.d.cts} +3 -3
  83. package/dist/{index-CUwyr1Kk.d.cts → index-CO8uBlUh.d.cts} +2 -2
  84. package/dist/{index-DrISNAOm.d.ts → index-CxFrXH4m.d.ts} +1 -1
  85. package/dist/{index-BEfE8H_G.d.cts → index-D8wS_PeY.d.cts} +9 -9
  86. package/dist/{index-CUyrtuOf.d.cts → index-DO_6JN9Z.d.cts} +1 -1
  87. package/dist/index-DVGiGFGT.d.cts +195 -0
  88. package/dist/{index-DFhjO4Gg.d.cts → index-DYme44FM.d.cts} +1 -1
  89. package/dist/{index-_oMEWlDq.d.cts → index-DlLp-2Xn.d.cts} +3 -3
  90. package/dist/{index-CPgZ5wRl.d.ts → index-Dzk2hrlR.d.ts} +1 -1
  91. package/dist/{index-Bd_fwmLf.d.cts → index-VHqptjhu.d.cts} +1 -1
  92. package/dist/{index-CDAjUFIv.d.ts → index-VdHQMPy1.d.ts} +1 -1
  93. package/dist/{index-B_IP40nB.d.cts → index-Xi3u0HCQ.d.cts} +1 -1
  94. package/dist/{index-BYOHF0zP.d.ts → index-wEn0eFe8.d.ts} +1 -1
  95. package/dist/index.d.cts +35 -1692
  96. package/dist/index.d.ts +35 -1692
  97. package/dist/index.js +307 -3731
  98. package/dist/index.js.map +1 -1
  99. package/dist/memory-C6Z2tGpC.d.cts +139 -0
  100. package/dist/memory-li6FL5RM.d.ts +139 -0
  101. package/dist/messaging-Gt4LPbyA.d.cts +269 -0
  102. package/dist/messaging-XDoYablx.d.ts +269 -0
  103. package/dist/{meta-C0-8XW6Q.d.cts → meta-BxCA7rcr.d.cts} +1 -1
  104. package/dist/{meta-BGqSZ7mt.d.ts → meta-CbznRPYJ.d.ts} +1 -1
  105. package/dist/{node-C_IBuvX2.d.cts → node-BmerH3kS.d.cts} +1 -1
  106. package/dist/{node-C_IBuvX2.d.ts → node-BmerH3kS.d.ts} +1 -1
  107. package/dist/{observable-DCk45RH5.d.ts → observable-BgGUwcqp.d.ts} +1 -1
  108. package/dist/{observable-Crr1jgzx.d.cts → observable-DJt_AxzQ.d.cts} +1 -1
  109. package/dist/patterns/ai.cjs +7930 -0
  110. package/dist/patterns/ai.cjs.map +1 -0
  111. package/dist/patterns/ai.d.cts +10 -0
  112. package/dist/patterns/ai.d.ts +10 -0
  113. package/dist/patterns/ai.js +71 -0
  114. package/dist/patterns/ai.js.map +1 -0
  115. package/dist/patterns/audit.cjs +5805 -0
  116. package/dist/patterns/audit.cjs.map +1 -0
  117. package/dist/patterns/audit.d.cts +6 -0
  118. package/dist/patterns/audit.d.ts +6 -0
  119. package/dist/patterns/audit.js +29 -0
  120. package/dist/patterns/audit.js.map +1 -0
  121. package/dist/patterns/demo-shell.d.cts +6 -6
  122. package/dist/patterns/demo-shell.d.ts +6 -6
  123. package/dist/patterns/demo-shell.js +4 -4
  124. package/dist/patterns/memory.cjs +5283 -0
  125. package/dist/patterns/memory.cjs.map +1 -0
  126. package/dist/patterns/memory.d.cts +5 -0
  127. package/dist/patterns/memory.d.ts +5 -0
  128. package/dist/patterns/memory.js +20 -0
  129. package/dist/patterns/memory.js.map +1 -0
  130. package/dist/patterns/reactive-layout/index.d.cts +6 -6
  131. package/dist/patterns/reactive-layout/index.d.ts +6 -6
  132. package/dist/patterns/reactive-layout/index.js +4 -4
  133. package/dist/{reactive-layout-BaOQefHu.d.cts → reactive-layout-MQP--J3F.d.cts} +2 -2
  134. package/dist/{reactive-layout-D9gejYXE.d.ts → reactive-layout-u5Ulnqag.d.ts} +2 -2
  135. package/dist/{storage-BMycWEh2.d.ts → storage-CMjUUuxn.d.ts} +2 -2
  136. package/dist/{storage-DiqWHzVI.d.cts → storage-DdWlZo6U.d.cts} +2 -2
  137. package/dist/sugar-CCOxXK1e.d.ts +201 -0
  138. package/dist/sugar-D02n5JjF.d.cts +201 -0
  139. package/package.json +32 -2
  140. package/dist/chunk-AMCG74RZ.js.map +0 -1
  141. package/dist/chunk-RB6QPHJ7.js.map +0 -1
  142. package/dist/index-C0ZXMaXO.d.cts +0 -392
  143. package/dist/index-CY2TljO4.d.ts +0 -392
  144. /package/dist/{chunk-JYXEWPH4.js.map → chunk-APFNLIRG.js.map} +0 -0
  145. /package/dist/{chunk-LCE3GF5P.js.map → chunk-GTE6PWRZ.js.map} +0 -0
  146. /package/dist/{chunk-FQMKGR6L.js.map → chunk-JWBCY4NC.js.map} +0 -0
  147. /package/dist/{chunk-6LDQFTYS.js.map → chunk-OU5CQKNW.js.map} +0 -0
  148. /package/dist/{chunk-THTWHNU4.js.map → chunk-PF7GRZMW.js.map} +0 -0
  149. /package/dist/{chunk-SN4YWWYO.js.map → chunk-WBZOVTYK.js.map} +0 -0
  150. /package/dist/{chunk-ZQMEI34O.js.map → chunk-X3VMZYBT.js.map} +0 -0
package/dist/index.js CHANGED
@@ -1,17 +1,30 @@
1
1
  import {
2
2
  reactive_layout_exports
3
- } from "./chunk-ZQMEI34O.js";
3
+ } from "./chunk-X3VMZYBT.js";
4
+ import {
5
+ demo_shell_exports
6
+ } from "./chunk-JWBCY4NC.js";
7
+ import "./chunk-GTE6PWRZ.js";
4
8
  import {
5
9
  compat_exports,
6
10
  signals_exports
7
- } from "./chunk-SN4YWWYO.js";
11
+ } from "./chunk-WBZOVTYK.js";
12
+ import {
13
+ vue_exports
14
+ } from "./chunk-MJ2NKQQL.js";
15
+ import {
16
+ zustand_exports
17
+ } from "./chunk-APFNLIRG.js";
18
+ import {
19
+ jotai_exports
20
+ } from "./chunk-XGPU467M.js";
8
21
  import {
9
22
  nanostores_exports
10
23
  } from "./chunk-N6UR7YVY.js";
11
24
  import {
12
25
  cqrs_exports,
13
26
  nestjs_exports
14
- } from "./chunk-IZYUSJC7.js";
27
+ } from "./chunk-DST5DKZS.js";
15
28
  import {
16
29
  react_exports
17
30
  } from "./chunk-J22W6HV3.js";
@@ -21,59 +34,25 @@ import {
21
34
  import {
22
35
  svelte_exports
23
36
  } from "./chunk-OHISZPOJ.js";
24
- import {
25
- vue_exports
26
- } from "./chunk-MJ2NKQQL.js";
27
- import {
28
- zustand_exports
29
- } from "./chunk-JYXEWPH4.js";
30
37
  import {
31
38
  CircuitOpenError,
32
- NS_PER_MS,
33
- NS_PER_SEC,
34
39
  NativeIndexBackend,
35
- NativeListBackend,
36
- NativeMapBackend,
37
40
  NativePubSubBackend,
38
41
  RateLimiterOverflowError,
39
42
  TimeoutError,
40
- audit,
41
- buffer,
42
- bufferCount,
43
- bufferTime,
44
43
  cascadingCache,
45
- catchError,
46
44
  checkpointToRedis,
47
45
  checkpointToS3,
48
46
  circuitBreaker,
49
- combine,
50
- combineLatest,
51
- concat,
52
- concatMap,
53
- constant,
54
47
  createTransport,
55
48
  csvRows,
56
- debounce,
57
- debounceTime,
58
- decorrelatedJitter,
59
- delay,
60
49
  deserializeError,
61
50
  dictStorage,
62
- distill,
63
- distinctUntilChanged,
64
- elementAt,
65
- exhaustMap,
66
- exponential,
67
51
  externalBundle,
68
52
  externalProducer,
69
53
  extra_exports,
70
54
  fallback,
71
- fibonacci,
72
55
  fileStorage,
73
- filter,
74
- find,
75
- first,
76
- flatMap,
77
56
  fromCSV,
78
57
  fromClickHouseWatch,
79
58
  fromDrizzle,
@@ -104,47 +83,22 @@ import {
104
83
  fromWebSocketReconnect,
105
84
  fromWebhook,
106
85
  indexedDbStorage,
107
- interval,
108
- last,
109
- linear,
110
86
  lru,
111
- map,
112
87
  memoryStorage,
113
- merge,
114
- mergeMap,
115
88
  nameToSignal,
116
89
  ndjsonRows,
117
- pairwise,
118
90
  parsePrometheusText,
119
91
  parseStatsD,
120
92
  parseSyslog,
121
- pausable,
122
93
  pubsub,
123
- race,
124
94
  rateLimiter,
125
95
  reactiveIndex,
126
- reactiveList,
127
- reactiveMap,
128
96
  reactiveSink,
129
- reduce,
130
- repeat,
131
- rescue,
132
- resolveBackoffPreset,
133
97
  retry,
134
98
  retrySource,
135
- sample,
136
- scan,
137
99
  serializeError,
138
100
  signalToName,
139
- skip,
140
101
  sqliteStorage,
141
- switchMap,
142
- take,
143
- takeUntil,
144
- takeWhile,
145
- tap,
146
- throttle,
147
- throttleTime,
148
102
  timeout,
149
103
  toCSV,
150
104
  toClickHouse,
@@ -166,3633 +120,255 @@ import {
166
120
  toTempo,
167
121
  toWebSocket,
168
122
  tokenBucket,
123
+ withBreaker,
124
+ withStatus,
125
+ workerBridge,
126
+ workerSelf
127
+ } from "./chunk-BQ6RQQFF.js";
128
+ import {
129
+ createWatermarkController,
130
+ toObservable
131
+ } from "./chunk-OFVJBJXR.js";
132
+ import {
133
+ ai_exports,
134
+ gate,
135
+ orchestration_exports,
136
+ promptNode
137
+ } from "./chunk-K2AUJHVP.js";
138
+ import {
139
+ decay,
140
+ memory_exports
141
+ } from "./chunk-AT5LKYNL.js";
142
+ import {
143
+ NS_PER_MS,
144
+ NS_PER_SEC,
145
+ audit,
146
+ buffer,
147
+ bufferCount,
148
+ bufferTime,
149
+ catchError,
150
+ combine,
151
+ combineLatest,
152
+ concat,
153
+ concatMap,
154
+ constant,
155
+ debounce,
156
+ debounceTime,
157
+ decorrelatedJitter,
158
+ delay,
159
+ distill,
160
+ distinctUntilChanged,
161
+ elementAt,
162
+ exhaustMap,
163
+ exponential,
164
+ fibonacci,
165
+ filter,
166
+ find,
167
+ first,
168
+ flatMap,
169
+ interval,
170
+ last,
171
+ linear,
172
+ map,
173
+ merge,
174
+ mergeMap,
175
+ pairwise,
176
+ pausable,
177
+ race,
178
+ reduce,
179
+ repeat,
180
+ rescue,
181
+ resolveBackoffPreset,
182
+ sample,
183
+ scan,
184
+ skip,
185
+ switchMap,
186
+ take,
187
+ takeUntil,
188
+ takeWhile,
189
+ tap,
190
+ throttle,
191
+ throttleTime,
169
192
  valve,
170
193
  verifiable,
171
194
  window,
172
195
  windowCount,
173
196
  windowTime,
174
- withBreaker,
175
197
  withLatestFrom,
176
198
  withMaxAttempts,
177
- withStatus,
178
- workerBridge,
179
- workerSelf,
180
199
  zip
181
- } from "./chunk-AMCG74RZ.js";
182
- import {
183
- NativeLogBackend,
184
- createWatermarkController,
185
- reactiveLog,
186
- toObservable
187
- } from "./chunk-RB6QPHJ7.js";
188
- import {
189
- core_exports
190
- } from "./chunk-3ZWCKRHX.js";
200
+ } from "./chunk-RNHBMHKA.js";
191
201
  import {
192
- graph_exports,
193
- watchTopologyTree
194
- } from "./chunk-6LDQFTYS.js";
202
+ audit_exports,
203
+ policyEnforcer,
204
+ reactiveExplainPath
205
+ } from "./chunk-NC6S43JJ.js";
195
206
  import {
196
- demo_shell_exports
197
- } from "./chunk-FQMKGR6L.js";
198
- import "./chunk-LCE3GF5P.js";
207
+ TopicGraph,
208
+ messaging_exports
209
+ } from "./chunk-X5R3GL6H.js";
199
210
  import {
200
211
  domainMeta,
201
212
  trackingKey,
202
213
  tryIncrementBounded
203
214
  } from "./chunk-JSCT3CR4.js";
204
215
  import {
205
- cached,
206
- empty,
207
- escapeRegexChar,
208
- firstValueFrom,
209
- firstWhere,
210
- forEach,
211
- fromAny,
212
- fromAsyncIter,
213
- fromCron,
214
- fromEvent,
215
- fromIter,
216
- fromPromise,
217
- fromRaf,
218
- fromTimer,
219
- globToRegExp,
220
- keepalive,
221
- matchesAnyPattern,
222
- matchesCron,
223
- never,
224
- of,
225
- parseCron,
226
- reactiveCounter,
227
- replay,
228
- share,
229
- shareReplay,
230
- throwError,
231
- toArray
232
- } from "./chunk-BVZYTZ5H.js";
233
- import {
234
- GRAPH_META_SEGMENT,
235
- Graph,
236
- OVERHEAD,
237
- SIZEOF_SYMBOL,
238
- SNAPSHOT_VERSION,
239
- diffForWAL,
240
- explainPath,
241
- graphProfile,
242
- reachable,
243
- sizeof
244
- } from "./chunk-THTWHNU4.js";
245
- import {
246
- ResettableTimer
247
- } from "./chunk-7TAQJHQV.js";
248
- import {
249
- resolveDescribeFields
250
- } from "./chunk-VYPWMZ6H.js";
216
+ core_exports
217
+ } from "./chunk-3ZWCKRHX.js";
251
218
  import {
252
- jotai_exports
253
- } from "./chunk-XGPU467M.js";
219
+ NativeListBackend,
220
+ NativeMapBackend,
221
+ reactiveList,
222
+ reactiveMap
223
+ } from "./chunk-WKNUIZOY.js";
254
224
  import {
255
- DEFAULT_ACTOR,
256
- ENVELOPE_VERSION,
257
- GraphReFlyConfig,
258
- GuardDenied,
259
- JsonCodec,
260
- NodeImpl,
261
- accessHintForGuard,
262
- advanceVersion,
263
- autoTrackNode,
264
- batch,
265
- configure,
266
- createDagCborCodec,
267
- createDagCborZstdCodec,
268
- createVersioning,
269
- decodeEnvelope,
270
- defaultConfig,
271
- defaultHash,
272
- derived,
273
- downWithBatch,
274
- dynamicNode,
275
- effect,
276
- encodeEnvelope,
277
- isBatching,
278
- isV1,
279
- monotonicNs,
280
- node,
281
- normalizeActor,
282
- pipe,
283
- policy,
284
- policyFromRules,
285
- producer,
286
- registerBuiltinCodecs,
287
- registerBuiltins,
288
- replayWAL,
289
- state,
290
- wallClockNs
291
- } from "./chunk-PHOUUNK7.js";
225
+ NativeLogBackend,
226
+ reactiveLog
227
+ } from "./chunk-J2VBW3DZ.js";
292
228
  import {
293
- COMPLETE,
294
- COMPLETE_MSG,
295
- COMPLETE_ONLY_BATCH,
296
- DATA,
297
- DIRTY,
298
- DIRTY_MSG,
299
- DIRTY_ONLY_BATCH,
300
- ERROR,
301
- INVALIDATE,
302
- INVALIDATE_MSG,
303
- INVALIDATE_ONLY_BATCH,
304
- PAUSE,
305
- RESOLVED,
306
- RESOLVED_MSG,
307
- RESOLVED_ONLY_BATCH,
308
- RESUME,
309
- START,
310
- START_MSG,
311
- TEARDOWN,
312
- TEARDOWN_MSG,
313
- TEARDOWN_ONLY_BATCH,
314
- __export
315
- } from "./chunk-SX52TAR4.js";
316
-
317
- // src/patterns/index.ts
318
- var patterns_exports = {};
319
- __export(patterns_exports, {
320
- SNAPSHOT_WIRE_VERSION: () => SNAPSHOT_WIRE_VERSION,
321
- SurfaceError: () => SurfaceError,
322
- accountability: () => audit_exports,
323
- ai: () => ai_exports,
324
- asSurfaceError: () => asSurfaceError,
325
- cqrs: () => cqrs_exports,
326
- createGraph: () => createGraph,
327
- deleteSnapshot: () => deleteSnapshot,
328
- demoShell: () => demo_shell_exports,
329
- diffSnapshots: () => diffSnapshots,
330
- domainTemplates: () => domain_templates_exports,
331
- graphspec: () => graphspec_exports,
332
- guarded: () => guarded_execution_exports,
333
- harness: () => harness_exports,
334
- layout: () => reactive_layout_exports,
335
- lens: () => lens_exports,
336
- listSnapshots: () => listSnapshots,
337
- memory: () => memory_exports,
338
- messaging: () => messaging_exports,
339
- orchestration: () => orchestration_exports,
340
- reduction: () => reduction_exports,
341
- resilientPipeline: () => resilient_pipeline_exports,
342
- restoreSnapshot: () => restoreSnapshot,
343
- runReduction: () => runReduction,
344
- saveSnapshot: () => saveSnapshot,
345
- surface: () => surface_exports
346
- });
347
-
348
- // src/patterns/ai.ts
349
- var ai_exports = {};
350
- __export(ai_exports, {
351
- AgentLoopGraph: () => AgentLoopGraph,
352
- ChatStreamGraph: () => ChatStreamGraph,
353
- ToolRegistryGraph: () => ToolRegistryGraph,
354
- admissionFilter3D: () => admissionFilter3D,
355
- agentLoop: () => agentLoop,
356
- agentMemory: () => agentMemory,
357
- chatStream: () => chatStream,
358
- contentGate: () => contentGate,
359
- costMeterExtractor: () => costMeterExtractor,
360
- fromLLM: () => fromLLM,
361
- gatedStream: () => gatedStream,
362
- gaugesAsContext: () => gaugesAsContext,
363
- graphFromSpec: () => graphFromSpec,
364
- keywordFlagExtractor: () => keywordFlagExtractor,
365
- knobsAsTools: () => knobsAsTools,
366
- llmConsolidator: () => llmConsolidator,
367
- llmExtractor: () => llmExtractor,
368
- promptNode: () => promptNode,
369
- redactor: () => redactor,
370
- streamExtractor: () => streamExtractor,
371
- streamingPromptNode: () => streamingPromptNode,
372
- suggestStrategy: () => suggestStrategy,
373
- systemPromptBuilder: () => systemPromptBuilder,
374
- toolCallExtractor: () => toolCallExtractor,
375
- toolRegistry: () => toolRegistry,
376
- validateGraphDef: () => validateGraphDef
377
- });
378
-
379
- // src/patterns/memory.ts
380
- var memory_exports = {};
381
- __export(memory_exports, {
382
- collection: () => collection,
383
- decay: () => decay,
384
- knowledgeGraph: () => knowledgeGraph,
385
- lightCollection: () => lightCollection,
386
- vectorIndex: () => vectorIndex
387
- });
388
- function decay(baseScore, ageSeconds, ratePerSecond, minScore = 0) {
389
- if (!Number.isFinite(baseScore)) return minScore;
390
- if (!Number.isFinite(ageSeconds) || ageSeconds <= 0) return Math.max(minScore, baseScore);
391
- if (!Number.isFinite(ratePerSecond) || ratePerSecond <= 0) return Math.max(minScore, baseScore);
392
- const decayed = baseScore * Math.exp(-ratePerSecond * ageSeconds);
393
- return Math.max(minScore, decayed);
394
- }
395
- function assertMaxSize(maxSize) {
396
- if (maxSize !== void 0 && maxSize < 1) {
397
- throw new RangeError("maxSize must be >= 1");
398
- }
399
- }
400
- function copyMap(m) {
401
- return new Map(m);
402
- }
403
- function readMap(node2) {
404
- return node2.cache ?? /* @__PURE__ */ new Map();
405
- }
406
- function readArray(node2) {
407
- return node2.cache ?? [];
408
- }
409
- function cosineSimilarity(a, b) {
410
- const n = Math.max(a.length, b.length);
411
- let dot = 0;
412
- let na = 0;
413
- let nb = 0;
414
- for (let i = 0; i < n; i += 1) {
415
- const av = a[i] ?? 0;
416
- const bv = b[i] ?? 0;
417
- dot += av * bv;
418
- na += av * av;
419
- nb += bv * bv;
420
- }
421
- if (na === 0 || nb === 0) return 0;
422
- return dot / Math.sqrt(na * nb);
423
- }
424
- function lightCollection(opts = {}) {
425
- const maxSize = opts.maxSize;
426
- const policy2 = opts.policy ?? "fifo";
427
- assertMaxSize(maxSize);
428
- const entries = state(/* @__PURE__ */ new Map(), {
429
- name: opts.name,
430
- describeKind: "state"
431
- });
432
- function evictIfNeeded(next) {
433
- if (maxSize === void 0) return;
434
- while (next.size > maxSize) {
435
- let victim;
436
- for (const entry of next.values()) {
437
- if (!victim) {
438
- victim = entry;
439
- continue;
440
- }
441
- const lhs = policy2 === "lru" ? entry.lastAccessNs : entry.createdAtNs;
442
- const rhs = policy2 === "lru" ? victim.lastAccessNs : victim.createdAtNs;
443
- if (lhs < rhs) victim = entry;
444
- }
445
- if (!victim) break;
446
- next.delete(victim.id);
447
- }
448
- }
449
- function commit(next) {
450
- entries.down([[DATA, next]]);
451
- }
452
- return {
453
- entries,
454
- upsert(id, value) {
455
- const now = monotonicNs();
456
- const current = readMap(entries);
457
- const prev = current.get(id);
458
- const next = copyMap(current);
459
- next.set(id, {
460
- id,
461
- value,
462
- createdAtNs: prev?.createdAtNs ?? now,
463
- lastAccessNs: now
464
- });
465
- evictIfNeeded(next);
466
- commit(next);
467
- },
468
- remove(id) {
469
- const next = copyMap(readMap(entries));
470
- if (!next.delete(id)) return;
471
- commit(next);
472
- },
473
- clear() {
474
- if (readMap(entries).size === 0) return;
475
- commit(/* @__PURE__ */ new Map());
476
- },
477
- get(id) {
478
- const current = readMap(entries);
479
- const found = current.get(id);
480
- if (!found) return void 0;
481
- if (policy2 === "lru") {
482
- const now = monotonicNs();
483
- const next = copyMap(current);
484
- next.set(id, { ...found, lastAccessNs: now });
485
- commit(next);
486
- }
487
- return found.value;
488
- },
489
- has(id) {
490
- return readMap(entries).has(id);
491
- }
492
- };
493
- }
494
- function collection(name, opts = {}) {
495
- const maxSize = opts.maxSize;
496
- const policy2 = opts.policy ?? "lru";
497
- const decayRate = opts.decayRate ?? 0;
498
- const minScore = opts.minScore ?? 0;
499
- const scoreFn = opts.score ?? (() => 1);
500
- assertMaxSize(maxSize);
501
- const graph = new Graph(name);
502
- const items = state(/* @__PURE__ */ new Map(), {
503
- name: "items",
504
- describeKind: "state"
505
- });
506
- const ranked = derived(
507
- [items],
508
- ([snapshot]) => {
509
- const typed = snapshot ?? /* @__PURE__ */ new Map();
510
- const now = monotonicNs();
511
- const out2 = [...typed.values()].map((entry) => {
512
- const ageSeconds = (now - entry.lastAccessNs) / 1e9;
513
- return {
514
- ...entry,
515
- score: decay(entry.baseScore, ageSeconds, decayRate, minScore)
516
- };
517
- });
518
- out2.sort((a, b) => b.score - a.score || b.lastAccessNs - a.lastAccessNs);
519
- return out2;
520
- },
521
- { name: "ranked", describeKind: "derived" }
522
- );
523
- const size = derived(
524
- [items],
525
- ([snapshot]) => (snapshot ?? /* @__PURE__ */ new Map()).size,
526
- {
527
- name: "size",
528
- describeKind: "derived",
529
- initial: 0
530
- }
531
- );
532
- void ranked.subscribe(() => void 0);
533
- void size.subscribe(() => void 0);
534
- graph.add("items", items);
535
- graph.add("ranked", ranked);
536
- graph.add("size", size);
537
- function effective(entry, now) {
538
- const ageSeconds = (now - entry.lastAccessNs) / 1e9;
539
- return decay(entry.baseScore, ageSeconds, decayRate, minScore);
540
- }
541
- function evictIfNeeded(next) {
542
- if (maxSize === void 0) return;
543
- while (next.size > maxSize) {
544
- const now = monotonicNs();
545
- let victim;
546
- let victimScore = Number.POSITIVE_INFINITY;
547
- for (const entry of next.values()) {
548
- const score = effective(entry, now);
549
- if (score < victimScore) {
550
- victim = entry;
551
- victimScore = score;
552
- continue;
553
- }
554
- if (score === victimScore && victim) {
555
- const lhs = policy2 === "lru" ? entry.lastAccessNs : entry.createdAtNs;
556
- const rhs = policy2 === "lru" ? victim.lastAccessNs : victim.createdAtNs;
557
- if (lhs < rhs) victim = entry;
558
- }
559
- }
560
- if (!victim) break;
561
- next.delete(victim.id);
562
- }
563
- }
564
- function commit(next) {
565
- items.down([[DATA, next]]);
566
- }
567
- const out = Object.assign(graph, {
568
- upsert(id, value, upsertOpts) {
569
- const now = monotonicNs();
570
- const current = readMap(items);
571
- const prev = current.get(id);
572
- const baseScore = upsertOpts?.score ?? scoreFn(value);
573
- const next = copyMap(current);
574
- next.set(id, {
575
- id,
576
- value,
577
- baseScore,
578
- createdAtNs: prev?.createdAtNs ?? now,
579
- lastAccessNs: now
580
- });
581
- evictIfNeeded(next);
582
- commit(next);
583
- },
584
- remove(id) {
585
- const next = copyMap(readMap(items));
586
- if (!next.delete(id)) return;
587
- commit(next);
588
- },
589
- clear() {
590
- if (readMap(items).size === 0) return;
591
- commit(/* @__PURE__ */ new Map());
592
- },
593
- getItem(id) {
594
- const current = readMap(items);
595
- const found = current.get(id);
596
- if (!found) return void 0;
597
- if (policy2 === "lru") {
598
- const next = copyMap(current);
599
- next.set(id, { ...found, lastAccessNs: monotonicNs() });
600
- commit(next);
601
- }
602
- return found;
603
- }
604
- });
605
- return out;
606
- }
607
- function vectorIndex(opts = {}) {
608
- const backend = opts.backend ?? "flat";
609
- const dimension = opts.dimension;
610
- let hnsw;
611
- if (backend === "hnsw") {
612
- hnsw = opts.hnswFactory?.();
613
- if (!hnsw) {
614
- throw new Error(
615
- 'vectorIndex backend "hnsw" requires an optional dependency adapter; install your HNSW package and provide `hnswFactory`.'
616
- );
617
- }
618
- }
619
- const entries = state(/* @__PURE__ */ new Map(), {
620
- describeKind: "state",
621
- name: "vector-index"
622
- });
623
- function assertDimension(vector) {
624
- if (dimension !== void 0 && vector.length !== dimension) {
625
- throw new RangeError(
626
- `vector dimension mismatch: expected ${dimension}, got ${vector.length}`
627
- );
628
- }
629
- }
630
- function commit(next) {
631
- entries.down([[DATA, next]]);
632
- }
633
- return {
634
- backend,
635
- entries,
636
- upsert(id, vector, meta) {
637
- assertDimension(vector);
638
- const next = copyMap(readMap(entries));
639
- next.set(id, { id, vector: [...vector], meta });
640
- if (backend === "hnsw") hnsw.upsert(id, vector, meta);
641
- commit(next);
642
- },
643
- remove(id) {
644
- const next = copyMap(readMap(entries));
645
- if (!next.delete(id)) return;
646
- if (backend === "hnsw") hnsw.remove(id);
647
- commit(next);
648
- },
649
- clear() {
650
- if (readMap(entries).size === 0) return;
651
- if (backend === "hnsw") hnsw.clear();
652
- commit(/* @__PURE__ */ new Map());
653
- },
654
- search(query, k = 5) {
655
- assertDimension(query);
656
- if (k <= 0) return [];
657
- if (backend === "hnsw") return hnsw.search(query, k);
658
- const ranked = [...readMap(entries).values()].map((row) => ({
659
- id: row.id,
660
- score: cosineSimilarity(query, row.vector),
661
- meta: row.meta
662
- })).sort((a, b) => b.score - a.score).slice(0, k);
663
- return ranked;
664
- }
665
- };
666
- }
667
- function knowledgeGraph(name) {
668
- const graph = new Graph(name);
669
- const entities = state(/* @__PURE__ */ new Map(), {
670
- name: "entities",
671
- describeKind: "state"
672
- });
673
- const edges = state([], {
674
- name: "edges",
675
- describeKind: "state"
676
- });
677
- const adjacency = derived(
678
- [edges],
679
- ([rows]) => {
680
- const typed = rows ?? [];
681
- const out2 = /* @__PURE__ */ new Map();
682
- for (const edge of typed) {
683
- const prev = out2.get(edge.from) ?? [];
684
- out2.set(edge.from, Object.freeze([...prev, edge]));
685
- }
686
- return out2;
687
- },
688
- { name: "adjacency", describeKind: "derived", initial: /* @__PURE__ */ new Map() }
689
- );
690
- void adjacency.subscribe(() => void 0);
691
- graph.add("entities", entities);
692
- graph.add("edges", edges);
693
- graph.add("adjacency", adjacency);
694
- function commitEntities(next) {
695
- entities.down([[DATA, next]]);
696
- }
697
- function commitEdges(next) {
698
- edges.down([[DATA, next]]);
699
- }
700
- const out = Object.assign(graph, {
701
- upsertEntity(id, value) {
702
- const next = copyMap(readMap(entities));
703
- next.set(id, value);
704
- commitEntities(next);
705
- },
706
- removeEntity(id) {
707
- const nextEntities = copyMap(readMap(entities));
708
- const existed = nextEntities.delete(id);
709
- const currentEdges = readArray(edges);
710
- const nextEdges = currentEdges.filter((edge) => edge.from !== id && edge.to !== id);
711
- if (!existed && nextEdges.length === currentEdges.length) return;
712
- commitEntities(nextEntities);
713
- commitEdges(nextEdges);
714
- },
715
- link(from, to, relation, weight = 1) {
716
- const key = `${from}\0${to}\0${relation}`;
717
- const currentEdges = readArray(edges);
718
- const existing = new Set(
719
- currentEdges.map((edge) => `${edge.from}\0${edge.to}\0${edge.relation}`)
720
- );
721
- const next = [...currentEdges];
722
- if (existing.has(key)) {
723
- for (let i = 0; i < next.length; i += 1) {
724
- const edge = next[i];
725
- if (edge.from === from && edge.to === to && edge.relation === relation) {
726
- next[i] = { ...edge, weight };
727
- break;
728
- }
729
- }
730
- } else {
731
- next.push({ from, to, relation, weight });
732
- }
733
- commitEdges(next);
734
- },
735
- unlink(from, to, relation) {
736
- const currentEdges = readArray(edges);
737
- const next = currentEdges.filter(
738
- (edge) => relation === void 0 ? !(edge.from === from && edge.to === to) : !(edge.from === from && edge.to === to && edge.relation === relation)
739
- );
740
- if (next.length === currentEdges.length) return;
741
- commitEdges(next);
742
- },
743
- related(id, relation) {
744
- return readArray(edges).filter(
745
- (edge) => (edge.from === id || edge.to === id) && (relation === void 0 || edge.relation === relation)
746
- );
747
- }
748
- });
749
- return out;
750
- }
751
-
752
- // src/patterns/messaging.ts
753
- var messaging_exports = {};
754
- __export(messaging_exports, {
755
- JobFlowGraph: () => JobFlowGraph,
756
- JobQueueGraph: () => JobQueueGraph,
757
- MessagingHubGraph: () => MessagingHubGraph,
758
- SubscriptionGraph: () => SubscriptionGraph,
759
- TopicBridgeGraph: () => TopicBridgeGraph,
760
- TopicGraph: () => TopicGraph,
761
- jobFlow: () => jobFlow,
762
- jobQueue: () => jobQueue,
763
- messagingHub: () => messagingHub,
764
- subscription: () => subscription,
765
- topic: () => topic,
766
- topicBridge: () => topicBridge
767
- });
768
- var DEFAULT_MAX_PER_PUMP = 2147483647;
769
- function requireNonNegativeInt(value, label) {
770
- if (!Number.isFinite(value) || !Number.isInteger(value) || value < 0) {
771
- throw new Error(`${label} must be a non-negative integer`);
772
- }
773
- return value;
774
- }
775
- function messagingMeta(kind, extra) {
776
- return domainMeta("messaging", kind, extra);
777
- }
778
- var TopicGraph = class extends Graph {
779
- _log;
780
- events;
781
- /**
782
- * Most recently published value, or `null` when the topic has no entries
783
- * yet. Spec §5.12 reserves `undefined` as the protocol-internal "never
784
- * sent DATA" sentinel — `null` is the idiomatic "empty / no value" signal
785
- * for domain nodes. F7.
786
- *
787
- * **Caveat when `T` itself includes `null`** (e.g., `topic<number | null>`):
788
- * `latest === null` is ambiguous — it could mean "no publish yet" OR "a
789
- * `null` value was published". Use {@link hasLatest} to disambiguate, or
790
- * observe {@link events} directly and track length yourself.
791
- */
792
- latest;
793
- /**
794
- * Reactive `true` once the topic has at least one published entry.
795
- * Disambiguates "`null` never published" from "`null` was published" when
796
- * `T` includes `null`.
797
- */
798
- hasLatest;
799
- constructor(name, opts = {}) {
800
- super(name, opts.graph);
801
- this._log = reactiveLog([], { name: "events", maxSize: opts.retainedLimit });
802
- this.events = this._log.entries;
803
- this.add("events", this.events);
804
- this.latest = derived(
805
- [this.events],
806
- ([snapshot]) => {
807
- const entries = snapshot;
808
- return entries.length === 0 ? null : entries[entries.length - 1];
809
- },
810
- {
811
- name: "latest",
812
- describeKind: "derived",
813
- meta: messagingMeta("topic_latest")
814
- }
815
- );
816
- this.add("latest", this.latest);
817
- this.addDisposer(keepalive(this.latest));
818
- this.hasLatest = derived(
819
- [this.events],
820
- ([snapshot]) => snapshot.length > 0,
821
- {
822
- name: "hasLatest",
823
- describeKind: "derived",
824
- meta: messagingMeta("topic_has_latest")
825
- }
826
- );
827
- this.add("hasLatest", this.hasLatest);
828
- this.addDisposer(keepalive(this.hasLatest));
829
- this.addDisposer(() => {
830
- this.events.down([[COMPLETE]]);
831
- });
832
- this.addDisposer(() => this._log.disposeAllViews());
833
- }
834
- publish(value) {
835
- this._log.append(value);
836
- }
837
- retained() {
838
- return this.events.cache;
839
- }
840
- };
841
- var SubscriptionGraph = class extends Graph {
842
- source;
843
- cursor;
844
- available;
845
- /**
846
- * Reference to the upstream topic graph. Intentionally NOT mounted
847
- * under this subscription: a subscription is a VIEW over an
848
- * externally-owned topic. Double-mounting (e.g. hub-owned topic +
849
- * sub-mount here) would make either-side teardown leave the other
850
- * holding a dead reference. Node-level `derived([topicEvents], …)`
851
- * still wires the data dependency across graph boundaries. D1(e).
852
- */
853
- topic;
854
- constructor(name, topicGraph, opts = {}) {
855
- super(name, opts.graph);
856
- const initialCursor = requireNonNegativeInt(opts.cursor ?? 0, "subscription cursor");
857
- this.topic = topicGraph;
858
- const topicEvents = topicGraph.events;
859
- this.source = derived([topicEvents], ([snapshot]) => snapshot, {
860
- name: "source",
861
- describeKind: "derived",
862
- meta: messagingMeta("subscription_source"),
863
- initial: topicEvents.cache
864
- });
865
- this.add("source", this.source);
866
- this.cursor = state(initialCursor, {
867
- name: "cursor",
868
- describeKind: "state",
869
- meta: messagingMeta("subscription_cursor")
870
- });
871
- this.add("cursor", this.cursor);
872
- this.available = derived(
873
- [this.source, this.cursor],
874
- ([sourceSnapshot, cursor]) => {
875
- const entries = sourceSnapshot;
876
- const start = Math.max(0, Math.trunc(cursor ?? 0));
877
- return entries.slice(start);
878
- },
879
- {
880
- name: "available",
881
- describeKind: "derived",
882
- meta: messagingMeta("subscription_available"),
883
- initial: []
884
- }
885
- );
886
- this.add("available", this.available);
887
- this.addDisposer(keepalive(this.source));
888
- this.addDisposer(keepalive(this.available));
889
- }
890
- ack(count) {
891
- const available = this.available.cache;
892
- const requested = count === void 0 ? available.length : requireNonNegativeInt(count, "subscription ack count");
893
- const step = Math.min(requested, available.length);
894
- if (step <= 0) return this.cursor.cache;
895
- const next = this.cursor.cache + step;
896
- this.cursor.emit(next);
897
- return next;
898
- }
899
- pull(limit, opts = {}) {
900
- const available = this.available.cache;
901
- const max = limit === void 0 ? available.length : requireNonNegativeInt(limit, "subscription pull limit");
902
- const out = available.slice(0, max);
903
- if (opts.ack && out.length > 0) this.ack(out.length);
904
- return out;
905
- }
906
- };
907
- var JobQueueGraph = class extends Graph {
908
- _pending;
909
- _jobs;
910
- _seq = 0;
911
- pending;
912
- jobs;
913
- depth;
914
- constructor(name, opts = {}) {
915
- super(name, opts.graph);
916
- this._pending = reactiveList([], { name: "pending" });
917
- this._jobs = reactiveMap({ name: "jobs" });
918
- this.pending = this._pending.items;
919
- this.jobs = this._jobs.entries;
920
- this.add("pending", this.pending);
921
- this.add("jobs", this.jobs);
922
- this.depth = derived([this.pending], ([snapshot]) => snapshot.length, {
923
- name: "depth",
924
- describeKind: "derived",
925
- meta: messagingMeta("queue_depth"),
926
- initial: 0
927
- });
928
- this.add("depth", this.depth);
929
- this.addDisposer(keepalive(this.depth));
930
- }
931
- enqueue(payload, opts = {}) {
932
- const id = opts.id ?? `${this.name}-${++this._seq}`;
933
- if (this._jobs.get(id) !== void 0) {
934
- throw new Error(`jobQueue("${this.name}"): duplicate job id "${id}"`);
935
- }
936
- const job = {
937
- id,
938
- payload,
939
- attempts: 0,
940
- metadata: Object.freeze({ ...opts.metadata ?? {} }),
941
- state: "queued"
942
- };
943
- this._jobs.set(id, job);
944
- this._pending.append(id);
945
- return id;
946
- }
947
- claim(limit = 1) {
948
- const max = requireNonNegativeInt(limit, "job queue claim limit");
949
- if (max === 0) return [];
950
- const out = [];
951
- while (out.length < max) {
952
- const ids = this.pending.cache;
953
- if (ids.length === 0) break;
954
- const id = this._pending.pop(0);
955
- const job = this._jobs.get(id);
956
- if (!job || job.state !== "queued") continue;
957
- const inflight = {
958
- ...job,
959
- state: "inflight",
960
- attempts: job.attempts + 1
961
- };
962
- this._jobs.set(id, inflight);
963
- out.push(inflight);
964
- }
965
- return out;
966
- }
967
- ack(id) {
968
- const job = this._jobs.get(id);
969
- if (!job || job.state !== "inflight") return false;
970
- this._jobs.delete(id);
971
- return true;
972
- }
973
- nack(id, opts = {}) {
974
- const job = this._jobs.get(id);
975
- if (!job || job.state !== "inflight") return false;
976
- if (opts.requeue ?? true) {
977
- this._jobs.set(id, { ...job, state: "queued" });
978
- this._pending.append(id);
979
- return true;
980
- }
981
- this._jobs.delete(id);
982
- return true;
983
- }
984
- };
985
- var JobFlowGraph = class extends Graph {
986
- _stageNames;
987
- _queues = /* @__PURE__ */ new Map();
988
- _completed;
989
- completed;
990
- completedCount;
991
- constructor(name, opts = {}) {
992
- super(name, opts.graph);
993
- const stages = (opts.stages ?? ["incoming", "processing", "done"]).map((v) => v.trim());
994
- if (stages.length < 2) {
995
- throw new Error(`jobFlow("${name}"): requires at least 2 stages`);
996
- }
997
- const unique = new Set(stages);
998
- if (unique.size !== stages.length) {
999
- throw new Error(`jobFlow("${name}"): stage names must be unique`);
1000
- }
1001
- this._stageNames = Object.freeze([...stages]);
1002
- for (const stage of this._stageNames) {
1003
- const q = jobQueue(`${name}-${stage}`);
1004
- this._queues.set(stage, q);
1005
- this.mount(stage, q);
1006
- }
1007
- this._completed = reactiveLog([], { name: "completed" });
1008
- this.completed = this._completed.entries;
1009
- this.add("completed", this.completed);
1010
- this.completedCount = derived(
1011
- [this.completed],
1012
- ([snapshot]) => snapshot.length,
1013
- {
1014
- name: "completedCount",
1015
- describeKind: "derived",
1016
- meta: messagingMeta("job_flow_completed_count"),
1017
- initial: 0
1018
- }
1019
- );
1020
- this.add("completedCount", this.completedCount);
1021
- this.addDisposer(keepalive(this.completedCount));
1022
- const maxPerPump = Math.max(
1023
- 1,
1024
- requireNonNegativeInt(opts.maxPerPump ?? DEFAULT_MAX_PER_PUMP, "job flow maxPerPump")
1025
- );
1026
- for (let i = 0; i < this._stageNames.length; i += 1) {
1027
- const stage = this._stageNames[i];
1028
- const current = this.queue(stage);
1029
- const next = i + 1 < this._stageNames.length ? this.queue(this._stageNames[i + 1]) : null;
1030
- const pump = node(
1031
- [current.pending],
1032
- () => {
1033
- let moved = 0;
1034
- while (moved < maxPerPump) {
1035
- const claim = current.claim(1);
1036
- if (claim.length === 0) break;
1037
- const job = claim[0];
1038
- if (!job) break;
1039
- if (next) {
1040
- next.enqueue(job.payload, {
1041
- metadata: {
1042
- ...job.metadata,
1043
- job_flow_from: stage
1044
- }
1045
- });
1046
- } else {
1047
- this._completed.append(job);
1048
- }
1049
- current.ack(job.id);
1050
- moved += 1;
1051
- }
1052
- },
1053
- {
1054
- name: `pump_${stage}`,
1055
- describeKind: "effect",
1056
- meta: messagingMeta("job_flow_pump")
1057
- }
1058
- );
1059
- this.add(`pump_${stage}`, pump);
1060
- this.addDisposer(keepalive(pump));
1061
- }
1062
- }
1063
- stages() {
1064
- return this._stageNames;
1065
- }
1066
- queue(stage) {
1067
- const q = this._queues.get(stage);
1068
- if (!q) throw new Error(`jobFlow("${this.name}"): unknown stage "${stage}"`);
1069
- return q;
1070
- }
1071
- enqueue(payload, opts = {}) {
1072
- return this.queue(this._stageNames[0]).enqueue(payload, opts);
1073
- }
1074
- retainedCompleted() {
1075
- return this.completed.cache;
1076
- }
1077
- };
1078
- var TopicBridgeGraph = class extends Graph {
1079
- _sourceSub;
1080
- _target;
1081
- bridgedCount;
1082
- constructor(name, sourceTopic, targetTopic, opts = {}) {
1083
- super(name, opts.graph);
1084
- this._sourceSub = subscription(`${name}-subscription`, sourceTopic, {
1085
- cursor: opts.cursor
1086
- });
1087
- this._target = targetTopic;
1088
- this.mount("subscription", this._sourceSub);
1089
- this.bridgedCount = state(0, {
1090
- name: "bridgedCount",
1091
- describeKind: "state",
1092
- meta: messagingMeta("topic_bridge_count")
1093
- });
1094
- this.add("bridgedCount", this.bridgedCount);
1095
- const maxPerPump = Math.max(
1096
- 1,
1097
- requireNonNegativeInt(opts.maxPerPump ?? DEFAULT_MAX_PER_PUMP, "topic bridge maxPerPump")
1098
- );
1099
- const mapValue = opts.map ?? ((value) => value);
1100
- const pump = node(
1101
- [this._sourceSub.available],
1102
- () => {
1103
- const available = this._sourceSub.pull(maxPerPump, { ack: true });
1104
- if (available.length === 0) return;
1105
- let bridged = 0;
1106
- for (const value of available) {
1107
- const mapped = mapValue(value);
1108
- if (mapped === void 0) continue;
1109
- this._target.publish(mapped);
1110
- bridged += 1;
1111
- }
1112
- if (bridged > 0) {
1113
- const current = this.bridgedCount.cache;
1114
- this.bridgedCount.down([[DATA, current + bridged]]);
1115
- }
1116
- },
1117
- {
1118
- name: "pump",
1119
- describeKind: "effect",
1120
- meta: messagingMeta("topic_bridge_pump")
1121
- }
1122
- );
1123
- this.add("pump", pump);
1124
- this.addDisposer(keepalive(pump));
1125
- }
1126
- };
1127
- var MessagingHubGraph = class extends Graph {
1128
- _topics = /* @__PURE__ */ new Map();
1129
- _version = 0;
1130
- _defaultTopicOptions;
1131
- constructor(name, opts = {}) {
1132
- super(name, opts.graph);
1133
- this._defaultTopicOptions = { ...opts.defaultTopicOptions ?? {} };
1134
- }
1135
- /** Monotonic counter advancing on topic create/remove. */
1136
- get version() {
1137
- return this._version;
1138
- }
1139
- /** Number of topics currently in the hub. */
1140
- get size() {
1141
- return this._topics.size;
1142
- }
1143
- /** Checks topic existence without creating. */
1144
- has(name) {
1145
- return this._topics.has(name);
1146
- }
1147
- /** Iterator over topic names. */
1148
- topicNames() {
1149
- return this._topics.keys();
1150
- }
1151
- /**
1152
- * Returns the {@link TopicGraph} for `name`, creating lazily on first call.
1153
- * Subsequent calls with the same name return the same instance (options on
1154
- * repeat calls are ignored — the topic is already configured).
1155
- */
1156
- topic(name, opts) {
1157
- let t = this._topics.get(name);
1158
- if (t === void 0) {
1159
- const effective = { ...this._defaultTopicOptions, ...opts ?? {} };
1160
- t = new TopicGraph(name, effective);
1161
- this._topics.set(name, t);
1162
- this.mount(name, t);
1163
- this._version += 1;
1164
- }
1165
- return t;
1166
- }
1167
- /**
1168
- * Publishes a value to the topic, lazily creating it on first publish.
1169
- *
1170
- * **Late-subscriber caveat:** the topic is created lazily, so subscribers
1171
- * that attach AFTER a publish only see the retained window (governed by
1172
- * `retainedLimit` on `TopicOptions` / `defaultTopicOptions`). If
1173
- * `retainedLimit === 0` is set explicitly, early publishes are
1174
- * effectively dropped — prefer an unset `retainedLimit` (unbounded
1175
- * retention) or subscribe before publishing when late-subscribers matter.
1176
- */
1177
- publish(name, value) {
1178
- this.topic(name).publish(value);
1179
- }
1180
- /**
1181
- * Bulk publish — issues all publishes inside one outer batch. New topics
1182
- * are created on demand. No-op if `entries` yields nothing.
1183
- *
1184
- * **Iterable consumption (F6):** `entries` is consumed once (single-pass)
1185
- * INSIDE the batch frame. If the iterator throws mid-way, the batch is
1186
- * discarded and NO publishes are visible to subscribers (all-or-nothing).
1187
- * Pass an array or `Set` for multi-shot callers.
1188
- */
1189
- publishMany(entries) {
1190
- batch(() => {
1191
- for (const [name, value] of entries) {
1192
- this.topic(name).publish(value);
1193
- }
1194
- });
1195
- }
1196
- /**
1197
- * Creates a {@link SubscriptionGraph} over a named topic. The topic is
1198
- * lazily created if missing. Subscription lifecycle is owned by the caller —
1199
- * the hub does NOT mount the subscription.
1200
- *
1201
- * @param subName - Local name for the subscription graph.
1202
- * @param topicName - Hub topic to subscribe to.
1203
- * @param opts - `SubscriptionOptions` (initial cursor, etc.).
1204
- */
1205
- subscribe(subName, topicName, opts) {
1206
- const t = this.topic(topicName);
1207
- return new SubscriptionGraph(subName, t, opts);
1208
- }
1209
- /**
1210
- * Unmounts and tears down the topic's graph. Returns `true` if the topic
1211
- * existed. Subscribers receive `TEARDOWN` via {@link Graph.remove}.
1212
- */
1213
- removeTopic(name) {
1214
- if (!this._topics.has(name)) return false;
1215
- try {
1216
- this.remove(name);
1217
- } finally {
1218
- this._topics.delete(name);
1219
- this._version += 1;
1220
- }
1221
- return true;
1222
- }
1223
- };
1224
- function topic(name, opts) {
1225
- return new TopicGraph(name, opts);
1226
- }
1227
- function messagingHub(name, opts) {
1228
- return new MessagingHubGraph(name, opts);
1229
- }
1230
- function subscription(name, topicGraph, opts) {
1231
- return new SubscriptionGraph(name, topicGraph, opts);
1232
- }
1233
- function jobQueue(name, opts) {
1234
- return new JobQueueGraph(name, opts);
1235
- }
1236
- function jobFlow(name, opts) {
1237
- return new JobFlowGraph(name, opts);
1238
- }
1239
- function topicBridge(name, sourceTopic, targetTopic, opts) {
1240
- return new TopicBridgeGraph(name, sourceTopic, targetTopic, opts);
1241
- }
1242
-
1243
- // src/patterns/orchestration.ts
1244
- var orchestration_exports = {};
1245
- __export(orchestration_exports, {
1246
- approval: () => approval,
1247
- branch: () => branch,
1248
- forEach: () => forEach2,
1249
- gate: () => gate,
1250
- join: () => join,
1251
- loop: () => loop,
1252
- onFailure: () => onFailure,
1253
- pipeline: () => pipeline,
1254
- sensor: () => sensor,
1255
- subPipeline: () => subPipeline,
1256
- task: () => task,
1257
- valve: () => valve2,
1258
- wait: () => wait
1259
- });
1260
- function resolveDep(graph, dep) {
1261
- if (typeof dep === "string") {
1262
- return { node: graph.resolve(dep), path: dep };
1263
- }
1264
- const path = findRegisteredNodePath(graph, dep);
1265
- if (!path) {
1266
- throw new Error(
1267
- "orchestration dep node must already be registered in the graph so explicit edges can be recorded; pass a string path or register the node first"
1268
- );
1269
- }
1270
- return { node: dep, path };
1271
- }
1272
- function findRegisteredNodePath(graph, target) {
1273
- const described = graph.describe();
1274
- const metaSegment = `::${GRAPH_META_SEGMENT}::`;
1275
- for (const path of Object.keys(described.nodes).sort()) {
1276
- if (path.includes(metaSegment)) continue;
1277
- try {
1278
- if (graph.resolve(path) === target) return path;
1279
- } catch {
1280
- }
1281
- }
1282
- return void 0;
1283
- }
1284
- function registerStep(graph, name, step, depPaths) {
1285
- graph.add(name, step);
1286
- void depPaths;
1287
- }
1288
- function baseMeta(kind, meta) {
1289
- return domainMeta("orchestration", kind, meta);
1290
- }
1291
- function coerceLoopIterations(raw) {
1292
- const parseString = (value) => {
1293
- const trimmed = value.trim();
1294
- if (trimmed.length === 0) return 0;
1295
- return Number(trimmed);
1296
- };
1297
- let parsed;
1298
- if (typeof raw === "string") {
1299
- parsed = parseString(raw);
1300
- } else if (raw === null) {
1301
- parsed = 0;
1302
- } else {
1303
- parsed = Number(raw);
1304
- }
1305
- if (!Number.isFinite(parsed)) return 1;
1306
- return Math.max(0, Math.trunc(parsed));
1307
- }
1308
- function pipeline(name, opts) {
1309
- return new Graph(name, opts);
1310
- }
1311
- function task(graph, name, run, opts) {
1312
- const depRefs = opts?.deps ?? [];
1313
- const deps = depRefs.map((dep) => resolveDep(graph, dep));
1314
- const { deps: _deps, ...nodeOpts } = opts ?? {};
1315
- const wrapped = (batchData, actions, ctx) => {
1316
- const data = batchData.map(
1317
- (batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
1318
- );
1319
- actions.emit(run(data, ctx));
1320
- return void 0;
1321
- };
1322
- const step = node(
1323
- deps.map((d) => d.node),
1324
- wrapped,
1325
- {
1326
- ...nodeOpts,
1327
- name,
1328
- describeKind: "derived",
1329
- meta: baseMeta("task", opts?.meta)
1330
- }
1331
- );
1332
- registerStep(
1333
- graph,
1334
- name,
1335
- step,
1336
- deps.flatMap((d) => d.path ? [d.path] : [])
1337
- );
1338
- return step;
1339
- }
1340
- function branch(graph, name, source, predicate, opts) {
1341
- const src = resolveDep(graph, source);
1342
- const step = derived(
1343
- [src.node],
1344
- ([value]) => ({
1345
- branch: predicate(value) ? "then" : "else",
1346
- value
1347
- }),
1348
- {
1349
- ...opts,
1350
- name,
1351
- meta: baseMeta("branch", opts?.meta)
1352
- }
1353
- );
1354
- registerStep(graph, name, step, src.path ? [src.path] : []);
1355
- return step;
1356
- }
1357
- function valve2(graph, name, source, control, opts) {
1358
- const src = resolveDep(graph, source);
1359
- const ctrl = resolveDep(graph, control);
1360
- const step = node(
1361
- [src.node, ctrl.node],
1362
- (batchData, actions, ctx) => {
1363
- const batch0 = batchData[0];
1364
- const batch1 = batchData[1];
1365
- const ctrlVal = batch1 != null && batch1.length > 0 ? batch1.at(-1) : ctx.prevData[1];
1366
- if (batch0 == null || batch0.length === 0) {
1367
- if (batch1 != null && batch1.length > 0 && ctrlVal && ctx.prevData[0] !== void 0) {
1368
- actions.emit(ctx.prevData[0]);
1369
- } else {
1370
- actions.down([[RESOLVED]]);
1371
- }
1372
- return;
1373
- }
1374
- if (!ctrlVal) {
1375
- actions.down([[RESOLVED]]);
1376
- return;
1377
- }
1378
- for (const v of batch0) actions.emit(v);
1379
- },
1380
- {
1381
- ...opts,
1382
- name,
1383
- describeKind: "derived",
1384
- meta: baseMeta("valve", opts?.meta)
1385
- }
1386
- );
1387
- registerStep(
1388
- graph,
1389
- name,
1390
- step,
1391
- [src.path, ctrl.path].filter((v) => typeof v === "string")
1392
- );
1393
- return step;
1394
- }
1395
- function approval(graph, name, source, approver, opts) {
1396
- const src = resolveDep(graph, source);
1397
- const ctrl = resolveDep(graph, approver);
1398
- const isApproved = opts?.isApproved ?? ((value) => Boolean(value));
1399
- const step = node(
1400
- [src.node, ctrl.node],
1401
- (batchData, actions, ctx) => {
1402
- const batch0 = batchData[0];
1403
- const batch1 = batchData[1];
1404
- const ctrlVal = batch1 != null && batch1.length > 0 ? batch1.at(-1) : ctx.prevData[1];
1405
- if (ctrlVal === void 0 || !isApproved(ctrlVal)) {
1406
- actions.down([[RESOLVED]]);
1407
- return;
1408
- }
1409
- if (batch0 == null || batch0.length === 0) {
1410
- if (batch1 != null && batch1.length > 0 && ctx.prevData[0] !== void 0) {
1411
- actions.emit(ctx.prevData[0]);
1412
- } else {
1413
- actions.down([[RESOLVED]]);
1414
- }
1415
- return;
1416
- }
1417
- for (const v of batch0) actions.emit(v);
1418
- },
1419
- {
1420
- ...opts,
1421
- name,
1422
- describeKind: "derived",
1423
- meta: baseMeta("approval", opts?.meta)
1424
- }
1425
- );
1426
- registerStep(
1427
- graph,
1428
- name,
1429
- step,
1430
- [src.path, ctrl.path].filter((v) => typeof v === "string")
1431
- );
1432
- return step;
1433
- }
1434
- function gate(graph, name, source, opts) {
1435
- const maxPending = opts?.maxPending ?? Infinity;
1436
- if (maxPending < 1 && maxPending !== Infinity) {
1437
- throw new RangeError("gate: maxPending must be >= 1");
1438
- }
1439
- const startOpen = opts?.startOpen ?? false;
1440
- const src = resolveDep(graph, source);
1441
- const pendingNode = state([], { name: "pending", equals: () => false });
1442
- const isOpenNode = state(startOpen, { name: "isOpen" });
1443
- const countNode = derived([pendingNode], ([arr]) => arr.length, {
1444
- name: "count"
1445
- });
1446
- let queue = [];
1447
- let torn = false;
1448
- let latestIsOpen = startOpen;
1449
- const isOpenUnsub = isOpenNode.subscribe((msgs) => {
1450
- for (const m of msgs) {
1451
- if (m[0] === DATA) latestIsOpen = m[1];
1452
- }
1453
- });
1454
- function syncPending() {
1455
- pendingNode.down([[DATA, [...queue]]]);
1456
- }
1457
- function enqueue(value) {
1458
- queue.push(value);
1459
- if (queue.length > maxPending) queue.shift();
1460
- syncPending();
1461
- }
1462
- function dequeue(n) {
1463
- const items = queue.splice(0, n);
1464
- syncPending();
1465
- return items;
1466
- }
1467
- function guardTorn(method) {
1468
- if (torn) throw new Error(`gate: ${method}() called after gate was torn down`);
1469
- }
1470
- const output = node(
1471
- [src.node],
1472
- (batchData, actions, ctx) => {
1473
- const terminal = ctx.terminalDeps[0];
1474
- if (terminal !== void 0) {
1475
- torn = true;
1476
- queue = [];
1477
- syncPending();
1478
- actions.down(terminal === true ? [[COMPLETE]] : [[ERROR, terminal]]);
1479
- return;
1480
- }
1481
- const batch0 = batchData[0];
1482
- if (batch0 == null || batch0.length === 0) {
1483
- actions.down([[RESOLVED]]);
1484
- return;
1485
- }
1486
- for (const v of batch0) {
1487
- if (latestIsOpen) {
1488
- actions.emit(v);
1489
- } else {
1490
- enqueue(v);
1491
- actions.down([[RESOLVED]]);
1492
- }
1493
- }
1494
- },
1495
- {
1496
- name,
1497
- describeKind: "derived",
1498
- meta: baseMeta("gate", opts?.meta)
1499
- }
1500
- );
1501
- const controller = {
1502
- node: output,
1503
- pending: pendingNode,
1504
- count: countNode,
1505
- isOpen: isOpenNode,
1506
- approve(count = 1) {
1507
- guardTorn("approve");
1508
- const items = dequeue(count);
1509
- for (const item of items) {
1510
- if (torn) break;
1511
- output.down([[DATA, item]]);
1512
- }
1513
- },
1514
- reject(count = 1) {
1515
- guardTorn("reject");
1516
- dequeue(count);
1517
- },
1518
- modify(fn, count = 1) {
1519
- guardTorn("modify");
1520
- const snapshot = [...queue];
1521
- const items = dequeue(count);
1522
- for (let i = 0; i < items.length; i++) {
1523
- if (torn) break;
1524
- output.down([[DATA, fn(items[i], i, snapshot)]]);
1525
- }
1526
- },
1527
- open() {
1528
- guardTorn("open");
1529
- batch(() => {
1530
- isOpenNode.down([[DATA, true]]);
1531
- const items = dequeue(queue.length);
1532
- for (const item of items) {
1533
- if (torn) break;
1534
- output.down([[DATA, item]]);
1535
- }
1536
- });
1537
- },
1538
- close() {
1539
- guardTorn("close");
1540
- isOpenNode.down([[DATA, false]]);
1541
- }
1542
- };
1543
- graph.addDisposer(countNode.subscribe(() => void 0));
1544
- graph.addDisposer(isOpenUnsub);
1545
- registerStep(graph, name, output, src.path ? [src.path] : []);
1546
- const internal = new Graph(`${name}_state`);
1547
- internal.add("pending", pendingNode);
1548
- internal.add("isOpen", isOpenNode);
1549
- internal.add("count", countNode);
1550
- graph.mount(`${name}_state`, internal);
1551
- return controller;
1552
- }
1553
- function forEach2(graph, name, source, run, opts) {
1554
- const src = resolveDep(graph, source);
1555
- let terminated = false;
1556
- const step = node(
1557
- [src.node],
1558
- (batchData, actions, ctx) => {
1559
- if (terminated) {
1560
- actions.down([[RESOLVED]]);
1561
- return;
1562
- }
1563
- const terminal = ctx.terminalDeps[0];
1564
- if (terminal !== void 0) {
1565
- terminated = true;
1566
- actions.down(terminal === true ? [[COMPLETE]] : [[ERROR, terminal]]);
1567
- return;
1568
- }
1569
- const batch0 = batchData[0];
1570
- if (batch0 == null || batch0.length === 0) {
1571
- actions.down([[RESOLVED]]);
1572
- return;
1573
- }
1574
- for (const v of batch0) {
1575
- try {
1576
- run(v, actions);
1577
- } catch (err) {
1578
- terminated = true;
1579
- actions.down([[ERROR, err]]);
1580
- return;
1581
- }
1582
- }
1583
- },
1584
- {
1585
- ...opts,
1586
- name,
1587
- describeKind: "effect",
1588
- completeWhenDepsComplete: false,
1589
- meta: baseMeta("forEach", opts?.meta)
1590
- }
1591
- );
1592
- registerStep(graph, name, step, src.path ? [src.path] : []);
1593
- return step;
1594
- }
1595
- function join(graph, name, deps, opts) {
1596
- const resolved = deps.map((dep) => resolveDep(graph, dep));
1597
- const step = derived(
1598
- resolved.map((d) => d.node),
1599
- (values) => values,
1600
- {
1601
- ...opts,
1602
- name,
1603
- meta: baseMeta("join", opts?.meta)
1604
- }
1605
- );
1606
- registerStep(
1607
- graph,
1608
- name,
1609
- step,
1610
- resolved.flatMap((d) => d.path ? [d.path] : [])
1611
- );
1612
- return step;
1613
- }
1614
- function loop(graph, name, source, iterate, opts) {
1615
- const src = resolveDep(graph, source);
1616
- const iterRef = opts?.iterations;
1617
- const iterDep = typeof iterRef === "number" || iterRef === void 0 ? void 0 : resolveDep(graph, iterRef);
1618
- const staticIterations = typeof iterRef === "number" ? iterRef : void 0;
1619
- const step = node(
1620
- iterDep ? [src.node, iterDep.node] : [src.node],
1621
- (depValues, actions, ctx) => {
1622
- const batch0 = depValues[0];
1623
- let current = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];
1624
- const batch1 = iterDep ? depValues[1] : void 0;
1625
- const rawCount = staticIterations ?? (iterDep ? batch1 != null && batch1.length > 0 ? batch1.at(-1) : ctx.prevData[1] : 1);
1626
- const count = coerceLoopIterations(rawCount);
1627
- for (let i = 0; i < count; i += 1) {
1628
- current = iterate(current, i, actions);
1629
- }
1630
- actions.emit(current);
1631
- },
1632
- {
1633
- ...opts,
1634
- name,
1635
- describeKind: "derived",
1636
- meta: baseMeta("loop", opts?.meta)
1637
- }
1638
- );
1639
- registerStep(
1640
- graph,
1641
- name,
1642
- step,
1643
- [src.path, iterDep?.path].filter((v) => typeof v === "string")
1644
- );
1645
- return step;
1646
- }
1647
- function subPipeline(graph, name, childOrBuild, opts) {
1648
- const child = childOrBuild instanceof Graph ? childOrBuild : pipeline(name, opts);
1649
- if (typeof childOrBuild === "function") {
1650
- childOrBuild(child);
1651
- }
1652
- graph.mount(name, child);
1653
- return child;
1654
- }
1655
- function sensor(graph, name, initial, opts) {
1656
- const source = node([], () => void 0, {
1657
- ...opts,
1658
- name,
1659
- initial,
1660
- describeKind: "producer",
1661
- meta: baseMeta("sensor", opts?.meta)
1662
- });
1663
- registerStep(graph, name, source, []);
1664
- return {
1665
- node: source,
1666
- push(value) {
1667
- source.down([[DATA, value]]);
1668
- },
1669
- error(err) {
1670
- source.down([[ERROR, err]]);
1671
- },
1672
- complete() {
1673
- source.down([[COMPLETE]]);
1674
- }
1675
- };
1676
- }
1677
- function wait(graph, name, source, ms, opts) {
1678
- const src = resolveDep(graph, source);
1679
- const timers = /* @__PURE__ */ new Set();
1680
- let terminated = false;
1681
- let completed = false;
1682
- function clearAllTimers() {
1683
- for (const id of timers) clearTimeout(id);
1684
- timers.clear();
1685
- }
1686
- const srcVal = src.node.cache;
1687
- const initialOpt = srcVal !== void 0 ? { initial: srcVal } : {};
1688
- const step = node(
1689
- [],
1690
- (_deps, actions) => {
1691
- clearAllTimers();
1692
- terminated = false;
1693
- completed = false;
1694
- const unsub = src.node.subscribe((msgs) => {
1695
- for (const msg of msgs) {
1696
- if (terminated) return;
1697
- if (msg[0] === DATA) {
1698
- const id = setTimeout(() => {
1699
- timers.delete(id);
1700
- actions.down([msg]);
1701
- if (completed && timers.size === 0) {
1702
- actions.down([[COMPLETE]]);
1703
- }
1704
- }, ms);
1705
- timers.add(id);
1706
- } else if (msg[0] === COMPLETE) {
1707
- terminated = true;
1708
- completed = true;
1709
- if (timers.size === 0) {
1710
- actions.down([[COMPLETE]]);
1711
- }
1712
- } else if (msg[0] === ERROR) {
1713
- terminated = true;
1714
- clearAllTimers();
1715
- actions.down([msg]);
1716
- } else {
1717
- actions.down([msg]);
1718
- }
1719
- }
1720
- });
1721
- return () => {
1722
- unsub();
1723
- clearAllTimers();
1724
- terminated = true;
1725
- };
1726
- },
1727
- {
1728
- ...opts,
1729
- name,
1730
- ...initialOpt,
1731
- describeKind: "derived",
1732
- completeWhenDepsComplete: false,
1733
- meta: baseMeta("wait", opts?.meta)
1734
- }
1735
- );
1736
- graph.add(name, step);
1737
- return step;
1738
- }
1739
- function onFailure(graph, name, source, recover, opts) {
1740
- const src = resolveDep(graph, source);
1741
- let terminated = false;
1742
- const step = node(
1743
- [],
1744
- (_data, actions) => {
1745
- const unsub = src.node.subscribe((msgs) => {
1746
- for (const msg of msgs) {
1747
- if (terminated) return;
1748
- if (msg[0] === ERROR) {
1749
- try {
1750
- actions.emit(recover(msg[1], actions));
1751
- } catch (err) {
1752
- terminated = true;
1753
- actions.down([[ERROR, err]]);
1754
- }
1755
- } else {
1756
- actions.down([msg]);
1757
- if (msg[0] === COMPLETE) terminated = true;
1758
- }
1759
- }
1760
- });
1761
- return () => unsub();
1762
- },
1763
- {
1764
- ...opts,
1765
- name,
1766
- describeKind: "derived",
1767
- completeWhenDepsComplete: false,
1768
- // onFailure handles errors via manual subscription (recover callback).
1769
- // Disable auto-propagation so dep-channel ERROR doesn't terminate this
1770
- // node before the recover callback has a chance to emit a replacement value.
1771
- errorWhenDepsError: false,
1772
- meta: baseMeta("onFailure", opts?.meta)
1773
- }
1774
- );
1775
- registerStep(graph, name, step, src.path ? [src.path] : []);
1776
- return step;
1777
- }
1778
-
1779
- // src/patterns/ai.ts
1780
- function aiMeta(kind, extra) {
1781
- return domainMeta("ai", kind, extra);
1782
- }
1783
- function isPromiseLike(x) {
1784
- return x != null && typeof x.then === "function";
1785
- }
1786
- function isNodeLike(x) {
1787
- return typeof x === "object" && x !== null && "subscribe" in x && typeof x.subscribe === "function" && "cache" in x;
1788
- }
1789
- function isAsyncIterableLike(x) {
1790
- return x != null && typeof x === "object" && Symbol.asyncIterator in x && typeof x[Symbol.asyncIterator] === "function";
1791
- }
1792
- var DEFAULT_TIMEOUT_MS = 3e4;
1793
- function firstDataFromNode(resolved, opts) {
1794
- if (resolved.status === "settled") {
1795
- const immediate = resolved.cache;
1796
- if (immediate !== void 0) {
1797
- return Promise.resolve(immediate);
1798
- }
1799
- }
1800
- const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
1801
- return new Promise((resolve, reject) => {
1802
- const timer = new ResettableTimer();
1803
- const unsub = resolved.subscribe((messages) => {
1804
- for (const msg of messages) {
1805
- if (msg[0] === DATA) {
1806
- timer.cancel();
1807
- unsub();
1808
- resolve(msg[1]);
1809
- return;
1810
- }
1811
- if (msg[0] === ERROR) {
1812
- timer.cancel();
1813
- unsub();
1814
- reject(msg[1]);
1815
- return;
1816
- }
1817
- if (msg[0] === COMPLETE) {
1818
- timer.cancel();
1819
- unsub();
1820
- reject(new Error("firstDataFromNode: completed without producing a value"));
1821
- return;
1822
- }
1823
- }
1824
- });
1825
- timer.start(timeoutMs, () => {
1826
- unsub();
1827
- reject(new Error(`firstDataFromNode: timed out after ${timeoutMs}ms`));
1828
- });
1829
- });
1830
- }
1831
- async function resolveToolHandlerResult(value) {
1832
- if (isPromiseLike(value)) {
1833
- return resolveToolHandlerResult(await value);
1834
- }
1835
- if (isNodeLike(value)) {
1836
- return firstDataFromNode(value);
1837
- }
1838
- if (isAsyncIterableLike(value)) {
1839
- return firstDataFromNode(fromAny(value));
1840
- }
1841
- return value;
1842
- }
1843
- function fromLLM(adapter, messages, opts) {
1844
- const msgsNode = fromAny(messages);
1845
- const result = switchMap(msgsNode, (msgs) => {
1846
- if (!msgs || msgs.length === 0) {
1847
- return state(null);
1848
- }
1849
- const tools = opts?.tools;
1850
- return adapter.invoke(msgs, {
1851
- model: opts?.model,
1852
- temperature: opts?.temperature,
1853
- maxTokens: opts?.maxTokens,
1854
- tools,
1855
- systemPrompt: opts?.systemPrompt
1856
- });
1857
- });
1858
- return result;
1859
- }
1860
- function streamingPromptNode(adapter, deps, prompt, opts) {
1861
- const sourceName = opts?.name ?? "llm";
1862
- const format = opts?.format ?? "text";
1863
- const streamTopic = topic(`${sourceName}/stream`);
1864
- const messagesNode = derived(deps, (values) => {
1865
- if (values.some((v) => v == null)) return [];
1866
- const text = typeof prompt === "string" ? prompt : prompt(...values);
1867
- if (!text) return [];
1868
- const msgs = [];
1869
- if (opts?.systemPrompt) msgs.push({ role: "system", content: opts.systemPrompt });
1870
- msgs.push({ role: "user", content: text });
1871
- return msgs;
1872
- });
1873
- const output = switchMap(messagesNode, (msgs) => {
1874
- const chatMsgs = msgs;
1875
- if (!chatMsgs || chatMsgs.length === 0) {
1876
- return state(null);
1877
- }
1878
- const ac = new AbortController();
1879
- async function* pumpAndCollect() {
1880
- let accumulated = "";
1881
- let index = 0;
1882
- try {
1883
- for await (const token of adapter.stream(chatMsgs, {
1884
- model: opts?.model,
1885
- temperature: opts?.temperature,
1886
- maxTokens: opts?.maxTokens,
1887
- systemPrompt: opts?.systemPrompt,
1888
- signal: ac.signal
1889
- })) {
1890
- accumulated += token;
1891
- streamTopic.publish({
1892
- source: sourceName,
1893
- token,
1894
- accumulated,
1895
- index: index++
1896
- });
1897
- }
1898
- let result;
1899
- if (format === "json") {
1900
- try {
1901
- result = JSON.parse(stripFences(accumulated));
1902
- } catch {
1903
- result = null;
1904
- }
1905
- } else {
1906
- result = accumulated;
1907
- }
1908
- yield result;
1909
- } finally {
1910
- ac.abort();
1911
- }
1912
- }
1913
- return fromAny(pumpAndCollect());
1914
- });
1915
- const unsub = keepalive(output);
1916
- return {
1917
- output,
1918
- stream: streamTopic,
1919
- dispose: () => {
1920
- unsub();
1921
- streamTopic.destroy();
1922
- }
1923
- };
1924
- }
1925
- function streamExtractor(streamTopic, extractFn, opts) {
1926
- return derived(
1927
- [streamTopic.latest],
1928
- ([chunk]) => {
1929
- if (chunk == null) return null;
1930
- return extractFn(chunk.accumulated);
1931
- },
1932
- {
1933
- name: opts?.name ?? "extractor",
1934
- describeKind: "derived",
1935
- initial: null,
1936
- meta: aiMeta("stream_extractor"),
1937
- ...opts?.equals ? { equals: opts.equals } : {}
1938
- }
1939
- );
1940
- }
1941
- var keywordFlagsEqual = (a, b) => {
1942
- if (a === b) return true;
1943
- if (a == null || b == null) return a === b;
1944
- if (a.length !== b.length) return false;
1945
- for (let i = 0; i < a.length; i++) {
1946
- const x = a[i];
1947
- const y = b[i];
1948
- if (x.label !== y.label || x.pattern !== y.pattern || x.match !== y.match || x.position !== y.position) {
1949
- return false;
1950
- }
1951
- }
1952
- return true;
1953
- };
1954
- function keywordFlagExtractor(streamTopic, opts) {
1955
- const maxPatternLength = opts.maxPatternLength ?? 128;
1956
- return derived(
1957
- [streamTopic.latest],
1958
- ([chunk], ctx) => {
1959
- if (chunk == null) return [];
1960
- const accumulated = chunk.accumulated;
1961
- if (!("flags" in ctx.store)) {
1962
- ctx.store.flags = [];
1963
- ctx.store.scannedTo = 0;
1964
- }
1965
- const flags = ctx.store.flags;
1966
- const scannedTo = ctx.store.scannedTo;
1967
- const startOffset = Math.max(0, scannedTo - maxPatternLength);
1968
- const region = accumulated.slice(startOffset);
1969
- let added = false;
1970
- for (const { pattern, label } of opts.patterns) {
1971
- const re = new RegExp(pattern.source, `${pattern.flags.replace("g", "")}g`);
1972
- for (const m of region.matchAll(re)) {
1973
- const pos = startOffset + m.index;
1974
- if (pos + m[0].length <= scannedTo) continue;
1975
- flags.push({ label, pattern, match: m[0], position: pos });
1976
- added = true;
1977
- }
1978
- }
1979
- ctx.store.scannedTo = accumulated.length;
1980
- return added ? [...flags] : flags.slice();
1981
- },
1982
- {
1983
- name: opts.name ?? "keyword-flag-extractor",
1984
- describeKind: "derived",
1985
- initial: [],
1986
- meta: aiMeta("keyword_flag_extractor"),
1987
- equals: keywordFlagsEqual
1988
- }
1989
- );
1990
- }
1991
- var toolCallsEqual = (a, b) => {
1992
- if (a === b) return true;
1993
- if (a == null || b == null) return a === b;
1994
- if (a.length !== b.length) return false;
1995
- for (let i = 0; i < a.length; i++) {
1996
- const x = a[i];
1997
- const y = b[i];
1998
- if (x.startIndex !== y.startIndex || x.name !== y.name || x.raw !== y.raw) {
1999
- return false;
2000
- }
2001
- }
2002
- return true;
2003
- };
2004
- function toolCallExtractor(streamTopic, opts) {
2005
- return derived(
2006
- [streamTopic.latest],
2007
- ([chunk], ctx) => {
2008
- if (chunk == null) return [];
2009
- const accumulated = chunk.accumulated;
2010
- if (!("calls" in ctx.store)) {
2011
- ctx.store.calls = [];
2012
- ctx.store.scanFrom = 0;
2013
- }
2014
- const calls = ctx.store.calls;
2015
- let i = ctx.store.scanFrom;
2016
- let added = false;
2017
- while (i < accumulated.length) {
2018
- const start = accumulated.indexOf("{", i);
2019
- if (start === -1) {
2020
- ctx.store.scanFrom = accumulated.length;
2021
- break;
2022
- }
2023
- let depth = 0;
2024
- let end = -1;
2025
- let inString = false;
2026
- for (let j = start; j < accumulated.length; j++) {
2027
- const ch = accumulated[j];
2028
- if (inString) {
2029
- if (ch === "\\" && j + 1 < accumulated.length) {
2030
- j++;
2031
- } else if (ch === '"') {
2032
- inString = false;
2033
- }
2034
- } else if (ch === '"') {
2035
- inString = true;
2036
- } else if (ch === "{") {
2037
- depth++;
2038
- } else if (ch === "}") {
2039
- depth--;
2040
- if (depth === 0) {
2041
- end = j;
2042
- break;
2043
- }
2044
- }
2045
- }
2046
- if (end === -1) {
2047
- ctx.store.scanFrom = start;
2048
- break;
2049
- }
2050
- const raw = accumulated.slice(start, end + 1);
2051
- try {
2052
- const parsed = JSON.parse(raw);
2053
- if (typeof parsed.name === "string" && parsed.arguments != null && typeof parsed.arguments === "object") {
2054
- calls.push({
2055
- name: parsed.name,
2056
- arguments: parsed.arguments,
2057
- raw,
2058
- startIndex: start
2059
- });
2060
- added = true;
2061
- }
2062
- } catch {
2063
- }
2064
- i = end + 1;
2065
- ctx.store.scanFrom = i;
2066
- }
2067
- return added ? [...calls] : calls.slice();
2068
- },
2069
- {
2070
- name: opts?.name ?? "tool-call-extractor",
2071
- describeKind: "derived",
2072
- initial: [],
2073
- meta: aiMeta("tool_call_extractor"),
2074
- equals: toolCallsEqual
2075
- }
2076
- );
2077
- }
2078
- var costMeterEqual = (a, b) => {
2079
- if (a === b) return true;
2080
- return a.chunkCount === b.chunkCount && a.charCount === b.charCount && a.estimatedTokens === b.estimatedTokens;
2081
- };
2082
- function costMeterExtractor(streamTopic, opts) {
2083
- const charsPerToken = opts?.charsPerToken ?? 4;
2084
- return derived(
2085
- [streamTopic.latest],
2086
- ([chunk]) => {
2087
- if (chunk == null) return { chunkCount: 0, charCount: 0, estimatedTokens: 0 };
2088
- const c = chunk;
2089
- const charCount = c.accumulated.length;
2090
- return {
2091
- chunkCount: c.index + 1,
2092
- charCount,
2093
- estimatedTokens: Math.ceil(charCount / charsPerToken)
2094
- };
2095
- },
2096
- {
2097
- name: opts?.name ?? "cost-meter",
2098
- describeKind: "derived",
2099
- initial: { chunkCount: 0, charCount: 0, estimatedTokens: 0 },
2100
- meta: aiMeta("cost_meter_extractor"),
2101
- equals: costMeterEqual
2102
- }
2103
- );
2104
- }
2105
- function redactor(streamTopic, patterns, replaceFn, opts) {
2106
- const replace = replaceFn ?? (() => "[REDACTED]");
2107
- function sanitize(text) {
2108
- let result = text;
2109
- for (const pat of patterns) {
2110
- const global = pat.global ? pat : new RegExp(pat.source, `${pat.flags}g`);
2111
- result = result.replace(global, (m) => replace(m, pat));
2112
- }
2113
- return result;
2114
- }
2115
- return derived(
2116
- [streamTopic.latest],
2117
- ([chunk]) => {
2118
- if (chunk == null) {
2119
- return { source: "", token: "", accumulated: "", index: -1 };
2120
- }
2121
- const c = chunk;
2122
- const sanitizedAccumulated = sanitize(c.accumulated);
2123
- const sanitizedToken = sanitize(c.token);
2124
- return {
2125
- source: c.source,
2126
- token: sanitizedToken,
2127
- accumulated: sanitizedAccumulated,
2128
- index: c.index
2129
- };
2130
- },
2131
- { name: opts?.name ?? "redactor" }
2132
- );
2133
- }
2134
- function contentGate(streamTopic, classifier, threshold, opts) {
2135
- const hardThreshold = threshold * (opts?.hardMultiplier ?? 1.5);
2136
- const isNodeClassifier = typeof classifier !== "function";
2137
- const deps = [streamTopic.latest];
2138
- if (isNodeClassifier) deps.push(classifier);
2139
- return derived(
2140
- deps,
2141
- (values) => {
2142
- const chunk = values[0];
2143
- if (chunk == null) return "allow";
2144
- const score = isNodeClassifier ? values[1] ?? 0 : classifier(chunk.accumulated);
2145
- if (score >= hardThreshold) return "block";
2146
- if (score >= threshold) return "review";
2147
- return "allow";
2148
- },
2149
- { name: opts?.name ?? "content-gate", initial: "allow" }
2150
- );
2151
- }
2152
- function gatedStream(graph, name, adapter, deps, prompt, opts) {
2153
- const cancelSignal = state(0, { name: `${name}/cancel` });
2154
- let cancelCounter = 0;
2155
- const allDeps = [...deps, cancelSignal];
2156
- const sourceName = opts?.name ?? name;
2157
- const format = opts?.format ?? "text";
2158
- const streamTopic = topic(`${sourceName}/stream`);
2159
- const messagesNode = derived(allDeps, (values) => {
2160
- const depValues = values.slice(0, -1);
2161
- if (depValues.some((v) => v == null)) return [];
2162
- const text = typeof prompt === "string" ? prompt : prompt(...depValues);
2163
- if (!text) return [];
2164
- const msgs = [];
2165
- if (opts?.systemPrompt) msgs.push({ role: "system", content: opts.systemPrompt });
2166
- msgs.push({ role: "user", content: text });
2167
- return msgs;
2168
- });
2169
- const output = switchMap(messagesNode, (msgs) => {
2170
- const chatMsgs = msgs;
2171
- if (!chatMsgs || chatMsgs.length === 0) {
2172
- return state(null);
2173
- }
2174
- const ac = new AbortController();
2175
- async function* pumpAndCollect() {
2176
- let accumulated = "";
2177
- let index = 0;
2178
- try {
2179
- for await (const token of adapter.stream(chatMsgs, {
2180
- model: opts?.model,
2181
- temperature: opts?.temperature,
2182
- maxTokens: opts?.maxTokens,
2183
- systemPrompt: opts?.systemPrompt,
2184
- signal: ac.signal
2185
- })) {
2186
- accumulated += token;
2187
- streamTopic.publish({
2188
- source: sourceName,
2189
- token,
2190
- accumulated,
2191
- index: index++
2192
- });
2193
- }
2194
- let result;
2195
- if (format === "json") {
2196
- try {
2197
- result = JSON.parse(stripFences(accumulated));
2198
- } catch {
2199
- result = null;
2200
- }
2201
- } else {
2202
- result = accumulated;
2203
- }
2204
- yield result;
2205
- } finally {
2206
- ac.abort();
2207
- }
2208
- }
2209
- return fromAny(pumpAndCollect());
2210
- });
2211
- const unsub = keepalive(output);
2212
- const nonNullOutput = derived(
2213
- [output],
2214
- ([v]) => {
2215
- if (v == null) return void 0;
2216
- return v;
2217
- },
2218
- {
2219
- name: `${name}/filter`
2220
- }
2221
- );
2222
- graph.add(`${name}/raw`, nonNullOutput);
2223
- const gateCtrl = gate(graph, `${name}/gate`, `${name}/raw`, opts?.gate);
2224
- const originalReject = gateCtrl.reject.bind(gateCtrl);
2225
- const gateWithAbort = {
2226
- ...gateCtrl,
2227
- reject(count = 1) {
2228
- originalReject(count);
2229
- cancelSignal.down([[DATA, ++cancelCounter]]);
2230
- }
2231
- };
2232
- return {
2233
- output: gateCtrl.node,
2234
- stream: streamTopic,
2235
- gate: gateWithAbort,
2236
- dispose: () => {
2237
- unsub();
2238
- streamTopic.destroy();
2239
- }
2240
- };
2241
- }
2242
- function extractContent(resp) {
2243
- if (resp != null && typeof resp === "object" && "content" in resp) {
2244
- return String(resp.content);
2245
- }
2246
- if (typeof resp === "string") return resp;
2247
- return String(resp);
2248
- }
2249
- function promptNode(adapter, deps, prompt, opts) {
2250
- const format = opts?.format ?? "text";
2251
- const retries = opts?.retries ?? 0;
2252
- const useCache = opts?.cache ?? false;
2253
- const cache = useCache ? /* @__PURE__ */ new Map() : null;
2254
- const messagesNode = derived(
2255
- deps,
2256
- (values) => {
2257
- if (values.some((v) => v == null)) return [];
2258
- const text = typeof prompt === "string" ? prompt : prompt(...values);
2259
- if (!text) return [];
2260
- const msgs = [];
2261
- if (opts?.systemPrompt) msgs.push({ role: "system", content: opts.systemPrompt });
2262
- msgs.push({ role: "user", content: text });
2263
- return msgs;
2264
- },
2265
- {
2266
- name: opts?.name ? `${opts.name}::messages` : "prompt_node::messages",
2267
- meta: aiMeta("prompt_node"),
2268
- initial: []
2269
- }
2270
- );
2271
- const result = switchMap(messagesNode, (msgs) => {
2272
- if (!msgs || msgs.length === 0) {
2273
- return state(null);
2274
- }
2275
- const cacheKey = useCache ? JSON.stringify(msgs.map((m) => [m.role, m.content])) : "";
2276
- if (cache?.has(cacheKey)) {
2277
- return state(cache.get(cacheKey));
2278
- }
2279
- async function attempt(remaining) {
2280
- try {
2281
- const resp = await new Promise((resolve, reject) => {
2282
- const input = adapter.invoke(msgs, {
2283
- model: opts?.model,
2284
- temperature: opts?.temperature,
2285
- maxTokens: opts?.maxTokens,
2286
- systemPrompt: opts?.systemPrompt
2287
- });
2288
- if (input && typeof input.then === "function") {
2289
- input.then(resolve, reject);
2290
- } else if (input && typeof input.subscribe === "function") {
2291
- resolve(input.cache);
2292
- } else {
2293
- resolve(input);
2294
- }
2295
- });
2296
- const content = extractContent(resp);
2297
- let parsed;
2298
- if (format === "json") {
2299
- parsed = JSON.parse(stripFences(content));
2300
- } else {
2301
- parsed = content;
2302
- }
2303
- cache?.set(cacheKey, parsed);
2304
- return parsed;
2305
- } catch (err) {
2306
- if (remaining > 0) return attempt(remaining - 1);
2307
- throw err;
2308
- }
2309
- }
2310
- return attempt(retries);
2311
- });
2312
- return result;
2313
- }
2314
- var ChatStreamGraph = class extends Graph {
2315
- _log;
2316
- messages;
2317
- latest;
2318
- messageCount;
2319
- constructor(name, opts = {}) {
2320
- super(name, opts.graph);
2321
- this._log = reactiveLog([], {
2322
- name: "messages",
2323
- maxSize: opts.maxMessages
2324
- });
2325
- this.messages = this._log.entries;
2326
- this.add("messages", this.messages);
2327
- this.latest = derived(
2328
- [this.messages],
2329
- ([snapshot]) => {
2330
- const entries = snapshot;
2331
- return entries.length === 0 ? null : entries[entries.length - 1];
2332
- },
2333
- {
2334
- name: "latest",
2335
- describeKind: "derived",
2336
- meta: aiMeta("chat_latest")
2337
- }
2338
- );
2339
- this.add("latest", this.latest);
2340
- this.addDisposer(keepalive(this.latest));
2341
- this.messageCount = derived(
2342
- [this.messages],
2343
- ([snapshot]) => snapshot.length,
2344
- {
2345
- name: "messageCount",
2346
- describeKind: "derived",
2347
- meta: aiMeta("chat_message_count"),
2348
- initial: 0
2349
- }
2350
- );
2351
- this.add("messageCount", this.messageCount);
2352
- this.addDisposer(keepalive(this.messageCount));
2353
- }
2354
- append(role, content, extra) {
2355
- this._log.append({ role, content, ...extra });
2356
- }
2357
- appendToolResult(callId, content) {
2358
- this._log.append({ role: "tool", content, toolCallId: callId });
2359
- }
2360
- clear() {
2361
- this._log.clear();
2362
- }
2363
- allMessages() {
2364
- return this.messages.cache;
2365
- }
2366
- };
2367
- function chatStream(name, opts) {
2368
- return new ChatStreamGraph(name, opts);
2369
- }
2370
- var ToolRegistryGraph = class extends Graph {
2371
- definitions;
2372
- schemas;
2373
- constructor(name, opts = {}) {
2374
- super(name, opts.graph);
2375
- this.definitions = state(/* @__PURE__ */ new Map(), {
2376
- name: "definitions",
2377
- describeKind: "state",
2378
- meta: aiMeta("tool_definitions")
2379
- });
2380
- this.add("definitions", this.definitions);
2381
- this.schemas = derived(
2382
- [this.definitions],
2383
- ([defs]) => [...(defs ?? /* @__PURE__ */ new Map()).values()],
2384
- {
2385
- name: "schemas",
2386
- describeKind: "derived",
2387
- meta: aiMeta("tool_schemas"),
2388
- initial: []
2389
- }
2390
- );
2391
- this.add("schemas", this.schemas);
2392
- this.addDisposer(keepalive(this.schemas));
2393
- }
2394
- register(tool) {
2395
- const current = this.definitions.cache;
2396
- const next = new Map(current);
2397
- next.set(tool.name, tool);
2398
- this.definitions.down([[DATA, next]]);
2399
- }
2400
- unregister(name) {
2401
- const current = this.definitions.cache;
2402
- if (!current.has(name)) return;
2403
- const next = new Map(current);
2404
- next.delete(name);
2405
- this.definitions.down([[DATA, next]]);
2406
- }
2407
- async execute(name, args) {
2408
- const defs = this.definitions.cache;
2409
- const tool = defs.get(name);
2410
- if (!tool) throw new Error(`toolRegistry: unknown tool "${name}"`);
2411
- const raw = tool.handler(args);
2412
- return resolveToolHandlerResult(raw);
2413
- }
2414
- getDefinition(name) {
2415
- return this.definitions.cache?.get(name);
2416
- }
2417
- };
2418
- function toolRegistry(name, opts) {
2419
- return new ToolRegistryGraph(name, opts);
2420
- }
2421
- function systemPromptBuilder(sections, opts) {
2422
- const separator = opts?.separator ?? "\n\n";
2423
- const sectionNodes = sections.map((s) => typeof s === "string" ? state(s) : fromAny(s));
2424
- const prompt = derived(
2425
- sectionNodes,
2426
- (values) => values.filter((v) => v != null && v !== "").join(separator),
2427
- {
2428
- name: opts?.name ?? "systemPrompt",
2429
- describeKind: "derived",
2430
- meta: aiMeta("system_prompt"),
2431
- initial: ""
2432
- }
2433
- );
2434
- const unsub = keepalive(prompt);
2435
- return Object.assign(prompt, { dispose: unsub });
2436
- }
2437
- function llmExtractor(systemPrompt, opts) {
2438
- return (raw, existing) => {
2439
- const existingKeys = [...existing.keys()].slice(0, 100);
2440
- const messages = [
2441
- { role: "system", content: systemPrompt },
2442
- {
2443
- role: "user",
2444
- content: JSON.stringify({
2445
- input: raw,
2446
- existingKeys
2447
- })
2448
- }
2449
- ];
2450
- return producer((actions) => {
2451
- let active = true;
2452
- const result = opts.adapter.invoke(messages, {
2453
- model: opts.model,
2454
- temperature: opts.temperature ?? 0,
2455
- maxTokens: opts.maxTokens
2456
- });
2457
- const resolved = fromAny(result);
2458
- const unsub = resolved.subscribe((msgs) => {
2459
- if (!active) return;
2460
- let done = false;
2461
- for (const msg of msgs) {
2462
- if (done) break;
2463
- if (msg[0] === DATA) {
2464
- const response = msg[1];
2465
- try {
2466
- const parsed = JSON.parse(response.content);
2467
- actions.emit(parsed);
2468
- actions.down([[COMPLETE]]);
2469
- } catch {
2470
- actions.down([
2471
- [ERROR, new Error("llmExtractor: failed to parse LLM response as JSON")]
2472
- ]);
2473
- }
2474
- done = true;
2475
- } else if (msg[0] === ERROR) {
2476
- actions.down([[ERROR, msg[1]]]);
2477
- done = true;
2478
- } else if (msg[0] === COMPLETE) {
2479
- actions.down([[COMPLETE]]);
2480
- done = true;
2481
- } else {
2482
- actions.down([[msg[0], msg[1]]]);
2483
- }
2484
- }
2485
- });
2486
- return () => {
2487
- unsub();
2488
- active = false;
2489
- };
2490
- });
2491
- };
2492
- }
2493
- function llmConsolidator(systemPrompt, opts) {
2494
- return (entries) => {
2495
- const entriesArray = [...entries.entries()].map(([key, value]) => ({ key, value }));
2496
- const messages = [
2497
- { role: "system", content: systemPrompt },
2498
- { role: "user", content: JSON.stringify({ memories: entriesArray }) }
2499
- ];
2500
- return producer((actions) => {
2501
- let active = true;
2502
- const result = opts.adapter.invoke(messages, {
2503
- model: opts.model,
2504
- temperature: opts.temperature ?? 0,
2505
- maxTokens: opts.maxTokens
2506
- });
2507
- const resolved = fromAny(result);
2508
- const unsub = resolved.subscribe((msgs) => {
2509
- if (!active) return;
2510
- let done = false;
2511
- for (const msg of msgs) {
2512
- if (done) break;
2513
- if (msg[0] === DATA) {
2514
- const response = msg[1];
2515
- try {
2516
- const parsed = JSON.parse(response.content);
2517
- actions.emit(parsed);
2518
- actions.down([[COMPLETE]]);
2519
- } catch {
2520
- actions.down([
2521
- [ERROR, new Error("llmConsolidator: failed to parse LLM response as JSON")]
2522
- ]);
2523
- }
2524
- done = true;
2525
- } else if (msg[0] === ERROR) {
2526
- actions.down([[ERROR, msg[1]]]);
2527
- done = true;
2528
- } else if (msg[0] === COMPLETE) {
2529
- actions.down([[COMPLETE]]);
2530
- done = true;
2531
- } else {
2532
- actions.down([[msg[0], msg[1]]]);
2533
- }
2534
- }
2535
- });
2536
- return () => {
2537
- unsub();
2538
- active = false;
2539
- };
2540
- });
2541
- };
2542
- }
2543
- function defaultAdmissionScorer(_raw) {
2544
- return { persistence: 0.5, structure: 0.5, personalValue: 0.5 };
2545
- }
2546
- function admissionFilter3D(opts = {}) {
2547
- const scoreFn = opts.scoreFn ?? defaultAdmissionScorer;
2548
- const pThresh = opts.persistenceThreshold ?? 0.3;
2549
- const pvThresh = opts.personalValueThreshold ?? 0.3;
2550
- const reqStructured = opts.requireStructured ?? false;
2551
- return (raw) => {
2552
- const scores = scoreFn(raw);
2553
- if (scores.persistence < pThresh) return false;
2554
- if (scores.personalValue < pvThresh) return false;
2555
- if (reqStructured && scores.structure <= 0) return false;
2556
- return true;
2557
- };
2558
- }
2559
- var DEFAULT_DECAY_RATE = Math.LN2 / (7 * 86400);
2560
- function extractStoreMap(snapshot) {
2561
- if (snapshot instanceof Map) return snapshot;
2562
- return /* @__PURE__ */ new Map();
2563
- }
2564
- function agentMemory(name, source, opts) {
2565
- const graph = new Graph(name, opts.graph);
2566
- const keepaliveSubs = [];
2567
- let rawExtractFn;
2568
- if (opts.extractFn) {
2569
- rawExtractFn = opts.extractFn;
2570
- } else if (opts.adapter && opts.extractPrompt) {
2571
- rawExtractFn = llmExtractor(opts.extractPrompt, { adapter: opts.adapter });
2572
- } else {
2573
- throw new Error("agentMemory: provide either extractFn or adapter + extractPrompt");
2574
- }
2575
- const extractFn = (raw, existing) => {
2576
- if (raw == null) return { upsert: [] };
2577
- return rawExtractFn(raw, existing);
2578
- };
2579
- let filteredSource = source;
2580
- if (opts.admissionFilter) {
2581
- const srcNode = fromAny(source);
2582
- const filter2 = opts.admissionFilter;
2583
- filteredSource = derived(
2584
- [srcNode],
2585
- ([raw]) => {
2586
- if (filter2(raw)) return raw;
2587
- return void 0;
2588
- },
2589
- { name: "admissionFilter", describeKind: "derived" }
2590
- );
2591
- }
2592
- let consolidateFn;
2593
- if (opts.consolidateFn) {
2594
- consolidateFn = opts.consolidateFn;
2595
- } else if (opts.adapter && opts.consolidatePrompt) {
2596
- consolidateFn = llmConsolidator(opts.consolidatePrompt, { adapter: opts.adapter });
2597
- }
2598
- let consolidateTrigger = opts.consolidateTrigger;
2599
- if (!consolidateTrigger && consolidateFn && opts.reflection?.enabled !== false) {
2600
- const interval2 = opts.reflection?.interval ?? 3e5;
2601
- consolidateTrigger = fromTimer(interval2, { period: interval2 });
2602
- }
2603
- const distillOpts = {
2604
- score: opts.score,
2605
- cost: opts.cost,
2606
- budget: opts.budget ?? 2e3,
2607
- context: opts.context,
2608
- consolidate: consolidateFn,
2609
- consolidateTrigger
2610
- };
2611
- const distillBundle = distill(filteredSource, extractFn, distillOpts);
2612
- graph.add("store", distillBundle.store.entries);
2613
- graph.add("compact", distillBundle.compact);
2614
- graph.add("size", distillBundle.size);
2615
- let vectors = null;
2616
- if (opts.vectorDimensions && opts.vectorDimensions > 0 && opts.embedFn) {
2617
- vectors = vectorIndex({ dimension: opts.vectorDimensions });
2618
- graph.add("vectorIndex", vectors.entries);
2619
- }
2620
- let kg = null;
2621
- if (opts.enableKnowledgeGraph) {
2622
- kg = knowledgeGraph(`${name}-kg`);
2623
- graph.mount("kg", kg);
2624
- }
2625
- let memoryTiersBundle = null;
2626
- if (opts.tiers) {
2627
- const tiersOpts = opts.tiers;
2628
- const decayRate = tiersOpts.decayRate ?? DEFAULT_DECAY_RATE;
2629
- const maxActive = tiersOpts.maxActive ?? 1e3;
2630
- const archiveThreshold = tiersOpts.archiveThreshold ?? 0.1;
2631
- const permanentFilter = tiersOpts.permanentFilter ?? (() => false);
2632
- const permanent = lightCollection({ name: "permanent" });
2633
- graph.add("permanent", permanent.entries);
2634
- const permanentKeys = /* @__PURE__ */ new Set();
2635
- const tierOf = (key) => {
2636
- if (permanentKeys.has(key)) return "permanent";
2637
- const storeMap = extractStoreMap(distillBundle.store.entries.cache);
2638
- if (storeMap.has(key)) return "active";
2639
- return "archived";
2640
- };
2641
- const markPermanent = (key, value) => {
2642
- permanentKeys.add(key);
2643
- permanent.upsert(key, value);
2644
- };
2645
- const entryCreatedAtNs = /* @__PURE__ */ new Map();
2646
- const storeNode = distillBundle.store.entries;
2647
- const contextNode = opts.context ? fromAny(opts.context) : state(null);
2648
- const tierClassifier = effect([storeNode, contextNode], ([snapshot, ctx]) => {
2649
- const storeMap = extractStoreMap(snapshot);
2650
- const nowNs = monotonicNs();
2651
- const toArchive = [];
2652
- const toPermanent = [];
2653
- for (const [key, mem] of storeMap) {
2654
- if (!entryCreatedAtNs.has(key)) {
2655
- entryCreatedAtNs.set(key, nowNs);
2656
- }
2657
- if (permanentFilter(key, mem)) {
2658
- toPermanent.push({ key, value: mem });
2659
- continue;
2660
- }
2661
- const baseScore = opts.score(mem, ctx);
2662
- const createdNs = entryCreatedAtNs.get(key) ?? nowNs;
2663
- const ageSeconds = Number(nowNs - createdNs) / 1e9;
2664
- const decayed = decay(baseScore, ageSeconds, decayRate);
2665
- if (decayed < archiveThreshold) {
2666
- toArchive.push(key);
2667
- }
2668
- }
2669
- for (const key of entryCreatedAtNs.keys()) {
2670
- if (!storeMap.has(key)) entryCreatedAtNs.delete(key);
2671
- }
2672
- for (const { key, value } of toPermanent) {
2673
- if (!permanentKeys.has(key)) {
2674
- markPermanent(key, value);
2675
- }
2676
- }
2677
- const activeCount = storeMap.size - permanentKeys.size;
2678
- if (activeCount > maxActive) {
2679
- const scored = [...storeMap.entries()].filter(([k]) => !permanentKeys.has(k)).map(([k, m]) => ({ key: k, score: opts.score(m, ctx) })).sort((a, b) => a.score - b.score);
2680
- const excess = activeCount - maxActive;
2681
- for (let i = 0; i < excess && i < scored.length; i++) {
2682
- const sk = scored[i].key;
2683
- if (!toArchive.includes(sk)) toArchive.push(sk);
2684
- }
2685
- }
2686
- if (toArchive.length > 0) {
2687
- batch(() => {
2688
- for (const key of toArchive) {
2689
- distillBundle.store.delete(key);
2690
- }
2691
- });
2692
- }
2693
- });
2694
- keepaliveSubs.push(tierClassifier.subscribe(() => void 0));
2695
- let archiveHandle = null;
2696
- if (tiersOpts.archiveTier) {
2697
- archiveHandle = graph.attachStorage(
2698
- [tiersOpts.archiveTier],
2699
- tiersOpts.archiveStorageOptions ?? {}
2700
- );
2701
- }
2702
- memoryTiersBundle = {
2703
- permanent,
2704
- activeEntries: storeNode,
2705
- archiveHandle,
2706
- tierOf,
2707
- markPermanent
2708
- };
2709
- }
2710
- if (vectors || kg) {
2711
- const embedFn = opts.embedFn;
2712
- const entityFn = opts.entityFn;
2713
- const storeNode = distillBundle.store.entries;
2714
- const indexer = effect([storeNode], ([snapshot]) => {
2715
- const storeMap = extractStoreMap(snapshot);
2716
- for (const [key, mem] of storeMap) {
2717
- if (vectors && embedFn) {
2718
- const vec = embedFn(mem);
2719
- if (vec) vectors.upsert(key, vec, mem);
2720
- }
2721
- if (kg && entityFn) {
2722
- const extracted = entityFn(key, mem);
2723
- if (extracted) {
2724
- for (const ent of extracted.entities ?? []) {
2725
- kg.upsertEntity(ent.id, ent.value);
2726
- }
2727
- for (const rel of extracted.relations ?? []) {
2728
- kg.link(rel.from, rel.to, rel.relation, rel.weight);
2729
- }
2730
- }
2731
- }
2732
- }
2733
- });
2734
- keepaliveSubs.push(indexer.subscribe(() => void 0));
2735
- }
2736
- let retrievalNode = null;
2737
- let retrievalTraceNode = null;
2738
- let retrieveFn = null;
2739
- if (vectors || kg) {
2740
- const topK = opts.retrieval?.topK ?? 20;
2741
- const graphDepth = opts.retrieval?.graphDepth ?? 1;
2742
- const budget = opts.budget ?? 2e3;
2743
- const costFn = opts.cost;
2744
- const scoreFn = opts.score;
2745
- const contextNode = opts.context ? fromAny(opts.context) : state(null);
2746
- const retrievalOutput = state([], {
2747
- name: "retrieval",
2748
- describeKind: "state",
2749
- meta: aiMeta("retrieval_pipeline")
2750
- });
2751
- graph.add("retrieval", retrievalOutput);
2752
- retrievalNode = retrievalOutput;
2753
- const traceState = state(null, {
2754
- name: "retrievalTrace",
2755
- describeKind: "state",
2756
- meta: aiMeta("retrieval_trace")
2757
- });
2758
- graph.add("retrievalTrace", traceState);
2759
- retrievalTraceNode = traceState;
2760
- retrieveFn = (query) => {
2761
- const storeMap = extractStoreMap(distillBundle.store.entries.cache);
2762
- const ctx = contextNode.cache;
2763
- const candidateMap = /* @__PURE__ */ new Map();
2764
- let vectorCandidates = [];
2765
- if (vectors && query.vector) {
2766
- vectorCandidates = vectors.search(query.vector, topK);
2767
- for (const vc of vectorCandidates) {
2768
- const mem = storeMap.get(vc.id);
2769
- if (mem) {
2770
- candidateMap.set(vc.id, { value: mem, sources: /* @__PURE__ */ new Set(["vector"]) });
2771
- }
2772
- }
2773
- }
2774
- const graphExpanded = [];
2775
- if (kg) {
2776
- const seedIds = [...query.entityIds ?? [], ...[...candidateMap.keys()]];
2777
- const visited = /* @__PURE__ */ new Set();
2778
- let frontier = seedIds;
2779
- for (let depth = 0; depth < graphDepth; depth++) {
2780
- const nextFrontier = [];
2781
- for (const id of frontier) {
2782
- if (visited.has(id)) continue;
2783
- visited.add(id);
2784
- const related = kg.related(id);
2785
- for (const edge of related) {
2786
- const targetId = edge.to;
2787
- if (!visited.has(targetId)) {
2788
- nextFrontier.push(targetId);
2789
- const mem = storeMap.get(targetId);
2790
- if (mem) {
2791
- const existing = candidateMap.get(targetId);
2792
- if (existing) {
2793
- existing.sources.add("graph");
2794
- } else {
2795
- candidateMap.set(targetId, { value: mem, sources: /* @__PURE__ */ new Set(["graph"]) });
2796
- }
2797
- graphExpanded.push(targetId);
2798
- }
2799
- }
2800
- }
2801
- }
2802
- frontier = nextFrontier;
2803
- }
2804
- }
2805
- for (const [key, mem] of storeMap) {
2806
- if (!candidateMap.has(key)) {
2807
- candidateMap.set(key, { value: mem, sources: /* @__PURE__ */ new Set(["store"]) });
2808
- }
2809
- }
2810
- const ranked = [];
2811
- for (const [key, { value, sources }] of candidateMap) {
2812
- const score = scoreFn(value, ctx);
2813
- ranked.push({ key, value, score, sources: [...sources] });
2814
- }
2815
- ranked.sort((a, b) => b.score - a.score);
2816
- const packed = [];
2817
- let usedBudget = 0;
2818
- for (const entry of ranked) {
2819
- const c = costFn(entry.value);
2820
- if (usedBudget + c > budget && packed.length > 0) break;
2821
- packed.push(entry);
2822
- usedBudget += c;
2823
- }
2824
- const trace = {
2825
- vectorCandidates,
2826
- graphExpanded,
2827
- ranked,
2828
- packed
2829
- };
2830
- batch(() => {
2831
- retrievalOutput.down([[DATA, packed]]);
2832
- traceState.down([[DATA, trace]]);
2833
- });
2834
- return packed;
2835
- };
2836
- }
2837
- graph.addDisposer(() => {
2838
- for (const unsub of keepaliveSubs) unsub();
2839
- keepaliveSubs.length = 0;
2840
- });
2841
- return Object.assign(graph, {
2842
- distillBundle,
2843
- compact: distillBundle.compact,
2844
- size: distillBundle.size,
2845
- vectors,
2846
- kg,
2847
- memoryTiers: memoryTiersBundle,
2848
- retrieval: retrievalNode,
2849
- retrievalTrace: retrievalTraceNode,
2850
- retrieve: retrieveFn
2851
- });
2852
- }
2853
- var AgentLoopGraph = class extends Graph {
2854
- chat;
2855
- tools;
2856
- status;
2857
- turnCount;
2858
- lastResponse;
2859
- _statusState;
2860
- _turnCountState;
2861
- _adapter;
2862
- _maxTurns;
2863
- _stopWhen;
2864
- _onToolCall;
2865
- _systemPrompt;
2866
- _model;
2867
- _temperature;
2868
- _maxTokens;
2869
- _running = false;
2870
- _abortController = null;
2871
- constructor(name, opts) {
2872
- super(name, opts.graph);
2873
- this._adapter = opts.adapter;
2874
- this._maxTurns = opts.maxTurns ?? 10;
2875
- this._stopWhen = opts.stopWhen;
2876
- this._onToolCall = opts.onToolCall;
2877
- this._systemPrompt = opts.systemPrompt;
2878
- this._model = opts.model;
2879
- this._temperature = opts.temperature;
2880
- this._maxTokens = opts.maxTokens;
2881
- this.chat = chatStream(`${name}-chat`, { maxMessages: opts.maxMessages });
2882
- this.mount("chat", this.chat);
2883
- this.tools = toolRegistry(`${name}-tools`);
2884
- this.mount("tools", this.tools);
2885
- if (opts.tools) {
2886
- for (const tool of opts.tools) {
2887
- this.tools.register(tool);
2888
- }
2889
- }
2890
- this._statusState = state("idle", {
2891
- name: "status",
2892
- describeKind: "state",
2893
- meta: aiMeta("agent_status")
2894
- });
2895
- this.status = this._statusState;
2896
- this.add("status", this.status);
2897
- this._turnCountState = state(0, {
2898
- name: "turnCount",
2899
- describeKind: "state",
2900
- meta: aiMeta("agent_turn_count")
2901
- });
2902
- this.turnCount = this._turnCountState;
2903
- this.add("turnCount", this.turnCount);
2904
- this.lastResponse = state(null, {
2905
- name: "lastResponse",
2906
- describeKind: "state",
2907
- meta: aiMeta("agent_last_response")
2908
- });
2909
- this.add("lastResponse", this.lastResponse);
2910
- }
2911
- /**
2912
- * Start the agent loop with a user message. The loop runs reactively:
2913
- * think (LLM call) → act (tool execution) → repeat until done.
2914
- *
2915
- * Messages accumulate across calls. Call `chat.clear()` before `run()`
2916
- * to reset conversation history.
2917
- */
2918
- async run(userMessage) {
2919
- if (this._running) throw new Error("agentLoop: already running");
2920
- this._running = true;
2921
- this._abortController = new AbortController();
2922
- const { signal } = this._abortController;
2923
- batch(() => {
2924
- this._statusState.down([[DATA, "idle"]]);
2925
- this._turnCountState.down([[DATA, 0]]);
2926
- });
2927
- this.chat.append("user", userMessage);
2928
- try {
2929
- let turns = 0;
2930
- while (turns < this._maxTurns) {
2931
- if (signal.aborted) throw new Error("agentLoop: aborted");
2932
- turns++;
2933
- batch(() => {
2934
- this._turnCountState.down([[DATA, turns]]);
2935
- this._statusState.down([[DATA, "thinking"]]);
2936
- });
2937
- const msgs = this.chat.allMessages();
2938
- const toolSchemas = this.tools.schemas.cache ?? [];
2939
- const response = await this._invokeLLM(msgs, toolSchemas, signal);
2940
- if (signal.aborted) throw new Error("agentLoop: aborted");
2941
- this.lastResponse.down([[DATA, response]]);
2942
- this.chat.append("assistant", response.content, {
2943
- toolCalls: response.toolCalls
2944
- });
2945
- if (this._shouldStop(response)) {
2946
- this._statusState.down([[DATA, "done"]]);
2947
- this._running = false;
2948
- this._abortController = null;
2949
- return response;
2950
- }
2951
- if (response.toolCalls && response.toolCalls.length > 0) {
2952
- this._statusState.down([[DATA, "acting"]]);
2953
- for (const call of response.toolCalls) {
2954
- if (signal.aborted) throw new Error("agentLoop: aborted");
2955
- this._onToolCall?.(call);
2956
- try {
2957
- const result = await this.tools.execute(call.name, call.arguments);
2958
- this.chat.appendToolResult(call.id, JSON.stringify(result));
2959
- } catch (err) {
2960
- this.chat.appendToolResult(call.id, JSON.stringify({ error: String(err) }));
2961
- }
2962
- }
2963
- } else {
2964
- this._statusState.down([[DATA, "done"]]);
2965
- this._running = false;
2966
- this._abortController = null;
2967
- return response;
2968
- }
2969
- }
2970
- this._statusState.down([[DATA, "done"]]);
2971
- this._running = false;
2972
- this._abortController = null;
2973
- return this.lastResponse.cache;
2974
- } catch (err) {
2975
- this._statusState.down([[DATA, "error"]]);
2976
- this._running = false;
2977
- this._abortController = null;
2978
- throw err;
2979
- }
2980
- }
2981
- async _invokeLLM(msgs, tools, signal) {
2982
- const result = this._adapter.invoke(msgs, {
2983
- tools: tools.length > 0 ? tools : void 0,
2984
- systemPrompt: this._systemPrompt,
2985
- model: this._model,
2986
- temperature: this._temperature,
2987
- maxTokens: this._maxTokens,
2988
- signal
2989
- });
2990
- if (result == null) {
2991
- throw new Error("_invokeLLM: adapter.invoke() returned null or undefined");
2992
- }
2993
- if (typeof result === "string") {
2994
- throw new Error("_invokeLLM: adapter.invoke() returned a string, expected LLMResponse");
2995
- }
2996
- if (typeof result === "object" && "content" in result && !("subscribe" in result) && !("then" in result)) {
2997
- return result;
2998
- }
2999
- if (isPromiseLike(result)) {
3000
- const awaited = await result;
3001
- if (typeof awaited === "object" && awaited !== null && "content" in awaited && !("subscribe" in awaited)) {
3002
- return awaited;
3003
- }
3004
- return firstDataFromNode(fromAny(awaited));
3005
- }
3006
- return firstDataFromNode(fromAny(result));
3007
- }
3008
- _shouldStop(response) {
3009
- if (response.finishReason === "end_turn" && (!response.toolCalls || response.toolCalls.length === 0))
3010
- return true;
3011
- if (this._stopWhen?.(response)) return true;
3012
- return false;
3013
- }
3014
- destroy() {
3015
- if (this._abortController) {
3016
- this._abortController.abort();
3017
- this._abortController = null;
3018
- }
3019
- this._running = false;
3020
- super.destroy();
3021
- }
3022
- };
3023
- function agentLoop(name, opts) {
3024
- return new AgentLoopGraph(name, opts);
3025
- }
3026
- function metaToJsonSchema(meta) {
3027
- const schema = {};
3028
- const metaType = meta.type;
3029
- if (metaType === "enum" && Array.isArray(meta.values)) {
3030
- schema.type = "string";
3031
- schema.enum = meta.values;
3032
- } else if (metaType === "integer") {
3033
- schema.type = "integer";
3034
- } else if (metaType === "number") {
3035
- schema.type = "number";
3036
- } else if (metaType === "boolean") {
3037
- schema.type = "boolean";
3038
- } else if (metaType === "string") {
3039
- schema.type = "string";
3040
- } else {
3041
- schema.type = ["string", "number", "boolean"];
3042
- }
3043
- if (Array.isArray(meta.range) && meta.range.length === 2) {
3044
- schema.minimum = meta.range[0];
3045
- schema.maximum = meta.range[1];
3046
- }
3047
- if (typeof meta.format === "string") {
3048
- schema.description = `Format: ${meta.format}`;
3049
- }
3050
- if (typeof meta.unit === "string") {
3051
- if (schema.description) {
3052
- schema.description += ` (${meta.unit})`;
3053
- } else {
3054
- schema.description = `Unit: ${meta.unit}`;
3055
- }
3056
- }
3057
- return schema;
3058
- }
3059
- function knobsAsTools(graph, actor) {
3060
- const described = graph.describe({ actor, detail: "full" });
3061
- const openai = [];
3062
- const mcp = [];
3063
- const definitions = [];
3064
- for (const [path, node2] of Object.entries(described.nodes)) {
3065
- if (node2.type !== "state") continue;
3066
- if (path.includes("::__meta__::")) continue;
3067
- if (node2.status === "completed" || node2.status === "errored") continue;
3068
- const meta = node2.meta ?? {};
3069
- const access = meta.access;
3070
- if (access === "human" || access === "system") continue;
3071
- const description = meta.description ?? `Set the value of ${path}`;
3072
- const valueSchema = metaToJsonSchema(meta);
3073
- const parameterSchema = {
3074
- type: "object",
3075
- required: ["value"],
3076
- properties: {
3077
- value: valueSchema
3078
- },
3079
- additionalProperties: false
3080
- };
3081
- const sanitizedName = path.replace(/::/g, "__");
3082
- openai.push({
3083
- type: "function",
3084
- function: {
3085
- name: sanitizedName,
3086
- description,
3087
- parameters: parameterSchema
3088
- }
3089
- });
3090
- mcp.push({
3091
- name: path,
3092
- description,
3093
- inputSchema: parameterSchema
3094
- });
3095
- const graphRef = graph;
3096
- const actorRef = actor;
3097
- const nv = node2.v;
3098
- definitions.push({
3099
- name: path,
3100
- description,
3101
- parameters: parameterSchema,
3102
- handler(args) {
3103
- graphRef.set(path, args.value, actorRef ? { actor: actorRef } : void 0);
3104
- return args.value;
3105
- },
3106
- ...nv != null ? { version: { id: nv.id, version: nv.version } } : {}
3107
- });
3108
- }
3109
- return { openai, mcp, definitions };
3110
- }
3111
- function gaugesAsContext(graph, actor, options) {
3112
- const described = graph.describe({ actor, detail: "full" });
3113
- const groupByTags = options?.groupByTags ?? true;
3114
- const separator = options?.separator ?? "\n";
3115
- const entries = [];
3116
- const sinceVersion = options?.sinceVersion;
3117
- for (const [path, node2] of Object.entries(described.nodes)) {
3118
- const meta = node2.meta ?? {};
3119
- const desc = meta.description;
3120
- const format = meta.format;
3121
- if (!desc && !format) continue;
3122
- if (sinceVersion != null && node2.v != null) {
3123
- const lastSeen = sinceVersion.get(path);
3124
- if (lastSeen != null && lastSeen.id === node2.v.id && node2.v.version <= lastSeen.version)
3125
- continue;
3126
- }
3127
- const label = desc ?? path;
3128
- const value = node2.value;
3129
- const unit = meta.unit;
3130
- let formatted;
3131
- if (format === "currency" && typeof value === "number") {
3132
- formatted = `$${value.toFixed(2)}`;
3133
- } else if (format === "percentage" && typeof value === "number") {
3134
- formatted = `${(value * 100).toFixed(1)}%`;
3135
- } else if (value === void 0 || value === null) {
3136
- formatted = "(no value)";
3137
- } else {
3138
- formatted = String(value);
3139
- }
3140
- if (unit && format !== "currency" && format !== "percentage") {
3141
- formatted = `${formatted} ${unit}`;
3142
- }
3143
- entries.push({ path, description: label, formatted });
3144
- }
3145
- if (entries.length === 0) return "";
3146
- if (groupByTags) {
3147
- const tagGroups = /* @__PURE__ */ new Map();
3148
- const ungrouped = [];
3149
- for (const entry of entries) {
3150
- const node2 = described.nodes[entry.path];
3151
- const tags = node2.meta?.tags;
3152
- if (tags && tags.length > 0) {
3153
- const tag = tags[0];
3154
- let group = tagGroups.get(tag);
3155
- if (!group) {
3156
- group = [];
3157
- tagGroups.set(tag, group);
3158
- }
3159
- group.push(entry);
3160
- } else {
3161
- ungrouped.push(entry);
3162
- }
3163
- }
3164
- if (tagGroups.size === 0) {
3165
- return entries.map((e) => `- ${e.description}: ${e.formatted}`).join(separator);
3166
- }
3167
- const sections = [];
3168
- for (const [tag, group] of [...tagGroups.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
3169
- sections.push(
3170
- `[${tag}]${separator}${group.map((e) => `- ${e.description}: ${e.formatted}`).join(separator)}`
3171
- );
3172
- }
3173
- if (ungrouped.length > 0) {
3174
- sections.push(ungrouped.map((e) => `- ${e.description}: ${e.formatted}`).join(separator));
3175
- }
3176
- return sections.join(separator + separator);
3177
- }
3178
- return entries.map((e) => `- ${e.description}: ${e.formatted}`).join(separator);
3179
- }
3180
- var VALID_NODE_TYPES = /* @__PURE__ */ new Set(["state", "derived", "producer", "operator", "effect"]);
3181
- function validateGraphDef(def) {
3182
- const errors = [];
3183
- if (def == null || typeof def !== "object") {
3184
- return { valid: false, errors: ["Definition must be a non-null object"] };
3185
- }
3186
- const d = def;
3187
- if (typeof d.name !== "string" || d.name.length === 0) {
3188
- errors.push("Missing or empty 'name' field");
3189
- }
3190
- if (d.nodes == null || typeof d.nodes !== "object" || Array.isArray(d.nodes)) {
3191
- errors.push("Missing or invalid 'nodes' field (must be an object)");
3192
- return { valid: false, errors };
3193
- }
3194
- const nodeNames = new Set(Object.keys(d.nodes));
3195
- for (const [name, raw] of Object.entries(d.nodes)) {
3196
- if (raw == null || typeof raw !== "object") {
3197
- errors.push(`Node "${name}": must be an object`);
3198
- continue;
3199
- }
3200
- const node2 = raw;
3201
- if (typeof node2.type !== "string" || !VALID_NODE_TYPES.has(node2.type)) {
3202
- errors.push(
3203
- `Node "${name}": invalid type "${String(node2.type)}" (expected: ${[...VALID_NODE_TYPES].join(", ")})`
3204
- );
3205
- }
3206
- if (Array.isArray(node2.deps)) {
3207
- for (const dep of node2.deps) {
3208
- if (typeof dep === "string" && !nodeNames.has(dep)) {
3209
- errors.push(`Node "${name}": dep "${dep}" does not reference an existing node`);
3210
- }
3211
- }
3212
- }
3213
- }
3214
- if (!Array.isArray(d.edges)) {
3215
- if (d.edges !== void 0) {
3216
- errors.push("'edges' must be an array");
3217
- }
3218
- } else {
3219
- const seen = /* @__PURE__ */ new Set();
3220
- for (let i = 0; i < d.edges.length; i++) {
3221
- const edge = d.edges[i];
3222
- if (edge == null || typeof edge !== "object") {
3223
- errors.push(`Edge [${i}]: must be an object`);
3224
- continue;
3225
- }
3226
- const e = edge;
3227
- if (typeof e.from !== "string" || !nodeNames.has(e.from)) {
3228
- errors.push(`Edge [${i}]: 'from' "${String(e.from)}" does not reference an existing node`);
3229
- }
3230
- if (typeof e.to !== "string" || !nodeNames.has(e.to)) {
3231
- errors.push(`Edge [${i}]: 'to' "${String(e.to)}" does not reference an existing node`);
3232
- }
3233
- const key = `${e.from}->${e.to}`;
3234
- if (seen.has(key)) {
3235
- errors.push(`Edge [${i}]: duplicate edge ${key}`);
3236
- }
3237
- seen.add(key);
3238
- }
3239
- }
3240
- return { valid: errors.length === 0, errors };
3241
- }
3242
- function stripFences(text) {
3243
- const match = text.match(/^```(?:json)?\s*([\s\S]*?)\s*```[\s\S]*$/);
3244
- return match ? match[1] : text;
3245
- }
3246
- var GRAPH_FROM_SPEC_SYSTEM_PROMPT = `You are a graph architect for GraphReFly, a reactive graph protocol.
3247
-
3248
- Given a natural-language description, produce a JSON graph definition with this structure:
3249
-
3250
- {
3251
- "name": "<graph_name>",
3252
- "nodes": {
3253
- "<node_name>": {
3254
- "type": "state" | "derived" | "producer" | "operator" | "effect",
3255
- "value": <initial_value_or_null>,
3256
- "deps": ["<dep_node_name>", ...],
3257
- "meta": {
3258
- "description": "<human-readable purpose>",
3259
- "type": "string" | "number" | "boolean" | "integer" | "enum",
3260
- "range": [min, max],
3261
- "values": ["a", "b"],
3262
- "format": "currency" | "percentage" | "status",
3263
- "access": "human" | "llm" | "both" | "system",
3264
- "unit": "<unit>",
3265
- "tags": ["<tag>"]
3266
- }
3267
- }
3268
- },
3269
- "edges": [
3270
- { "from": "<source_node>", "to": "<target_node>" }
3271
- ]
3272
- }
3273
-
3274
- Rules:
3275
- - "state" nodes have no deps and hold user/LLM-writable values (knobs).
3276
- - "derived" nodes have deps and compute from them.
3277
- - "effect" nodes have deps but produce side effects (no return value).
3278
- - "producer" nodes have no deps but generate values asynchronously.
3279
- - Edges wire output of one node as input to another. They must match deps.
3280
- - meta.description is required for every node.
3281
- - Return ONLY valid JSON, no markdown fences or commentary.`;
3282
- async function graphFromSpec(naturalLanguage, adapter, opts) {
3283
- const systemPrompt = opts?.systemPromptExtra ? `${GRAPH_FROM_SPEC_SYSTEM_PROMPT}
3284
-
3285
- ${opts.systemPromptExtra}` : GRAPH_FROM_SPEC_SYSTEM_PROMPT;
3286
- const messages = [
3287
- { role: "system", content: systemPrompt },
3288
- { role: "user", content: naturalLanguage }
3289
- ];
3290
- const rawResult = adapter.invoke(messages, {
3291
- model: opts?.model,
3292
- temperature: opts?.temperature ?? 0,
3293
- maxTokens: opts?.maxTokens
3294
- });
3295
- const response = await resolveToolHandlerResult(rawResult);
3296
- let content = response.content.trim();
3297
- if (content.startsWith("```")) {
3298
- content = stripFences(content);
3299
- }
3300
- let parsed;
3301
- try {
3302
- parsed = JSON.parse(content);
3303
- } catch {
3304
- throw new Error(`graphFromSpec: LLM response is not valid JSON: ${content.slice(0, 200)}`);
3305
- }
3306
- const validation = validateGraphDef(parsed);
3307
- if (!validation.valid) {
3308
- throw new Error(`graphFromSpec: invalid graph definition:
3309
- ${validation.errors.join("\n")}`);
3310
- }
3311
- const def = parsed;
3312
- if (def.version === void 0) def.version = 1;
3313
- if (!Array.isArray(def.subgraphs)) def.subgraphs = [];
3314
- return Graph.fromSnapshot(def, opts?.build);
3315
- }
3316
- var SUGGEST_STRATEGY_SYSTEM_PROMPT = `You are a reactive graph optimizer for GraphReFly.
3317
-
3318
- Given a graph's current structure (from describe()) and a problem statement, suggest topology and parameter changes to solve the problem.
3319
-
3320
- Return ONLY valid JSON with this structure:
3321
- {
3322
- "summary": "<one-line summary of the strategy>",
3323
- "reasoning": "<explanation of why these changes help>",
3324
- "operations": [
3325
- { "type": "add_node", "name": "<name>", "nodeType": "state|derived|effect|producer|operator", "meta": {...}, "initial": <value> },
3326
- { "type": "remove_node", "name": "<name>" },
3327
- { "type": "connect", "from": "<source>", "to": "<target>" },
3328
- { "type": "disconnect", "from": "<source>", "to": "<target>" },
3329
- { "type": "set_value", "name": "<name>", "value": <new_value> },
3330
- { "type": "update_meta", "name": "<name>", "key": "<meta_key>", "value": <new_value> }
3331
- ]
3332
- }
3333
-
3334
- Rules:
3335
- - Only suggest operations that reference existing nodes (for remove/disconnect/set_value/update_meta) or new nodes you define (for add_node).
3336
- - Keep changes minimal \u2014 prefer the smallest set of operations that solves the problem.
3337
- - Return ONLY valid JSON, no markdown fences or commentary.`;
3338
- async function suggestStrategy(graph, problem, adapter, opts) {
3339
- const { expand: _, ...described } = graph.describe({ actor: opts?.actor, detail: "standard" });
3340
- const messages = [
3341
- { role: "system", content: SUGGEST_STRATEGY_SYSTEM_PROMPT },
3342
- {
3343
- role: "user",
3344
- content: JSON.stringify({
3345
- graph: described,
3346
- problem
3347
- })
3348
- }
3349
- ];
3350
- const rawResult = adapter.invoke(messages, {
3351
- model: opts?.model,
3352
- temperature: opts?.temperature ?? 0,
3353
- maxTokens: opts?.maxTokens
3354
- });
3355
- const response = await resolveToolHandlerResult(rawResult);
3356
- let content = response.content.trim();
3357
- if (content.startsWith("```")) {
3358
- content = content.replace(/^```(?:json)?\s*/, "").replace(/\s*```$/, "");
3359
- }
3360
- let parsed;
3361
- try {
3362
- parsed = JSON.parse(content);
3363
- } catch {
3364
- throw new Error(`suggestStrategy: LLM response is not valid JSON: ${content.slice(0, 200)}`);
3365
- }
3366
- const plan = parsed;
3367
- if (typeof plan.summary !== "string") {
3368
- throw new Error("suggestStrategy: missing 'summary' in response");
3369
- }
3370
- if (typeof plan.reasoning !== "string") {
3371
- throw new Error("suggestStrategy: missing 'reasoning' in response");
3372
- }
3373
- if (!Array.isArray(plan.operations)) {
3374
- throw new Error("suggestStrategy: missing 'operations' array in response");
3375
- }
3376
- return {
3377
- summary: plan.summary,
3378
- reasoning: plan.reasoning,
3379
- operations: plan.operations
3380
- };
3381
- }
229
+ cached,
230
+ empty,
231
+ escapeRegexChar,
232
+ firstValueFrom,
233
+ firstWhere,
234
+ forEach,
235
+ fromAny,
236
+ fromAsyncIter,
237
+ fromCron,
238
+ fromEvent,
239
+ fromIter,
240
+ fromPromise,
241
+ fromRaf,
242
+ fromTimer,
243
+ globToRegExp,
244
+ keepalive,
245
+ matchesAnyPattern,
246
+ matchesCron,
247
+ never,
248
+ of,
249
+ parseCron,
250
+ reactiveCounter,
251
+ replay,
252
+ share,
253
+ shareReplay,
254
+ throwError,
255
+ toArray
256
+ } from "./chunk-BVZYTZ5H.js";
257
+ import {
258
+ graph_exports,
259
+ watchTopologyTree
260
+ } from "./chunk-OU5CQKNW.js";
261
+ import {
262
+ GRAPH_META_SEGMENT,
263
+ Graph,
264
+ OVERHEAD,
265
+ SIZEOF_SYMBOL,
266
+ SNAPSHOT_VERSION,
267
+ diffForWAL,
268
+ explainPath,
269
+ graphProfile,
270
+ reachable,
271
+ sizeof
272
+ } from "./chunk-PF7GRZMW.js";
273
+ import {
274
+ resolveDescribeFields
275
+ } from "./chunk-VYPWMZ6H.js";
276
+ import {
277
+ ResettableTimer
278
+ } from "./chunk-7TAQJHQV.js";
279
+ import {
280
+ DEFAULT_ACTOR,
281
+ ENVELOPE_VERSION,
282
+ GraphReFlyConfig,
283
+ GuardDenied,
284
+ JsonCodec,
285
+ NodeImpl,
286
+ accessHintForGuard,
287
+ advanceVersion,
288
+ autoTrackNode,
289
+ batch,
290
+ configure,
291
+ createDagCborCodec,
292
+ createDagCborZstdCodec,
293
+ createVersioning,
294
+ decodeEnvelope,
295
+ defaultConfig,
296
+ defaultHash,
297
+ derived,
298
+ downWithBatch,
299
+ dynamicNode,
300
+ effect,
301
+ encodeEnvelope,
302
+ isBatching,
303
+ isV1,
304
+ monotonicNs,
305
+ node,
306
+ normalizeActor,
307
+ pipe,
308
+ policy,
309
+ policyFromRules,
310
+ producer,
311
+ registerBuiltinCodecs,
312
+ registerBuiltins,
313
+ replayWAL,
314
+ state,
315
+ wallClockNs
316
+ } from "./chunk-PHOUUNK7.js";
317
+ import {
318
+ COMPLETE,
319
+ COMPLETE_MSG,
320
+ COMPLETE_ONLY_BATCH,
321
+ DATA,
322
+ DIRTY,
323
+ DIRTY_MSG,
324
+ DIRTY_ONLY_BATCH,
325
+ ERROR,
326
+ INVALIDATE,
327
+ INVALIDATE_MSG,
328
+ INVALIDATE_ONLY_BATCH,
329
+ PAUSE,
330
+ RESOLVED,
331
+ RESOLVED_MSG,
332
+ RESOLVED_ONLY_BATCH,
333
+ RESUME,
334
+ START,
335
+ START_MSG,
336
+ TEARDOWN,
337
+ TEARDOWN_MSG,
338
+ TEARDOWN_ONLY_BATCH,
339
+ __export
340
+ } from "./chunk-SX52TAR4.js";
3382
341
 
3383
- // src/patterns/audit.ts
3384
- var audit_exports = {};
3385
- __export(audit_exports, {
3386
- AuditTrailGraph: () => AuditTrailGraph,
3387
- PolicyEnforcerGraph: () => PolicyEnforcerGraph,
3388
- auditTrail: () => auditTrail,
3389
- complianceSnapshot: () => complianceSnapshot,
3390
- policyEnforcer: () => policyEnforcer,
3391
- reactiveExplainPath: () => reactiveExplainPath
342
+ // src/patterns/index.ts
343
+ var patterns_exports = {};
344
+ __export(patterns_exports, {
345
+ SNAPSHOT_WIRE_VERSION: () => SNAPSHOT_WIRE_VERSION,
346
+ SurfaceError: () => SurfaceError,
347
+ accountability: () => audit_exports,
348
+ ai: () => ai_exports,
349
+ asSurfaceError: () => asSurfaceError,
350
+ cqrs: () => cqrs_exports,
351
+ createGraph: () => createGraph,
352
+ deleteSnapshot: () => deleteSnapshot,
353
+ demoShell: () => demo_shell_exports,
354
+ diffSnapshots: () => diffSnapshots,
355
+ domainTemplates: () => domain_templates_exports,
356
+ graphspec: () => graphspec_exports,
357
+ guarded: () => guarded_execution_exports,
358
+ harness: () => harness_exports,
359
+ layout: () => reactive_layout_exports,
360
+ lens: () => lens_exports,
361
+ listSnapshots: () => listSnapshots,
362
+ memory: () => memory_exports,
363
+ messaging: () => messaging_exports,
364
+ orchestration: () => orchestration_exports,
365
+ reduction: () => reduction_exports,
366
+ resilientPipeline: () => resilient_pipeline_exports,
367
+ restoreSnapshot: () => restoreSnapshot,
368
+ runReduction: () => runReduction,
369
+ saveSnapshot: () => saveSnapshot,
370
+ surface: () => surface_exports
3392
371
  });
3393
- function auditMeta(kind, extra) {
3394
- return domainMeta("audit", kind, extra);
3395
- }
3396
- var DEFAULT_INCLUDE_TYPES = /* @__PURE__ */ new Set([
3397
- "data",
3398
- "error",
3399
- "complete",
3400
- "teardown"
3401
- ]);
3402
- var AuditTrailGraph = class extends Graph {
3403
- entries;
3404
- count;
3405
- _log;
3406
- _target;
3407
- constructor(target, opts) {
3408
- super(opts.name ?? `${target.name}_audit`, opts.graph);
3409
- this._target = target;
3410
- this._log = reactiveLog([], {
3411
- name: "entries",
3412
- ...opts.maxSize != null ? { maxSize: opts.maxSize } : {}
3413
- });
3414
- this.entries = this._log.entries;
3415
- this.add("entries", this.entries);
3416
- this.count = derived(
3417
- [this.entries],
3418
- ([snapshot]) => snapshot.length,
3419
- { name: "count", describeKind: "derived", meta: auditMeta("count") }
3420
- );
3421
- this.add("count", this.count);
3422
- this.addDisposer(keepalive(this.count));
3423
- const includeTypes = opts.includeTypes != null ? new Set(opts.includeTypes) : DEFAULT_INCLUDE_TYPES;
3424
- const filter2 = opts.filter;
3425
- let seq = 0;
3426
- const handle = target.observe({ timeline: true, structured: true });
3427
- const offEvent = handle.onEvent((event) => {
3428
- if (event.type === "derived") return;
3429
- const type = event.type;
3430
- if (!includeTypes.has(type)) return;
3431
- const path = event.path ?? "";
3432
- const entry = {
3433
- seq: seq++,
3434
- timestamp_ns: event.timestamp_ns ?? monotonicNs(),
3435
- wall_clock_ns: wallClockNs(),
3436
- path,
3437
- type
3438
- };
3439
- const node2 = path ? safeNode(target, path) : void 0;
3440
- const lastMutation = node2?.lastMutation;
3441
- if (lastMutation != null) entry.actor = lastMutation.actor;
3442
- if (type === "data") entry.value = event.data;
3443
- if (type === "error") entry.error = event.data;
3444
- const reason = path ? safeAnnotation(target, path) : void 0;
3445
- if (reason != null) entry.reason = reason;
3446
- if (filter2 != null && !filter2(entry)) return;
3447
- this._log.append(entry);
3448
- });
3449
- this.addDisposer(() => {
3450
- offEvent();
3451
- handle.dispose();
3452
- });
3453
- this.addDisposer(() => this._log.disposeAllViews());
3454
- }
3455
- /** All entries currently in the ring (snapshot). */
3456
- all() {
3457
- return this.entries.cache ?? [];
3458
- }
3459
- /** Entries matching `path`. Order preserved. */
3460
- byNode(path) {
3461
- return this.all().filter((e) => e.path === path);
3462
- }
3463
- /** Entries whose `actor.id` matches. Use `byActorType` for type filtering. */
3464
- byActor(actorId) {
3465
- return this.all().filter((e) => e.actor?.id === actorId);
3466
- }
3467
- /** Entries whose `actor.type` matches (e.g. `"llm"`, `"human"`). */
3468
- byActorType(type) {
3469
- return this.all().filter((e) => e.actor?.type === type);
3470
- }
3471
- /**
3472
- * Entries with `timestamp_ns` in `[start_ns, end_ns)` (end exclusive).
3473
- * Omit `end_ns` to query open-ended.
3474
- */
3475
- byTimeRange(start_ns, end_ns) {
3476
- return this.all().filter((e) => {
3477
- if (e.timestamp_ns < start_ns) return false;
3478
- if (end_ns != null && e.timestamp_ns >= end_ns) return false;
3479
- return true;
3480
- });
3481
- }
3482
- /** Reference to the audited graph (escape hatch for tooling). */
3483
- get target() {
3484
- return this._target;
3485
- }
3486
- };
3487
- function auditTrail(target, opts = {}) {
3488
- return new AuditTrailGraph(target, opts);
3489
- }
3490
- var PolicyEnforcerGraph = class extends Graph {
3491
- policies;
3492
- violations;
3493
- violationCount;
3494
- _target;
3495
- _mode;
3496
- _currentGuard;
3497
- constructor(target, policies, opts) {
3498
- super(opts.name ?? `${target.name}_policy`, opts.graph);
3499
- this._target = target;
3500
- this._mode = opts.mode ?? "audit";
3501
- const policiesNode = isNode(policies) ? policies : state(policies, { name: "policies" });
3502
- this.policies = policiesNode;
3503
- this.add("policies", this.policies);
3504
- this.violations = new TopicGraph("violations", {
3505
- retainedLimit: opts.violationsLimit ?? 1e3
3506
- });
3507
- this.mount("violations", this.violations);
3508
- this.violationCount = derived(
3509
- [this.violations.events],
3510
- ([snapshot]) => snapshot.length,
3511
- {
3512
- name: "violationCount",
3513
- describeKind: "derived",
3514
- meta: auditMeta("policy_violation_count")
3515
- }
3516
- );
3517
- this.add("violationCount", this.violationCount);
3518
- this.addDisposer(keepalive(this.violationCount));
3519
- const initialRules = policiesNode.cache ?? [];
3520
- let latestRules = initialRules;
3521
- this._currentGuard = policyFromRules(latestRules);
3522
- const offPolicies = policiesNode.subscribe((msgs) => {
3523
- for (const m of msgs) {
3524
- if (m[0] === DATA) {
3525
- latestRules = m[1] ?? [];
3526
- this._currentGuard = policyFromRules(latestRules);
3527
- }
3528
- }
3529
- });
3530
- this.addDisposer(offPolicies);
3531
- const paths = opts.paths != null ? [...opts.paths] : collectPaths(target);
3532
- if (this._mode === "enforce") {
3533
- const restorers = /* @__PURE__ */ new Map();
3534
- const wrapAndPush = (path) => {
3535
- if (restorers.has(path)) return;
3536
- const node2 = safeNode(target, path);
3537
- if (!(node2 instanceof NodeImpl)) return;
3538
- const pathGuard = (actor, action) => {
3539
- const ok = this._currentGuard(actor, action);
3540
- if (!ok) {
3541
- this._publishViolation(actor, action, path, "blocked");
3542
- }
3543
- return ok;
3544
- };
3545
- restorers.set(path, node2._pushGuard(pathGuard));
3546
- };
3547
- for (const path of paths) wrapAndPush(path);
3548
- if (opts.paths == null) {
3549
- const offTopology = watchTopologyTree(target, (event, emitter, prefix) => {
3550
- if (event.kind === "added") {
3551
- if (event.nodeKind === "node") {
3552
- wrapAndPush(`${prefix}${event.name}`);
3553
- } else {
3554
- const child = emitter._mounts.get(event.name);
3555
- if (!(child instanceof Graph)) return;
3556
- const mountPrefix = `${prefix}${event.name}::`;
3557
- const localPaths = collectPaths(child);
3558
- for (const localPath of localPaths) {
3559
- wrapAndPush(
3560
- localPath === "" ? `${prefix}${event.name}` : `${mountPrefix}${localPath}`
3561
- );
3562
- }
3563
- }
3564
- } else if (event.kind === "removed") {
3565
- if (event.nodeKind === "node") {
3566
- const qp = `${prefix}${event.name}`;
3567
- const r = restorers.get(qp);
3568
- if (r != null) {
3569
- r();
3570
- restorers.delete(qp);
3571
- }
3572
- } else {
3573
- const mountQp = `${prefix}${event.name}`;
3574
- const mountPrefix = `${mountQp}::`;
3575
- for (const [p, r] of restorers) {
3576
- if (p === mountQp || p.startsWith(mountPrefix)) {
3577
- r();
3578
- restorers.delete(p);
3579
- }
3580
- }
3581
- }
3582
- }
3583
- });
3584
- this.addDisposer(offTopology);
3585
- } else {
3586
- const offCleanup = target.topology.subscribe((msgs) => {
3587
- for (const m of msgs) {
3588
- if (m[0] !== DATA) continue;
3589
- const event = m[1];
3590
- if (event.kind !== "removed" || event.nodeKind !== "node") continue;
3591
- const r = restorers.get(event.name);
3592
- if (r != null) {
3593
- r();
3594
- restorers.delete(event.name);
3595
- }
3596
- }
3597
- });
3598
- this.addDisposer(offCleanup);
3599
- }
3600
- this.addDisposer(() => {
3601
- for (const r of restorers.values()) r();
3602
- restorers.clear();
3603
- });
3604
- } else {
3605
- const handle = target.observe({ timeline: true, structured: true });
3606
- const off = handle.onEvent((event) => {
3607
- if (event.type !== "data" && event.type !== "error") return;
3608
- const path = event.path ?? "";
3609
- if (!path) return;
3610
- if (opts.paths != null && !opts.paths.includes(path)) return;
3611
- const node2 = safeNode(target, path);
3612
- const lastMutation = node2?.lastMutation;
3613
- if (lastMutation == null) return;
3614
- const action = "write";
3615
- if (this._currentGuard(lastMutation.actor, action)) return;
3616
- this._publishViolation(lastMutation.actor, action, path, "observed");
3617
- });
3618
- this.addDisposer(() => {
3619
- off();
3620
- handle.dispose();
3621
- });
3622
- }
3623
- }
3624
- _publishViolation(actor, action, path, result) {
3625
- this.violations.publish({
3626
- timestamp_ns: monotonicNs(),
3627
- wall_clock_ns: wallClockNs(),
3628
- path,
3629
- actor,
3630
- action,
3631
- mode: this._mode,
3632
- result
3633
- });
3634
- }
3635
- /** Snapshot of recorded violations. */
3636
- all() {
3637
- return this.violations.retained();
3638
- }
3639
- get mode() {
3640
- return this._mode;
3641
- }
3642
- get target() {
3643
- return this._target;
3644
- }
3645
- };
3646
- function policyEnforcer(target, policies, opts = {}) {
3647
- return new PolicyEnforcerGraph(target, policies, opts);
3648
- }
3649
- function reactiveExplainPath(target, from, to, opts) {
3650
- let v = 0;
3651
- const version2 = state(v, { name: "explain_version" });
3652
- const handle = target.observe({ timeline: true, structured: true });
3653
- const off = handle.onEvent((event) => {
3654
- const t = event.type;
3655
- if (t !== "data" && t !== "error" && t !== "complete" && t !== "teardown") return;
3656
- v += 1;
3657
- version2.emit(v);
3658
- });
3659
- const explainOpts = {
3660
- ...opts?.maxDepth != null ? { maxDepth: opts.maxDepth } : {},
3661
- ...opts?.findCycle === true ? { findCycle: true } : {}
3662
- };
3663
- const node2 = derived([version2], () => target.explain(from, to, explainOpts), {
3664
- name: opts?.name ?? "explain",
3665
- describeKind: "derived",
3666
- equals: (a, b) => a.found === b.found && a.reason === b.reason && a.steps.length === b.steps.length && causalStepsEqual(a.steps, b.steps),
3667
- meta: auditMeta("explain_path", { from, to })
3668
- });
3669
- const stopKeepalive = keepalive(node2);
3670
- return {
3671
- node: node2,
3672
- dispose() {
3673
- off();
3674
- handle.dispose();
3675
- stopKeepalive();
3676
- }
3677
- };
3678
- }
3679
- function causalStepsEqual(a, b) {
3680
- for (let i = 0; i < a.length; i++) {
3681
- const x = a[i];
3682
- const y = b[i];
3683
- if (x.path !== y.path) return false;
3684
- if (x.type !== y.type) return false;
3685
- if (x.status !== y.status) return false;
3686
- if (x.hop !== y.hop) return false;
3687
- if (x.dep_index !== y.dep_index) return false;
3688
- if (x.reason !== y.reason) return false;
3689
- if (x.value !== y.value) return false;
3690
- if (x.lastMutation !== y.lastMutation) return false;
3691
- const xv = x.v;
3692
- const yv = y.v;
3693
- if (xv !== yv) {
3694
- if (xv == null || yv == null) return false;
3695
- if (xv.id !== yv.id || xv.version !== yv.version) return false;
3696
- }
3697
- }
3698
- return true;
3699
- }
3700
- function complianceSnapshot(target, opts = {}) {
3701
- const result = {
3702
- format_version: 1,
3703
- timestamp_ns: monotonicNs(),
3704
- wall_clock_ns: wallClockNs(),
3705
- graph: target.snapshot()
3706
- };
3707
- if (opts.actor != null) result.actor = opts.actor;
3708
- if (opts.audit != null) {
3709
- const entries = [...opts.audit.all()];
3710
- result.audit = { count: entries.length, entries };
3711
- }
3712
- if (opts.policies != null) {
3713
- const rules = opts.policies.policies.cache ?? [];
3714
- result.policies = {
3715
- mode: opts.policies.mode,
3716
- rules,
3717
- violations: [...opts.policies.all()]
3718
- };
3719
- }
3720
- const fingerprint = computeFingerprint(result);
3721
- return { ...result, fingerprint };
3722
- }
3723
- function isNode(x) {
3724
- return typeof x === "object" && x !== null && "subscribe" in x;
3725
- }
3726
- function safeNode(target, path) {
3727
- try {
3728
- return target.node(path);
3729
- } catch {
3730
- return void 0;
3731
- }
3732
- }
3733
- function safeAnnotation(target, path) {
3734
- try {
3735
- return target.annotation(path);
3736
- } catch {
3737
- return void 0;
3738
- }
3739
- }
3740
- function collectPaths(target) {
3741
- const described = target.describe({ detail: "minimal" });
3742
- return Object.keys(described.nodes);
3743
- }
3744
- function computeFingerprint(value) {
3745
- return defaultHash(JSON.stringify(canonicalize(value)));
3746
- }
3747
- function canonicalize(value) {
3748
- const stack = /* @__PURE__ */ new Set();
3749
- const walk = (v) => {
3750
- if (v === void 0) return { __undefined: true };
3751
- if (v === null) return null;
3752
- const t = typeof v;
3753
- if (t === "bigint") return { __bigint: v.toString() };
3754
- if (t !== "object") return v;
3755
- const obj = v;
3756
- if (stack.has(obj)) return { __circular: true };
3757
- stack.add(obj);
3758
- try {
3759
- if (Array.isArray(obj)) {
3760
- return obj.map(walk);
3761
- }
3762
- if (obj instanceof Date) {
3763
- return { __date: obj.toISOString() };
3764
- }
3765
- if (obj instanceof RegExp) {
3766
- return { __regexp: { source: obj.source, flags: obj.flags } };
3767
- }
3768
- if (obj instanceof Map) {
3769
- const entries = [...obj.entries()].map(([k, mv]) => [
3770
- walk(k),
3771
- walk(mv)
3772
- ]);
3773
- return { __map: entries };
3774
- }
3775
- if (obj instanceof Set) {
3776
- const items = [...obj].map(walk);
3777
- return { __set: items };
3778
- }
3779
- if (ArrayBuffer.isView(obj)) {
3780
- const ta = obj;
3781
- const arr = new Array(ta.length);
3782
- for (let i = 0; i < ta.length; i++) arr[i] = ta[i] ?? 0;
3783
- return { __typed_array: { ctor: obj.constructor.name, data: arr } };
3784
- }
3785
- const out = {};
3786
- for (const k of Object.keys(obj).sort()) {
3787
- out[k] = walk(obj[k]);
3788
- }
3789
- return out;
3790
- } finally {
3791
- stack.delete(obj);
3792
- }
3793
- };
3794
- return walk(value);
3795
- }
3796
372
 
3797
373
  // src/patterns/domain-templates.ts
3798
374
  var domain_templates_exports = {};
@@ -3813,14 +389,14 @@ __export(reduction_exports, {
3813
389
  scorer: () => scorer,
3814
390
  stratify: () => stratify
3815
391
  });
3816
- function baseMeta2(kind, meta) {
392
+ function baseMeta(kind, meta) {
3817
393
  return domainMeta("reduction", kind, meta);
3818
394
  }
3819
395
  function stratify(name, source, rules, opts) {
3820
396
  const g = new Graph(name, opts);
3821
397
  g.add("source", source);
3822
398
  const rulesNode = state(rules, {
3823
- meta: baseMeta2("stratify_rules")
399
+ meta: baseMeta("stratify_rules")
3824
400
  });
3825
401
  g.add("rules", rulesNode);
3826
402
  for (const rule of rules) {
@@ -3889,7 +465,7 @@ function _addBranch(graph, source, rulesNode, rule) {
3889
465
  },
3890
466
  {
3891
467
  describeKind: "derived",
3892
- meta: baseMeta2("stratify_branch", { branch: rule.name }),
468
+ meta: baseMeta("stratify_branch", { branch: rule.name }),
3893
469
  completeWhenDepsComplete: false
3894
470
  }
3895
471
  );
@@ -3983,7 +559,7 @@ function feedback(graph, condition, reentry, opts) {
3983
559
  const maxIter = opts?.maxIterations ?? 10;
3984
560
  const counterName = `__feedback_${condition}`;
3985
561
  const counter = state(0, {
3986
- meta: baseMeta2("feedback_counter", {
562
+ meta: baseMeta("feedback_counter", {
3987
563
  maxIterations: maxIter,
3988
564
  feedbackFrom: condition,
3989
565
  feedbackTo: reentry
@@ -4019,7 +595,7 @@ function feedback(graph, condition, reentry, opts) {
4019
595
  name: feedbackEffectName,
4020
596
  describeKind: "effect",
4021
597
  meta: {
4022
- ...baseMeta2("feedback_effect", {
598
+ ...baseMeta("feedback_effect", {
4023
599
  feedbackFrom: condition,
4024
600
  feedbackTo: reentry
4025
601
  }),
@@ -4078,7 +654,7 @@ function budgetGate(source, constraints, opts) {
4078
654
  {
4079
655
  ...opts,
4080
656
  describeKind: "derived",
4081
- meta: baseMeta2("budget_gate", opts?.meta)
657
+ meta: baseMeta("budget_gate", opts?.meta)
4082
658
  }
4083
659
  );
4084
660
  function _handleBudgetMessage(msg, depIndex, actions) {
@@ -4188,7 +764,7 @@ function scorer(sources, weights, opts) {
4188
764
  resetOnTeardown: opts.resetOnTeardown
4189
765
  } : {},
4190
766
  describeKind: "derived",
4191
- meta: baseMeta2("scorer", opts?.meta)
767
+ meta: baseMeta("scorer", opts?.meta)
4192
768
  }
4193
769
  );
4194
770
  }
@@ -4239,7 +815,7 @@ function effectivenessTracker(opts) {
4239
815
  }
4240
816
 
4241
817
  // src/patterns/domain-templates.ts
4242
- function baseMeta3(kind, extra) {
818
+ function baseMeta2(kind, extra) {
4243
819
  return domainMeta("domain_template", kind, extra);
4244
820
  }
4245
821
  function observabilityGraph(name, opts) {
@@ -4270,16 +846,16 @@ function observabilityGraph(name, opts) {
4270
846
  branchNodes,
4271
847
  (vals) => correlateFn(vals),
4272
848
  {
4273
- meta: baseMeta3("observability", { stage: "correlate" })
849
+ meta: baseMeta2("observability", { stage: "correlate" })
4274
850
  }
4275
851
  );
4276
852
  g.add("correlate", correlateNode);
4277
853
  const sloCheckFn = opts.sloCheck ?? (() => ({ pass: true }));
4278
854
  const sloValue = derived([correlateNode], (vals) => vals[0], {
4279
- meta: baseMeta3("observability", { stage: "slo_value" })
855
+ meta: baseMeta2("observability", { stage: "slo_value" })
4280
856
  });
4281
857
  const sloVerified = derived([sloValue], (vals) => sloCheckFn(vals[0]), {
4282
- meta: baseMeta3("observability", { stage: "slo_verified" })
858
+ meta: baseMeta2("observability", { stage: "slo_verified" })
4283
859
  });
4284
860
  g.add("slo_value", sloValue);
4285
861
  g.add("slo_verified", sloVerified);
@@ -4304,12 +880,12 @@ function observabilityGraph(name, opts) {
4304
880
  slo: vals[1]
4305
881
  }),
4306
882
  {
4307
- meta: baseMeta3("observability", { stage: "output" })
883
+ meta: baseMeta2("observability", { stage: "output" })
4308
884
  }
4309
885
  );
4310
886
  g.add("output", output);
4311
887
  const fbReentry = state(null, {
4312
- meta: baseMeta3("observability", { stage: "feedback_reentry" })
888
+ meta: baseMeta2("observability", { stage: "feedback_reentry" })
4313
889
  });
4314
890
  g.add("feedback_reentry", fbReentry);
4315
891
  const fbCondition = derived(
@@ -4320,7 +896,7 @@ function observabilityGraph(name, opts) {
4320
896
  return null;
4321
897
  },
4322
898
  {
4323
- meta: baseMeta3("observability", { stage: "feedback_condition" })
899
+ meta: baseMeta2("observability", { stage: "feedback_condition" })
4324
900
  }
4325
901
  );
4326
902
  g.add("feedback_condition", fbCondition);
@@ -4342,7 +918,7 @@ function issueTrackerGraph(name, opts) {
4342
918
  });
4343
919
  const extractFn = opts.extract ?? defaultExtract;
4344
920
  const extractNode = derived([opts.source], (vals) => extractFn(vals[0]), {
4345
- meta: baseMeta3("issue_tracker", { stage: "extract" })
921
+ meta: baseMeta2("issue_tracker", { stage: "extract" })
4346
922
  });
4347
923
  g.add("extract", extractNode);
4348
924
  const verifyFn = opts.verify ?? (() => ({ valid: true }));
@@ -4353,12 +929,12 @@ function issueTrackerGraph(name, opts) {
4353
929
  return { issue, verification: verifyFn(issue) };
4354
930
  },
4355
931
  {
4356
- meta: baseMeta3("issue_tracker", { stage: "verify" })
932
+ meta: baseMeta2("issue_tracker", { stage: "verify" })
4357
933
  }
4358
934
  );
4359
935
  g.add("verify", verifyNode);
4360
936
  const knownPatterns = state([], {
4361
- meta: baseMeta3("issue_tracker", { stage: "known_patterns" })
937
+ meta: baseMeta2("issue_tracker", { stage: "known_patterns" })
4362
938
  });
4363
939
  g.add("known_patterns", knownPatterns);
4364
940
  const detectFn = opts.detectRegression ?? (() => ({ regression: false }));
@@ -4369,7 +945,7 @@ function issueTrackerGraph(name, opts) {
4369
945
  const known = vals[1];
4370
946
  return { issue, regression: detectFn(issue, known) };
4371
947
  },
4372
- { meta: baseMeta3("issue_tracker", { stage: "regression" }) }
948
+ { meta: baseMeta2("issue_tracker", { stage: "regression" }) }
4373
949
  );
4374
950
  g.add("regression", regressionNode);
4375
951
  const severitySignal = derived([extractNode], (vals) => {
@@ -4395,11 +971,11 @@ function issueTrackerGraph(name, opts) {
4395
971
  regression: vals[1],
4396
972
  priority: vals[2]
4397
973
  }),
4398
- { meta: baseMeta3("issue_tracker", { stage: "output" }) }
974
+ { meta: baseMeta2("issue_tracker", { stage: "output" }) }
4399
975
  );
4400
976
  g.add("output", output);
4401
977
  const fbReentry = state(null, {
4402
- meta: baseMeta3("issue_tracker", { stage: "feedback_reentry" })
978
+ meta: baseMeta2("issue_tracker", { stage: "feedback_reentry" })
4403
979
  });
4404
980
  g.add("feedback_reentry", fbReentry);
4405
981
  const fbCondition = derived(
@@ -4413,7 +989,7 @@ function issueTrackerGraph(name, opts) {
4413
989
  return null;
4414
990
  },
4415
991
  {
4416
- meta: baseMeta3("issue_tracker", { stage: "feedback_condition" })
992
+ meta: baseMeta2("issue_tracker", { stage: "feedback_condition" })
4417
993
  }
4418
994
  );
4419
995
  g.add("feedback_condition", fbCondition);
@@ -4432,7 +1008,7 @@ function contentModerationGraph(name, opts) {
4432
1008
  });
4433
1009
  const classifyFn = opts.classify ?? defaultClassify;
4434
1010
  const classifyNode = derived([opts.source], (vals) => classifyFn(vals[0]), {
4435
- meta: baseMeta3("content_moderation", { stage: "classify" })
1011
+ meta: baseMeta2("content_moderation", { stage: "classify" })
4436
1012
  });
4437
1013
  g.add("classify", classifyNode);
4438
1014
  const strat = stratify("stratify", classifyNode, [
@@ -4467,7 +1043,7 @@ function contentModerationGraph(name, opts) {
4467
1043
  const policy2 = state(
4468
1044
  {},
4469
1045
  {
4470
- meta: baseMeta3("content_moderation", {
1046
+ meta: baseMeta2("content_moderation", {
4471
1047
  stage: "policy",
4472
1048
  access: "both",
4473
1049
  description: "Moderation policy rules \u2014 updated via feedback"
@@ -4499,7 +1075,7 @@ function contentModerationGraph(name, opts) {
4499
1075
  classification: vals[0],
4500
1076
  priority: vals[1]
4501
1077
  }),
4502
- { meta: baseMeta3("content_moderation", { stage: "output" }) }
1078
+ { meta: baseMeta2("content_moderation", { stage: "output" }) }
4503
1079
  );
4504
1080
  g.add("output", output);
4505
1081
  const fbCondition = derived(
@@ -4515,7 +1091,7 @@ function contentModerationGraph(name, opts) {
4515
1091
  return null;
4516
1092
  },
4517
1093
  {
4518
- meta: baseMeta3("content_moderation", { stage: "feedback_condition" })
1094
+ meta: baseMeta2("content_moderation", { stage: "feedback_condition" })
4519
1095
  }
4520
1096
  );
4521
1097
  g.add("feedback_condition", fbCondition);
@@ -4535,7 +1111,7 @@ function dataQualityGraph(name, opts) {
4535
1111
  const validateNode = derived(
4536
1112
  [opts.source],
4537
1113
  (vals) => vals[0] != null ? validateFn(vals[0]) : void 0,
4538
- { meta: baseMeta3("data_quality", { stage: "validate" }) }
1114
+ { meta: baseMeta2("data_quality", { stage: "validate" }) }
4539
1115
  );
4540
1116
  g.add("validate", validateNode);
4541
1117
  const detectAnomalyFn = opts.detectAnomaly ?? ((record) => ({
@@ -4546,11 +1122,11 @@ function dataQualityGraph(name, opts) {
4546
1122
  const anomalyNode = derived(
4547
1123
  [opts.source],
4548
1124
  (vals) => vals[0] != null ? detectAnomalyFn(vals[0]) : void 0,
4549
- { meta: baseMeta3("data_quality", { stage: "anomaly" }) }
1125
+ { meta: baseMeta2("data_quality", { stage: "anomaly" }) }
4550
1126
  );
4551
1127
  g.add("anomaly", anomalyNode);
4552
1128
  const baseline = state(null, {
4553
- meta: baseMeta3("data_quality", {
1129
+ meta: baseMeta2("data_quality", {
4554
1130
  stage: "baseline",
4555
1131
  description: "Rolling baseline for drift detection"
4556
1132
  })
@@ -4570,7 +1146,7 @@ function dataQualityGraph(name, opts) {
4570
1146
  const driftNode = derived(
4571
1147
  [opts.source, baseline],
4572
1148
  (vals) => detectDriftFn(vals[0], vals[1]),
4573
- { meta: baseMeta3("data_quality", { stage: "drift" }) }
1149
+ { meta: baseMeta2("data_quality", { stage: "drift" }) }
4574
1150
  );
4575
1151
  g.add("drift", driftNode);
4576
1152
  const suggestFn = opts.suggest ?? (() => null);
@@ -4580,7 +1156,7 @@ function dataQualityGraph(name, opts) {
4580
1156
  validation: vals[0],
4581
1157
  anomaly: vals[1]
4582
1158
  }),
4583
- { meta: baseMeta3("data_quality", { stage: "remediate" }) }
1159
+ { meta: baseMeta2("data_quality", { stage: "remediate" }) }
4584
1160
  );
4585
1161
  g.add("remediate", remediateNode);
4586
1162
  const output = derived(
@@ -4591,11 +1167,11 @@ function dataQualityGraph(name, opts) {
4591
1167
  drift: vals[2],
4592
1168
  remediation: vals[3]
4593
1169
  }),
4594
- { meta: baseMeta3("data_quality", { stage: "output" }) }
1170
+ { meta: baseMeta2("data_quality", { stage: "output" }) }
4595
1171
  );
4596
1172
  g.add("output", output);
4597
1173
  const validationRules = state([], {
4598
- meta: baseMeta3("data_quality", { stage: "validation_rules" })
1174
+ meta: baseMeta2("data_quality", { stage: "validation_rules" })
4599
1175
  });
4600
1176
  g.add("validation_rules", validationRules);
4601
1177
  const fbCondition = derived(
@@ -4606,7 +1182,7 @@ function dataQualityGraph(name, opts) {
4606
1182
  return null;
4607
1183
  },
4608
1184
  {
4609
- meta: baseMeta3("data_quality", { stage: "feedback_condition" })
1185
+ meta: baseMeta2("data_quality", { stage: "feedback_condition" })
4610
1186
  }
4611
1187
  );
4612
1188
  g.add("feedback_condition", fbCondition);
@@ -4793,7 +1369,7 @@ function levenshtein(a, b) {
4793
1369
  }
4794
1370
  return dp[m][n];
4795
1371
  }
4796
- var VALID_NODE_TYPES2 = /* @__PURE__ */ new Set([
1372
+ var VALID_NODE_TYPES = /* @__PURE__ */ new Set([
4797
1373
  "state",
4798
1374
  "producer",
4799
1375
  "derived",
@@ -4880,9 +1456,9 @@ function validateSpec(spec) {
4880
1456
  continue;
4881
1457
  }
4882
1458
  const n = raw;
4883
- if (typeof n.type !== "string" || !VALID_NODE_TYPES2.has(n.type)) {
1459
+ if (typeof n.type !== "string" || !VALID_NODE_TYPES.has(n.type)) {
4884
1460
  errors.push(
4885
- `Node "${name}": invalid type "${String(n.type)}" (expected: ${[...VALID_NODE_TYPES2].join(", ")})`
1461
+ `Node "${name}": invalid type "${String(n.type)}" (expected: ${[...VALID_NODE_TYPES].join(", ")})`
4886
1462
  );
4887
1463
  continue;
4888
1464
  }
@@ -5507,7 +2083,7 @@ Rules:
5507
2083
  - Use "feedback" for bounded cycles where a derived value writes back to a state node.
5508
2084
  - meta.description is required for every node.
5509
2085
  - Return ONLY valid JSON, no markdown fences or commentary.`;
5510
- function stripFences2(text) {
2086
+ function stripFences(text) {
5511
2087
  const match = text.match(/^```(?:json)?\s*([\s\S]*?)\s*```[\s\S]*$/);
5512
2088
  return match ? match[1] : text;
5513
2089
  }
@@ -5537,7 +2113,7 @@ ${opts.systemPromptExtra}`;
5537
2113
  const response = await rawResult;
5538
2114
  let content = response.content.trim();
5539
2115
  if (content.startsWith("```")) {
5540
- content = stripFences2(content);
2116
+ content = stripFences(content);
5541
2117
  }
5542
2118
  let parsed;
5543
2119
  try {
@@ -5608,7 +2184,7 @@ Return the complete modified GraphSpec as JSON.`
5608
2184
  const response = await rawResult;
5609
2185
  let content = response.content.trim();
5610
2186
  if (content.startsWith("```")) {
5611
- content = stripFences2(content);
2187
+ content = stripFences(content);
5612
2188
  }
5613
2189
  let parsed;
5614
2190
  try {
@@ -5686,7 +2262,7 @@ function guardedExecution(target, opts) {
5686
2262
  // src/patterns/harness/index.ts
5687
2263
  var harness_exports = {};
5688
2264
  __export(harness_exports, {
5689
- DEFAULT_DECAY_RATE: () => DEFAULT_DECAY_RATE2,
2265
+ DEFAULT_DECAY_RATE: () => DEFAULT_DECAY_RATE,
5690
2266
  DEFAULT_QUEUE_CONFIGS: () => DEFAULT_QUEUE_CONFIGS,
5691
2267
  DEFAULT_SEVERITY_WEIGHTS: () => DEFAULT_SEVERITY_WEIGHTS,
5692
2268
  HarnessGraph: () => HarnessGraph,
@@ -5729,28 +2305,28 @@ function evalIntakeBridge(evalSource2, intakeTopic, opts) {
5729
2305
  if (results == null) return;
5730
2306
  const runs = Array.isArray(results) ? results : [results];
5731
2307
  for (const run of runs) {
5732
- for (const task2 of run.tasks) {
5733
- if (task2.valid && task2.judge_scores?.every((s) => s.pass)) continue;
5734
- if (!task2.valid && (!task2.judge_scores || task2.judge_scores.length === 0)) {
2308
+ for (const task of run.tasks) {
2309
+ if (task.valid && task.judge_scores?.every((s) => s.pass)) continue;
2310
+ if (!task.valid && (!task.judge_scores || task.judge_scores.length === 0)) {
5735
2311
  intakeTopic.publish({
5736
2312
  source: "eval",
5737
- summary: `Task ${task2.task_id} invalid (model: ${run.model})`,
2313
+ summary: `Task ${task.task_id} invalid (model: ${run.model})`,
5738
2314
  evidence: `Run ${run.run_id}: task produced invalid output`,
5739
2315
  affectsAreas: ["graphspec"],
5740
- affectsEvalTasks: [task2.task_id],
2316
+ affectsEvalTasks: [task.task_id],
5741
2317
  severity: defaultSeverity
5742
2318
  });
5743
2319
  continue;
5744
2320
  }
5745
- if (task2.judge_scores) {
5746
- for (const score of task2.judge_scores) {
2321
+ if (task.judge_scores) {
2322
+ for (const score of task.judge_scores) {
5747
2323
  if (score.pass) continue;
5748
2324
  intakeTopic.publish({
5749
2325
  source: "eval",
5750
- summary: `${task2.task_id}: ${score.claim} (model: ${run.model})`,
2326
+ summary: `${task.task_id}: ${score.claim} (model: ${run.model})`,
5751
2327
  evidence: score.reasoning,
5752
2328
  affectsAreas: ["graphspec"],
5753
- affectsEvalTasks: [task2.task_id],
2329
+ affectsEvalTasks: [task.task_id],
5754
2330
  severity: defaultSeverity
5755
2331
  });
5756
2332
  }
@@ -5855,9 +2431,9 @@ function codeChangeBridge(source, intakeTopic, parser, opts) {
5855
2431
  { name: opts?.name ?? "code-change-bridge" }
5856
2432
  );
5857
2433
  }
5858
- function notifyEffect(topic2, transport, opts) {
2434
+ function notifyEffect(topic, transport, opts) {
5859
2435
  return effect(
5860
- [topic2.latest],
2436
+ [topic.latest],
5861
2437
  ([item]) => {
5862
2438
  if (item == null) return;
5863
2439
  void transport(item);
@@ -5889,7 +2465,7 @@ var DEFAULT_SEVERITY_WEIGHTS = {
5889
2465
  medium: 40,
5890
2466
  low: 10
5891
2467
  };
5892
- var DEFAULT_DECAY_RATE2 = Math.LN2 / (7 * 24 * 3600);
2468
+ var DEFAULT_DECAY_RATE = Math.LN2 / (7 * 24 * 3600);
5893
2469
  var DEFAULT_QUEUE_CONFIGS = {
5894
2470
  "auto-fix": { gated: false },
5895
2471
  "needs-decision": { gated: true },
@@ -5945,7 +2521,7 @@ function strategyModel() {
5945
2521
  }
5946
2522
  function priorityScore(item, strategy, lastInteractionNs, urgency, signals) {
5947
2523
  const severityWeights = { ...DEFAULT_SEVERITY_WEIGHTS, ...signals?.severityWeights };
5948
- const decayRate = signals?.decayRate ?? DEFAULT_DECAY_RATE2;
2524
+ const decayRate = signals?.decayRate ?? DEFAULT_DECAY_RATE;
5949
2525
  const effectivenessThreshold = signals?.effectivenessThreshold ?? 0.7;
5950
2526
  const effectivenessBoost = signals?.effectivenessBoost ?? 15;
5951
2527
  const deps = [item, strategy, lastInteractionNs];
@@ -6089,8 +2665,8 @@ function harnessLoop(name, opts) {
6089
2665
  if (!classification || !classification.route) return;
6090
2666
  const intakeItem = triagePair?.[0];
6091
2667
  const merged = { ...intakeItem, ...classification };
6092
- const topic2 = queueTopics.get(merged.route);
6093
- if (topic2) topic2.publish(merged);
2668
+ const topic = queueTopics.get(merged.route);
2669
+ if (topic) topic.publish(merged);
6094
2670
  });
6095
2671
  const routerUnsub = router.subscribe(() => {
6096
2672
  });
@@ -6098,9 +2674,9 @@ function harnessLoop(name, opts) {
6098
2674
  const gateControllers = /* @__PURE__ */ new Map();
6099
2675
  for (const route of QUEUE_NAMES) {
6100
2676
  const config = queueConfigs.get(route);
6101
- const topic2 = queueTopics.get(route);
2677
+ const topic = queueTopics.get(route);
6102
2678
  if (config.gated) {
6103
- gateGraph.add(`${route}/source`, topic2.latest);
2679
+ gateGraph.add(`${route}/source`, topic.latest);
6104
2680
  const ctrl = gate(gateGraph, `${route}/gate`, `${route}/source`, {
6105
2681
  maxPending: config.maxPending,
6106
2682
  startOpen: config.startOpen
@@ -6239,8 +2815,8 @@ function harnessLoop(name, opts) {
6239
2815
  harness.add("verify", verifyNode);
6240
2816
  harness.add("strategy", strategy.node);
6241
2817
  harness.mount("intake", intake);
6242
- for (const [route, topic2] of queueTopics) {
6243
- harness.mount(`queue/${route}`, topic2);
2818
+ for (const [route, topic] of queueTopics) {
2819
+ harness.mount(`queue/${route}`, topic);
6244
2820
  }
6245
2821
  harness.mount("gates", gateGraph);
6246
2822
  harness.mount("retry-input", retryTopic);
@@ -6252,8 +2828,8 @@ function harnessLoop(name, opts) {
6252
2828
  function harnessProfile(harness, opts) {
6253
2829
  const base = graphProfile(harness, opts);
6254
2830
  const queueDepths = {};
6255
- for (const [route, topic2] of harness.queues) {
6256
- queueDepths[route] = topic2.retained().length;
2831
+ for (const [route, topic] of harness.queues) {
2832
+ queueDepths[route] = topic.retained().length;
6257
2833
  }
6258
2834
  return {
6259
2835
  ...base,
@@ -6746,11 +3322,11 @@ ${catalogValidation.errors.join("\n")}`,
6746
3322
  }
6747
3323
 
6748
3324
  // src/patterns/surface/reduce.ts
6749
- var DEFAULT_TIMEOUT_MS2 = 3e4;
3325
+ var DEFAULT_TIMEOUT_MS = 3e4;
6750
3326
  async function runReduction(spec, input, opts) {
6751
3327
  const inputPath = opts?.inputPath ?? "input";
6752
3328
  const outputPath = opts?.outputPath ?? "output";
6753
- const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
3329
+ const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
6754
3330
  const graph = createGraph(spec, { catalog: opts?.catalog });
6755
3331
  let outputNode;
6756
3332
  try {