@graphrefly/graphrefly 0.25.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 (231) hide show
  1. package/README.md +8 -0
  2. package/dist/ai-CaR_912Q.d.cts +1033 -0
  3. package/dist/ai-WlRltJV7.d.ts +1033 -0
  4. package/dist/audit-ClmqGOCx.d.cts +245 -0
  5. package/dist/audit-DRlSzBu9.d.ts +245 -0
  6. package/dist/{chunk-QOWVNWOC.js → chunk-3ZWCKRHX.js} +27 -25
  7. package/dist/{chunk-QOWVNWOC.js.map → chunk-3ZWCKRHX.js.map} +1 -1
  8. package/dist/chunk-APFNLIRG.js +62 -0
  9. package/dist/chunk-APFNLIRG.js.map +1 -0
  10. package/dist/chunk-AT5LKYNL.js +395 -0
  11. package/dist/chunk-AT5LKYNL.js.map +1 -0
  12. package/dist/{chunk-IAHGTNOZ.js → chunk-BQ6RQQFF.js} +351 -2095
  13. package/dist/chunk-BQ6RQQFF.js.map +1 -0
  14. package/dist/{chunk-L2GLW2U7.js → chunk-BVZYTZ5H.js} +9 -103
  15. package/dist/chunk-BVZYTZ5H.js.map +1 -0
  16. package/dist/{chunk-EVR6UFUV.js → chunk-DST5DKZS.js} +19 -15
  17. package/dist/{chunk-EVR6UFUV.js.map → chunk-DST5DKZS.js.map} +1 -1
  18. package/dist/{chunk-TKE3JGOH.js → chunk-GTE6PWRZ.js} +5 -692
  19. package/dist/chunk-GTE6PWRZ.js.map +1 -0
  20. package/dist/chunk-HXZEYDUR.js +94 -0
  21. package/dist/chunk-HXZEYDUR.js.map +1 -0
  22. package/dist/chunk-J22W6HV3.js +107 -0
  23. package/dist/chunk-J22W6HV3.js.map +1 -0
  24. package/dist/{chunk-PY4XCDLR.js → chunk-J2VBW3DZ.js} +6 -95
  25. package/dist/chunk-J2VBW3DZ.js.map +1 -0
  26. package/dist/{chunk-HWPIFSW2.js → chunk-JSCT3CR4.js} +6 -4
  27. package/dist/{chunk-HWPIFSW2.js.map → chunk-JSCT3CR4.js.map} +1 -1
  28. package/dist/chunk-JWBCY4NC.js +330 -0
  29. package/dist/chunk-JWBCY4NC.js.map +1 -0
  30. package/dist/chunk-K2AUJHVP.js +2251 -0
  31. package/dist/chunk-K2AUJHVP.js.map +1 -0
  32. package/dist/chunk-MJ2NKQQL.js +119 -0
  33. package/dist/chunk-MJ2NKQQL.js.map +1 -0
  34. package/dist/chunk-N6UR7YVY.js +198 -0
  35. package/dist/chunk-N6UR7YVY.js.map +1 -0
  36. package/dist/chunk-NC6S43JJ.js +456 -0
  37. package/dist/chunk-NC6S43JJ.js.map +1 -0
  38. package/dist/chunk-OFVJBJXR.js +98 -0
  39. package/dist/chunk-OFVJBJXR.js.map +1 -0
  40. package/dist/chunk-OHISZPOJ.js +97 -0
  41. package/dist/chunk-OHISZPOJ.js.map +1 -0
  42. package/dist/chunk-OU5CQKNW.js +102 -0
  43. package/dist/chunk-OU5CQKNW.js.map +1 -0
  44. package/dist/{chunk-XOFWRC73.js → chunk-PF7GRZMW.js} +316 -21
  45. package/dist/chunk-PF7GRZMW.js.map +1 -0
  46. package/dist/{chunk-5DJTTKX3.js → chunk-PHOUUNK7.js} +74 -111
  47. package/dist/chunk-PHOUUNK7.js.map +1 -0
  48. package/dist/chunk-RNHBMHKA.js +1665 -0
  49. package/dist/chunk-RNHBMHKA.js.map +1 -0
  50. package/dist/chunk-SX52TAR4.js +110 -0
  51. package/dist/chunk-SX52TAR4.js.map +1 -0
  52. package/dist/{chunk-H4RVA4VE.js → chunk-VYPWMZ6H.js} +2 -2
  53. package/dist/chunk-WBZOVTYK.js +171 -0
  54. package/dist/chunk-WBZOVTYK.js.map +1 -0
  55. package/dist/chunk-WKNUIZOY.js +354 -0
  56. package/dist/chunk-WKNUIZOY.js.map +1 -0
  57. package/dist/chunk-X3VMZYBT.js +713 -0
  58. package/dist/chunk-X3VMZYBT.js.map +1 -0
  59. package/dist/chunk-X5R3GL6H.js +525 -0
  60. package/dist/chunk-X5R3GL6H.js.map +1 -0
  61. package/dist/chunk-XGPU467M.js +136 -0
  62. package/dist/chunk-XGPU467M.js.map +1 -0
  63. package/dist/compat/index.cjs +7656 -0
  64. package/dist/compat/index.cjs.map +1 -0
  65. package/dist/compat/index.d.cts +18 -0
  66. package/dist/compat/index.d.ts +18 -0
  67. package/dist/compat/index.js +50 -0
  68. package/dist/compat/index.js.map +1 -0
  69. package/dist/compat/jotai/index.cjs +2048 -0
  70. package/dist/compat/jotai/index.cjs.map +1 -0
  71. package/dist/compat/jotai/index.d.cts +2 -0
  72. package/dist/compat/jotai/index.d.ts +2 -0
  73. package/dist/compat/jotai/index.js +9 -0
  74. package/dist/compat/jotai/index.js.map +1 -0
  75. package/dist/compat/nanostores/index.cjs +2175 -0
  76. package/dist/compat/nanostores/index.cjs.map +1 -0
  77. package/dist/compat/nanostores/index.d.cts +2 -0
  78. package/dist/compat/nanostores/index.d.ts +2 -0
  79. package/dist/compat/nanostores/index.js +23 -0
  80. package/dist/compat/nanostores/index.js.map +1 -0
  81. package/dist/compat/nestjs/index.cjs +350 -16
  82. package/dist/compat/nestjs/index.cjs.map +1 -1
  83. package/dist/compat/nestjs/index.d.cts +6 -6
  84. package/dist/compat/nestjs/index.d.ts +6 -6
  85. package/dist/compat/nestjs/index.js +11 -9
  86. package/dist/compat/react/index.cjs +141 -0
  87. package/dist/compat/react/index.cjs.map +1 -0
  88. package/dist/compat/react/index.d.cts +2 -0
  89. package/dist/compat/react/index.d.ts +2 -0
  90. package/dist/compat/react/index.js +12 -0
  91. package/dist/compat/react/index.js.map +1 -0
  92. package/dist/compat/solid/index.cjs +128 -0
  93. package/dist/compat/solid/index.cjs.map +1 -0
  94. package/dist/compat/solid/index.d.cts +2 -0
  95. package/dist/compat/solid/index.d.ts +2 -0
  96. package/dist/compat/solid/index.js +12 -0
  97. package/dist/compat/solid/index.js.map +1 -0
  98. package/dist/compat/svelte/index.cjs +131 -0
  99. package/dist/compat/svelte/index.cjs.map +1 -0
  100. package/dist/compat/svelte/index.d.cts +2 -0
  101. package/dist/compat/svelte/index.d.ts +2 -0
  102. package/dist/compat/svelte/index.js +12 -0
  103. package/dist/compat/svelte/index.js.map +1 -0
  104. package/dist/compat/vue/index.cjs +146 -0
  105. package/dist/compat/vue/index.cjs.map +1 -0
  106. package/dist/compat/vue/index.d.cts +3 -0
  107. package/dist/compat/vue/index.d.ts +3 -0
  108. package/dist/compat/vue/index.js +12 -0
  109. package/dist/compat/vue/index.js.map +1 -0
  110. package/dist/compat/zustand/index.cjs +4931 -0
  111. package/dist/compat/zustand/index.cjs.map +1 -0
  112. package/dist/compat/zustand/index.d.cts +5 -0
  113. package/dist/compat/zustand/index.d.ts +5 -0
  114. package/dist/compat/zustand/index.js +12 -0
  115. package/dist/compat/zustand/index.js.map +1 -0
  116. package/dist/composite-C7PcQvcs.d.cts +303 -0
  117. package/dist/composite-aUCvjZVR.d.ts +303 -0
  118. package/dist/core/index.cjs +53 -4
  119. package/dist/core/index.cjs.map +1 -1
  120. package/dist/core/index.d.cts +4 -3
  121. package/dist/core/index.d.ts +4 -3
  122. package/dist/core/index.js +26 -24
  123. package/dist/demo-shell-BDkOptd6.d.ts +102 -0
  124. package/dist/demo-shell-Crid1WdR.d.cts +102 -0
  125. package/dist/extra/index.cjs +222 -110
  126. package/dist/extra/index.cjs.map +1 -1
  127. package/dist/extra/index.d.cts +6 -4
  128. package/dist/extra/index.d.ts +6 -4
  129. package/dist/extra/index.js +72 -65
  130. package/dist/extra/sources.cjs +2486 -0
  131. package/dist/extra/sources.cjs.map +1 -0
  132. package/dist/extra/sources.d.cts +465 -0
  133. package/dist/extra/sources.d.ts +465 -0
  134. package/dist/extra/sources.js +57 -0
  135. package/dist/extra/sources.js.map +1 -0
  136. package/dist/graph/index.cjs +408 -14
  137. package/dist/graph/index.cjs.map +1 -1
  138. package/dist/graph/index.d.cts +5 -5
  139. package/dist/graph/index.d.ts +5 -5
  140. package/dist/graph/index.js +13 -5
  141. package/dist/{graph-D-3JIQme.d.cts → graph-CCwGKLCm.d.ts} +195 -4
  142. package/dist/{graph-B6NFqv3z.d.ts → graph-DNCrvZSn.d.cts} +195 -4
  143. package/dist/index-3lsddbbS.d.ts +86 -0
  144. package/dist/index-B1tloyhO.d.cts +34 -0
  145. package/dist/{index-CYkjxu3s.d.ts → index-B6D3QNSA.d.ts} +33 -4
  146. package/dist/index-B6EhDnjH.d.cts +37 -0
  147. package/dist/index-B9B7_HEY.d.ts +37 -0
  148. package/dist/{index-Ds23Wvou.d.ts → index-BHlKbUwO.d.cts} +131 -883
  149. package/dist/{index-DiobMNwE.d.ts → index-BPVt8kqc.d.ts} +3 -3
  150. package/dist/index-BaSM3aYt.d.ts +195 -0
  151. package/dist/index-BuEoe-Qu.d.ts +121 -0
  152. package/dist/{index-Ch0IpIO0.d.cts → index-BwfLUNw4.d.ts} +131 -883
  153. package/dist/index-ByQxazQJ.d.cts +86 -0
  154. package/dist/index-C0svESO4.d.ts +127 -0
  155. package/dist/{index-OXImXMq6.d.ts → index-C8oil6M6.d.ts} +18 -196
  156. package/dist/{index-DKE1EATr.d.cts → index-CI3DprxP.d.cts} +18 -196
  157. package/dist/{index-AMWewNDe.d.cts → index-CO8uBlUh.d.cts} +33 -4
  158. package/dist/index-CxFrXH4m.d.ts +45 -0
  159. package/dist/index-D8wS_PeY.d.cts +121 -0
  160. package/dist/index-DO_6JN9Z.d.cts +127 -0
  161. package/dist/index-DVGiGFGT.d.cts +195 -0
  162. package/dist/index-DYme44FM.d.cts +44 -0
  163. package/dist/{index-J7Kc0oIQ.d.cts → index-DlLp-2Xn.d.cts} +3 -3
  164. package/dist/index-Dzk2hrlR.d.ts +44 -0
  165. package/dist/index-VHqptjhu.d.cts +45 -0
  166. package/dist/index-VdHQMPy1.d.ts +36 -0
  167. package/dist/index-Xi3u0HCQ.d.cts +36 -0
  168. package/dist/index-wEn0eFe8.d.ts +34 -0
  169. package/dist/index.cjs +1780 -176
  170. package/dist/index.cjs.map +1 -1
  171. package/dist/index.d.cts +784 -2082
  172. package/dist/index.d.ts +784 -2082
  173. package/dist/index.js +955 -4349
  174. package/dist/index.js.map +1 -1
  175. package/dist/memory-C6Z2tGpC.d.cts +139 -0
  176. package/dist/memory-li6FL5RM.d.ts +139 -0
  177. package/dist/messaging-Gt4LPbyA.d.cts +269 -0
  178. package/dist/messaging-XDoYablx.d.ts +269 -0
  179. package/dist/{meta-DWbkoq1s.d.cts → meta-BxCA7rcr.d.cts} +1 -1
  180. package/dist/{meta-CnkLA_43.d.ts → meta-CbznRPYJ.d.ts} +1 -1
  181. package/dist/{node-B-f-Lu-k.d.cts → node-BmerH3kS.d.cts} +26 -1
  182. package/dist/{node-B-f-Lu-k.d.ts → node-BmerH3kS.d.ts} +26 -1
  183. package/dist/{observable-uP-wy_uK.d.ts → observable-BgGUwcqp.d.ts} +1 -1
  184. package/dist/{observable-DBnrwcar.d.cts → observable-DJt_AxzQ.d.cts} +1 -1
  185. package/dist/patterns/ai.cjs +7930 -0
  186. package/dist/patterns/ai.cjs.map +1 -0
  187. package/dist/patterns/ai.d.cts +10 -0
  188. package/dist/patterns/ai.d.ts +10 -0
  189. package/dist/patterns/ai.js +71 -0
  190. package/dist/patterns/ai.js.map +1 -0
  191. package/dist/patterns/audit.cjs +5805 -0
  192. package/dist/patterns/audit.cjs.map +1 -0
  193. package/dist/patterns/audit.d.cts +6 -0
  194. package/dist/patterns/audit.d.ts +6 -0
  195. package/dist/patterns/audit.js +29 -0
  196. package/dist/patterns/audit.js.map +1 -0
  197. package/dist/patterns/demo-shell.cjs +5604 -0
  198. package/dist/patterns/demo-shell.cjs.map +1 -0
  199. package/dist/patterns/demo-shell.d.cts +6 -0
  200. package/dist/patterns/demo-shell.d.ts +6 -0
  201. package/dist/patterns/demo-shell.js +15 -0
  202. package/dist/patterns/demo-shell.js.map +1 -0
  203. package/dist/patterns/memory.cjs +5283 -0
  204. package/dist/patterns/memory.cjs.map +1 -0
  205. package/dist/patterns/memory.d.cts +5 -0
  206. package/dist/patterns/memory.d.ts +5 -0
  207. package/dist/patterns/memory.js +20 -0
  208. package/dist/patterns/memory.js.map +1 -0
  209. package/dist/patterns/reactive-layout/index.cjs +355 -13
  210. package/dist/patterns/reactive-layout/index.cjs.map +1 -1
  211. package/dist/patterns/reactive-layout/index.d.cts +6 -5
  212. package/dist/patterns/reactive-layout/index.d.ts +6 -5
  213. package/dist/patterns/reactive-layout/index.js +15 -12
  214. package/dist/reactive-layout-MQP--J3F.d.cts +183 -0
  215. package/dist/reactive-layout-u5Ulnqag.d.ts +183 -0
  216. package/dist/{storage-BuTdpCI1.d.cts → storage-CMjUUuxn.d.ts} +10 -2
  217. package/dist/{storage-F2X1U1x0.d.ts → storage-DdWlZo6U.d.cts} +10 -2
  218. package/dist/sugar-CCOxXK1e.d.ts +201 -0
  219. package/dist/sugar-D02n5JjF.d.cts +201 -0
  220. package/package.json +63 -3
  221. package/dist/chunk-5DJTTKX3.js.map +0 -1
  222. package/dist/chunk-IAHGTNOZ.js.map +0 -1
  223. package/dist/chunk-L2GLW2U7.js.map +0 -1
  224. package/dist/chunk-MW4VAKAO.js +0 -47
  225. package/dist/chunk-MW4VAKAO.js.map +0 -1
  226. package/dist/chunk-PY4XCDLR.js.map +0 -1
  227. package/dist/chunk-TKE3JGOH.js.map +0 -1
  228. package/dist/chunk-XOFWRC73.js.map +0 -1
  229. package/dist/index-BJB7t9gg.d.cts +0 -392
  230. package/dist/index-C-TXEa7C.d.ts +0 -392
  231. /package/dist/{chunk-H4RVA4VE.js.map → chunk-VYPWMZ6H.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/patterns/ai.ts","../src/patterns/orchestration.ts"],"sourcesContent":["/**\n * AI surface patterns (roadmap §4.4).\n *\n * Domain-layer factories for LLM-backed agents, chat, tool registries, and\n * agentic memory. Composed from core + extra + Phase 3–4.3 primitives.\n */\n\nimport type { Actor } from \"../core/actor.js\";\nimport { batch } from \"../core/batch.js\";\nimport { monotonicNs } from \"../core/clock.js\";\nimport { COMPLETE, DATA, ERROR } from \"../core/messages.js\";\nimport type { Node } from \"../core/node.js\";\nimport { derived, effect, producer, state } from \"../core/sugar.js\";\nimport {\n\ttype DistillBundle,\n\ttype DistillOptions,\n\tdistill,\n\ttype Extraction,\n} from \"../extra/composite.js\";\nimport { switchMap } from \"../extra/operators.js\";\nimport { type ReactiveLogBundle, reactiveLog } from \"../extra/reactive-log.js\";\nimport { fromAny, fromTimer, type NodeInput } from \"../extra/sources.js\";\nimport type { StorageHandle, StorageTier } from \"../extra/storage.js\";\nimport { ResettableTimer } from \"../extra/timer.js\";\nimport {\n\tGraph,\n\ttype GraphAttachStorageOptions,\n\ttype GraphOptions,\n\ttype GraphPersistSnapshot,\n} from \"../graph/graph.js\";\nimport {\n\tdecay,\n\ttype KnowledgeGraphGraph,\n\tknowledgeGraph,\n\ttype LightCollectionBundle,\n\tlightCollection,\n\ttype VectorIndexBundle,\n\ttype VectorSearchResult,\n\tvectorIndex,\n} from \"./memory.js\";\nimport { type TopicGraph, topic } from \"./messaging.js\";\nimport { type GateController, type GateOptions, gate } from \"./orchestration.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** A single chat message in a conversation. */\nexport type ChatMessage = {\n\treadonly role: \"system\" | \"user\" | \"assistant\" | \"tool\";\n\treadonly content: string;\n\treadonly name?: string;\n\treadonly toolCallId?: string;\n\treadonly toolCalls?: readonly ToolCall[];\n\treadonly metadata?: Record<string, unknown>;\n};\n\n/** A tool invocation request from an LLM. */\nexport type ToolCall = {\n\treadonly id: string;\n\treadonly name: string;\n\treadonly arguments: Record<string, unknown>;\n};\n\n/** The response from an LLM invocation. */\nexport type LLMResponse = {\n\treadonly content: string;\n\treadonly toolCalls?: readonly ToolCall[];\n\treadonly usage?: { readonly inputTokens: number; readonly outputTokens: number };\n\treadonly finishReason?: string;\n\treadonly metadata?: Record<string, unknown>;\n};\n\n/** Provider-agnostic LLM client adapter protocol. */\nexport type LLMAdapter = {\n\tinvoke(messages: readonly ChatMessage[], opts?: LLMInvokeOptions): NodeInput<LLMResponse>;\n\tstream(messages: readonly ChatMessage[], opts?: LLMInvokeOptions): AsyncIterable<string>;\n};\n\nexport type LLMInvokeOptions = {\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\ttools?: readonly ToolDefinition[];\n\tsystemPrompt?: string;\n\tsignal?: AbortSignal;\n};\n\n/** A tool definition for LLM consumption. */\nexport type ToolDefinition = {\n\treadonly name: string;\n\treadonly description: string;\n\treadonly parameters: Record<string, unknown>; // JSON Schema\n\treadonly handler: (args: Record<string, unknown>) => NodeInput<unknown>;\n\t/**\n\t * V0 version of the backing node at `knobsAsTools()` call time (§6.0b).\n\t * Snapshot — re-call `knobsAsTools()` to refresh.\n\t */\n\treadonly version?: { id: string; version: number };\n};\n\nexport type AgentLoopStatus = \"idle\" | \"thinking\" | \"acting\" | \"done\" | \"error\";\n\n/**\n * A single chunk from any streaming source (LLM tokens, WebSocket, SSE, file tail).\n * Generic enough for any streaming source, not just LLM.\n */\nexport type StreamChunk = {\n\t/** Identifier for the stream source (adapter name, URL, etc.). */\n\treadonly source: string;\n\t/** This chunk's content. */\n\treadonly token: string;\n\t/** Full accumulated text so far. */\n\treadonly accumulated: string;\n\t/** 0-based chunk counter. */\n\treadonly index: number;\n};\n\n// ---------------------------------------------------------------------------\n// Meta helpers\n// ---------------------------------------------------------------------------\n\nimport { domainMeta, keepalive } from \"./_internal.js\";\n\nfunction aiMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"ai\", kind, extra);\n}\n\nfunction isPromiseLike(x: unknown): x is PromiseLike<unknown> {\n\treturn x != null && typeof (x as PromiseLike<unknown>).then === \"function\";\n}\n\nfunction isNodeLike(x: unknown): x is Node<unknown> {\n\treturn (\n\t\ttypeof x === \"object\" &&\n\t\tx !== null &&\n\t\t\"subscribe\" in x &&\n\t\ttypeof (x as Node<unknown>).subscribe === \"function\" &&\n\t\t\"cache\" in x\n\t);\n}\n\nfunction isAsyncIterableLike(x: unknown): x is AsyncIterable<unknown> {\n\treturn (\n\t\tx != null &&\n\t\ttypeof x === \"object\" &&\n\t\tSymbol.asyncIterator in x &&\n\t\ttypeof (x as AsyncIterable<unknown>)[Symbol.asyncIterator] === \"function\"\n\t);\n}\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/** First settled `DATA` from a `Node` (do not pass plain strings — `fromAny` would iterate chars). */\nfunction firstDataFromNode(\n\tresolved: Node<unknown>,\n\topts?: { timeoutMs?: number },\n): Promise<unknown> {\n\t// Only trust get() when node is in settled state\n\tif ((resolved as { status?: string }).status === \"settled\") {\n\t\tconst immediate = resolved.cache;\n\t\tif (immediate !== undefined) {\n\t\t\treturn Promise.resolve(immediate);\n\t\t}\n\t}\n\tconst timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\treturn new Promise((resolve, reject) => {\n\t\tconst timer = new ResettableTimer();\n\t\tconst unsub = resolved.subscribe((messages) => {\n\t\t\tfor (const msg of messages) {\n\t\t\t\tif (msg[0] === DATA) {\n\t\t\t\t\ttimer.cancel();\n\t\t\t\t\tunsub();\n\t\t\t\t\tresolve(msg[1]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (msg[0] === ERROR) {\n\t\t\t\t\ttimer.cancel();\n\t\t\t\t\tunsub();\n\t\t\t\t\treject(msg[1]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (msg[0] === COMPLETE) {\n\t\t\t\t\ttimer.cancel();\n\t\t\t\t\tunsub();\n\t\t\t\t\treject(new Error(\"firstDataFromNode: completed without producing a value\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\ttimer.start(timeoutMs, () => {\n\t\t\tunsub();\n\t\t\treject(new Error(`firstDataFromNode: timed out after ${timeoutMs}ms`));\n\t\t});\n\t});\n}\n\n/** Await Promise-likes, then resolve `Node` / async-iterable inputs via `fromAny` + first `DATA`. */\nasync function resolveToolHandlerResult(value: unknown): Promise<unknown> {\n\tif (isPromiseLike(value)) {\n\t\treturn resolveToolHandlerResult(await value);\n\t}\n\tif (isNodeLike(value)) {\n\t\treturn firstDataFromNode(value);\n\t}\n\tif (isAsyncIterableLike(value)) {\n\t\treturn firstDataFromNode(fromAny(value as NodeInput<unknown>));\n\t}\n\treturn value;\n}\n\n// ---------------------------------------------------------------------------\n// fromLLM\n// ---------------------------------------------------------------------------\n\nexport type FromLLMOptions = {\n\tname?: string;\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\ttools?: readonly ToolDefinition[];\n\tsystemPrompt?: string;\n};\n\n/**\n * Reactive LLM invocation adapter. Returns a derived node that re-invokes\n * the LLM whenever the messages dep changes.\n *\n * Uses `switchMap` internally — new invocations cancel stale in-flight ones.\n */\nexport function fromLLM(\n\tadapter: LLMAdapter,\n\tmessages: NodeInput<readonly ChatMessage[]>,\n\topts?: FromLLMOptions,\n): Node<LLMResponse | null> {\n\tconst msgsNode = fromAny(messages);\n\tconst result = switchMap(msgsNode, (msgs) => {\n\t\tif (!msgs || (msgs as readonly ChatMessage[]).length === 0) {\n\t\t\treturn state<LLMResponse | null>(null) as NodeInput<LLMResponse | null>;\n\t\t}\n\t\tconst tools = opts?.tools;\n\t\treturn adapter.invoke(msgs as readonly ChatMessage[], {\n\t\t\tmodel: opts?.model,\n\t\t\ttemperature: opts?.temperature,\n\t\t\tmaxTokens: opts?.maxTokens,\n\t\t\ttools,\n\t\t\tsystemPrompt: opts?.systemPrompt,\n\t\t}) as NodeInput<LLMResponse | null>;\n\t});\n\n\treturn result;\n}\n\n// ---------------------------------------------------------------------------\n// streamingPromptNode\n// ---------------------------------------------------------------------------\n\nexport type StreamingPromptNodeOptions = {\n\tname?: string;\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/** Output format — `\"json\"` attempts JSON.parse on the final accumulated text. Default: `\"text\"`. */\n\tformat?: \"text\" | \"json\";\n\tsystemPrompt?: string;\n};\n\n/**\n * Bundle returned by {@link streamingPromptNode}.\n */\nexport type StreamingPromptNodeHandle<T> = {\n\t/** Final parsed result (emits once per invocation, after stream completes). */\n\toutput: Node<T | null>;\n\t/** Live stream topic — subscribe to `stream.latest` or `stream.events` for chunks. */\n\tstream: TopicGraph<StreamChunk>;\n\t/** Tear down the keepalive subscription and release resources. */\n\tdispose: () => void;\n};\n\n/**\n * Streaming LLM transform: wraps a prompt template + adapter into a reactive\n * streaming pipeline. Re-invokes the LLM whenever any dep changes; the\n * previous in-flight stream is canceled automatically via `switchMap`.\n *\n * Each token chunk is published to a {@link TopicGraph} as a {@link StreamChunk}.\n * Extractors can mount on the topic independently (see {@link streamExtractor}).\n * Zero overhead if nobody subscribes to the stream topic.\n *\n * The `output` node emits the final parsed result (like {@link promptNode}).\n * The async boundary is handled by `fromAny` (spec §5.10 compliant).\n */\nexport function streamingPromptNode<T = string>(\n\tadapter: LLMAdapter,\n\tdeps: readonly Node<unknown>[],\n\tprompt: string | ((...depValues: unknown[]) => string),\n\topts?: StreamingPromptNodeOptions,\n): StreamingPromptNodeHandle<T> {\n\tconst sourceName = opts?.name ?? \"llm\";\n\tconst format = opts?.format ?? \"text\";\n\tconst streamTopic = topic<StreamChunk>(`${sourceName}/stream`);\n\n\tconst messagesNode = derived<readonly ChatMessage[]>(deps as Node<unknown>[], (values) => {\n\t\tif (values.some((v) => v == null)) return [];\n\t\tconst text = typeof prompt === \"string\" ? prompt : prompt(...values);\n\t\tif (!text) return [];\n\t\tconst msgs: ChatMessage[] = [];\n\t\tif (opts?.systemPrompt) msgs.push({ role: \"system\", content: opts.systemPrompt });\n\t\tmsgs.push({ role: \"user\", content: text });\n\t\treturn msgs;\n\t});\n\n\tconst output = switchMap(messagesNode, (msgs) => {\n\t\tconst chatMsgs = msgs as readonly ChatMessage[];\n\t\tif (!chatMsgs || chatMsgs.length === 0) {\n\t\t\treturn state<T | null>(null) as NodeInput<T | null>;\n\t\t}\n\n\t\tconst ac = new AbortController();\n\n\t\tasync function* pumpAndCollect(): AsyncGenerator<T | null> {\n\t\t\tlet accumulated = \"\";\n\t\t\tlet index = 0;\n\t\t\ttry {\n\t\t\t\tfor await (const token of adapter.stream(chatMsgs, {\n\t\t\t\t\tmodel: opts?.model,\n\t\t\t\t\ttemperature: opts?.temperature,\n\t\t\t\t\tmaxTokens: opts?.maxTokens,\n\t\t\t\t\tsystemPrompt: opts?.systemPrompt,\n\t\t\t\t\tsignal: ac.signal,\n\t\t\t\t})) {\n\t\t\t\t\taccumulated += token;\n\t\t\t\t\tstreamTopic.publish({\n\t\t\t\t\t\tsource: sourceName,\n\t\t\t\t\t\ttoken,\n\t\t\t\t\t\taccumulated,\n\t\t\t\t\t\tindex: index++,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tlet result: T | null;\n\t\t\t\tif (format === \"json\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = JSON.parse(stripFences(accumulated)) as T;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tresult = null;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tresult = accumulated as unknown as T;\n\t\t\t\t}\n\t\t\t\tyield result;\n\t\t\t} finally {\n\t\t\t\tac.abort();\n\t\t\t}\n\t\t}\n\n\t\treturn fromAny(pumpAndCollect());\n\t});\n\n\tconst unsub = keepalive(output);\n\n\treturn {\n\t\toutput,\n\t\tstream: streamTopic,\n\t\tdispose: () => {\n\t\t\tunsub();\n\t\t\tstreamTopic.destroy();\n\t\t},\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// streamExtractor\n// ---------------------------------------------------------------------------\n\n/**\n * Mounts an extractor function on a streaming topic. Returns a derived node\n * that emits extracted values as chunks arrive.\n *\n * `extractFn` receives the accumulated text from the latest chunk and returns\n * the extracted value, or `null` if nothing detected yet. This is the building\n * block for keyword flags, tool call detection, cost metering, etc.\n *\n * @param streamTopic - The stream topic to extract from.\n * @param extractFn - `(accumulated: string) => T | null`.\n * @param opts - Optional name.\n * @returns Derived node emitting extracted values.\n */\nexport function streamExtractor<T>(\n\tstreamTopic: TopicGraph<StreamChunk>,\n\textractFn: (accumulated: string) => T | null,\n\topts?: {\n\t\tname?: string;\n\t\t/**\n\t\t * Optional structural equals for the extractor output. When two\n\t\t * consecutive chunks produce structurally-equal outputs, the framework\n\t\t * emits `RESOLVED` instead of `DATA`, saving downstream work. Default:\n\t\t * reference equality (`Object.is`). The library cannot know your\n\t\t * output shape — supply this when your `extractFn` returns structured\n\t\t * objects or arrays.\n\t\t */\n\t\tequals?: (a: T | null, b: T | null) => boolean;\n\t},\n): Node<T | null> {\n\treturn derived<T | null>(\n\t\t[streamTopic.latest as Node<StreamChunk | null>],\n\t\t([chunk]) => {\n\t\t\tif (chunk == null) return null;\n\t\t\treturn extractFn((chunk as StreamChunk).accumulated);\n\t\t},\n\t\t{\n\t\t\tname: opts?.name ?? \"extractor\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: null,\n\t\t\tmeta: aiMeta(\"stream_extractor\"),\n\t\t\t...(opts?.equals ? { equals: opts.equals } : {}),\n\t\t},\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// keywordFlagExtractor\n// ---------------------------------------------------------------------------\n\n/** A keyword match detected in the stream. */\nexport type KeywordFlag = {\n\treadonly label: string;\n\treadonly pattern: RegExp;\n\treadonly match: string;\n\treadonly position: number;\n};\n\nexport type KeywordFlagExtractorOptions = {\n\tpatterns: readonly { pattern: RegExp; label: string }[];\n\tname?: string;\n\t/**\n\t * Maximum length of any pattern's literal text. Used as an overlap window\n\t * when cursoring through the accumulated stream so matches that span\n\t * chunk boundaries aren't missed. Default: 128.\n\t */\n\tmaxPatternLength?: number;\n};\n\nconst keywordFlagsEqual = (\n\ta: readonly KeywordFlag[] | null,\n\tb: readonly KeywordFlag[] | null,\n): boolean => {\n\tif (a === b) return true;\n\tif (a == null || b == null) return a === b;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i++) {\n\t\tconst x = a[i];\n\t\tconst y = b[i];\n\t\tif (\n\t\t\tx.label !== y.label ||\n\t\t\tx.pattern !== y.pattern ||\n\t\t\tx.match !== y.match ||\n\t\t\tx.position !== y.position\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n};\n\n/**\n * Mounts a keyword-flag extractor on a streaming topic. Scans accumulated text\n * for all configured patterns and emits an array of matches.\n *\n * Use cases: design invariant violations (`setTimeout`, `EventEmitter`), PII\n * detection (SSN, email, phone), toxicity keywords, off-track reasoning.\n *\n * **Streaming optimization.** Maintains a cursor across chunks in `ctx.store`\n * so each chunk scans only the delta region `accumulated.slice(scannedTo -\n * maxPatternLength)` — not the full string. Default structural equals\n * suppresses DATA emission when no new flags were found this chunk.\n */\nexport function keywordFlagExtractor(\n\tstreamTopic: TopicGraph<StreamChunk>,\n\topts: KeywordFlagExtractorOptions,\n): Node<readonly KeywordFlag[]> {\n\tconst maxPatternLength = opts.maxPatternLength ?? 128;\n\treturn derived<readonly KeywordFlag[]>(\n\t\t[streamTopic.latest as Node<StreamChunk | null>],\n\t\t([chunk], ctx) => {\n\t\t\tif (chunk == null) return [];\n\t\t\tconst accumulated = (chunk as StreamChunk).accumulated;\n\n\t\t\tif (!(\"flags\" in ctx.store)) {\n\t\t\t\tctx.store.flags = [] as KeywordFlag[];\n\t\t\t\tctx.store.scannedTo = 0;\n\t\t\t}\n\t\t\tconst flags = ctx.store.flags as KeywordFlag[];\n\t\t\tconst scannedTo = ctx.store.scannedTo as number;\n\n\t\t\t// Scan the delta plus an overlap window so matches that span\n\t\t\t// chunk boundaries (e.g. \"EventE\" + \"mitter\") are still found.\n\t\t\tconst startOffset = Math.max(0, scannedTo - maxPatternLength);\n\t\t\tconst region = accumulated.slice(startOffset);\n\t\t\tlet added = false;\n\t\t\tfor (const { pattern, label } of opts.patterns) {\n\t\t\t\tconst re = new RegExp(pattern.source, `${pattern.flags.replace(\"g\", \"\")}g`);\n\t\t\t\tfor (const m of region.matchAll(re)) {\n\t\t\t\t\tconst pos = startOffset + m.index!;\n\t\t\t\t\t// Skip matches that end inside the already-scanned prefix.\n\t\t\t\t\tif (pos + m[0].length <= scannedTo) continue;\n\t\t\t\t\tflags.push({ label, pattern, match: m[0], position: pos });\n\t\t\t\t\tadded = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tctx.store.scannedTo = accumulated.length;\n\n\t\t\t// Always return a fresh copy so downstream never holds a live\n\t\t\t// reference to ctx.store.flags. Structural equals suppresses the\n\t\t\t// emission when no new flag was added this chunk.\n\t\t\treturn added ? [...flags] : flags.slice();\n\t\t},\n\t\t{\n\t\t\tname: opts.name ?? \"keyword-flag-extractor\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: [],\n\t\t\tmeta: aiMeta(\"keyword_flag_extractor\"),\n\t\t\tequals: keywordFlagsEqual,\n\t\t},\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// toolCallExtractor\n// ---------------------------------------------------------------------------\n\n/** A tool call detected in the stream. */\nexport type ExtractedToolCall = {\n\treadonly name: string;\n\treadonly arguments: Record<string, unknown>;\n\treadonly raw: string;\n\treadonly startIndex: number;\n};\n\nconst toolCallsEqual = (\n\ta: readonly ExtractedToolCall[] | null,\n\tb: readonly ExtractedToolCall[] | null,\n): boolean => {\n\tif (a === b) return true;\n\tif (a == null || b == null) return a === b;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i++) {\n\t\tconst x = a[i];\n\t\tconst y = b[i];\n\t\tif (x.startIndex !== y.startIndex || x.name !== y.name || x.raw !== y.raw) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n};\n\n/**\n * Mounts a tool-call extractor on a streaming topic. Scans accumulated text\n * for complete JSON objects containing `\"name\"` and `\"arguments\"` keys (the\n * standard tool_call shape). Partial JSON is ignored until the closing brace.\n *\n * Feeds into the tool interception chain for reactive tool gating mid-stream.\n *\n * **Streaming optimization.** Maintains a cursor (`scanFrom`) in `ctx.store`\n * so each chunk resumes brace-scanning from the position after the last\n * complete parse (or the last incomplete open brace). Already-parsed objects\n * are not re-parsed. Default structural equals suppresses DATA emission when\n * no new tool call completed this chunk.\n */\nexport function toolCallExtractor(\n\tstreamTopic: TopicGraph<StreamChunk>,\n\topts?: { name?: string },\n): Node<readonly ExtractedToolCall[]> {\n\treturn derived<readonly ExtractedToolCall[]>(\n\t\t[streamTopic.latest as Node<StreamChunk | null>],\n\t\t([chunk], ctx) => {\n\t\t\tif (chunk == null) return [];\n\t\t\tconst accumulated = (chunk as StreamChunk).accumulated;\n\n\t\t\tif (!(\"calls\" in ctx.store)) {\n\t\t\t\tctx.store.calls = [] as ExtractedToolCall[];\n\t\t\t\tctx.store.scanFrom = 0;\n\t\t\t}\n\t\t\tconst calls = ctx.store.calls as ExtractedToolCall[];\n\t\t\tlet i = ctx.store.scanFrom as number;\n\t\t\tlet added = false;\n\n\t\t\twhile (i < accumulated.length) {\n\t\t\t\tconst start = accumulated.indexOf(\"{\", i);\n\t\t\t\tif (start === -1) {\n\t\t\t\t\tctx.store.scanFrom = accumulated.length;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tlet depth = 0;\n\t\t\t\tlet end = -1;\n\t\t\t\tlet inString = false;\n\t\t\t\tfor (let j = start; j < accumulated.length; j++) {\n\t\t\t\t\tconst ch = accumulated[j];\n\t\t\t\t\tif (inString) {\n\t\t\t\t\t\tif (ch === \"\\\\\" && j + 1 < accumulated.length) {\n\t\t\t\t\t\t\tj++; // skip escaped character\n\t\t\t\t\t\t} else if (ch === '\"') {\n\t\t\t\t\t\t\tinString = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (ch === '\"') {\n\t\t\t\t\t\tinString = true;\n\t\t\t\t\t} else if (ch === \"{\") {\n\t\t\t\t\t\tdepth++;\n\t\t\t\t\t} else if (ch === \"}\") {\n\t\t\t\t\t\tdepth--;\n\t\t\t\t\t\tif (depth === 0) {\n\t\t\t\t\t\t\tend = j;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (end === -1) {\n\t\t\t\t\t// Incomplete — resume brace-scanning from this open brace\n\t\t\t\t\t// next chunk. Do NOT advance past it.\n\t\t\t\t\tctx.store.scanFrom = start;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tconst raw = accumulated.slice(start, end + 1);\n\t\t\t\ttry {\n\t\t\t\t\tconst parsed = JSON.parse(raw) as Record<string, unknown>;\n\t\t\t\t\tif (\n\t\t\t\t\t\ttypeof parsed.name === \"string\" &&\n\t\t\t\t\t\tparsed.arguments != null &&\n\t\t\t\t\t\ttypeof parsed.arguments === \"object\"\n\t\t\t\t\t) {\n\t\t\t\t\t\tcalls.push({\n\t\t\t\t\t\t\tname: parsed.name,\n\t\t\t\t\t\t\targuments: parsed.arguments as Record<string, unknown>,\n\t\t\t\t\t\t\traw,\n\t\t\t\t\t\t\tstartIndex: start,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tadded = true;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Not valid JSON — skip\n\t\t\t\t}\n\t\t\t\ti = end + 1;\n\t\t\t\tctx.store.scanFrom = i;\n\t\t\t}\n\n\t\t\t// Always return a fresh copy so downstream never holds a live\n\t\t\t// reference to ctx.store.calls.\n\t\t\treturn added ? [...calls] : calls.slice();\n\t\t},\n\t\t{\n\t\t\tname: opts?.name ?? \"tool-call-extractor\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: [],\n\t\t\tmeta: aiMeta(\"tool_call_extractor\"),\n\t\t\tequals: toolCallsEqual,\n\t\t},\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// costMeterExtractor\n// ---------------------------------------------------------------------------\n\n/** A cost meter reading from the stream. */\nexport type CostMeterReading = {\n\treadonly chunkCount: number;\n\treadonly charCount: number;\n\treadonly estimatedTokens: number;\n};\n\nexport type CostMeterOptions = {\n\t/** Characters per token approximation. Default: 4 (GPT-family). */\n\tcharsPerToken?: number;\n\tname?: string;\n};\n\nconst costMeterEqual = (a: CostMeterReading, b: CostMeterReading): boolean => {\n\tif (a === b) return true;\n\treturn (\n\t\ta.chunkCount === b.chunkCount &&\n\t\ta.charCount === b.charCount &&\n\t\ta.estimatedTokens === b.estimatedTokens\n\t);\n};\n\n/**\n * Mounts a cost meter on a streaming topic. Counts chunks, characters, and\n * estimates token count. Compose with `budgetGate` for hard-stop when LLM\n * output exceeds budget mid-generation.\n *\n * Default structural equals suppresses DATA emission when two consecutive\n * readings are identical (same chunk count + char count + token estimate).\n */\nexport function costMeterExtractor(\n\tstreamTopic: TopicGraph<StreamChunk>,\n\topts?: CostMeterOptions,\n): Node<CostMeterReading> {\n\tconst charsPerToken = opts?.charsPerToken ?? 4;\n\treturn derived<CostMeterReading>(\n\t\t[streamTopic.latest as Node<StreamChunk | null>],\n\t\t([chunk]) => {\n\t\t\tif (chunk == null) return { chunkCount: 0, charCount: 0, estimatedTokens: 0 };\n\t\t\tconst c = chunk as StreamChunk;\n\t\t\tconst charCount = c.accumulated.length;\n\t\t\treturn {\n\t\t\t\tchunkCount: c.index + 1,\n\t\t\t\tcharCount,\n\t\t\t\testimatedTokens: Math.ceil(charCount / charsPerToken),\n\t\t\t};\n\t\t},\n\t\t{\n\t\t\tname: opts?.name ?? \"cost-meter\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: { chunkCount: 0, charCount: 0, estimatedTokens: 0 },\n\t\t\tmeta: aiMeta(\"cost_meter_extractor\"),\n\t\t\tequals: costMeterEqual,\n\t\t},\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Composition B: Content safety pipeline\n// ---------------------------------------------------------------------------\n\n/** Options for {@link redactor}. */\nexport type RedactorOptions = {\n\tname?: string;\n};\n\n/**\n * Stream extractor that replaces matched patterns in the accumulated text.\n *\n * Returns a derived node emitting a sanitized `StreamChunk` on every chunk:\n * `accumulated` and `token` have matched substrings replaced by `replaceFn`.\n * The default `replaceFn` replaces with `\"[REDACTED]\"`.\n *\n * Compose with `contentGate` for in-flight safety pipelines.\n *\n * @param streamTopic - Streaming topic to monitor.\n * @param patterns - Array of RegExps to match against accumulated text.\n * @param replaceFn - Replacement producer (default: always `\"[REDACTED]\"`).\n */\nexport function redactor(\n\tstreamTopic: TopicGraph<StreamChunk>,\n\tpatterns: RegExp[],\n\treplaceFn?: (match: string, pattern: RegExp) => string,\n\topts?: RedactorOptions,\n): Node<StreamChunk> {\n\tconst replace = replaceFn ?? (() => \"[REDACTED]\");\n\n\tfunction sanitize(text: string): string {\n\t\tlet result = text;\n\t\tfor (const pat of patterns) {\n\t\t\tconst global = pat.global ? pat : new RegExp(pat.source, `${pat.flags}g`);\n\t\t\tresult = result.replace(global, (m) => replace(m, pat));\n\t\t}\n\t\treturn result;\n\t}\n\n\treturn derived<StreamChunk>(\n\t\t[streamTopic.latest as Node<StreamChunk | null>],\n\t\t([chunk]) => {\n\t\t\tif (chunk == null) {\n\t\t\t\treturn { source: \"\", token: \"\", accumulated: \"\", index: -1 };\n\t\t\t}\n\t\t\tconst c = chunk as StreamChunk;\n\t\t\tconst sanitizedAccumulated = sanitize(c.accumulated);\n\t\t\tconst sanitizedToken = sanitize(c.token);\n\t\t\treturn {\n\t\t\t\tsource: c.source,\n\t\t\t\ttoken: sanitizedToken,\n\t\t\t\taccumulated: sanitizedAccumulated,\n\t\t\t\tindex: c.index,\n\t\t\t};\n\t\t},\n\t\t{ name: opts?.name ?? \"redactor\" },\n\t);\n}\n\n// ---------------------------------------------------------------------------\n\n/** Content safety decision. */\nexport type ContentDecision = \"allow\" | \"block\" | \"review\";\n\n/** Options for {@link contentGate}. */\nexport type ContentGateOptions = {\n\t/**\n\t * Hard-block threshold multiplier (default 1.5).\n\t * Scores above `threshold * hardMultiplier` emit `\"block\"`.\n\t * Scores between `threshold` and that emit `\"review\"`.\n\t */\n\thardMultiplier?: number;\n\tname?: string;\n};\n\n/**\n * Derived node that classifies accumulated stream text as `\"allow\"`,\n * `\"review\"`, or `\"block\"` based on a classifier score.\n *\n * Emits a three-way decision on every new chunk:\n * - `\"allow\"` — score below `threshold`\n * - `\"review\"` — score in `[threshold, threshold × hardMultiplier)`\n * - `\"block\"` — score at or above `threshold × hardMultiplier`\n *\n * Wire the output into a `valve` (automatic) or `gate` (human approval).\n * This node does not itself control flow — it just classifies.\n *\n * @param streamTopic - Streaming topic to classify.\n * @param classifier - `(accumulated: string) => number` scoring function, or\n * a `Node<number>` for live scores.\n * @param threshold - Score at which output becomes \"review\" or \"block\".\n */\nexport function contentGate(\n\tstreamTopic: TopicGraph<StreamChunk>,\n\tclassifier: ((accumulated: string) => number) | Node<number>,\n\tthreshold: number,\n\topts?: ContentGateOptions,\n): Node<ContentDecision> {\n\tconst hardThreshold = threshold * (opts?.hardMultiplier ?? 1.5);\n\tconst isNodeClassifier = typeof classifier !== \"function\";\n\n\tconst deps: Node<unknown>[] = [streamTopic.latest as Node<StreamChunk | null>];\n\tif (isNodeClassifier) deps.push(classifier as Node<unknown>);\n\n\treturn derived<ContentDecision>(\n\t\tdeps,\n\t\t(values) => {\n\t\t\tconst chunk = values[0] as StreamChunk | undefined;\n\t\t\tif (chunk == null) return \"allow\";\n\n\t\t\tconst score = isNodeClassifier\n\t\t\t\t? ((values[1] as number | undefined) ?? 0)\n\t\t\t\t: (classifier as (text: string) => number)(chunk.accumulated);\n\n\t\t\tif (score >= hardThreshold) return \"block\";\n\t\t\tif (score >= threshold) return \"review\";\n\t\t\treturn \"allow\";\n\t\t},\n\t\t{ name: opts?.name ?? \"content-gate\", initial: \"allow\" },\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// gatedStream\n// ---------------------------------------------------------------------------\n\nexport type GatedStreamOptions = StreamingPromptNodeOptions & {\n\t/** Gate options (maxPending, startOpen). */\n\tgate?: Omit<GateOptions, \"meta\">;\n};\n\n/**\n * Bundle returned by {@link gatedStream}.\n */\nexport type GatedStreamHandle<T> = {\n\t/** Final parsed result (after gate approval). */\n\toutput: Node<T | null>;\n\t/** Live stream topic — subscribe to `stream.latest` for chunks. */\n\tstream: TopicGraph<StreamChunk>;\n\t/** Gate controller — approve, reject (aborts in-flight stream), modify. */\n\tgate: GateController<T | null>;\n\t/** Tear down everything. */\n\tdispose: () => void;\n};\n\n/**\n * Streaming LLM transform with human-in-the-loop gate integration.\n *\n * Composes {@link streamingPromptNode} with {@link gate} so that:\n * - `gate.reject()` discards the pending value **and** aborts the in-flight\n * stream (cancels the `AbortController`).\n * - `gate.modify()` transforms the pending value before forwarding downstream.\n * - `gate.approve()` forwards the final result as normal.\n *\n * The abort-on-reject works by toggling an internal cancel signal that causes\n * the `switchMap` inside `streamingPromptNode` to restart with an empty message\n * list, which triggers the `AbortController.abort()` in the async generator's\n * `finally` block.\n */\nexport function gatedStream<T = string>(\n\tgraph: Graph,\n\tname: string,\n\tadapter: LLMAdapter,\n\tdeps: readonly Node<unknown>[],\n\tprompt: string | ((...depValues: unknown[]) => string),\n\topts?: GatedStreamOptions,\n): GatedStreamHandle<T> {\n\t// Cancel signal: toggling this forces switchMap to restart (aborting stream).\n\tconst cancelSignal = state<number>(0, { name: `${name}/cancel` });\n\tlet cancelCounter = 0;\n\n\t// Build the streaming prompt node with cancelSignal as an extra dep.\n\t// The cancel dep is excluded from prompt template arguments.\n\tconst allDeps = [...deps, cancelSignal] as readonly Node<unknown>[];\n\n\tconst sourceName = opts?.name ?? name;\n\tconst format = opts?.format ?? \"text\";\n\tconst streamTopic = topic<StreamChunk>(`${sourceName}/stream`);\n\n\tconst messagesNode = derived<readonly ChatMessage[]>(allDeps as Node<unknown>[], (values) => {\n\t\t// Last dep is the cancel signal — exclude from prompt args\n\t\tconst depValues = values.slice(0, -1);\n\t\tif (depValues.some((v) => v == null)) return [];\n\t\tconst text = typeof prompt === \"string\" ? prompt : prompt(...depValues);\n\t\tif (!text) return [];\n\t\tconst msgs: ChatMessage[] = [];\n\t\tif (opts?.systemPrompt) msgs.push({ role: \"system\", content: opts.systemPrompt });\n\t\tmsgs.push({ role: \"user\", content: text });\n\t\treturn msgs;\n\t});\n\n\tconst output = switchMap(messagesNode, (msgs) => {\n\t\tconst chatMsgs = msgs as readonly ChatMessage[];\n\t\tif (!chatMsgs || chatMsgs.length === 0) {\n\t\t\treturn state<T | null>(null) as NodeInput<T | null>;\n\t\t}\n\n\t\tconst ac = new AbortController();\n\n\t\tasync function* pumpAndCollect(): AsyncGenerator<T | null> {\n\t\t\tlet accumulated = \"\";\n\t\t\tlet index = 0;\n\t\t\ttry {\n\t\t\t\tfor await (const token of adapter.stream(chatMsgs, {\n\t\t\t\t\tmodel: opts?.model,\n\t\t\t\t\ttemperature: opts?.temperature,\n\t\t\t\t\tmaxTokens: opts?.maxTokens,\n\t\t\t\t\tsystemPrompt: opts?.systemPrompt,\n\t\t\t\t\tsignal: ac.signal,\n\t\t\t\t})) {\n\t\t\t\t\taccumulated += token;\n\t\t\t\t\tstreamTopic.publish({\n\t\t\t\t\t\tsource: sourceName,\n\t\t\t\t\t\ttoken,\n\t\t\t\t\t\taccumulated,\n\t\t\t\t\t\tindex: index++,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tlet result: T | null;\n\t\t\t\tif (format === \"json\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = JSON.parse(stripFences(accumulated)) as T;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tresult = null;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tresult = accumulated as unknown as T;\n\t\t\t\t}\n\t\t\t\tyield result;\n\t\t\t} finally {\n\t\t\t\tac.abort();\n\t\t\t}\n\t\t}\n\n\t\treturn fromAny(pumpAndCollect());\n\t});\n\n\tconst unsub = keepalive(output);\n\n\t// Filter: only forward non-null results to the gate. Null is the switchMap\n\t// initial/cancel state — not a real LLM result worth gating. Returning\n\t// undefined from a derived fn means \"no auto-emit\" (spec §2.4), so null\n\t// values are silently suppressed.\n\tconst nonNullOutput = derived<T>(\n\t\t[output],\n\t\t([v]) => {\n\t\t\tif (v == null) return undefined;\n\t\t\treturn v as T;\n\t\t},\n\t\t{\n\t\t\tname: `${name}/filter`,\n\t\t},\n\t);\n\n\t// Register the filtered output so gate() can find it as a dep\n\tgraph.add(`${name}/raw`, nonNullOutput);\n\n\t// Wire gate on the output\n\tconst gateCtrl = gate<T | null>(graph, `${name}/gate`, `${name}/raw`, opts?.gate);\n\n\t// Wrap reject to also abort the in-flight stream\n\tconst originalReject = gateCtrl.reject.bind(gateCtrl);\n\tconst gateWithAbort: GateController<T | null> = {\n\t\t...gateCtrl,\n\t\treject(count = 1) {\n\t\t\toriginalReject(count);\n\t\t\t// Toggle cancel signal to force switchMap restart → abort\n\t\t\tcancelSignal.down([[DATA, ++cancelCounter]]);\n\t\t},\n\t};\n\n\treturn {\n\t\toutput: gateCtrl.node,\n\t\tstream: streamTopic,\n\t\tgate: gateWithAbort,\n\t\tdispose: () => {\n\t\t\tunsub();\n\t\t\tstreamTopic.destroy();\n\t\t},\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// promptNode\n// ---------------------------------------------------------------------------\n\nexport type PromptNodeOptions = {\n\tname?: string;\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/** Output format — `\"json\"` attempts JSON.parse on the response. Default: `\"text\"`. */\n\tformat?: \"text\" | \"json\";\n\t/** Number of retries on transient errors. Default: 0. */\n\tretries?: number;\n\t/** Cache LLM responses for identical inputs. Default: false. */\n\tcache?: boolean;\n\tsystemPrompt?: string;\n\tmeta?: Record<string, unknown>;\n};\n\n/** Extract text content from an LLM response, handling various response shapes. */\nfunction extractContent(resp: unknown): string {\n\tif (resp != null && typeof resp === \"object\" && \"content\" in resp) {\n\t\treturn String((resp as LLMResponse).content);\n\t}\n\tif (typeof resp === \"string\") return resp;\n\treturn String(resp);\n}\n\n/**\n * Universal LLM transform: wraps a prompt template + model adapter into a reactive derived node.\n * Re-invokes the LLM whenever any dep changes. Suitable for triage, QA, hypothesis, parity, etc.\n *\n * @param adapter - LLM adapter (provider-agnostic).\n * @param deps - Input nodes whose values feed the prompt.\n * @param prompt - Static string or template function receiving dep values.\n * @param opts - Optional configuration.\n * @returns `Node` emitting LLM responses (string or parsed JSON).\n */\nexport function promptNode<T = string>(\n\tadapter: LLMAdapter,\n\tdeps: readonly Node<unknown>[],\n\tprompt: string | ((...depValues: unknown[]) => string),\n\topts?: PromptNodeOptions,\n): Node<T | null> {\n\tconst format = opts?.format ?? \"text\";\n\tconst retries = opts?.retries ?? 0;\n\tconst useCache = opts?.cache ?? false;\n\tconst cache = useCache ? new Map<string, T>() : null;\n\n\t// Seed with `initial: []` so `switchMap` below fires with `[]` during the\n\t// initial activation pass and emits null (composition guide §8 — promptNode\n\t// gates on nullish deps). Dep-level null guarding is done inside the fn.\n\tconst messagesNode = derived<readonly ChatMessage[]>(\n\t\tdeps as Node<unknown>[],\n\t\t(values) => {\n\t\t\t// Dep-level null guard (composition guide §8): if any dep is\n\t\t\t// nullish, return empty messages → switchMap emits null.\n\t\t\tif (values.some((v) => v == null)) return [];\n\t\t\tconst text = typeof prompt === \"string\" ? prompt : prompt(...values);\n\t\t\tif (!text) return [];\n\t\t\tconst msgs: ChatMessage[] = [];\n\t\t\tif (opts?.systemPrompt) msgs.push({ role: \"system\", content: opts.systemPrompt });\n\t\t\tmsgs.push({ role: \"user\", content: text });\n\t\t\treturn msgs;\n\t\t},\n\t\t{\n\t\t\tname: opts?.name ? `${opts.name}::messages` : \"prompt_node::messages\",\n\t\t\tmeta: aiMeta(\"prompt_node\"),\n\t\t\tinitial: [] as readonly ChatMessage[],\n\t\t},\n\t);\n\n\tconst result = switchMap<readonly ChatMessage[], T | null>(messagesNode, (msgs) => {\n\t\tif (!msgs || msgs.length === 0) {\n\t\t\treturn state<T | null>(null) as NodeInput<T | null>;\n\t\t}\n\n\t\tconst cacheKey = useCache ? JSON.stringify(msgs.map((m) => [m.role, m.content])) : \"\";\n\t\tif (cache?.has(cacheKey)) {\n\t\t\treturn state<T | null>(cache.get(cacheKey)!) as NodeInput<T | null>;\n\t\t}\n\n\t\tasync function attempt(remaining: number): Promise<T | null> {\n\t\t\ttry {\n\t\t\t\tconst resp = await new Promise<LLMResponse>((resolve, reject) => {\n\t\t\t\t\tconst input = adapter.invoke(msgs, {\n\t\t\t\t\t\tmodel: opts?.model,\n\t\t\t\t\t\ttemperature: opts?.temperature,\n\t\t\t\t\t\tmaxTokens: opts?.maxTokens,\n\t\t\t\t\t\tsystemPrompt: opts?.systemPrompt,\n\t\t\t\t\t});\n\t\t\t\t\t// NodeInput may be a Node, Promise, or raw value\n\t\t\t\t\tif (input && typeof (input as PromiseLike<LLMResponse>).then === \"function\") {\n\t\t\t\t\t\t(input as PromiseLike<LLMResponse>).then(resolve, reject);\n\t\t\t\t\t} else if (input && typeof (input as Node<LLMResponse>).subscribe === \"function\") {\n\t\t\t\t\t\tresolve((input as Node<LLMResponse>).cache as LLMResponse);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresolve(input as LLMResponse);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tconst content = extractContent(resp);\n\t\t\t\tlet parsed: T;\n\t\t\t\tif (format === \"json\") {\n\t\t\t\t\tparsed = JSON.parse(stripFences(content)) as T;\n\t\t\t\t} else {\n\t\t\t\t\tparsed = content as unknown as T;\n\t\t\t\t}\n\t\t\t\tcache?.set(cacheKey, parsed);\n\t\t\t\treturn parsed;\n\t\t\t} catch (err) {\n\t\t\t\tif (remaining > 0) return attempt(remaining - 1);\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t}\n\n\t\treturn attempt(retries) as NodeInput<T | null>;\n\t});\n\n\treturn result;\n}\n\n// ---------------------------------------------------------------------------\n// chatStream\n// ---------------------------------------------------------------------------\n\nexport type ChatStreamOptions = {\n\tgraph?: GraphOptions;\n\tmaxMessages?: number;\n};\n\nexport class ChatStreamGraph extends Graph {\n\tprivate readonly _log: ReactiveLogBundle<ChatMessage>;\n\treadonly messages: Node<readonly ChatMessage[]>;\n\treadonly latest: Node<ChatMessage | null>;\n\treadonly messageCount: Node<number>;\n\n\tconstructor(name: string, opts: ChatStreamOptions = {}) {\n\t\tsuper(name, opts.graph);\n\n\t\tthis._log = reactiveLog<ChatMessage>([], {\n\t\t\tname: \"messages\",\n\t\t\tmaxSize: opts.maxMessages,\n\t\t});\n\t\tthis.messages = this._log.entries;\n\t\tthis.add(\"messages\", this.messages);\n\n\t\tthis.latest = derived<ChatMessage | null>(\n\t\t\t[this.messages],\n\t\t\t([snapshot]) => {\n\t\t\t\tconst entries = snapshot as readonly ChatMessage[];\n\t\t\t\treturn entries.length === 0 ? null : (entries[entries.length - 1] as ChatMessage);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"latest\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"chat_latest\"),\n\t\t\t},\n\t\t);\n\t\tthis.add(\"latest\", this.latest);\n\t\tthis.addDisposer(keepalive(this.latest));\n\n\t\tthis.messageCount = derived<number>(\n\t\t\t[this.messages],\n\t\t\t([snapshot]) => (snapshot as readonly ChatMessage[]).length,\n\t\t\t{\n\t\t\t\tname: \"messageCount\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"chat_message_count\"),\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t);\n\t\tthis.add(\"messageCount\", this.messageCount);\n\t\tthis.addDisposer(keepalive(this.messageCount));\n\t}\n\n\tappend(role: ChatMessage[\"role\"], content: string, extra?: Partial<ChatMessage>): void {\n\t\tthis._log.append({ role, content, ...extra });\n\t}\n\n\tappendToolResult(callId: string, content: string): void {\n\t\tthis._log.append({ role: \"tool\", content, toolCallId: callId });\n\t}\n\n\tclear(): void {\n\t\tthis._log.clear();\n\t}\n\n\tallMessages(): readonly ChatMessage[] {\n\t\treturn this.messages.cache as readonly ChatMessage[];\n\t}\n}\n\nexport function chatStream(name: string, opts?: ChatStreamOptions): ChatStreamGraph {\n\treturn new ChatStreamGraph(name, opts);\n}\n\n// ---------------------------------------------------------------------------\n// toolRegistry\n// ---------------------------------------------------------------------------\n\nexport type ToolRegistryOptions = {\n\tgraph?: GraphOptions;\n};\n\nexport class ToolRegistryGraph extends Graph {\n\treadonly definitions: Node<ReadonlyMap<string, ToolDefinition>>;\n\treadonly schemas: Node<readonly ToolDefinition[]>;\n\n\tconstructor(name: string, opts: ToolRegistryOptions = {}) {\n\t\tsuper(name, opts.graph);\n\n\t\tthis.definitions = state<ReadonlyMap<string, ToolDefinition>>(new Map(), {\n\t\t\tname: \"definitions\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"tool_definitions\"),\n\t\t});\n\t\tthis.add(\"definitions\", this.definitions);\n\n\t\tthis.schemas = derived<readonly ToolDefinition[]>(\n\t\t\t[this.definitions],\n\t\t\t([defs]) => [...((defs ?? new Map()) as ReadonlyMap<string, ToolDefinition>).values()],\n\t\t\t{\n\t\t\t\tname: \"schemas\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"tool_schemas\"),\n\t\t\t\tinitial: [],\n\t\t\t},\n\t\t);\n\t\tthis.add(\"schemas\", this.schemas);\n\t\tthis.addDisposer(keepalive(this.schemas));\n\t}\n\n\tregister(tool: ToolDefinition): void {\n\t\tconst current = this.definitions.cache as ReadonlyMap<string, ToolDefinition>;\n\t\tconst next = new Map(current);\n\t\tnext.set(tool.name, tool);\n\t\tthis.definitions.down([[DATA, next]]);\n\t}\n\n\tunregister(name: string): void {\n\t\tconst current = this.definitions.cache as ReadonlyMap<string, ToolDefinition>;\n\t\tif (!current.has(name)) return;\n\t\tconst next = new Map(current);\n\t\tnext.delete(name);\n\t\tthis.definitions.down([[DATA, next]]);\n\t}\n\n\tasync execute(name: string, args: Record<string, unknown>): Promise<unknown> {\n\t\tconst defs = this.definitions.cache as ReadonlyMap<string, ToolDefinition>;\n\t\tconst tool = defs.get(name);\n\t\tif (!tool) throw new Error(`toolRegistry: unknown tool \"${name}\"`);\n\t\tconst raw = tool.handler(args);\n\t\treturn resolveToolHandlerResult(raw);\n\t}\n\n\tgetDefinition(name: string): ToolDefinition | undefined {\n\t\treturn (this.definitions.cache as ReadonlyMap<string, ToolDefinition>)?.get(name);\n\t}\n}\n\nexport function toolRegistry(name: string, opts?: ToolRegistryOptions): ToolRegistryGraph {\n\treturn new ToolRegistryGraph(name, opts);\n}\n\n// ---------------------------------------------------------------------------\n// systemPromptBuilder\n// ---------------------------------------------------------------------------\n\n/**\n * Assembles a system prompt from reactive sections. Each section is a\n * `NodeInput<string>` — the prompt updates when any section changes.\n */\nexport type SystemPromptHandle = Node<string> & { dispose: () => void };\n\nexport function systemPromptBuilder(\n\tsections: readonly NodeInput<string>[],\n\topts?: { separator?: string; name?: string },\n): SystemPromptHandle {\n\tconst separator = opts?.separator ?? \"\\n\\n\";\n\tconst sectionNodes = sections.map((s) => (typeof s === \"string\" ? state(s) : fromAny(s)));\n\tconst prompt = derived(\n\t\tsectionNodes,\n\t\t(values) => (values as string[]).filter((v) => v != null && v !== \"\").join(separator),\n\t\t{\n\t\t\tname: opts?.name ?? \"systemPrompt\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tmeta: aiMeta(\"system_prompt\"),\n\t\t\tinitial: \"\",\n\t\t},\n\t);\n\tconst unsub = keepalive(prompt);\n\treturn Object.assign(prompt, { dispose: unsub });\n}\n\n// ---------------------------------------------------------------------------\n// llmExtractor / llmConsolidator\n// ---------------------------------------------------------------------------\n\nexport type LLMExtractorOptions = {\n\tadapter: LLMAdapter;\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n};\n\n/**\n * Returns an `extractFn` callback for `distill()` that invokes an LLM to\n * extract structured memories from raw input.\n *\n * The system prompt should instruct the LLM to return JSON matching\n * `Extraction<TMem>` shape: `{ upsert: [{ key, value }], remove?: [key] }`.\n */\nexport function llmExtractor<TRaw, TMem>(\n\tsystemPrompt: string,\n\topts: LLMExtractorOptions,\n): (raw: TRaw, existing: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>> {\n\treturn (raw: TRaw, existing: ReadonlyMap<string, TMem>) => {\n\t\tconst existingKeys = [...existing.keys()].slice(0, 100); // sample for dedup\n\t\tconst messages: ChatMessage[] = [\n\t\t\t{ role: \"system\", content: systemPrompt },\n\t\t\t{\n\t\t\t\trole: \"user\",\n\t\t\t\tcontent: JSON.stringify({\n\t\t\t\t\tinput: raw,\n\t\t\t\t\texistingKeys,\n\t\t\t\t}),\n\t\t\t},\n\t\t];\n\t\t// Wrap the adapter call in a producer that parses the JSON response\n\t\treturn producer<Extraction<TMem>>((actions) => {\n\t\t\tlet active = true;\n\t\t\tconst result = opts.adapter.invoke(messages, {\n\t\t\t\tmodel: opts.model,\n\t\t\t\ttemperature: opts.temperature ?? 0,\n\t\t\t\tmaxTokens: opts.maxTokens,\n\t\t\t});\n\t\t\t// result is NodeInput — could be a Promise, Node, etc.\n\t\t\tconst resolved = fromAny(result);\n\t\t\tconst unsub = resolved.subscribe((msgs) => {\n\t\t\t\tif (!active) return;\n\t\t\t\tlet done = false;\n\t\t\t\tfor (const msg of msgs) {\n\t\t\t\t\tif (done) break;\n\t\t\t\t\tif (msg[0] === DATA) {\n\t\t\t\t\t\tconst response = msg[1] as LLMResponse;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst parsed = JSON.parse(response.content) as Extraction<TMem>;\n\t\t\t\t\t\t\tactions.emit(parsed);\n\t\t\t\t\t\t\tactions.down([[COMPLETE]]);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tactions.down([\n\t\t\t\t\t\t\t\t[ERROR, new Error(\"llmExtractor: failed to parse LLM response as JSON\")],\n\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdone = true;\n\t\t\t\t\t} else if (msg[0] === ERROR) {\n\t\t\t\t\t\tactions.down([[ERROR, msg[1]]]);\n\t\t\t\t\t\tdone = true;\n\t\t\t\t\t} else if (msg[0] === COMPLETE) {\n\t\t\t\t\t\tactions.down([[COMPLETE]]);\n\t\t\t\t\t\tdone = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Forward unknown message types (spec §1.3.6)\n\t\t\t\t\t\tactions.down([[msg[0], msg[1]]]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn () => {\n\t\t\t\tunsub();\n\t\t\t\tactive = false;\n\t\t\t};\n\t\t});\n\t};\n}\n\nexport type LLMConsolidatorOptions = LLMExtractorOptions;\n\n/**\n * Returns a `consolidateFn` callback for `distill()` that invokes an LLM to\n * cluster and merge related memories.\n */\nexport function llmConsolidator<TMem>(\n\tsystemPrompt: string,\n\topts: LLMConsolidatorOptions,\n): (entries: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>> {\n\treturn (entries: ReadonlyMap<string, TMem>) => {\n\t\tconst entriesArray = [...entries.entries()].map(([key, value]) => ({ key, value }));\n\t\tconst messages: ChatMessage[] = [\n\t\t\t{ role: \"system\", content: systemPrompt },\n\t\t\t{ role: \"user\", content: JSON.stringify({ memories: entriesArray }) },\n\t\t];\n\t\treturn producer<Extraction<TMem>>((actions) => {\n\t\t\tlet active = true;\n\t\t\tconst result = opts.adapter.invoke(messages, {\n\t\t\t\tmodel: opts.model,\n\t\t\t\ttemperature: opts.temperature ?? 0,\n\t\t\t\tmaxTokens: opts.maxTokens,\n\t\t\t});\n\t\t\tconst resolved = fromAny(result);\n\t\t\tconst unsub = resolved.subscribe((msgs) => {\n\t\t\t\tif (!active) return;\n\t\t\t\tlet done = false;\n\t\t\t\tfor (const msg of msgs) {\n\t\t\t\t\tif (done) break;\n\t\t\t\t\tif (msg[0] === DATA) {\n\t\t\t\t\t\tconst response = msg[1] as LLMResponse;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst parsed = JSON.parse(response.content) as Extraction<TMem>;\n\t\t\t\t\t\t\tactions.emit(parsed);\n\t\t\t\t\t\t\tactions.down([[COMPLETE]]);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tactions.down([\n\t\t\t\t\t\t\t\t[ERROR, new Error(\"llmConsolidator: failed to parse LLM response as JSON\")],\n\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdone = true;\n\t\t\t\t\t} else if (msg[0] === ERROR) {\n\t\t\t\t\t\tactions.down([[ERROR, msg[1]]]);\n\t\t\t\t\t\tdone = true;\n\t\t\t\t\t} else if (msg[0] === COMPLETE) {\n\t\t\t\t\t\tactions.down([[COMPLETE]]);\n\t\t\t\t\t\tdone = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Forward unknown message types (spec §1.3.6)\n\t\t\t\t\t\tactions.down([[msg[0], msg[1]]]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn () => {\n\t\t\t\tunsub();\n\t\t\t\tactive = false;\n\t\t\t};\n\t\t});\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// 3D Admission Scoring\n// ---------------------------------------------------------------------------\n\n/** Scores for the three admission dimensions. Each 0–1. */\nexport type AdmissionScores = {\n\treadonly persistence: number;\n\treadonly structure: number;\n\treadonly personalValue: number;\n};\n\nexport type AdmissionScore3DOptions = {\n\t/** Custom scoring function. Default: rule-based (all dimensions 0.5). */\n\tscoreFn?: (raw: unknown) => AdmissionScores;\n\t/** Minimum persistence score to admit (default 0.3). */\n\tpersistenceThreshold?: number;\n\t/** Minimum personalValue score to admit (default 0.3). */\n\tpersonalValueThreshold?: number;\n\t/** Require structure score > 0 to admit (default false). */\n\trequireStructured?: boolean;\n};\n\n/**\n * Default 3D admission scorer. Returns middle scores for all dimensions.\n * Override with `scoreFn` for LLM-backed or domain-specific scoring.\n */\nfunction defaultAdmissionScorer(_raw: unknown): AdmissionScores {\n\treturn { persistence: 0.5, structure: 0.5, personalValue: 0.5 };\n}\n\n/**\n * Creates a 3D admission filter function compatible with `agentMemory`'s\n * `admissionFilter` option. Scores each candidate on persistence, structure,\n * and personalValue, then applies thresholds.\n */\nexport function admissionFilter3D(opts: AdmissionScore3DOptions = {}): (raw: unknown) => boolean {\n\tconst scoreFn = opts.scoreFn ?? defaultAdmissionScorer;\n\tconst pThresh = opts.persistenceThreshold ?? 0.3;\n\tconst pvThresh = opts.personalValueThreshold ?? 0.3;\n\tconst reqStructured = opts.requireStructured ?? false;\n\treturn (raw: unknown): boolean => {\n\t\tconst scores = scoreFn(raw);\n\t\tif (scores.persistence < pThresh) return false;\n\t\tif (scores.personalValue < pvThresh) return false;\n\t\tif (reqStructured && scores.structure <= 0) return false;\n\t\treturn true;\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Memory Tiers\n// ---------------------------------------------------------------------------\n\nexport type MemoryTier = \"permanent\" | \"active\" | \"archived\";\n\nexport type MemoryTiersOptions<TMem> = {\n\t/** Exponential decay rate per second for active tier.\n\t * Default: 7-day half-life ≈ ln(2)/(7×86400) ≈ 0.00000114. */\n\tdecayRate?: number;\n\t/** Max entries in the active tier before archiving lowest-scored (default 1000). */\n\tmaxActive?: number;\n\t/** Score threshold below which active entries get archived (default 0.1). */\n\tarchiveThreshold?: number;\n\t/** Predicate: true → entry belongs in permanent tier (default: never). */\n\tpermanentFilter?: (key: string, mem: TMem) => boolean;\n\t/** Storage tier for the archive. Omit to disable archiving. */\n\tarchiveTier?: StorageTier;\n\t/** Options forwarded to `graph.attachStorage` for the archive tier. */\n\tarchiveStorageOptions?: GraphAttachStorageOptions;\n};\n\nconst DEFAULT_DECAY_RATE = Math.LN2 / (7 * 86_400); // 7-day half-life\n\nexport type MemoryTiersBundle<TMem> = {\n\t/** Permanent tier: never evicted. */\n\treadonly permanent: LightCollectionBundle<TMem>;\n\t/** Active entries node (reactive, holds ReadonlyMap). */\n\treadonly activeEntries: Node<unknown>;\n\t/** Archive storage handle (null if no tier configured). */\n\treadonly archiveHandle: StorageHandle | null;\n\t/** Classify a key into its current tier. */\n\ttierOf: (key: string) => MemoryTier;\n\t/** Move a key to the permanent tier. */\n\tmarkPermanent: (key: string, value: TMem) => void;\n};\n\n// ---------------------------------------------------------------------------\n// Retrieval Pipeline\n// ---------------------------------------------------------------------------\n\nexport type RetrievalQuery = {\n\treadonly text?: string;\n\treadonly vector?: readonly number[];\n\treadonly entityIds?: readonly string[];\n};\n\nexport type RetrievalPipelineOptions<TMem> = {\n\t/** Max candidates from vector search (default 20). */\n\ttopK?: number;\n\t/** KG expansion depth in hops (default 1). */\n\tgraphDepth?: number;\n\t/** Token budget for final packing (default 2000). */\n\tbudget?: number;\n\t/** Cost function for budget packing. */\n\tcost: (mem: TMem) => number;\n\t/** Score function for ranking. */\n\tscore: (mem: TMem, context: unknown) => number;\n};\n\n/** A single entry in the retrieval result, with causal trace metadata. */\nexport type RetrievalEntry<TMem> = {\n\treadonly key: string;\n\treadonly value: TMem;\n\treadonly score: number;\n\treadonly sources: ReadonlyArray<\"vector\" | \"graph\" | \"store\">;\n};\n\n/** Causal trace for a retrieval run. */\nexport type RetrievalTrace<TMem> = {\n\treadonly vectorCandidates: ReadonlyArray<VectorSearchResult<TMem>>;\n\treadonly graphExpanded: ReadonlyArray<string>;\n\treadonly ranked: ReadonlyArray<RetrievalEntry<TMem>>;\n\treadonly packed: ReadonlyArray<RetrievalEntry<TMem>>;\n};\n\n// ---------------------------------------------------------------------------\n// agentMemory\n// ---------------------------------------------------------------------------\n\nexport type AgentMemoryOptions<TMem = unknown> = {\n\tgraph?: GraphOptions;\n\t/** LLM adapter for extraction and consolidation. */\n\tadapter?: LLMAdapter;\n\t/** System prompt for the extractor LLM. */\n\textractPrompt?: string;\n\t/** Custom extractFn (overrides adapter + extractPrompt). */\n\textractFn?: (raw: unknown, existing: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>>;\n\t/** System prompt for the consolidation LLM. */\n\tconsolidatePrompt?: string;\n\t/** Custom consolidateFn (overrides adapter + consolidatePrompt). */\n\tconsolidateFn?: (entries: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>>;\n\t/** Reactive trigger for consolidation (caller supplies e.g. `fromTimer`). */\n\tconsolidateTrigger?: NodeInput<unknown>;\n\t/** Score function for budget packing (required). */\n\tscore: (mem: TMem, context: unknown) => number;\n\t/** Cost function for budget packing (required). */\n\tcost: (mem: TMem) => number;\n\t/** Token budget for compact view (default 2000). */\n\tbudget?: number;\n\t/** Context node for scoring. */\n\tcontext?: NodeInput<unknown>;\n\t/** Admission filter (default: admit all). */\n\tadmissionFilter?: (candidate: unknown) => boolean;\n\t/** Vector index dimensions (> 0 enables vector index for retrieval). */\n\tvectorDimensions?: number;\n\n\t// --- In-factory composition (new) ---\n\n\t/** Extract embedding vector from a memory entry (enables vector index). */\n\tembedFn?: (mem: TMem) => readonly number[] | undefined;\n\t/** Enable knowledge graph for entity/relation tracking. */\n\tenableKnowledgeGraph?: boolean;\n\t/** Extract entities and relations from a memory entry. */\n\tentityFn?: (\n\t\tkey: string,\n\t\tmem: TMem,\n\t) =>\n\t\t| {\n\t\t\t\tentities?: Array<{ id: string; value: unknown }>;\n\t\t\t\trelations?: Array<{ from: string; to: string; relation: string; weight?: number }>;\n\t\t }\n\t\t| undefined;\n\n\t/** 3-tier storage configuration. Omit to use single-tier (existing behavior). */\n\ttiers?: MemoryTiersOptions<TMem>;\n\n\t/** Retrieval pipeline configuration. Requires vector index or knowledge graph. */\n\tretrieval?: {\n\t\t/** Max candidates from vector search (default 20). */\n\t\ttopK?: number;\n\t\t/** KG expansion depth in hops (default 1). */\n\t\tgraphDepth?: number;\n\t};\n\n\t/** Periodic reflection/consolidation configuration. */\n\treflection?: {\n\t\t/** Interval in ms between consolidation runs (default 300_000 = 5 min). */\n\t\tinterval?: number;\n\t\t/** Enable/disable periodic reflection (default true when consolidateFn is available). */\n\t\tenabled?: boolean;\n\t};\n};\n\nexport type AgentMemoryGraph<TMem = unknown> = Graph & {\n\treadonly distillBundle: DistillBundle<TMem>;\n\treadonly compact: Node<Array<{ key: string; value: TMem; score: number }>>;\n\treadonly size: Node<number>;\n\t/** Vector index bundle (null if not enabled). */\n\treadonly vectors: VectorIndexBundle<TMem> | null;\n\t/** Knowledge graph (null if not enabled). */\n\treadonly kg: KnowledgeGraphGraph<unknown, string> | null;\n\t/** Memory tiers bundle (null if not configured). */\n\treadonly memoryTiers: MemoryTiersBundle<TMem> | null;\n\t/** Retrieval result node (null if no retrieval pipeline configured). */\n\treadonly retrieval: Node<ReadonlyArray<RetrievalEntry<TMem>>> | null;\n\t/** Latest retrieval trace for observability (null if no retrieval pipeline). */\n\treadonly retrievalTrace: Node<RetrievalTrace<TMem> | null> | null;\n\t/**\n\t * Execute a retrieval query (null if no retrieval pipeline).\n\t *\n\t * **Synchronous consumer API** — returns the result immediately and batch-writes\n\t * `retrieval` and `retrievalTrace` state nodes for observers. Reads the store\n\t * snapshot and context value **at call time** (external-boundary read).\n\t *\n\t * **Do not call from inside a reactive fn body** (derived fn, subscribe callback,\n\t * effect body). The cache reads would become transitive protocol violations and\n\t * may observe wave-progressive rather than wave-final state.\n\t *\n\t * **Caller-batch caveat:** if invoked inside a caller's `batch(() => ...)` alongside\n\t * upstream store mutations, the store snapshot reflects what has been committed to\n\t * `store.entries.cache` at call time. State-backed stores update cache synchronously\n\t * so batched inserts are visible; derived-backed store transforms may defer. If you\n\t * need fresh state after batched mutations, call `retrieve` after the batch returns.\n\t */\n\treadonly retrieve: ((query: RetrievalQuery) => ReadonlyArray<RetrievalEntry<TMem>>) | null;\n};\n\n/**\n * Pre-wired agentic memory graph. Composes `distill()` with optional\n * `knowledgeGraph()`, `vectorIndex()`, `lightCollection()` (permanent tier),\n * `decay()`, and `attachStorage()` (archive tier). Supports 3D admission\n * scoring, a default retrieval pipeline, periodic reflection, and\n * retrieval observability traces.\n */\n\n/** Extract the key→value map from a reactive_map snapshot. */\nfunction extractStoreMap<TMem>(snapshot: unknown): ReadonlyMap<string, TMem> {\n\tif (snapshot instanceof Map) return snapshot as ReadonlyMap<string, TMem>;\n\treturn new Map<string, TMem>();\n}\n\nexport function agentMemory<TMem = unknown>(\n\tname: string,\n\tsource: NodeInput<unknown>,\n\topts: AgentMemoryOptions<TMem>,\n): AgentMemoryGraph<TMem> {\n\tconst graph = new Graph(name, opts.graph);\n\tconst keepaliveSubs: Array<() => void> = [];\n\n\t// --- Extract function resolution ---\n\tlet rawExtractFn: (\n\t\traw: unknown,\n\t\texisting: ReadonlyMap<string, TMem>,\n\t) => NodeInput<Extraction<TMem>>;\n\tif (opts.extractFn) {\n\t\trawExtractFn = opts.extractFn;\n\t} else if (opts.adapter && opts.extractPrompt) {\n\t\trawExtractFn = llmExtractor<unknown, TMem>(opts.extractPrompt, { adapter: opts.adapter });\n\t} else {\n\t\tthrow new Error(\"agentMemory: provide either extractFn or adapter + extractPrompt\");\n\t}\n\tconst extractFn = (\n\t\traw: unknown,\n\t\texisting: ReadonlyMap<string, TMem>,\n\t): NodeInput<Extraction<TMem>> => {\n\t\tif (raw == null) return { upsert: [] };\n\t\treturn rawExtractFn(raw, existing);\n\t};\n\n\t// --- Admission filter ---\n\tlet filteredSource = source;\n\tif (opts.admissionFilter) {\n\t\tconst srcNode = fromAny(source);\n\t\tconst filter = opts.admissionFilter;\n\t\tfilteredSource = derived(\n\t\t\t[srcNode],\n\t\t\t([raw]) => {\n\t\t\t\tif (filter(raw)) return raw;\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t\t{ name: \"admissionFilter\", describeKind: \"derived\" },\n\t\t);\n\t}\n\n\t// --- Consolidation ---\n\tlet consolidateFn:\n\t\t| ((entries: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>>)\n\t\t| undefined;\n\tif (opts.consolidateFn) {\n\t\tconsolidateFn = opts.consolidateFn;\n\t} else if (opts.adapter && opts.consolidatePrompt) {\n\t\tconsolidateFn = llmConsolidator<TMem>(opts.consolidatePrompt, { adapter: opts.adapter });\n\t}\n\n\t// --- Reflection: default consolidateTrigger from fromTimer ---\n\tlet consolidateTrigger = opts.consolidateTrigger;\n\tif (!consolidateTrigger && consolidateFn && opts.reflection?.enabled !== false) {\n\t\tconst interval = opts.reflection?.interval ?? 300_000;\n\t\tconsolidateTrigger = fromTimer(interval, { period: interval });\n\t}\n\n\t// --- Build distill bundle ---\n\tconst distillOpts: DistillOptions<TMem> = {\n\t\tscore: opts.score,\n\t\tcost: opts.cost,\n\t\tbudget: opts.budget ?? 2000,\n\t\tcontext: opts.context,\n\t\tconsolidate: consolidateFn,\n\t\tconsolidateTrigger,\n\t};\n\tconst distillBundle = distill<unknown, TMem>(filteredSource, extractFn, distillOpts);\n\n\tgraph.add(\"store\", distillBundle.store.entries);\n\tgraph.add(\"compact\", distillBundle.compact);\n\tgraph.add(\"size\", distillBundle.size);\n\n\t// --- Vector index (optional) ---\n\tlet vectors: VectorIndexBundle<TMem> | null = null;\n\tif (opts.vectorDimensions && opts.vectorDimensions > 0 && opts.embedFn) {\n\t\tvectors = vectorIndex<TMem>({ dimension: opts.vectorDimensions });\n\t\tgraph.add(\"vectorIndex\", vectors.entries);\n\t}\n\n\t// --- Knowledge graph (optional) ---\n\tlet kg: KnowledgeGraphGraph<unknown, string> | null = null;\n\tif (opts.enableKnowledgeGraph) {\n\t\tkg = knowledgeGraph<unknown, string>(`${name}-kg`);\n\t\tgraph.mount(\"kg\", kg);\n\t}\n\n\t// --- 3-tier storage (optional) ---\n\tlet memoryTiersBundle: MemoryTiersBundle<TMem> | null = null;\n\tif (opts.tiers) {\n\t\tconst tiersOpts = opts.tiers;\n\t\tconst decayRate = tiersOpts.decayRate ?? DEFAULT_DECAY_RATE;\n\t\tconst maxActive = tiersOpts.maxActive ?? 1000;\n\t\tconst archiveThreshold = tiersOpts.archiveThreshold ?? 0.1;\n\t\tconst permanentFilter = tiersOpts.permanentFilter ?? (() => false);\n\n\t\t// Permanent tier\n\t\tconst permanent = lightCollection<TMem>({ name: \"permanent\" });\n\t\tgraph.add(\"permanent\", permanent.entries);\n\n\t\t// Track which keys are permanent\n\t\tconst permanentKeys = new Set<string>();\n\n\t\tconst tierOf = (key: string): MemoryTier => {\n\t\t\tif (permanentKeys.has(key)) return \"permanent\";\n\t\t\tconst storeMap = extractStoreMap<TMem>(distillBundle.store.entries.cache);\n\t\t\tif (storeMap.has(key)) return \"active\";\n\t\t\treturn \"archived\";\n\t\t};\n\n\t\tconst markPermanent = (key: string, value: TMem): void => {\n\t\t\tpermanentKeys.add(key);\n\t\t\tpermanent.upsert(key, value);\n\t\t};\n\n\t\t// Track entry creation times for accurate decay age calculation\n\t\tconst entryCreatedAtNs = new Map<string, number>();\n\n\t\t// Post-extraction hook: classify into tiers and archive low-scored entries\n\t\tconst storeNode = distillBundle.store.entries;\n\t\tconst contextNode = opts.context ? fromAny(opts.context) : state<unknown>(null);\n\t\tconst tierClassifier = effect([storeNode, contextNode], ([snapshot, ctx]) => {\n\t\t\tconst storeMap = extractStoreMap<TMem>(snapshot);\n\t\t\tconst nowNs = monotonicNs();\n\t\t\tconst toArchive: string[] = [];\n\t\t\tconst toPermanent: Array<{ key: string; value: TMem }> = [];\n\n\t\t\tfor (const [key, mem] of storeMap) {\n\t\t\t\t// Track creation time for new entries\n\t\t\t\tif (!entryCreatedAtNs.has(key)) {\n\t\t\t\t\tentryCreatedAtNs.set(key, nowNs);\n\t\t\t\t}\n\n\t\t\t\t// Check permanent classification\n\t\t\t\tif (permanentFilter(key, mem)) {\n\t\t\t\t\ttoPermanent.push({ key, value: mem });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Compute decayed score for active tier\n\t\t\t\tconst baseScore = opts.score(mem, ctx);\n\t\t\t\tconst createdNs = entryCreatedAtNs.get(key) ?? nowNs;\n\t\t\t\tconst ageSeconds = Number(nowNs - createdNs) / 1e9;\n\t\t\t\tconst decayed = decay(baseScore, ageSeconds, decayRate);\n\t\t\t\tif (decayed < archiveThreshold) {\n\t\t\t\t\ttoArchive.push(key);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Clean up creation times for removed entries\n\t\t\tfor (const key of entryCreatedAtNs.keys()) {\n\t\t\t\tif (!storeMap.has(key)) entryCreatedAtNs.delete(key);\n\t\t\t}\n\n\t\t\t// Move to permanent\n\t\t\tfor (const { key, value } of toPermanent) {\n\t\t\t\tif (!permanentKeys.has(key)) {\n\t\t\t\t\tmarkPermanent(key, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Archive and evict from active (respect maxActive, excluding permanent keys)\n\t\t\tconst activeCount = storeMap.size - permanentKeys.size;\n\t\t\tif (activeCount > maxActive) {\n\t\t\t\tconst scored = [...storeMap.entries()]\n\t\t\t\t\t.filter(([k]) => !permanentKeys.has(k))\n\t\t\t\t\t.map(([k, m]) => ({ key: k, score: opts.score(m, ctx) }))\n\t\t\t\t\t.sort((a, b) => a.score - b.score);\n\t\t\t\tconst excess = activeCount - maxActive;\n\t\t\t\tfor (let i = 0; i < excess && i < scored.length; i++) {\n\t\t\t\t\tconst sk = scored[i]!.key;\n\t\t\t\t\tif (!toArchive.includes(sk)) toArchive.push(sk);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Evict archived keys from active store\n\t\t\tif (toArchive.length > 0) {\n\t\t\t\tbatch(() => {\n\t\t\t\t\tfor (const key of toArchive) {\n\t\t\t\t\t\tdistillBundle.store.delete(key);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\tkeepaliveSubs.push(tierClassifier.subscribe(() => undefined));\n\n\t\t// Archive checkpoint\n\t\tlet archiveHandle: StorageHandle | null = null;\n\t\tif (tiersOpts.archiveTier) {\n\t\t\tarchiveHandle = graph.attachStorage(\n\t\t\t\t[tiersOpts.archiveTier],\n\t\t\t\ttiersOpts.archiveStorageOptions ?? {},\n\t\t\t);\n\t\t}\n\n\t\tmemoryTiersBundle = {\n\t\t\tpermanent,\n\t\t\tactiveEntries: storeNode,\n\t\t\tarchiveHandle,\n\t\t\ttierOf,\n\t\t\tmarkPermanent,\n\t\t};\n\t}\n\n\t// --- Post-extraction hooks: vector + KG indexing ---\n\tif (vectors || kg) {\n\t\tconst embedFn = opts.embedFn;\n\t\tconst entityFn = opts.entityFn;\n\t\tconst storeNode = distillBundle.store.entries;\n\n\t\tconst indexer = effect([storeNode], ([snapshot]) => {\n\t\t\tconst storeMap = extractStoreMap<TMem>(snapshot);\n\t\t\tfor (const [key, mem] of storeMap) {\n\t\t\t\t// Vector indexing\n\t\t\t\tif (vectors && embedFn) {\n\t\t\t\t\tconst vec = embedFn(mem);\n\t\t\t\t\tif (vec) vectors.upsert(key, vec, mem);\n\t\t\t\t}\n\t\t\t\t// Knowledge graph entity/relation extraction\n\t\t\t\tif (kg && entityFn) {\n\t\t\t\t\tconst extracted = entityFn(key, mem);\n\t\t\t\t\tif (extracted) {\n\t\t\t\t\t\tfor (const ent of extracted.entities ?? []) {\n\t\t\t\t\t\t\tkg.upsertEntity(ent.id, ent.value);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (const rel of extracted.relations ?? []) {\n\t\t\t\t\t\t\tkg.link(rel.from, rel.to, rel.relation as string, rel.weight);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tkeepaliveSubs.push(indexer.subscribe(() => undefined));\n\t}\n\n\t// --- Retrieval pipeline (optional) ---\n\tlet retrievalNode: Node<ReadonlyArray<RetrievalEntry<TMem>>> | null = null;\n\tlet retrievalTraceNode: Node<RetrievalTrace<TMem> | null> | null = null;\n\tlet retrieveFn: ((query: RetrievalQuery) => ReadonlyArray<RetrievalEntry<TMem>>) | null = null;\n\n\tif (vectors || kg) {\n\t\tconst topK = opts.retrieval?.topK ?? 20;\n\t\tconst graphDepth = opts.retrieval?.graphDepth ?? 1;\n\t\tconst budget = opts.budget ?? 2000;\n\t\tconst costFn = opts.cost;\n\t\tconst scoreFn = opts.score;\n\n\t\tconst contextNode = opts.context ? fromAny(opts.context) : state<unknown>(null);\n\n\t\t// Observer-facing state nodes. `retrieve()` writes both in a batch on every call.\n\t\t// (Option W from the 2026-04-12 P3 audit — retrieveFn is a sync consumer API that\n\t\t// reads store/context at call time, computes inline, and publishes results via\n\t\t// state writes. No derived, no queryInput, no closure side-channel.)\n\t\tconst retrievalOutput = state<ReadonlyArray<RetrievalEntry<TMem>>>([], {\n\t\t\tname: \"retrieval\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"retrieval_pipeline\"),\n\t\t});\n\t\tgraph.add(\"retrieval\", retrievalOutput);\n\t\tretrievalNode = retrievalOutput;\n\n\t\tconst traceState = state<RetrievalTrace<TMem> | null>(null, {\n\t\t\tname: \"retrievalTrace\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"retrieval_trace\"),\n\t\t});\n\t\tgraph.add(\"retrievalTrace\", traceState);\n\t\tretrievalTraceNode = traceState;\n\n\t\t// Sync consumer API. Reads `store.entries.cache` and `contextNode.cache` at\n\t\t// call time — these are external-boundary reads, allowed per the foundation\n\t\t// redesign. **Do not call from inside a reactive fn body**: the cache reads\n\t\t// would become transitive P3 violations.\n\t\tretrieveFn = (query: RetrievalQuery): ReadonlyArray<RetrievalEntry<TMem>> => {\n\t\t\tconst storeMap = extractStoreMap<TMem>(distillBundle.store.entries.cache);\n\t\t\tconst ctx = contextNode.cache;\n\n\t\t\tconst candidateMap = new Map<\n\t\t\t\tstring,\n\t\t\t\t{ value: TMem; sources: Set<\"vector\" | \"graph\" | \"store\"> }\n\t\t\t>();\n\n\t\t\t// Stage 1: Vector search\n\t\t\tlet vectorCandidates: VectorSearchResult<TMem>[] = [];\n\t\t\tif (vectors && query.vector) {\n\t\t\t\tvectorCandidates = vectors.search(query.vector, topK) as VectorSearchResult<TMem>[];\n\t\t\t\tfor (const vc of vectorCandidates) {\n\t\t\t\t\tconst mem = storeMap.get(vc.id);\n\t\t\t\t\tif (mem) {\n\t\t\t\t\t\tcandidateMap.set(vc.id, { value: mem, sources: new Set([\"vector\"]) });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Stage 2: KG expansion\n\t\t\tconst graphExpanded: string[] = [];\n\t\t\tif (kg) {\n\t\t\t\tconst seedIds = [...(query.entityIds ?? []), ...[...candidateMap.keys()]];\n\t\t\t\tconst visited = new Set<string>();\n\t\t\t\tlet frontier = seedIds;\n\t\t\t\tfor (let depth = 0; depth < graphDepth; depth++) {\n\t\t\t\t\tconst nextFrontier: string[] = [];\n\t\t\t\t\tfor (const id of frontier) {\n\t\t\t\t\t\tif (visited.has(id)) continue;\n\t\t\t\t\t\tvisited.add(id);\n\t\t\t\t\t\tconst related = kg.related(id);\n\t\t\t\t\t\tfor (const edge of related) {\n\t\t\t\t\t\t\tconst targetId = edge.to;\n\t\t\t\t\t\t\tif (!visited.has(targetId)) {\n\t\t\t\t\t\t\t\tnextFrontier.push(targetId);\n\t\t\t\t\t\t\t\tconst mem = storeMap.get(targetId);\n\t\t\t\t\t\t\t\tif (mem) {\n\t\t\t\t\t\t\t\t\tconst existing = candidateMap.get(targetId);\n\t\t\t\t\t\t\t\t\tif (existing) {\n\t\t\t\t\t\t\t\t\t\texisting.sources.add(\"graph\");\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tcandidateMap.set(targetId, { value: mem, sources: new Set([\"graph\"]) });\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tgraphExpanded.push(targetId);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfrontier = nextFrontier;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Also include direct store matches not yet in candidates\n\t\t\tfor (const [key, mem] of storeMap) {\n\t\t\t\tif (!candidateMap.has(key)) {\n\t\t\t\t\tcandidateMap.set(key, { value: mem, sources: new Set([\"store\"]) });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Stage 3: Score and rank\n\t\t\tconst ranked: RetrievalEntry<TMem>[] = [];\n\t\t\tfor (const [key, { value, sources }] of candidateMap) {\n\t\t\t\tconst score = scoreFn(value, ctx);\n\t\t\t\tranked.push({ key, value, score, sources: [...sources] });\n\t\t\t}\n\t\t\tranked.sort((a, b) => b.score - a.score);\n\n\t\t\t// Stage 4: Budget packing\n\t\t\tconst packed: RetrievalEntry<TMem>[] = [];\n\t\t\tlet usedBudget = 0;\n\t\t\tfor (const entry of ranked) {\n\t\t\t\tconst c = costFn(entry.value);\n\t\t\t\tif (usedBudget + c > budget && packed.length > 0) break;\n\t\t\t\tpacked.push(entry);\n\t\t\t\tusedBudget += c;\n\t\t\t}\n\n\t\t\tconst trace: RetrievalTrace<TMem> = {\n\t\t\t\tvectorCandidates,\n\t\t\t\tgraphExpanded,\n\t\t\t\tranked,\n\t\t\t\tpacked,\n\t\t\t};\n\n\t\t\tbatch(() => {\n\t\t\t\tretrievalOutput.down([[DATA, packed]]);\n\t\t\t\ttraceState.down([[DATA, trace]]);\n\t\t\t});\n\n\t\t\treturn packed;\n\t\t};\n\t}\n\n\t// --- Cleanup ---\n\tgraph.addDisposer(() => {\n\t\tfor (const unsub of keepaliveSubs) unsub();\n\t\tkeepaliveSubs.length = 0;\n\t});\n\n\treturn Object.assign(graph, {\n\t\tdistillBundle,\n\t\tcompact: distillBundle.compact,\n\t\tsize: distillBundle.size,\n\t\tvectors,\n\t\tkg,\n\t\tmemoryTiers: memoryTiersBundle,\n\t\tretrieval: retrievalNode,\n\t\tretrievalTrace: retrievalTraceNode,\n\t\tretrieve: retrieveFn,\n\t}) as AgentMemoryGraph<TMem>;\n}\n\n// ---------------------------------------------------------------------------\n// agentLoop\n// ---------------------------------------------------------------------------\n\nexport type AgentLoopOptions = {\n\tgraph?: GraphOptions;\n\tadapter: LLMAdapter;\n\ttools?: readonly ToolDefinition[];\n\tsystemPrompt?: string;\n\tmaxTurns?: number;\n\tstopWhen?: (response: LLMResponse) => boolean;\n\tonToolCall?: (call: ToolCall) => void;\n\tmaxMessages?: number;\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n};\n\nexport class AgentLoopGraph extends Graph {\n\treadonly chat: ChatStreamGraph;\n\treadonly tools: ToolRegistryGraph;\n\treadonly status: Node<AgentLoopStatus>;\n\treadonly turnCount: Node<number>;\n\treadonly lastResponse: Node<LLMResponse | null>;\n\tprivate readonly _statusState: Node<AgentLoopStatus>;\n\tprivate readonly _turnCountState: Node<number>;\n\tprivate readonly _adapter: LLMAdapter;\n\tprivate readonly _maxTurns: number;\n\tprivate readonly _stopWhen?: (response: LLMResponse) => boolean;\n\tprivate readonly _onToolCall?: (call: ToolCall) => void;\n\tprivate readonly _systemPrompt?: string;\n\tprivate readonly _model?: string;\n\tprivate readonly _temperature?: number;\n\tprivate readonly _maxTokens?: number;\n\tprivate _running = false;\n\tprivate _abortController: AbortController | null = null;\n\n\tconstructor(name: string, opts: AgentLoopOptions) {\n\t\tsuper(name, opts.graph);\n\n\t\tthis._adapter = opts.adapter;\n\t\tthis._maxTurns = opts.maxTurns ?? 10;\n\t\tthis._stopWhen = opts.stopWhen;\n\t\tthis._onToolCall = opts.onToolCall;\n\t\tthis._systemPrompt = opts.systemPrompt;\n\t\tthis._model = opts.model;\n\t\tthis._temperature = opts.temperature;\n\t\tthis._maxTokens = opts.maxTokens;\n\n\t\t// Mount chat subgraph\n\t\tthis.chat = chatStream(`${name}-chat`, { maxMessages: opts.maxMessages });\n\t\tthis.mount(\"chat\", this.chat);\n\n\t\t// Mount tool registry subgraph\n\t\tthis.tools = toolRegistry(`${name}-tools`);\n\t\tthis.mount(\"tools\", this.tools);\n\n\t\t// Register initial tools\n\t\tif (opts.tools) {\n\t\t\tfor (const tool of opts.tools) {\n\t\t\t\tthis.tools.register(tool);\n\t\t\t}\n\t\t}\n\n\t\t// Status state\n\t\tthis._statusState = state<AgentLoopStatus>(\"idle\", {\n\t\t\tname: \"status\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"agent_status\"),\n\t\t});\n\t\tthis.status = this._statusState;\n\t\tthis.add(\"status\", this.status);\n\n\t\t// Turn count\n\t\tthis._turnCountState = state<number>(0, {\n\t\t\tname: \"turnCount\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"agent_turn_count\"),\n\t\t});\n\t\tthis.turnCount = this._turnCountState;\n\t\tthis.add(\"turnCount\", this.turnCount);\n\n\t\t// Last LLM response\n\t\tthis.lastResponse = state<LLMResponse | null>(null, {\n\t\t\tname: \"lastResponse\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"agent_last_response\"),\n\t\t});\n\t\tthis.add(\"lastResponse\", this.lastResponse);\n\t}\n\n\t/**\n\t * Start the agent loop with a user message. The loop runs reactively:\n\t * think (LLM call) → act (tool execution) → repeat until done.\n\t *\n\t * Messages accumulate across calls. Call `chat.clear()` before `run()`\n\t * to reset conversation history.\n\t */\n\tasync run(userMessage: string): Promise<LLMResponse | null> {\n\t\tif (this._running) throw new Error(\"agentLoop: already running\");\n\t\tthis._running = true;\n\t\tthis._abortController = new AbortController();\n\t\tconst { signal } = this._abortController;\n\n\t\tbatch(() => {\n\t\t\tthis._statusState.down([[DATA, \"idle\" as AgentLoopStatus]]);\n\t\t\tthis._turnCountState.down([[DATA, 0]]);\n\t\t});\n\t\tthis.chat.append(\"user\", userMessage);\n\n\t\ttry {\n\t\t\tlet turns = 0;\n\t\t\twhile (turns < this._maxTurns) {\n\t\t\t\tif (signal.aborted) throw new Error(\"agentLoop: aborted\");\n\t\t\t\tturns++;\n\t\t\t\tbatch(() => {\n\t\t\t\t\tthis._turnCountState.down([[DATA, turns]]);\n\t\t\t\t\tthis._statusState.down([[DATA, \"thinking\" as AgentLoopStatus]]);\n\t\t\t\t});\n\n\t\t\t\t// Invoke LLM\n\t\t\t\tconst msgs = this.chat.allMessages();\n\t\t\t\tconst toolSchemas = (this.tools.schemas.cache as readonly ToolDefinition[]) ?? [];\n\t\t\t\tconst response = await this._invokeLLM(msgs, toolSchemas, signal);\n\t\t\t\tif (signal.aborted) throw new Error(\"agentLoop: aborted\");\n\n\t\t\t\t(this.lastResponse as Node<LLMResponse | null>).down([[DATA, response]]);\n\n\t\t\t\t// Append assistant message\n\t\t\t\tthis.chat.append(\"assistant\", response.content, {\n\t\t\t\t\ttoolCalls: response.toolCalls,\n\t\t\t\t});\n\n\t\t\t\t// Check stop conditions\n\t\t\t\tif (this._shouldStop(response)) {\n\t\t\t\t\tthis._statusState.down([[DATA, \"done\" as AgentLoopStatus]]);\n\t\t\t\t\tthis._running = false;\n\t\t\t\t\tthis._abortController = null;\n\t\t\t\t\treturn response;\n\t\t\t\t}\n\n\t\t\t\t// Execute tool calls if present\n\t\t\t\tif (response.toolCalls && response.toolCalls.length > 0) {\n\t\t\t\t\tthis._statusState.down([[DATA, \"acting\" as AgentLoopStatus]]);\n\t\t\t\t\tfor (const call of response.toolCalls) {\n\t\t\t\t\t\tif (signal.aborted) throw new Error(\"agentLoop: aborted\");\n\t\t\t\t\t\tthis._onToolCall?.(call);\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result = await this.tools.execute(call.name, call.arguments);\n\t\t\t\t\t\t\tthis.chat.appendToolResult(call.id, JSON.stringify(result));\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tthis.chat.appendToolResult(call.id, JSON.stringify({ error: String(err) }));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// No tool calls and not explicitly stopped → done\n\t\t\t\t\tthis._statusState.down([[DATA, \"done\" as AgentLoopStatus]]);\n\t\t\t\t\tthis._running = false;\n\t\t\t\t\tthis._abortController = null;\n\t\t\t\t\treturn response;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Max turns reached\n\t\t\tthis._statusState.down([[DATA, \"done\" as AgentLoopStatus]]);\n\t\t\tthis._running = false;\n\t\t\tthis._abortController = null;\n\t\t\treturn this.lastResponse.cache as LLMResponse | null;\n\t\t} catch (err) {\n\t\t\tthis._statusState.down([[DATA, \"error\" as AgentLoopStatus]]);\n\t\t\tthis._running = false;\n\t\t\tthis._abortController = null;\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\tprivate async _invokeLLM(\n\t\tmsgs: readonly ChatMessage[],\n\t\ttools: readonly ToolDefinition[],\n\t\tsignal?: AbortSignal,\n\t): Promise<LLMResponse> {\n\t\tconst result = this._adapter.invoke(msgs, {\n\t\t\ttools: tools.length > 0 ? tools : undefined,\n\t\t\tsystemPrompt: this._systemPrompt,\n\t\t\tmodel: this._model,\n\t\t\ttemperature: this._temperature,\n\t\t\tmaxTokens: this._maxTokens,\n\t\t\tsignal,\n\t\t});\n\t\t// Null/undefined guard\n\t\tif (result == null) {\n\t\t\tthrow new Error(\"_invokeLLM: adapter.invoke() returned null or undefined\");\n\t\t}\n\t\t// String guard — fromAny would iterate characters\n\t\tif (typeof result === \"string\") {\n\t\t\tthrow new Error(\"_invokeLLM: adapter.invoke() returned a string, expected LLMResponse\");\n\t\t}\n\t\t// If result is already an LLMResponse (sync adapter), return directly\n\t\tif (\n\t\t\ttypeof result === \"object\" &&\n\t\t\t\"content\" in result &&\n\t\t\t!(\"subscribe\" in result) &&\n\t\t\t!(\"then\" in result)\n\t\t) {\n\t\t\treturn result as LLMResponse;\n\t\t}\n\t\t// If result is a Promise, await it then check for LLMResponse\n\t\tif (isPromiseLike(result)) {\n\t\t\tconst awaited = await result;\n\t\t\tif (\n\t\t\t\ttypeof awaited === \"object\" &&\n\t\t\t\tawaited !== null &&\n\t\t\t\t\"content\" in awaited &&\n\t\t\t\t!(\"subscribe\" in awaited)\n\t\t\t) {\n\t\t\t\treturn awaited as LLMResponse;\n\t\t\t}\n\t\t\treturn firstDataFromNode(fromAny(awaited as NodeInput<LLMResponse>)) as Promise<LLMResponse>;\n\t\t}\n\t\t// If result is a Node or async iterable, resolve via fromAny + firstDataFromNode\n\t\treturn firstDataFromNode(fromAny(result)) as Promise<LLMResponse>;\n\t}\n\n\tprivate _shouldStop(response: LLMResponse): boolean {\n\t\tif (\n\t\t\tresponse.finishReason === \"end_turn\" &&\n\t\t\t(!response.toolCalls || response.toolCalls.length === 0)\n\t\t)\n\t\t\treturn true;\n\t\tif (this._stopWhen?.(response)) return true;\n\t\treturn false;\n\t}\n\n\toverride destroy(): void {\n\t\tif (this._abortController) {\n\t\t\tthis._abortController.abort();\n\t\t\tthis._abortController = null;\n\t\t}\n\t\tthis._running = false;\n\t\tsuper.destroy();\n\t}\n}\n\nexport function agentLoop(name: string, opts: AgentLoopOptions): AgentLoopGraph {\n\treturn new AgentLoopGraph(name, opts);\n}\n\n// ---------------------------------------------------------------------------\n// 5.4 — LLM tool integration\n// ---------------------------------------------------------------------------\n\n/** OpenAI function-calling tool schema. */\nexport type OpenAIToolSchema = {\n\treadonly type: \"function\";\n\treadonly function: {\n\t\treadonly name: string;\n\t\treadonly description: string;\n\t\treadonly parameters: Record<string, unknown>;\n\t};\n};\n\n/** MCP (Model Context Protocol) tool schema. */\nexport type McpToolSchema = {\n\treadonly name: string;\n\treadonly description: string;\n\treadonly inputSchema: Record<string, unknown>;\n};\n\n/** Result of {@link knobsAsTools}. */\nexport type KnobsAsToolsResult = {\n\t/** OpenAI function-calling tool schemas. */\n\treadonly openai: readonly OpenAIToolSchema[];\n\t/** MCP tool schemas. */\n\treadonly mcp: readonly McpToolSchema[];\n\t/** GraphReFly ToolDefinitions with handlers that call `graph.set()`. */\n\treadonly definitions: readonly ToolDefinition[];\n};\n\n/**\n * Build a JSON Schema `properties.value` descriptor from a node's meta fields.\n *\n * Maps `meta.type`, `meta.range`, `meta.values`, `meta.format`, and `meta.unit`\n * to a JSON Schema property definition.\n */\nfunction metaToJsonSchema(meta: Record<string, unknown>): Record<string, unknown> {\n\tconst schema: Record<string, unknown> = {};\n\n\tconst metaType = meta.type as string | undefined;\n\tif (metaType === \"enum\" && Array.isArray(meta.values)) {\n\t\tschema.type = \"string\";\n\t\tschema.enum = meta.values;\n\t} else if (metaType === \"integer\") {\n\t\tschema.type = \"integer\";\n\t} else if (metaType === \"number\") {\n\t\tschema.type = \"number\";\n\t} else if (metaType === \"boolean\") {\n\t\tschema.type = \"boolean\";\n\t} else if (metaType === \"string\") {\n\t\tschema.type = \"string\";\n\t} else {\n\t\t// Unknown or unspecified — accept anything\n\t\tschema.type = [\"string\", \"number\", \"boolean\"];\n\t}\n\n\tif (Array.isArray(meta.range) && meta.range.length === 2) {\n\t\tschema.minimum = meta.range[0];\n\t\tschema.maximum = meta.range[1];\n\t}\n\n\tif (typeof meta.format === \"string\") {\n\t\tschema.description = `Format: ${meta.format}`;\n\t}\n\n\tif (typeof meta.unit === \"string\") {\n\t\tif (schema.description) {\n\t\t\tschema.description += ` (${meta.unit})`;\n\t\t} else {\n\t\t\tschema.description = `Unit: ${meta.unit}`;\n\t\t}\n\t}\n\n\treturn schema;\n}\n\n/**\n * Derive tool schemas from a graph's writable (knob) nodes.\n *\n * Knobs are state nodes whose `meta.access` is `\"llm\"`, `\"both\"`, or absent\n * (default: writable). Each knob becomes a tool that calls `graph.set()`.\n *\n * Speaks **domain language** (spec §5.4): the returned schemas use node names\n * and meta descriptions — no protocol internals exposed.\n *\n * @param graph - The graph to introspect.\n * @param actor - Optional actor for guard-scoped describe.\n * @returns OpenAI, MCP, and GraphReFly tool schemas.\n */\nexport function knobsAsTools(graph: Graph, actor?: Actor): KnobsAsToolsResult {\n\tconst described = graph.describe({ actor, detail: \"full\" });\n\tconst openai: OpenAIToolSchema[] = [];\n\tconst mcp: McpToolSchema[] = [];\n\tconst definitions: ToolDefinition[] = [];\n\n\tfor (const [path, node] of Object.entries(described.nodes)) {\n\t\t// Only state nodes are writable knobs\n\t\tif (node.type !== \"state\") continue;\n\n\t\t// Skip meta companion nodes (§2.3)\n\t\tif (path.includes(\"::__meta__::\")) continue;\n\n\t\t// Skip terminal-state nodes (§1.3.4 — no further messages after COMPLETE/ERROR)\n\t\tif (node.status === \"completed\" || node.status === \"errored\") continue;\n\n\t\t// Skip if access explicitly excludes LLM\n\t\tconst meta = node.meta ?? {};\n\t\tconst access = meta.access as string | undefined;\n\t\tif (access === \"human\" || access === \"system\") continue;\n\n\t\tconst description = (meta.description as string) ?? `Set the value of ${path}`;\n\t\tconst valueSchema = metaToJsonSchema(meta);\n\n\t\tconst parameterSchema: Record<string, unknown> = {\n\t\t\ttype: \"object\",\n\t\t\trequired: [\"value\"],\n\t\t\tproperties: {\n\t\t\t\tvalue: valueSchema,\n\t\t\t},\n\t\t\tadditionalProperties: false,\n\t\t};\n\n\t\t// OpenAI requires [a-zA-Z0-9_-] in function names; sanitize :: separators\n\t\tconst sanitizedName = path.replace(/::/g, \"__\");\n\n\t\topenai.push({\n\t\t\ttype: \"function\",\n\t\t\tfunction: {\n\t\t\t\tname: sanitizedName,\n\t\t\t\tdescription,\n\t\t\t\tparameters: parameterSchema,\n\t\t\t},\n\t\t});\n\n\t\tmcp.push({\n\t\t\tname: path,\n\t\t\tdescription,\n\t\t\tinputSchema: parameterSchema,\n\t\t});\n\n\t\tconst graphRef = graph;\n\t\tconst actorRef = actor;\n\t\tconst nv = node.v;\n\t\tdefinitions.push({\n\t\t\tname: path,\n\t\t\tdescription,\n\t\t\tparameters: parameterSchema,\n\t\t\thandler(args: Record<string, unknown>) {\n\t\t\t\tgraphRef.set(path, args.value, actorRef ? { actor: actorRef } : undefined);\n\t\t\t\treturn args.value;\n\t\t\t},\n\t\t\t...(nv != null ? { version: { id: nv.id, version: nv.version } } : {}),\n\t\t});\n\t}\n\n\treturn { openai, mcp, definitions };\n}\n\n// ---------------------------------------------------------------------------\n// gaugesAsContext\n// ---------------------------------------------------------------------------\n\nexport type GaugesAsContextOptions = {\n\t/** Group gauges by `meta.tags` (default true). */\n\tgroupByTags?: boolean;\n\t/** Separator between gauge lines (default \"\\n\"). */\n\tseparator?: string;\n\t/**\n\t * V0 delta mode (§6.0b): only include nodes whose `v.version` exceeds\n\t * the corresponding entry in this map. Nodes without V0 or not in the\n\t * map are always included. Callers maintain this map across calls.\n\t *\n\t * The `id` field guards against node replacement: if a node is removed\n\t * and re-added under the same name (new id), it is always included.\n\t */\n\tsinceVersion?: ReadonlyMap<string, { id: string; version: number }>;\n};\n\n/**\n * Format a graph's readable (gauge) nodes as a context string for LLM\n * system prompts.\n *\n * Gauges are nodes with `meta.description` or `meta.format`. Values are\n * formatted using `meta.format` and `meta.unit` hints.\n *\n * @param graph - The graph to introspect.\n * @param actor - Optional actor for guard-scoped describe.\n * @param options - Formatting options.\n * @returns A formatted string ready for system prompt injection.\n */\nexport function gaugesAsContext(\n\tgraph: Graph,\n\tactor?: Actor,\n\toptions?: GaugesAsContextOptions,\n): string {\n\tconst described = graph.describe({ actor, detail: \"full\" });\n\tconst groupByTags = options?.groupByTags ?? true;\n\tconst separator = options?.separator ?? \"\\n\";\n\n\ttype GaugeEntry = { path: string; description: string; formatted: string };\n\tconst entries: GaugeEntry[] = [];\n\n\tconst sinceVersion = options?.sinceVersion;\n\tfor (const [path, node] of Object.entries(described.nodes)) {\n\t\tconst meta = node.meta ?? {};\n\t\tconst desc = meta.description as string | undefined;\n\t\tconst format = meta.format as string | undefined;\n\t\t// Must have description or format to be a gauge\n\t\tif (!desc && !format) continue;\n\t\t// V0 delta filter: skip nodes unchanged since last seen version (§6.0b).\n\t\tif (sinceVersion != null && node.v != null) {\n\t\t\tconst lastSeen = sinceVersion.get(path);\n\t\t\tif (lastSeen != null && lastSeen.id === node.v.id && node.v.version <= lastSeen.version)\n\t\t\t\tcontinue;\n\t\t}\n\n\t\tconst label = desc ?? path;\n\t\tconst value = node.value;\n\t\tconst unit = meta.unit as string | undefined;\n\n\t\tlet formatted: string;\n\t\tif (format === \"currency\" && typeof value === \"number\") {\n\t\t\tformatted = `$${value.toFixed(2)}`;\n\t\t} else if (format === \"percentage\" && typeof value === \"number\") {\n\t\t\tformatted = `${(value * 100).toFixed(1)}%`;\n\t\t} else if (value === undefined || value === null) {\n\t\t\tformatted = \"(no value)\";\n\t\t} else {\n\t\t\tformatted = String(value);\n\t\t}\n\n\t\tif (unit && format !== \"currency\" && format !== \"percentage\") {\n\t\t\tformatted = `${formatted} ${unit}`;\n\t\t}\n\n\t\tentries.push({ path, description: label, formatted });\n\t}\n\n\tif (entries.length === 0) return \"\";\n\n\tif (groupByTags) {\n\t\tconst tagGroups = new Map<string, GaugeEntry[]>();\n\t\tconst ungrouped: GaugeEntry[] = [];\n\n\t\tfor (const entry of entries) {\n\t\t\tconst node = described.nodes[entry.path]!;\n\t\t\tconst tags = node.meta?.tags as string[] | undefined;\n\t\t\tif (tags && tags.length > 0) {\n\t\t\t\t// Use first tag for grouping to avoid duplicating entries across groups\n\t\t\t\tconst tag = tags[0]!;\n\t\t\t\tlet group = tagGroups.get(tag);\n\t\t\t\tif (!group) {\n\t\t\t\t\tgroup = [];\n\t\t\t\t\ttagGroups.set(tag, group);\n\t\t\t\t}\n\t\t\t\tgroup.push(entry);\n\t\t\t} else {\n\t\t\t\tungrouped.push(entry);\n\t\t\t}\n\t\t}\n\n\t\tif (tagGroups.size === 0) {\n\t\t\treturn entries.map((e) => `- ${e.description}: ${e.formatted}`).join(separator);\n\t\t}\n\n\t\tconst sections: string[] = [];\n\t\tfor (const [tag, group] of [...tagGroups.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {\n\t\t\tsections.push(\n\t\t\t\t`[${tag}]${separator}${group.map((e) => `- ${e.description}: ${e.formatted}`).join(separator)}`,\n\t\t\t);\n\t\t}\n\t\tif (ungrouped.length > 0) {\n\t\t\tsections.push(ungrouped.map((e) => `- ${e.description}: ${e.formatted}`).join(separator));\n\t\t}\n\t\treturn sections.join(separator + separator);\n\t}\n\n\treturn entries.map((e) => `- ${e.description}: ${e.formatted}`).join(separator);\n}\n\n// ---------------------------------------------------------------------------\n// validateGraphDef\n// ---------------------------------------------------------------------------\n\n/** Validation result from {@link validateGraphDef}. */\nexport type GraphDefValidation = {\n\treadonly valid: boolean;\n\treadonly errors: readonly string[];\n};\n\nconst VALID_NODE_TYPES = new Set([\"state\", \"derived\", \"producer\", \"operator\", \"effect\"]);\n\n/**\n * Validate an LLM-generated graph definition before passing to\n * `Graph.fromSnapshot()`.\n *\n * Checks:\n * - Required fields: `name`, `nodes`, `edges`\n * - Node types are valid enum values\n * - Edge `from`/`to` reference existing nodes\n * - No duplicate edge entries\n *\n * @param def - The graph definition to validate (parsed JSON).\n * @returns Validation result with errors array.\n */\nexport function validateGraphDef(def: unknown): GraphDefValidation {\n\tconst errors: string[] = [];\n\n\tif (def == null || typeof def !== \"object\") {\n\t\treturn { valid: false, errors: [\"Definition must be a non-null object\"] };\n\t}\n\n\tconst d = def as Record<string, unknown>;\n\n\tif (typeof d.name !== \"string\" || d.name.length === 0) {\n\t\terrors.push(\"Missing or empty 'name' field\");\n\t}\n\n\tif (d.nodes == null || typeof d.nodes !== \"object\" || Array.isArray(d.nodes)) {\n\t\terrors.push(\"Missing or invalid 'nodes' field (must be an object)\");\n\t\treturn { valid: false, errors };\n\t}\n\n\tconst nodeNames = new Set(Object.keys(d.nodes as object));\n\n\tfor (const [name, raw] of Object.entries(d.nodes as Record<string, unknown>)) {\n\t\tif (raw == null || typeof raw !== \"object\") {\n\t\t\terrors.push(`Node \"${name}\": must be an object`);\n\t\t\tcontinue;\n\t\t}\n\t\tconst node = raw as Record<string, unknown>;\n\t\tif (typeof node.type !== \"string\" || !VALID_NODE_TYPES.has(node.type)) {\n\t\t\terrors.push(\n\t\t\t\t`Node \"${name}\": invalid type \"${String(node.type)}\" (expected: ${[...VALID_NODE_TYPES].join(\", \")})`,\n\t\t\t);\n\t\t}\n\t\tif (Array.isArray(node.deps)) {\n\t\t\tfor (const dep of node.deps) {\n\t\t\t\tif (typeof dep === \"string\" && !nodeNames.has(dep)) {\n\t\t\t\t\terrors.push(`Node \"${name}\": dep \"${dep}\" does not reference an existing node`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!Array.isArray(d.edges)) {\n\t\tif (d.edges !== undefined) {\n\t\t\terrors.push(\"'edges' must be an array\");\n\t\t}\n\t\t// edges are optional — no error if absent\n\t} else {\n\t\tconst seen = new Set<string>();\n\t\tfor (let i = 0; i < (d.edges as unknown[]).length; i++) {\n\t\t\tconst edge = (d.edges as unknown[])[i];\n\t\t\tif (edge == null || typeof edge !== \"object\") {\n\t\t\t\terrors.push(`Edge [${i}]: must be an object`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst e = edge as Record<string, unknown>;\n\t\t\tif (typeof e.from !== \"string\" || !nodeNames.has(e.from)) {\n\t\t\t\terrors.push(`Edge [${i}]: 'from' \"${String(e.from)}\" does not reference an existing node`);\n\t\t\t}\n\t\t\tif (typeof e.to !== \"string\" || !nodeNames.has(e.to)) {\n\t\t\t\terrors.push(`Edge [${i}]: 'to' \"${String(e.to)}\" does not reference an existing node`);\n\t\t\t}\n\t\t\tconst key = `${e.from}->${e.to}`;\n\t\t\tif (seen.has(key)) {\n\t\t\t\terrors.push(`Edge [${i}]: duplicate edge ${key}`);\n\t\t\t}\n\t\t\tseen.add(key);\n\t\t}\n\t}\n\n\treturn { valid: errors.length === 0, errors };\n}\n\n// ---------------------------------------------------------------------------\n// graphFromSpec\n// ---------------------------------------------------------------------------\n\nexport type GraphFromSpecOptions = {\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/** Callback to construct topology before values are applied (passed to `Graph.fromSnapshot`). */\n\tbuild?: (g: Graph) => void;\n\t/** Extra instructions appended to the system prompt. */\n\tsystemPromptExtra?: string;\n};\n\n/** Strip markdown code fences, handling trailing commentary after closing fence. */\nfunction stripFences(text: string): string {\n\tconst match = text.match(/^```(?:json)?\\s*([\\s\\S]*?)\\s*```[\\s\\S]*$/);\n\treturn match ? match[1]! : text;\n}\n\nconst GRAPH_FROM_SPEC_SYSTEM_PROMPT = `You are a graph architect for GraphReFly, a reactive graph protocol.\n\nGiven a natural-language description, produce a JSON graph definition with this structure:\n\n{\n \"name\": \"<graph_name>\",\n \"nodes\": {\n \"<node_name>\": {\n \"type\": \"state\" | \"derived\" | \"producer\" | \"operator\" | \"effect\",\n \"value\": <initial_value_or_null>,\n \"deps\": [\"<dep_node_name>\", ...],\n \"meta\": {\n \"description\": \"<human-readable purpose>\",\n \"type\": \"string\" | \"number\" | \"boolean\" | \"integer\" | \"enum\",\n \"range\": [min, max],\n \"values\": [\"a\", \"b\"],\n \"format\": \"currency\" | \"percentage\" | \"status\",\n \"access\": \"human\" | \"llm\" | \"both\" | \"system\",\n \"unit\": \"<unit>\",\n \"tags\": [\"<tag>\"]\n }\n }\n },\n \"edges\": [\n { \"from\": \"<source_node>\", \"to\": \"<target_node>\" }\n ]\n}\n\nRules:\n- \"state\" nodes have no deps and hold user/LLM-writable values (knobs).\n- \"derived\" nodes have deps and compute from them.\n- \"effect\" nodes have deps but produce side effects (no return value).\n- \"producer\" nodes have no deps but generate values asynchronously.\n- Edges wire output of one node as input to another. They must match deps.\n- meta.description is required for every node.\n- Return ONLY valid JSON, no markdown fences or commentary.`;\n\n/**\n * Ask an LLM to compose a Graph from a natural-language description.\n *\n * The LLM returns a JSON graph definition which is validated and then\n * constructed via `Graph.fromSnapshot()`.\n *\n * @param naturalLanguage - The problem/use-case description.\n * @param adapter - LLM adapter for the generation call.\n * @param opts - Model options and optional `build` callback for node factories.\n * @returns A constructed Graph.\n * @throws On invalid LLM output or validation failure.\n */\nexport async function graphFromSpec(\n\tnaturalLanguage: string,\n\tadapter: LLMAdapter,\n\topts?: GraphFromSpecOptions,\n): Promise<Graph> {\n\tconst systemPrompt = opts?.systemPromptExtra\n\t\t? `${GRAPH_FROM_SPEC_SYSTEM_PROMPT}\\n\\n${opts.systemPromptExtra}`\n\t\t: GRAPH_FROM_SPEC_SYSTEM_PROMPT;\n\n\tconst messages: ChatMessage[] = [\n\t\t{ role: \"system\", content: systemPrompt },\n\t\t{ role: \"user\", content: naturalLanguage },\n\t];\n\n\tconst rawResult = adapter.invoke(messages, {\n\t\tmodel: opts?.model,\n\t\ttemperature: opts?.temperature ?? 0,\n\t\tmaxTokens: opts?.maxTokens,\n\t});\n\n\tconst response = (await resolveToolHandlerResult(rawResult)) as LLMResponse;\n\tlet content = response.content.trim();\n\n\t// Strip markdown fences if present (handles trailing commentary after ```)\n\tif (content.startsWith(\"```\")) {\n\t\tcontent = stripFences(content);\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(content);\n\t} catch {\n\t\tthrow new Error(`graphFromSpec: LLM response is not valid JSON: ${content.slice(0, 200)}`);\n\t}\n\n\tconst validation = validateGraphDef(parsed);\n\tif (!validation.valid) {\n\t\tthrow new Error(`graphFromSpec: invalid graph definition:\\n${validation.errors.join(\"\\n\")}`);\n\t}\n\n\tconst def = parsed as Record<string, unknown>;\n\t// Ensure version field is present for fromSnapshot envelope check\n\tif (def.version === undefined) def.version = 1;\n\tif (!Array.isArray(def.subgraphs)) def.subgraphs = [];\n\treturn Graph.fromSnapshot(def as GraphPersistSnapshot, opts?.build);\n}\n\n// ---------------------------------------------------------------------------\n// suggestStrategy\n// ---------------------------------------------------------------------------\n\n/** A single operation in a strategy plan. */\nexport type StrategyOperation =\n\t| {\n\t\t\treadonly type: \"add_node\";\n\t\t\treadonly name: string;\n\t\t\treadonly nodeType: string;\n\t\t\treadonly meta?: Record<string, unknown>;\n\t\t\treadonly initial?: unknown;\n\t }\n\t| { readonly type: \"remove_node\"; readonly name: string }\n\t| { readonly type: \"connect\"; readonly from: string; readonly to: string }\n\t| { readonly type: \"disconnect\"; readonly from: string; readonly to: string }\n\t| { readonly type: \"set_value\"; readonly name: string; readonly value: unknown }\n\t| {\n\t\t\treadonly type: \"update_meta\";\n\t\t\treadonly name: string;\n\t\t\treadonly key: string;\n\t\t\treadonly value: unknown;\n\t };\n\n/** Structured strategy plan returned by {@link suggestStrategy}. */\nexport type StrategyPlan = {\n\treadonly summary: string;\n\treadonly operations: readonly StrategyOperation[];\n\treadonly reasoning: string;\n};\n\nexport type SuggestStrategyOptions = {\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\tactor?: Actor;\n};\n\nconst SUGGEST_STRATEGY_SYSTEM_PROMPT = `You are a reactive graph optimizer for GraphReFly.\n\nGiven a graph's current structure (from describe()) and a problem statement, suggest topology and parameter changes to solve the problem.\n\nReturn ONLY valid JSON with this structure:\n{\n \"summary\": \"<one-line summary of the strategy>\",\n \"reasoning\": \"<explanation of why these changes help>\",\n \"operations\": [\n { \"type\": \"add_node\", \"name\": \"<name>\", \"nodeType\": \"state|derived|effect|producer|operator\", \"meta\": {...}, \"initial\": <value> },\n { \"type\": \"remove_node\", \"name\": \"<name>\" },\n { \"type\": \"connect\", \"from\": \"<source>\", \"to\": \"<target>\" },\n { \"type\": \"disconnect\", \"from\": \"<source>\", \"to\": \"<target>\" },\n { \"type\": \"set_value\", \"name\": \"<name>\", \"value\": <new_value> },\n { \"type\": \"update_meta\", \"name\": \"<name>\", \"key\": \"<meta_key>\", \"value\": <new_value> }\n ]\n}\n\nRules:\n- Only suggest operations that reference existing nodes (for remove/disconnect/set_value/update_meta) or new nodes you define (for add_node).\n- Keep changes minimal — prefer the smallest set of operations that solves the problem.\n- Return ONLY valid JSON, no markdown fences or commentary.`;\n\n/**\n * Ask an LLM to analyze a graph and suggest topology/parameter changes\n * to solve a stated problem.\n *\n * Returns a structured plan — does NOT auto-apply. The caller reviews\n * and selectively applies operations.\n *\n * @param graph - The graph to analyze.\n * @param problem - Natural-language problem statement.\n * @param adapter - LLM adapter for the analysis call.\n * @param opts - Model and actor options.\n * @returns A structured strategy plan.\n * @throws On invalid LLM output.\n */\nexport async function suggestStrategy(\n\tgraph: Graph,\n\tproblem: string,\n\tadapter: LLMAdapter,\n\topts?: SuggestStrategyOptions,\n): Promise<StrategyPlan> {\n\tconst { expand: _, ...described } = graph.describe({ actor: opts?.actor, detail: \"standard\" });\n\n\tconst messages: ChatMessage[] = [\n\t\t{ role: \"system\", content: SUGGEST_STRATEGY_SYSTEM_PROMPT },\n\t\t{\n\t\t\trole: \"user\",\n\t\t\tcontent: JSON.stringify({\n\t\t\t\tgraph: described,\n\t\t\t\tproblem,\n\t\t\t}),\n\t\t},\n\t];\n\n\tconst rawResult = adapter.invoke(messages, {\n\t\tmodel: opts?.model,\n\t\ttemperature: opts?.temperature ?? 0,\n\t\tmaxTokens: opts?.maxTokens,\n\t});\n\n\tconst response = (await resolveToolHandlerResult(rawResult)) as LLMResponse;\n\tlet content = response.content.trim();\n\n\tif (content.startsWith(\"```\")) {\n\t\tcontent = content.replace(/^```(?:json)?\\s*/, \"\").replace(/\\s*```$/, \"\");\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(content);\n\t} catch {\n\t\tthrow new Error(`suggestStrategy: LLM response is not valid JSON: ${content.slice(0, 200)}`);\n\t}\n\n\tconst plan = parsed as Record<string, unknown>;\n\n\tif (typeof plan.summary !== \"string\") {\n\t\tthrow new Error(\"suggestStrategy: missing 'summary' in response\");\n\t}\n\tif (typeof plan.reasoning !== \"string\") {\n\t\tthrow new Error(\"suggestStrategy: missing 'reasoning' in response\");\n\t}\n\tif (!Array.isArray(plan.operations)) {\n\t\tthrow new Error(\"suggestStrategy: missing 'operations' array in response\");\n\t}\n\n\treturn {\n\t\tsummary: plan.summary,\n\t\treasoning: plan.reasoning,\n\t\toperations: plan.operations as readonly StrategyOperation[],\n\t};\n}\n","/**\n * Orchestration patterns (roadmap §4.1).\n *\n * Domain-layer helpers that build workflow shapes on top of core + extra primitives.\n * Exported under the `patterns.orchestration` namespace to avoid collisions with\n * Phase 2 operator names (for example `gate`, `forEach`).\n */\n\nimport { batch } from \"../core/batch.js\";\nimport type { NodeActions } from \"../core/config.js\";\nimport { COMPLETE, DATA, ERROR, type Messages, RESOLVED } from \"../core/messages.js\";\nimport { type Node, type NodeFn, type NodeOptions, node } from \"../core/node.js\";\nimport { type DerivedFn, derived, state } from \"../core/sugar.js\";\nimport { GRAPH_META_SEGMENT, Graph, type GraphOptions } from \"../graph/graph.js\";\n\nexport type StepRef = string | Node<unknown>;\n\ntype OrchestrationMeta = {\n\torchestration?: true;\n\torchestration_type?: string;\n};\n\nexport type OrchestrationStepOptions = Omit<\n\tNodeOptions<unknown>,\n\t\"describeKind\" | \"name\" | \"meta\"\n> & {\n\tdeps?: ReadonlyArray<StepRef>;\n\tmeta?: Record<string, unknown> & OrchestrationMeta;\n};\n\nexport type BranchResult<T> = {\n\tbranch: \"then\" | \"else\";\n\tvalue: T;\n};\n\nexport type SensorControls<T> = {\n\tnode: Node<T>;\n\tpush(value: T): void;\n\terror(err: unknown): void;\n\tcomplete(): void;\n};\n\nexport type LoopOptions = Omit<OrchestrationStepOptions, \"deps\"> & {\n\titerations?: number | StepRef;\n};\n\nexport type WaitOptions = Omit<OrchestrationStepOptions, \"deps\">;\n\nexport type SubPipelineBuilder = (sub: Graph) => void;\n\nfunction resolveDep(graph: Graph, dep: StepRef): { node: Node<unknown>; path?: string } {\n\tif (typeof dep === \"string\") {\n\t\treturn { node: graph.resolve(dep), path: dep };\n\t}\n\tconst path = findRegisteredNodePath(graph, dep);\n\tif (!path) {\n\t\tthrow new Error(\n\t\t\t\"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\",\n\t\t);\n\t}\n\treturn { node: dep, path };\n}\n\nfunction findRegisteredNodePath(graph: Graph, target: Node<unknown>): string | undefined {\n\tconst described = graph.describe();\n\tconst metaSegment = `::${GRAPH_META_SEGMENT}::`;\n\tfor (const path of Object.keys(described.nodes).sort()) {\n\t\tif (path.includes(metaSegment)) continue;\n\t\ttry {\n\t\t\tif (graph.resolve(path) === target) return path;\n\t\t} catch {\n\t\t\t/* ignore stale path while scanning */\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction registerStep(\n\tgraph: Graph,\n\tname: string,\n\tstep: Node<unknown>,\n\tdepPaths: ReadonlyArray<string>,\n): void {\n\tgraph.add(name, step);\n\t// depPaths used to drive graph.connect() edge-registry calls; after\n\t// Unit 7 edges are derived from node _deps and this wiring is a no-op.\n\tvoid depPaths;\n}\n\nimport { domainMeta } from \"./_internal.js\";\n\nfunction baseMeta(kind: string, meta?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"orchestration\", kind, meta);\n}\n\nfunction coerceLoopIterations(raw: unknown): number {\n\tconst parseString = (value: string): number => {\n\t\tconst trimmed = value.trim();\n\t\tif (trimmed.length === 0) return 0;\n\t\treturn Number(trimmed);\n\t};\n\tlet parsed: number;\n\tif (typeof raw === \"string\") {\n\t\tparsed = parseString(raw);\n\t} else if (raw === null) {\n\t\tparsed = 0;\n\t} else {\n\t\tparsed = Number(raw);\n\t}\n\tif (!Number.isFinite(parsed)) return 1;\n\treturn Math.max(0, Math.trunc(parsed));\n}\n\n/**\n * Creates an orchestration graph container.\n */\nexport function pipeline(name: string, opts?: GraphOptions): Graph {\n\treturn new Graph(name, opts);\n}\n\n/**\n * Registers a workflow task node.\n */\nexport function task<T>(\n\tgraph: Graph,\n\tname: string,\n\trun: DerivedFn<T>,\n\topts?: OrchestrationStepOptions,\n): Node<T> {\n\tconst depRefs = opts?.deps ?? [];\n\tconst deps = depRefs.map((dep) => resolveDep(graph, dep));\n\tconst { deps: _deps, ...nodeOpts } = opts ?? {};\n\tconst wrapped: NodeFn = (batchData, actions, ctx) => {\n\t\tconst data = batchData.map((batch, i) =>\n\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t);\n\t\tactions.emit(run(data, ctx));\n\t\treturn undefined;\n\t};\n\tconst step = node<T>(\n\t\tdeps.map((d) => d.node),\n\t\twrapped,\n\t\t{\n\t\t\t...nodeOpts,\n\t\t\tname,\n\t\t\tdescribeKind: \"derived\",\n\t\t\tmeta: baseMeta(\"task\", opts?.meta),\n\t\t} as NodeOptions<T>,\n\t);\n\tregisterStep(\n\t\tgraph,\n\t\tname,\n\t\tstep as unknown as Node<unknown>,\n\t\tdeps.flatMap((d) => (d.path ? [d.path] : [])),\n\t);\n\treturn step;\n}\n\n/**\n * Emits tagged branch outcomes (`then` / `else`) for each source value.\n */\nexport function branch<T>(\n\tgraph: Graph,\n\tname: string,\n\tsource: StepRef,\n\tpredicate: (value: T) => boolean,\n\topts?: Omit<OrchestrationStepOptions, \"deps\">,\n): Node<BranchResult<T>> {\n\tconst src = resolveDep(graph, source);\n\tconst step = derived<BranchResult<T>>(\n\t\t[src.node],\n\t\t([value]) => ({\n\t\t\tbranch: predicate(value as T) ? \"then\" : \"else\",\n\t\t\tvalue: value as T,\n\t\t}),\n\t\t{\n\t\t\t...opts,\n\t\t\tname,\n\t\t\tmeta: baseMeta(\"branch\", opts?.meta),\n\t\t} as NodeOptions<BranchResult<T>>,\n\t);\n\tregisterStep(graph, name, step as unknown as Node<unknown>, src.path ? [src.path] : []);\n\treturn step;\n}\n\n/**\n * Forwards source values only while `control` is truthy.\n */\nexport function valve<T>(\n\tgraph: Graph,\n\tname: string,\n\tsource: StepRef,\n\tcontrol: StepRef,\n\topts?: Omit<OrchestrationStepOptions, \"deps\">,\n): Node<T> {\n\tconst src = resolveDep(graph, source);\n\tconst ctrl = resolveDep(graph, control);\n\t// Raw node so we can emit RESOLVED (hold) instead of DATA(undefined) when closed.\n\tconst step = node<T>(\n\t\t[src.node, ctrl.node],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst batch0 = batchData[0];\n\t\t\tconst batch1 = batchData[1];\n\t\t\t// undefined = control never sent DATA (closed); falsy = explicitly closed.\n\t\t\tconst ctrlVal = batch1 != null && batch1.length > 0 ? batch1.at(-1) : ctx.prevData[1];\n\t\t\t// Control just opened and no new source data this wave: re-emit last source value.\n\t\t\tif (batch0 == null || batch0.length === 0) {\n\t\t\t\tif (batch1 != null && batch1.length > 0 && ctrlVal && ctx.prevData[0] !== undefined) {\n\t\t\t\t\tactions.emit(ctx.prevData[0] as T);\n\t\t\t\t} else {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!ctrlVal) {\n\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const v of batch0 as T[]) actions.emit(v);\n\t\t},\n\t\t{\n\t\t\t...opts,\n\t\t\tname,\n\t\t\tdescribeKind: \"derived\",\n\t\t\tmeta: baseMeta(\"valve\", opts?.meta),\n\t\t} as NodeOptions<T>,\n\t);\n\tregisterStep(\n\t\tgraph,\n\t\tname,\n\t\tstep as unknown as Node<unknown>,\n\t\t[src.path, ctrl.path].filter((v): v is string => typeof v === \"string\"),\n\t);\n\treturn step;\n}\n\nexport type ApprovalOptions = Omit<OrchestrationStepOptions, \"deps\"> & {\n\tisApproved?: (value: unknown) => boolean;\n};\n\n/**\n * Human/LLM approval gate over a source value.\n */\nexport function approval<T>(\n\tgraph: Graph,\n\tname: string,\n\tsource: StepRef,\n\tapprover: StepRef,\n\topts?: ApprovalOptions,\n): Node<T> {\n\tconst src = resolveDep(graph, source);\n\tconst ctrl = resolveDep(graph, approver);\n\tconst isApproved = opts?.isApproved ?? ((value: unknown) => Boolean(value));\n\t// Raw node so we can emit RESOLVED (hold) instead of DATA(undefined) when not approved.\n\tconst step = node<T>(\n\t\t[src.node, ctrl.node],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst batch0 = batchData[0];\n\t\t\tconst batch1 = batchData[1];\n\t\t\t// undefined = approver never sent DATA (not yet approved).\n\t\t\tconst ctrlVal = batch1 != null && batch1.length > 0 ? batch1.at(-1) : ctx.prevData[1];\n\t\t\tif (ctrlVal === undefined || !isApproved(ctrlVal)) {\n\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (batch0 == null || batch0.length === 0) {\n\t\t\t\t// Approval just granted and no new source data: re-emit last source value.\n\t\t\t\tif (batch1 != null && batch1.length > 0 && ctx.prevData[0] !== undefined) {\n\t\t\t\t\tactions.emit(ctx.prevData[0] as T);\n\t\t\t\t} else {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const v of batch0 as T[]) actions.emit(v);\n\t\t},\n\t\t{\n\t\t\t...opts,\n\t\t\tname,\n\t\t\tdescribeKind: \"derived\",\n\t\t\tmeta: baseMeta(\"approval\", opts?.meta),\n\t\t} as NodeOptions<T>,\n\t);\n\tregisterStep(\n\t\tgraph,\n\t\tname,\n\t\tstep as unknown as Node<unknown>,\n\t\t[src.path, ctrl.path].filter((v): v is string => typeof v === \"string\"),\n\t);\n\treturn step;\n}\n\n// ---------------------------------------------------------------------------\n// gate — human-in-the-loop approval with pending queue\n// ---------------------------------------------------------------------------\n\nexport interface GateOptions {\n\t/** Maximum queue size. Oldest values are FIFO-dropped when exceeded. Default: Infinity. */\n\tmaxPending?: number;\n\t/** Start in open mode (auto-approve). Default: false. */\n\tstartOpen?: boolean;\n\tmeta?: Record<string, unknown>;\n}\n\n/** Control surface returned by {@link gate}. */\nexport interface GateController<T> {\n\t/** The output node registered in the graph (subscribe to receive approved values). */\n\tnode: Node<T>;\n\t/** Reactive queue of values waiting for approval. */\n\tpending: Node<T[]>;\n\t/** Derived count of pending items. */\n\tcount: Node<number>;\n\t/** Whether the gate is currently open (auto-approving). */\n\tisOpen: Node<boolean>;\n\t/** Approve and forward the next `count` pending values (default: 1). */\n\tapprove(count?: number): void;\n\t/** Reject (discard) the next `count` pending values (default: 1). */\n\treject(count?: number): void;\n\t/**\n\t * Transform and forward `count` pending values (default: 1).\n\t * `fn` receives `(value, index, pending)` — Array.map-style.\n\t */\n\tmodify(fn: (value: T, index: number, pending: readonly T[]) => T, count?: number): void;\n\t/** Flush all pending values and auto-approve future values. */\n\topen(): void;\n\t/** Re-enable manual gating (stop auto-approving). */\n\tclose(): void;\n}\n\n/**\n * Human-in-the-loop gate: queues incoming values from `source` and lets an external\n * controller {@link GateController.approve approve}, {@link GateController.reject reject},\n * or {@link GateController.modify modify} them before forwarding downstream.\n *\n * Observable surfaces (`pending`, `count`, `isOpen`) are reactive nodes registered in\n * the graph. The gate output node is also registered.\n */\nexport function gate<T>(\n\tgraph: Graph,\n\tname: string,\n\tsource: StepRef,\n\topts?: GateOptions,\n): GateController<T> {\n\tconst maxPending = opts?.maxPending ?? Infinity;\n\tif (maxPending < 1 && maxPending !== Infinity) {\n\t\tthrow new RangeError(\"gate: maxPending must be >= 1\");\n\t}\n\tconst startOpen = opts?.startOpen ?? false;\n\n\tconst src = resolveDep(graph, source);\n\n\t// Internal reactive state\n\tconst pendingNode = state<T[]>([], { name: \"pending\", equals: () => false });\n\tconst isOpenNode = state<boolean>(startOpen, { name: \"isOpen\" });\n\tconst countNode = derived<number>([pendingNode], ([arr]) => (arr as T[]).length, {\n\t\tname: \"count\",\n\t});\n\n\tlet queue: T[] = [];\n\tlet torn = false;\n\t// Capture `isOpenNode` DATA into a closure variable fed by its own subscribe\n\t// handler. The output producer consults `latestIsOpen` instead of reading\n\t// `isOpenNode.cache` from inside its callback — keeps the gate decision on\n\t// the protocol delivery path (P3 audit #11). Seeded with `startOpen` at\n\t// wiring time so the first item arriving before any open()/close() uses\n\t// the same value the state node was constructed with. Same template as\n\t// the `stratify` rule-capture pattern.\n\tlet latestIsOpen = startOpen;\n\tconst isOpenUnsub = isOpenNode.subscribe((msgs) => {\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] === DATA) latestIsOpen = m[1] as boolean;\n\t\t}\n\t});\n\n\tfunction syncPending(): void {\n\t\tpendingNode.down([[DATA, [...queue]]]);\n\t}\n\n\tfunction enqueue(value: T): void {\n\t\tqueue.push(value);\n\t\tif (queue.length > maxPending) queue.shift();\n\t\tsyncPending();\n\t}\n\n\tfunction dequeue(n: number): T[] {\n\t\tconst items = queue.splice(0, n);\n\t\tsyncPending();\n\t\treturn items;\n\t}\n\n\tfunction guardTorn(method: string): void {\n\t\tif (torn) throw new Error(`gate: ${method}() called after gate was torn down`);\n\t}\n\n\tconst output = node<T>(\n\t\t[src.node],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst terminal = ctx.terminalDeps[0];\n\t\t\tif (terminal !== undefined) {\n\t\t\t\ttorn = true;\n\t\t\t\tqueue = [];\n\t\t\t\tsyncPending();\n\t\t\t\tactions.down(terminal === true ? [[COMPLETE]] : [[ERROR, terminal]]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst batch0 = batchData[0];\n\t\t\tif (batch0 == null || batch0.length === 0) {\n\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const v of batch0 as T[]) {\n\t\t\t\tif (latestIsOpen) {\n\t\t\t\t\tactions.emit(v);\n\t\t\t\t} else {\n\t\t\t\t\tenqueue(v);\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tname,\n\t\t\tdescribeKind: \"derived\",\n\t\t\tmeta: baseMeta(\"gate\", opts?.meta),\n\t\t},\n\t);\n\n\tconst controller: GateController<T> = {\n\t\tnode: output,\n\t\tpending: pendingNode,\n\t\tcount: countNode,\n\t\tisOpen: isOpenNode,\n\t\tapprove(count = 1) {\n\t\t\tguardTorn(\"approve\");\n\t\t\tconst items = dequeue(count);\n\t\t\tfor (const item of items) {\n\t\t\t\tif (torn) break;\n\t\t\t\toutput.down([[DATA, item]]);\n\t\t\t}\n\t\t},\n\t\treject(count = 1) {\n\t\t\tguardTorn(\"reject\");\n\t\t\tdequeue(count);\n\t\t},\n\t\tmodify(fn, count = 1) {\n\t\t\tguardTorn(\"modify\");\n\t\t\tconst snapshot = [...queue] as readonly T[];\n\t\t\tconst items = dequeue(count);\n\t\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\t\tif (torn) break;\n\t\t\t\toutput.down([[DATA, fn(items[i], i, snapshot)]]);\n\t\t\t}\n\t\t},\n\t\topen() {\n\t\t\tguardTorn(\"open\");\n\t\t\t// Wrap the isOpen transition + queued flush in one batch so every\n\t\t\t// `output.down` is tier-3-deferred until after the `isOpenNode` dep\n\t\t\t// wave settles. Without this, queued DATAs could interleave with\n\t\t\t// the in-flight isOpen settlement wave under async runners — item\n\t\t\t// order relative to the open signal would be non-deterministic.\n\t\t\tbatch(() => {\n\t\t\t\tisOpenNode.down([[DATA, true]]);\n\t\t\t\tconst items = dequeue(queue.length);\n\t\t\t\tfor (const item of items) {\n\t\t\t\t\tif (torn) break;\n\t\t\t\t\toutput.down([[DATA, item]]);\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tclose() {\n\t\t\tguardTorn(\"close\");\n\t\t\tisOpenNode.down([[DATA, false]]);\n\t\t},\n\t};\n\n\t// Activate count so it stays reactive\n\tgraph.addDisposer(countNode.subscribe(() => undefined));\n\t// Tear down the isOpen capture when the owning graph disposes.\n\tgraph.addDisposer(isOpenUnsub);\n\n\t// Register output + internal state as a mounted subgraph (aligned with PY)\n\tregisterStep(graph, name, output as unknown as Node<unknown>, src.path ? [src.path] : []);\n\tconst internal = new Graph(`${name}_state`);\n\tinternal.add(\"pending\", pendingNode);\n\tinternal.add(\"isOpen\", isOpenNode);\n\tinternal.add(\"count\", countNode);\n\tgraph.mount(`${name}_state`, internal);\n\n\treturn controller;\n}\n\n/**\n * Registers a workflow side-effect step that runs `run` for each upstream\n * DATA value.\n *\n * `run` receives the full `NodeActions` and is the **sole emission point** —\n * call `actions.emit(v)` or `actions.down(msgs)` inside `run` to produce\n * downstream output. If `run` does not emit, this step acts as a pure\n * side-effect sink (graph-observable but no output). Throwing inside `run`\n * terminates the step with ERROR.\n */\nexport function forEach<T>(\n\tgraph: Graph,\n\tname: string,\n\tsource: StepRef,\n\trun: (value: T, actions: NodeActions) => void,\n\topts?: Omit<OrchestrationStepOptions, \"deps\">,\n): Node<T> {\n\tconst src = resolveDep(graph, source);\n\tlet terminated = false;\n\tconst step = node<T>(\n\t\t[src.node],\n\t\t(batchData, actions, ctx) => {\n\t\t\tif (terminated) {\n\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Terminal from dep\n\t\t\tconst terminal = ctx.terminalDeps[0];\n\t\t\tif (terminal !== undefined) {\n\t\t\t\tterminated = true;\n\t\t\t\tactions.down(terminal === true ? [[COMPLETE]] : [[ERROR, terminal]]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst batch0 = batchData[0];\n\t\t\tif (batch0 == null || batch0.length === 0) {\n\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const v of batch0 as T[]) {\n\t\t\t\ttry {\n\t\t\t\t\trun(v, actions);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tterminated = true;\n\t\t\t\t\tactions.down([[ERROR, err]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t...opts,\n\t\t\tname,\n\t\t\tdescribeKind: \"effect\",\n\t\t\tcompleteWhenDepsComplete: false,\n\t\t\tmeta: baseMeta(\"forEach\", opts?.meta),\n\t\t} as NodeOptions<T>,\n\t);\n\t// registerStep registers the edge for graph visibility. g.connect's dedup\n\t// check skips _addDep since src.node is already a constructor dep.\n\tregisterStep(graph, name, step as unknown as Node<unknown>, src.path ? [src.path] : []);\n\treturn step;\n}\n\n/**\n * Registers a join step that emits a tuple of latest dependency values.\n */\nexport function join<T extends readonly unknown[]>(\n\tgraph: Graph,\n\tname: string,\n\tdeps: { [K in keyof T]: StepRef },\n\topts?: Omit<OrchestrationStepOptions, \"deps\">,\n): Node<T> {\n\tconst resolved = deps.map((dep) => resolveDep(graph, dep));\n\tconst step = derived<T>(\n\t\tresolved.map((d) => d.node),\n\t\t(values) => values as T,\n\t\t{\n\t\t\t...opts,\n\t\t\tname,\n\t\t\tmeta: baseMeta(\"join\", opts?.meta),\n\t\t} as NodeOptions<T>,\n\t);\n\tregisterStep(\n\t\tgraph,\n\t\tname,\n\t\tstep as unknown as Node<unknown>,\n\t\tresolved.flatMap((d) => (d.path ? [d.path] : [])),\n\t);\n\treturn step;\n}\n\n/**\n * Registers a loop step that applies `iterate` to each source value N times.\n */\nexport function loop<T>(\n\tgraph: Graph,\n\tname: string,\n\tsource: StepRef,\n\titerate: (value: T, iteration: number, actions: NodeActions) => T,\n\topts?: LoopOptions,\n): Node<T> {\n\tconst src = resolveDep(graph, source);\n\tconst iterRef = opts?.iterations;\n\tconst iterDep =\n\t\ttypeof iterRef === \"number\" || iterRef === undefined ? undefined : resolveDep(graph, iterRef);\n\tconst staticIterations = typeof iterRef === \"number\" ? iterRef : undefined;\n\tconst step = node<T>(\n\t\titerDep ? [src.node, iterDep.node] : [src.node],\n\t\t(depValues, actions, ctx) => {\n\t\t\tconst batch0 = depValues[0];\n\t\t\tlet current = (batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0]) as T;\n\t\t\tconst batch1 = iterDep ? depValues[1] : undefined;\n\t\t\tconst rawCount =\n\t\t\t\tstaticIterations ??\n\t\t\t\t(iterDep ? (batch1 != null && batch1.length > 0 ? batch1.at(-1) : ctx.prevData[1]) : 1);\n\t\t\tconst count = coerceLoopIterations(rawCount);\n\t\t\tfor (let i = 0; i < count; i += 1) {\n\t\t\t\tcurrent = iterate(current, i, actions);\n\t\t\t}\n\t\t\tactions.emit(current);\n\t\t},\n\t\t{\n\t\t\t...opts,\n\t\t\tname,\n\t\t\tdescribeKind: \"derived\",\n\t\t\tmeta: baseMeta(\"loop\", opts?.meta),\n\t\t} as NodeOptions<T>,\n\t);\n\tregisterStep(\n\t\tgraph,\n\t\tname,\n\t\tstep as unknown as Node<unknown>,\n\t\t[src.path, iterDep?.path].filter((v): v is string => typeof v === \"string\"),\n\t);\n\treturn step;\n}\n\n/**\n * Mounts and returns a child workflow graph.\n */\nexport function subPipeline(\n\tgraph: Graph,\n\tname: string,\n\tchildOrBuild?: Graph | SubPipelineBuilder,\n\topts?: GraphOptions,\n): Graph {\n\tconst child = childOrBuild instanceof Graph ? childOrBuild : pipeline(name, opts);\n\tif (typeof childOrBuild === \"function\") {\n\t\tchildOrBuild(child);\n\t}\n\tgraph.mount(name, child);\n\treturn child;\n}\n\n/**\n * Registers a producer-style sensor source and returns imperative controls.\n */\nexport function sensor<T>(\n\tgraph: Graph,\n\tname: string,\n\tinitial?: T,\n\topts?: Omit<NodeOptions<unknown>, \"name\" | \"describeKind\" | \"meta\"> & {\n\t\tmeta?: Record<string, unknown>;\n\t},\n): SensorControls<T> {\n\tconst source = node<T>([], () => undefined, {\n\t\t...opts,\n\t\tname,\n\t\tinitial,\n\t\tdescribeKind: \"producer\",\n\t\tmeta: baseMeta(\"sensor\", opts?.meta),\n\t});\n\tregisterStep(graph, name, source as unknown as Node<unknown>, []);\n\treturn {\n\t\tnode: source,\n\t\tpush(value: T) {\n\t\t\tsource.down([[DATA, value]] satisfies Messages);\n\t\t},\n\t\terror(err: unknown) {\n\t\t\tsource.down([[ERROR, err]] satisfies Messages);\n\t\t},\n\t\tcomplete() {\n\t\t\tsource.down([[COMPLETE]] satisfies Messages);\n\t\t},\n\t};\n}\n\n/**\n * Registers a delayed-forwarding step (value-level wait).\n */\nexport function wait<T>(\n\tgraph: Graph,\n\tname: string,\n\tsource: StepRef,\n\tms: number,\n\topts?: WaitOptions,\n): Node<T> {\n\tconst src = resolveDep(graph, source);\n\tconst timers = new Set<ReturnType<typeof setTimeout>>();\n\tlet terminated = false;\n\tlet completed = false;\n\n\tfunction clearAllTimers(): void {\n\t\tfor (const id of timers) clearTimeout(id);\n\t\ttimers.clear();\n\t}\n\n\t// Producer pattern: 0 deps, manual subscribe to source.\n\t// Under Model B (push-on-subscribe) the fn runs eagerly via _startProducer,\n\t// ensuring the cleanup is registered and timers are cleared on teardown.\n\t// Only set initial if source has a real cached value (not SENTINEL/undefined).\n\tconst srcVal = src.node.cache;\n\tconst initialOpt = srcVal !== undefined ? { initial: srcVal as T } : {};\n\n\tconst step = node<T>(\n\t\t[],\n\t\t(_deps, actions) => {\n\t\t\tclearAllTimers();\n\t\t\tterminated = false;\n\t\t\tcompleted = false;\n\t\t\tconst unsub = src.node.subscribe((msgs) => {\n\t\t\t\tfor (const msg of msgs) {\n\t\t\t\t\tif (terminated) return;\n\t\t\t\t\tif (msg[0] === DATA) {\n\t\t\t\t\t\tconst id = setTimeout(() => {\n\t\t\t\t\t\t\ttimers.delete(id);\n\t\t\t\t\t\t\tactions.down([msg] satisfies Messages);\n\t\t\t\t\t\t\tif (completed && timers.size === 0) {\n\t\t\t\t\t\t\t\tactions.down([[COMPLETE]] satisfies Messages);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, ms);\n\t\t\t\t\t\ttimers.add(id);\n\t\t\t\t\t} else if (msg[0] === COMPLETE) {\n\t\t\t\t\t\tterminated = true;\n\t\t\t\t\t\tcompleted = true;\n\t\t\t\t\t\tif (timers.size === 0) {\n\t\t\t\t\t\t\tactions.down([[COMPLETE]] satisfies Messages);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (msg[0] === ERROR) {\n\t\t\t\t\t\tterminated = true;\n\t\t\t\t\t\tclearAllTimers();\n\t\t\t\t\t\tactions.down([msg] satisfies Messages);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tactions.down([msg] satisfies Messages);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn () => {\n\t\t\t\tunsub();\n\t\t\t\tclearAllTimers();\n\t\t\t\tterminated = true;\n\t\t\t};\n\t\t},\n\t\t{\n\t\t\t...opts,\n\t\t\tname,\n\t\t\t...initialOpt,\n\t\t\tdescribeKind: \"derived\",\n\t\t\tcompleteWhenDepsComplete: false,\n\t\t\tmeta: baseMeta(\"wait\", opts?.meta),\n\t\t} as NodeOptions<T>,\n\t);\n\t// Producer pattern: register in graph without dep edges (manual subscription).\n\t// Post edge-registry deletion (Unit 7), edges are derived from node `_deps`\n\t// exclusively; this producer's logical dep on `src` is not reflected in\n\t// `describe()` — by design, since there is no real constructor-time\n\t// dependency to show.\n\tgraph.add(name, step as unknown as Node<unknown>);\n\treturn step;\n}\n\n/**\n * Registers an error-recovery step for a source.\n */\nexport function onFailure<T>(\n\tgraph: Graph,\n\tname: string,\n\tsource: StepRef,\n\trecover: (err: unknown, actions: NodeActions) => T,\n\topts?: Omit<OrchestrationStepOptions, \"deps\">,\n): Node<T> {\n\tconst src = resolveDep(graph, source);\n\tlet terminated = false;\n\t// Producer pattern: manually subscribe to source for per-message interception\n\t// (onMessage removed in v5 — use producer+subscribe instead)\n\tconst step = node<T>(\n\t\t[],\n\t\t(_data, actions) => {\n\t\t\tconst unsub = src.node.subscribe((msgs) => {\n\t\t\t\tfor (const msg of msgs) {\n\t\t\t\t\tif (terminated) return;\n\t\t\t\t\tif (msg[0] === ERROR) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tactions.emit(recover(msg[1], actions));\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tterminated = true;\n\t\t\t\t\t\t\tactions.down([[ERROR, err]] satisfies Messages);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tactions.down([msg] satisfies Messages);\n\t\t\t\t\t\tif (msg[0] === COMPLETE) terminated = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn () => unsub();\n\t\t},\n\t\t{\n\t\t\t...opts,\n\t\t\tname,\n\t\t\tdescribeKind: \"derived\",\n\t\t\tcompleteWhenDepsComplete: false,\n\t\t\t// onFailure handles errors via manual subscription (recover callback).\n\t\t\t// Disable auto-propagation so dep-channel ERROR doesn't terminate this\n\t\t\t// node before the recover callback has a chance to emit a replacement value.\n\t\t\terrorWhenDepsError: false,\n\t\t\tmeta: baseMeta(\"onFailure\", opts?.meta),\n\t\t} as NodeOptions<T>,\n\t);\n\tregisterStep(graph, name, step as unknown as Node<unknown>, src.path ? [src.path] : []);\n\treturn step;\n}\n"],"mappings":"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","names":["batch","node"]}
@@ -0,0 +1,119 @@
1
+ import {
2
+ DATA,
3
+ DIRTY,
4
+ __export
5
+ } from "./chunk-SX52TAR4.js";
6
+
7
+ // src/compat/vue/index.ts
8
+ var vue_exports = {};
9
+ __export(vue_exports, {
10
+ useStore: () => useStore,
11
+ useSubscribe: () => useSubscribe,
12
+ useSubscribeRecord: () => useSubscribeRecord
13
+ });
14
+ import {
15
+ computed,
16
+ getCurrentScope,
17
+ isRef,
18
+ onScopeDispose,
19
+ readonly,
20
+ shallowRef,
21
+ watch
22
+ } from "vue";
23
+ function useSubscribe(node) {
24
+ const ref = shallowRef(node.cache);
25
+ const unsub = node.subscribe(() => {
26
+ ref.value = node.cache;
27
+ });
28
+ if (getCurrentScope()) {
29
+ onScopeDispose(() => unsub());
30
+ } else if (typeof console !== "undefined") {
31
+ console.warn(
32
+ "[graphrefly-ts] useSubscribe called outside a Vue scope \u2014 subscription will not be auto-disposed."
33
+ );
34
+ }
35
+ return readonly(ref);
36
+ }
37
+ function useStore(node) {
38
+ const inner = shallowRef(node.cache);
39
+ const unsub = node.subscribe(() => {
40
+ inner.value = node.cache;
41
+ });
42
+ if (getCurrentScope()) {
43
+ onScopeDispose(() => unsub());
44
+ } else if (typeof console !== "undefined") {
45
+ console.warn(
46
+ "[graphrefly-ts] useStore called outside a Vue scope \u2014 subscription will not be auto-disposed."
47
+ );
48
+ }
49
+ return computed({
50
+ get: () => inner.value,
51
+ set: (v) => {
52
+ node.down([[DIRTY], [DATA, v]]);
53
+ }
54
+ });
55
+ }
56
+ function useSubscribeRecord(keys, factory) {
57
+ const result = shallowRef({});
58
+ const activeSubs = /* @__PURE__ */ new Map();
59
+ function flushResult() {
60
+ const snap = {};
61
+ for (const [key, entry] of activeSubs) {
62
+ snap[key] = { ...entry.values };
63
+ }
64
+ result.value = snap;
65
+ }
66
+ function sync(newKeys) {
67
+ for (const entry of activeSubs.values()) {
68
+ for (const unsub of entry.subs) unsub();
69
+ }
70
+ activeSubs.clear();
71
+ for (const key of newKeys) {
72
+ const nodes = factory(key);
73
+ const fields = Object.keys(nodes);
74
+ const values = {};
75
+ const subs = [];
76
+ for (const field of fields) {
77
+ const node = nodes[field];
78
+ values[field] = node.cache;
79
+ const unsub = node.subscribe(() => {
80
+ values[field] = node.cache;
81
+ flushResult();
82
+ });
83
+ subs.push(unsub);
84
+ }
85
+ activeSubs.set(key, { subs, values });
86
+ }
87
+ const snap = {};
88
+ for (const [key, entry] of activeSubs) {
89
+ snap[key] = { ...entry.values };
90
+ }
91
+ result.value = snap;
92
+ }
93
+ const readKeys = () => {
94
+ const current = typeof keys === "function" ? keys() : isRef(keys) ? keys.value : keys;
95
+ return [...current ?? []];
96
+ };
97
+ watch(readKeys, (newKeys) => sync(newKeys ?? []), { immediate: true });
98
+ if (getCurrentScope()) {
99
+ onScopeDispose(() => {
100
+ for (const entry of activeSubs.values()) {
101
+ for (const unsub of entry.subs) unsub();
102
+ }
103
+ activeSubs.clear();
104
+ });
105
+ } else if (typeof console !== "undefined") {
106
+ console.warn(
107
+ "[graphrefly-ts] useSubscribeRecord called outside a Vue scope \u2014 subscription will not be auto-disposed."
108
+ );
109
+ }
110
+ return readonly(result);
111
+ }
112
+
113
+ export {
114
+ useSubscribe,
115
+ useStore,
116
+ useSubscribeRecord,
117
+ vue_exports
118
+ };
119
+ //# sourceMappingURL=chunk-MJ2NKQQL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/compat/vue/index.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Vue bindings — useStore / useSubscribe\n// ---------------------------------------------------------------------------\n// Bridges GraphReFly nodes into Vue reactivity. Works with any\n// Node<T>, including companion nodes (node.meta.status).\n//\n// Usage:\n// import { useStore, useSubscribe } from '@graphrefly/graphrefly-ts/compat/vue';\n// // Optional peer install (only for this adapter): pnpm add vue\n// const count = useStore(counterNode); // Ref<number | undefined> (read + write)\n// const status = useSubscribe(wsStatusNode); // Readonly<Ref<string | undefined>>\n// ---------------------------------------------------------------------------\n\nimport {\n\tcomputed,\n\tgetCurrentScope,\n\tisRef,\n\tonScopeDispose,\n\ttype Ref,\n\treadonly,\n\tshallowRef,\n\ttype WatchSource,\n\twatch,\n} from \"vue\";\nimport { DATA, DIRTY } from \"../../core/messages.js\";\nimport type { Node } from \"../../core/node.js\";\n\n/**\n * Subscribe to a read-only `Node<T>` as a Vue `Ref<T>`. Auto-unsubscribes on scope disposal.\n * Subscription lifecycle is tied to Vue scope disposal (not node terminal messages).\n */\nexport function useSubscribe<T>(node: Node<T>): Readonly<Ref<T | undefined | null>> {\n\tconst ref = shallowRef(node.cache) as Ref<T | undefined | null>;\n\n\tconst unsub = node.subscribe(() => {\n\t\tref.value = node.cache;\n\t});\n\n\tif (getCurrentScope()) {\n\t\tonScopeDispose(() => unsub());\n\t} else if (typeof console !== \"undefined\") {\n\t\tconsole.warn(\n\t\t\t\"[graphrefly-ts] useSubscribe called outside a Vue scope — subscription will not be auto-disposed.\",\n\t\t);\n\t}\n\n\treturn readonly(ref) as Readonly<Ref<T | undefined | null>>;\n}\n\n/**\n * Bind a writable `Node<T>` as a Vue `Ref<T>`. Reads and writes are bidirectional.\n * Value sets always dispatch `[[DIRTY], [DATA, value]]`, including `value === undefined`.\n * Subscription lifecycle is tied to Vue scope disposal (not node terminal messages).\n */\nexport function useStore<T>(node: Node<T>): Ref<T | undefined | null> {\n\tconst inner = shallowRef(node.cache) as Ref<T | undefined | null>;\n\n\tconst unsub = node.subscribe(() => {\n\t\tinner.value = node.cache;\n\t});\n\n\tif (getCurrentScope()) {\n\t\tonScopeDispose(() => unsub());\n\t} else if (typeof console !== \"undefined\") {\n\t\tconsole.warn(\n\t\t\t\"[graphrefly-ts] useStore called outside a Vue scope — subscription will not be auto-disposed.\",\n\t\t);\n\t}\n\n\treturn computed({\n\t\tget: () => inner.value,\n\t\tset: (v: T | undefined | null) => {\n\t\t\tnode.down([[DIRTY], [DATA, v]]);\n\t\t},\n\t});\n}\n\n/** Maps a key to an object of nodes. Used by `useSubscribeRecord` factory. */\nexport type NodeFactory<K, R extends Record<string, any>> = (key: K) => {\n\t[P in keyof R]: Node<R[P]>;\n};\n\n/**\n * Subscribe to a dynamic set of keyed node records. When keys change,\n * old subscriptions are torn down and new ones created automatically.\n * Must be called during Vue `setup()`.\n */\nexport function useSubscribeRecord<K extends string, R extends Record<string, any>>(\n\tkeys: WatchSource<K[] | undefined>,\n\tfactory: NodeFactory<K, R>,\n): Readonly<Ref<Record<K, R>>> {\n\tconst result = shallowRef<Record<K, R>>({} as Record<K, R>);\n\n\t// Track active subscriptions per key (strictly enclosed memory mapping)\n\tconst activeSubs = new Map<K, { subs: Array<() => void>; values: R }>();\n\tfunction flushResult() {\n\t\tconst snap = {} as Record<K, R>;\n\t\tfor (const [key, entry] of activeSubs) {\n\t\t\tsnap[key] = { ...entry.values };\n\t\t}\n\t\tresult.value = snap;\n\t}\n\n\tfunction sync(newKeys: K[]) {\n\t\tfor (const entry of activeSubs.values()) {\n\t\t\tfor (const unsub of entry.subs) unsub();\n\t\t}\n\t\tactiveSubs.clear();\n\n\t\tfor (const key of newKeys) {\n\t\t\tconst nodes = factory(key);\n\t\t\tconst fields = Object.keys(nodes) as (keyof R)[];\n\t\t\tconst values = {} as R;\n\t\t\tconst subs: Array<() => void> = [];\n\n\t\t\tfor (const field of fields) {\n\t\t\t\tconst node = nodes[field];\n\t\t\t\tvalues[field] = node.cache as R[keyof R];\n\t\t\t\tconst unsub = node.subscribe(() => {\n\t\t\t\t\tvalues[field] = node.cache as R[keyof R];\n\t\t\t\t\tflushResult();\n\t\t\t\t});\n\t\t\t\tsubs.push(unsub);\n\t\t\t}\n\n\t\t\tactiveSubs.set(key, { subs, values });\n\t\t}\n\n\t\tconst snap = {} as Record<K, R>;\n\t\tfor (const [key, entry] of activeSubs) {\n\t\t\tsnap[key] = { ...entry.values };\n\t\t}\n\t\tresult.value = snap;\n\t}\n\n\tconst readKeys = (): K[] => {\n\t\tconst current = typeof keys === \"function\" ? keys() : isRef(keys) ? keys.value : keys;\n\t\treturn [...(current ?? [])];\n\t};\n\n\twatch(readKeys, (newKeys) => sync(newKeys ?? []), { immediate: true });\n\n\tif (getCurrentScope()) {\n\t\tonScopeDispose(() => {\n\t\t\tfor (const entry of activeSubs.values()) {\n\t\t\t\tfor (const unsub of entry.subs) unsub();\n\t\t\t}\n\t\t\tactiveSubs.clear();\n\t\t});\n\t} else if (typeof console !== \"undefined\") {\n\t\tconsole.warn(\n\t\t\t\"[graphrefly-ts] useSubscribeRecord called outside a Vue scope — subscription will not be auto-disposed.\",\n\t\t);\n\t}\n\n\treturn readonly(result) as Readonly<Ref<Record<K, R>>>;\n}\n"],"mappings":"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","names":[]}