gauss-ai 4.0.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 (232) hide show
  1. package/CHANGELOG.md +489 -0
  2. package/LICENSE +21 -0
  3. package/README.md +269 -0
  4. package/dist/a2a/index.cjs +7 -0
  5. package/dist/a2a/index.cjs.map +1 -0
  6. package/dist/a2a/index.d.cts +30 -0
  7. package/dist/a2a/index.d.ts +30 -0
  8. package/dist/a2a/index.js +7 -0
  9. package/dist/a2a/index.js.map +1 -0
  10. package/dist/agent-UIQDSYCE.js +16 -0
  11. package/dist/agent-UIQDSYCE.js.map +1 -0
  12. package/dist/agent-builder-8W3mBR-N.d.ts +1075 -0
  13. package/dist/agent-builder-GEMYdb1p.d.cts +1075 -0
  14. package/dist/agent-graph-AMQYAWNF.js +1422 -0
  15. package/dist/agent-graph-AMQYAWNF.js.map +1 -0
  16. package/dist/ai-sdk-mcp.adapter-SEN6KHNU.js +124 -0
  17. package/dist/ai-sdk-mcp.adapter-SEN6KHNU.js.map +1 -0
  18. package/dist/browser/index.js +10 -0
  19. package/dist/browser/index.js.map +1 -0
  20. package/dist/bun-runtime.adapter-MQDAJLQM.js +8 -0
  21. package/dist/bun-runtime.adapter-MQDAJLQM.js.map +1 -0
  22. package/dist/bun-runtime.adapter-XKOUXVAK.cjs +8 -0
  23. package/dist/bun-runtime.adapter-XKOUXVAK.cjs.map +1 -0
  24. package/dist/chat-A3XMRPJL.js +129 -0
  25. package/dist/chat-A3XMRPJL.js.map +1 -0
  26. package/dist/chunk-2ZRU47NC.js +91 -0
  27. package/dist/chunk-2ZRU47NC.js.map +1 -0
  28. package/dist/chunk-3LD3JTH4.cjs +18 -0
  29. package/dist/chunk-3LD3JTH4.cjs.map +1 -0
  30. package/dist/chunk-5FE5TG2W.cjs +16 -0
  31. package/dist/chunk-5FE5TG2W.cjs.map +1 -0
  32. package/dist/chunk-6XF673YC.cjs +436 -0
  33. package/dist/chunk-6XF673YC.cjs.map +1 -0
  34. package/dist/chunk-7CKWZJNS.js +230 -0
  35. package/dist/chunk-7CKWZJNS.js.map +1 -0
  36. package/dist/chunk-BI2G665F.js +4588 -0
  37. package/dist/chunk-BI2G665F.js.map +1 -0
  38. package/dist/chunk-C5NLWJS2.js +139 -0
  39. package/dist/chunk-C5NLWJS2.js.map +1 -0
  40. package/dist/chunk-CJZ66SU3.cjs +4321 -0
  41. package/dist/chunk-CJZ66SU3.cjs.map +1 -0
  42. package/dist/chunk-DAMT2CXW.cjs +91 -0
  43. package/dist/chunk-DAMT2CXW.cjs.map +1 -0
  44. package/dist/chunk-E7WG3MO5.js +18 -0
  45. package/dist/chunk-E7WG3MO5.js.map +1 -0
  46. package/dist/chunk-EFDM6R4J.js +99 -0
  47. package/dist/chunk-EFDM6R4J.js.map +1 -0
  48. package/dist/chunk-F7WIPPEO.js +256 -0
  49. package/dist/chunk-F7WIPPEO.js.map +1 -0
  50. package/dist/chunk-FAYDE67N.js +6927 -0
  51. package/dist/chunk-FAYDE67N.js.map +1 -0
  52. package/dist/chunk-GAE2KKCM.js +21 -0
  53. package/dist/chunk-GAE2KKCM.js.map +1 -0
  54. package/dist/chunk-INLNGRXM.cjs +130 -0
  55. package/dist/chunk-INLNGRXM.cjs.map +1 -0
  56. package/dist/chunk-JKXKXB5O.js +130 -0
  57. package/dist/chunk-JKXKXB5O.js.map +1 -0
  58. package/dist/chunk-K6SAETGP.js +375 -0
  59. package/dist/chunk-K6SAETGP.js.map +1 -0
  60. package/dist/chunk-KEASLAYR.js +157 -0
  61. package/dist/chunk-KEASLAYR.js.map +1 -0
  62. package/dist/chunk-KKJVNM6O.js +436 -0
  63. package/dist/chunk-KKJVNM6O.js.map +1 -0
  64. package/dist/chunk-KYIMVRIM.js +16 -0
  65. package/dist/chunk-KYIMVRIM.js.map +1 -0
  66. package/dist/chunk-MB7NXIZD.js +4321 -0
  67. package/dist/chunk-MB7NXIZD.js.map +1 -0
  68. package/dist/chunk-MHHDXPGE.js +209 -0
  69. package/dist/chunk-MHHDXPGE.js.map +1 -0
  70. package/dist/chunk-NE6JJA5W.js +401 -0
  71. package/dist/chunk-NE6JJA5W.js.map +1 -0
  72. package/dist/chunk-PF46XZBF.cjs +6927 -0
  73. package/dist/chunk-PF46XZBF.cjs.map +1 -0
  74. package/dist/chunk-PSJIAGDE.cjs +375 -0
  75. package/dist/chunk-PSJIAGDE.cjs.map +1 -0
  76. package/dist/chunk-PWOQDXNQ.js +16 -0
  77. package/dist/chunk-PWOQDXNQ.js.map +1 -0
  78. package/dist/chunk-QYOMQBBZ.cjs +230 -0
  79. package/dist/chunk-QYOMQBBZ.cjs.map +1 -0
  80. package/dist/chunk-UDFXLC4J.cjs +16 -0
  81. package/dist/chunk-UDFXLC4J.cjs.map +1 -0
  82. package/dist/chunk-UO4NGXRT.cjs +259 -0
  83. package/dist/chunk-UO4NGXRT.cjs.map +1 -0
  84. package/dist/chunk-UPFDFLEW.js +40 -0
  85. package/dist/chunk-UPFDFLEW.js.map +1 -0
  86. package/dist/chunk-V55JSQS7.cjs +16 -0
  87. package/dist/chunk-V55JSQS7.cjs.map +1 -0
  88. package/dist/chunk-VJADHXZL.cjs +16 -0
  89. package/dist/chunk-VJADHXZL.cjs.map +1 -0
  90. package/dist/chunk-VRWD7LCI.js +59 -0
  91. package/dist/chunk-VRWD7LCI.js.map +1 -0
  92. package/dist/chunk-WKKQ443C.js +487 -0
  93. package/dist/chunk-WKKQ443C.js.map +1 -0
  94. package/dist/chunk-X2GHUHAF.js +436 -0
  95. package/dist/chunk-X2GHUHAF.js.map +1 -0
  96. package/dist/chunk-XLGW3XNI.cjs +256 -0
  97. package/dist/chunk-XLGW3XNI.cjs.map +1 -0
  98. package/dist/chunk-ZFJKX4DP.js +16 -0
  99. package/dist/chunk-ZFJKX4DP.js.map +1 -0
  100. package/dist/chunk-ZM2OEWM2.js +259 -0
  101. package/dist/chunk-ZM2OEWM2.js.map +1 -0
  102. package/dist/chunk-ZNAIP2XV.js +16 -0
  103. package/dist/chunk-ZNAIP2XV.js.map +1 -0
  104. package/dist/chunk-ZYFAZYSL.js +42 -0
  105. package/dist/chunk-ZYFAZYSL.js.map +1 -0
  106. package/dist/cli/index.js +421 -0
  107. package/dist/cli/index.js.map +1 -0
  108. package/dist/config-4MHT6TQW.js +153 -0
  109. package/dist/config-4MHT6TQW.js.map +1 -0
  110. package/dist/config-REERQFK4.cjs +153 -0
  111. package/dist/config-REERQFK4.cjs.map +1 -0
  112. package/dist/cost-tracker-JLOU7IZJ.js +7 -0
  113. package/dist/cost-tracker-JLOU7IZJ.js.map +1 -0
  114. package/dist/demo-C52GMSYH.js +188 -0
  115. package/dist/demo-C52GMSYH.js.map +1 -0
  116. package/dist/deno/index.js +306 -0
  117. package/dist/deno/index.js.map +1 -0
  118. package/dist/deno-runtime.adapter-F744HY7K.js +8 -0
  119. package/dist/deno-runtime.adapter-F744HY7K.js.map +1 -0
  120. package/dist/deno-runtime.adapter-RFEVNSCV.cjs +8 -0
  121. package/dist/deno-runtime.adapter-RFEVNSCV.cjs.map +1 -0
  122. package/dist/dev-D7DDVDA4.js +218 -0
  123. package/dist/dev-D7DDVDA4.js.map +1 -0
  124. package/dist/edge/index.js +10 -0
  125. package/dist/edge/index.js.map +1 -0
  126. package/dist/edge-runtime.adapter-UQCW2F7X.js +8 -0
  127. package/dist/edge-runtime.adapter-UQCW2F7X.js.map +1 -0
  128. package/dist/edge-runtime.adapter-YED6F3AY.cjs +8 -0
  129. package/dist/edge-runtime.adapter-YED6F3AY.cjs.map +1 -0
  130. package/dist/graph-MGFAQZ5W.js +50 -0
  131. package/dist/graph-MGFAQZ5W.js.map +1 -0
  132. package/dist/graph-visualization-HBSVQXJK.js +9 -0
  133. package/dist/graph-visualization-HBSVQXJK.js.map +1 -0
  134. package/dist/index-BRgqNnh3.d.cts +982 -0
  135. package/dist/index-CZxpYUxZ.d.ts +982 -0
  136. package/dist/index.cjs +14789 -0
  137. package/dist/index.cjs.map +1 -0
  138. package/dist/index.d.cts +10275 -0
  139. package/dist/index.d.ts +10275 -0
  140. package/dist/index.js +14789 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/init-CFWXTQ35.js +133 -0
  143. package/dist/init-CFWXTQ35.js.map +1 -0
  144. package/dist/llm-VWO4MC7J.cjs +17 -0
  145. package/dist/llm-VWO4MC7J.cjs.map +1 -0
  146. package/dist/llm-XLXVSPBI.js +17 -0
  147. package/dist/llm-XLXVSPBI.js.map +1 -0
  148. package/dist/logging-WRAK5ZXT.js +33 -0
  149. package/dist/logging-WRAK5ZXT.js.map +1 -0
  150. package/dist/metrics-FAHZVVD4.js +47 -0
  151. package/dist/metrics-FAHZVVD4.js.map +1 -0
  152. package/dist/node/index.cjs +280 -0
  153. package/dist/node/index.cjs.map +1 -0
  154. package/dist/node/index.d.cts +51 -0
  155. package/dist/node/index.d.ts +51 -0
  156. package/dist/node/index.js +280 -0
  157. package/dist/node/index.js.map +1 -0
  158. package/dist/node-runtime.adapter-5L7PJ6W2.js +8 -0
  159. package/dist/node-runtime.adapter-5L7PJ6W2.js.map +1 -0
  160. package/dist/node-runtime.adapter-CCRZVGHB.cjs +8 -0
  161. package/dist/node-runtime.adapter-CCRZVGHB.cjs.map +1 -0
  162. package/dist/persist-usage-WTBTCWEF.js +7 -0
  163. package/dist/persist-usage-WTBTCWEF.js.map +1 -0
  164. package/dist/plugin-RCPBWUUA.js +207 -0
  165. package/dist/plugin-RCPBWUUA.js.map +1 -0
  166. package/dist/plugins/index.cjs +75 -0
  167. package/dist/plugins/index.cjs.map +1 -0
  168. package/dist/plugins/index.d.cts +8 -0
  169. package/dist/plugins/index.d.ts +8 -0
  170. package/dist/plugins/index.js +75 -0
  171. package/dist/plugins/index.js.map +1 -0
  172. package/dist/plugins-L4ING3CX.js +4625 -0
  173. package/dist/plugins-L4ING3CX.js.map +1 -0
  174. package/dist/providers/index.cjs +189 -0
  175. package/dist/providers/index.cjs.map +1 -0
  176. package/dist/providers/index.d.cts +168 -0
  177. package/dist/providers/index.d.ts +168 -0
  178. package/dist/providers/index.js +189 -0
  179. package/dist/providers/index.js.map +1 -0
  180. package/dist/providers-3RNQ5CKZ.js +59 -0
  181. package/dist/providers-3RNQ5CKZ.js.map +1 -0
  182. package/dist/providers-66GPXUGQ.cjs +59 -0
  183. package/dist/providers-66GPXUGQ.cjs.map +1 -0
  184. package/dist/repl-K6QN4I2S.js +678 -0
  185. package/dist/repl-K6QN4I2S.js.map +1 -0
  186. package/dist/rest/index.cjs +17 -0
  187. package/dist/rest/index.cjs.map +1 -0
  188. package/dist/rest/index.d.cts +102 -0
  189. package/dist/rest/index.d.ts +102 -0
  190. package/dist/rest/index.js +17 -0
  191. package/dist/rest/index.js.map +1 -0
  192. package/dist/runtime-deno.js +15 -0
  193. package/dist/runtime-deno.js.map +1 -0
  194. package/dist/runtime-edge.js +15 -0
  195. package/dist/runtime-edge.js.map +1 -0
  196. package/dist/runtime-node.js +15 -0
  197. package/dist/runtime-node.js.map +1 -0
  198. package/dist/scraping/index.cjs +11 -0
  199. package/dist/scraping/index.cjs.map +1 -0
  200. package/dist/scraping/index.d.cts +17 -0
  201. package/dist/scraping/index.d.ts +17 -0
  202. package/dist/scraping/index.js +11 -0
  203. package/dist/scraping/index.js.map +1 -0
  204. package/dist/semantic-scraping.port-CZWUea88.d.cts +54 -0
  205. package/dist/semantic-scraping.port-CZWUea88.d.ts +54 -0
  206. package/dist/server/index.js +166 -0
  207. package/dist/server/index.js.map +1 -0
  208. package/dist/testing/index.cjs +25 -0
  209. package/dist/testing/index.cjs.map +1 -0
  210. package/dist/testing/index.d.cts +63 -0
  211. package/dist/testing/index.d.ts +63 -0
  212. package/dist/testing/index.js +25 -0
  213. package/dist/testing/index.js.map +1 -0
  214. package/dist/token-counter.port-CRgxZZGe.d.ts +334 -0
  215. package/dist/token-counter.port-D7BHMCRR.d.cts +334 -0
  216. package/dist/tools-BZM33OBZ.js +10 -0
  217. package/dist/tools-BZM33OBZ.js.map +1 -0
  218. package/dist/tracing-XA3TEWP4.js +48 -0
  219. package/dist/tracing-XA3TEWP4.js.map +1 -0
  220. package/dist/types-CVsP7gFI.d.cts +235 -0
  221. package/dist/types-CVsP7gFI.d.ts +235 -0
  222. package/dist/virtual-fs.adapter-BBLS-3AY.d.ts +26 -0
  223. package/dist/virtual-fs.adapter-nb0CTYOj.d.cts +26 -0
  224. package/dist/workflow/index.cjs +9 -0
  225. package/dist/workflow/index.cjs.map +1 -0
  226. package/dist/workflow/index.d.cts +62 -0
  227. package/dist/workflow/index.d.ts +62 -0
  228. package/dist/workflow/index.js +9 -0
  229. package/dist/workflow/index.js.map +1 -0
  230. package/dist/workflow.port-BaCttxrw.d.cts +153 -0
  231. package/dist/workflow.port-BaCttxrw.d.ts +153 -0
  232. package/package.json +230 -0
@@ -0,0 +1,1422 @@
1
+ import {
2
+ AsciiGraphAdapter,
3
+ MermaidGraphAdapter
4
+ } from "./chunk-C5NLWJS2.js";
5
+ import {
6
+ AbstractBuilder,
7
+ Agent,
8
+ VirtualFilesystem
9
+ } from "./chunk-BI2G665F.js";
10
+ import "./chunk-ZFJKX4DP.js";
11
+ import "./chunk-PWOQDXNQ.js";
12
+ import "./chunk-X2GHUHAF.js";
13
+ import "./chunk-K6SAETGP.js";
14
+ import "./chunk-KYIMVRIM.js";
15
+ import "./chunk-ZNAIP2XV.js";
16
+ import "./chunk-E7WG3MO5.js";
17
+
18
+ // src/domain/graph.schema.ts
19
+ import { z } from "zod";
20
+ var GraphConfigSchema = z.object({
21
+ maxDepth: z.number().default(10),
22
+ maxConcurrency: z.number().default(5),
23
+ timeoutMs: z.number().default(6e5),
24
+ maxTokenBudget: z.number().default(1e6)
25
+ });
26
+ var NodeConfigSchema = z.object({
27
+ id: z.string(),
28
+ type: z.enum(["agent", "graph"])
29
+ });
30
+ var NodeResultSchema = z.object({
31
+ nodeId: z.string(),
32
+ output: z.string(),
33
+ tokenUsage: z.object({
34
+ input: z.number(),
35
+ output: z.number()
36
+ }).optional(),
37
+ durationMs: z.number()
38
+ });
39
+ var GraphResultSchema = z.object({
40
+ output: z.string(),
41
+ nodeResults: z.record(z.string(), NodeResultSchema),
42
+ totalDurationMs: z.number(),
43
+ totalTokenUsage: z.object({
44
+ input: z.number(),
45
+ output: z.number()
46
+ })
47
+ });
48
+
49
+ // src/graph/agent-node.ts
50
+ var AgentNode = class {
51
+ id;
52
+ type;
53
+ config;
54
+ constructor(config) {
55
+ this.id = config.id;
56
+ this.type = config.type;
57
+ this.config = config;
58
+ }
59
+ async run(prompt, sharedContext) {
60
+ const start = Date.now();
61
+ if (this.config.type === "graph" && this.config.graph) {
62
+ const graphResult = await this.config.graph.run(prompt);
63
+ const result = {
64
+ nodeId: this.id,
65
+ output: graphResult.output,
66
+ tokenUsage: graphResult.totalTokenUsage,
67
+ durationMs: Date.now() - start
68
+ };
69
+ await sharedContext.setNodeResult(this.id, result.output);
70
+ return result;
71
+ }
72
+ if (!this.config.agentConfig) {
73
+ throw new Error(`Node "${this.id}" has no agentConfig or graph`);
74
+ }
75
+ const agent = Agent.minimal(this.config.agentConfig);
76
+ try {
77
+ const agentResult = await agent.run(prompt);
78
+ const result = {
79
+ nodeId: this.id,
80
+ output: agentResult.text,
81
+ durationMs: Date.now() - start
82
+ };
83
+ await sharedContext.setNodeResult(this.id, result.output);
84
+ return result;
85
+ } finally {
86
+ await agent.dispose();
87
+ }
88
+ }
89
+ };
90
+
91
+ // src/graph/priority-queue.ts
92
+ var PriorityQueue = class {
93
+ heap = [];
94
+ compare;
95
+ constructor(compare) {
96
+ this.compare = compare;
97
+ }
98
+ get size() {
99
+ return this.heap.length;
100
+ }
101
+ enqueue(item) {
102
+ this.heap.push(item);
103
+ this.bubbleUp(this.heap.length - 1);
104
+ }
105
+ dequeue() {
106
+ if (this.heap.length === 0) return void 0;
107
+ const top = this.heap[0];
108
+ const last = this.heap.pop();
109
+ if (this.heap.length > 0) {
110
+ this.heap[0] = last;
111
+ this.sinkDown(0);
112
+ }
113
+ return top;
114
+ }
115
+ peek() {
116
+ return this.heap[0];
117
+ }
118
+ bubbleUp(i) {
119
+ while (i > 0) {
120
+ const parent = i - 1 >> 1;
121
+ if (this.compare(this.heap[i], this.heap[parent]) >= 0) break;
122
+ [this.heap[i], this.heap[parent]] = [this.heap[parent], this.heap[i]];
123
+ i = parent;
124
+ }
125
+ }
126
+ sinkDown(i) {
127
+ const n = this.heap.length;
128
+ while (true) {
129
+ let smallest = i;
130
+ const left = 2 * i + 1;
131
+ const right = 2 * i + 2;
132
+ if (left < n && this.compare(this.heap[left], this.heap[smallest]) < 0) {
133
+ smallest = left;
134
+ }
135
+ if (right < n && this.compare(this.heap[right], this.heap[smallest]) < 0) {
136
+ smallest = right;
137
+ }
138
+ if (smallest === i) break;
139
+ [this.heap[i], this.heap[smallest]] = [this.heap[smallest], this.heap[i]];
140
+ i = smallest;
141
+ }
142
+ }
143
+ };
144
+
145
+ // src/graph/worker-pool.ts
146
+ var DEFAULT_POOL_CONFIG = {
147
+ initialSize: 4,
148
+ minSize: 1,
149
+ maxSize: 16,
150
+ taskTimeoutMs: 6e4,
151
+ heartbeatIntervalMs: 5e3,
152
+ idleShrinkMs: 3e4,
153
+ growThreshold: 3
154
+ };
155
+ var WorkerPool = class _WorkerPool {
156
+ queue;
157
+ workers = /* @__PURE__ */ new Map();
158
+ executor;
159
+ config;
160
+ onEvent;
161
+ latencies = [];
162
+ completionTimestamps = [];
163
+ static MAX_METRICS_ENTRIES = 1e3;
164
+ nextWorkerId = 0;
165
+ draining = false;
166
+ drainingResolve;
167
+ heartbeatTimer = null;
168
+ totalCompleted = 0;
169
+ totalFailed = 0;
170
+ workStealCount = 0;
171
+ constructor(executor, config, onEvent) {
172
+ this.executor = executor;
173
+ this.config = { ...DEFAULT_POOL_CONFIG, ...config };
174
+ this.onEvent = onEvent;
175
+ this.queue = new PriorityQueue(
176
+ (a, b) => a.priority - b.priority
177
+ );
178
+ for (let i = 0; i < this.config.initialSize; i++) {
179
+ this.spawnWorker();
180
+ }
181
+ this.startHeartbeatMonitor();
182
+ }
183
+ // ── Public API ─────────────────────────────────────────────────────────────
184
+ submit(id, input, priority = 0) {
185
+ if (this.draining) throw new Error("Pool is draining, cannot submit");
186
+ return new Promise((resolve, reject) => {
187
+ const task = {
188
+ id,
189
+ input,
190
+ priority,
191
+ enqueuedAt: Date.now(),
192
+ abortController: new AbortController(),
193
+ resolve,
194
+ reject
195
+ };
196
+ this.queue.enqueue(task);
197
+ this.wakeOneIdleWorker();
198
+ });
199
+ }
200
+ async drain(timeoutMs = 3e4) {
201
+ this.draining = true;
202
+ if (this.allIdle() && this.queue.size === 0) {
203
+ this.cleanup();
204
+ this.emit({ type: "pool:drained" });
205
+ return;
206
+ }
207
+ return new Promise((resolve, reject) => {
208
+ this.drainingResolve = () => {
209
+ this.cleanup();
210
+ this.emit({ type: "pool:drained" });
211
+ resolve();
212
+ };
213
+ const timer = setTimeout(() => {
214
+ for (const [, slot] of this.workers) {
215
+ slot.currentTask?.abortController.abort(
216
+ new Error("Pool drain timeout")
217
+ );
218
+ slot.state = "dead";
219
+ if (slot.wakeResolve) {
220
+ slot.wakeResolve();
221
+ slot.wakeResolve = null;
222
+ }
223
+ }
224
+ this.cleanup();
225
+ reject(new Error(`Drain timeout after ${timeoutMs}ms`));
226
+ }, timeoutMs);
227
+ const originalResolve = this.drainingResolve;
228
+ this.drainingResolve = () => {
229
+ clearTimeout(timer);
230
+ originalResolve();
231
+ };
232
+ for (const [, slot] of this.workers) {
233
+ if (slot.state === "idle" && slot.wakeResolve) {
234
+ slot.wakeResolve();
235
+ slot.wakeResolve = null;
236
+ }
237
+ }
238
+ });
239
+ }
240
+ getMetrics() {
241
+ let active = 0;
242
+ let idle = 0;
243
+ for (const slot of this.workers.values()) {
244
+ if (slot.state === "busy") active++;
245
+ else if (slot.state === "idle") idle++;
246
+ }
247
+ const now = Date.now();
248
+ const windowMs = 6e4;
249
+ const recentCompletions = this.completionTimestamps.filter(
250
+ (t) => now - t < windowMs
251
+ );
252
+ const sorted = [...this.latencies].sort((a, b) => a - b);
253
+ const p = (pct) => {
254
+ if (sorted.length === 0) return 0;
255
+ const idx = Math.min(
256
+ Math.floor(pct / 100 * sorted.length),
257
+ sorted.length - 1
258
+ );
259
+ return sorted[idx];
260
+ };
261
+ return {
262
+ activeWorkers: active,
263
+ idleWorkers: idle,
264
+ queueDepth: this.queue.size,
265
+ totalCompleted: this.totalCompleted,
266
+ totalFailed: this.totalFailed,
267
+ throughputPerSecond: recentCompletions.length > 0 ? recentCompletions.length / (windowMs / 1e3) : 0,
268
+ latencyP50Ms: p(50),
269
+ latencyP95Ms: p(95),
270
+ latencyP99Ms: p(99),
271
+ utilizationRatio: this.workers.size > 0 ? active / this.workers.size : 0,
272
+ workStealCount: this.workStealCount
273
+ };
274
+ }
275
+ // ── Worker lifecycle ───────────────────────────────────────────────────────
276
+ spawnWorker() {
277
+ const id = this.nextWorkerId++;
278
+ const slot = {
279
+ state: "idle",
280
+ currentTask: null,
281
+ idleSince: Date.now(),
282
+ wakeResolve: null
283
+ };
284
+ this.workers.set(id, slot);
285
+ this.emit({
286
+ type: "worker:spawned",
287
+ workerId: id,
288
+ poolSize: this.workers.size
289
+ });
290
+ this.workerLoop(id).catch(() => {
291
+ });
292
+ }
293
+ removeWorker(id, reason) {
294
+ const slot = this.workers.get(id);
295
+ if (!slot) return;
296
+ slot.state = "dead";
297
+ if (slot.wakeResolve) {
298
+ slot.wakeResolve();
299
+ slot.wakeResolve = null;
300
+ }
301
+ this.workers.delete(id);
302
+ this.emit({
303
+ type: "worker:removed",
304
+ workerId: id,
305
+ poolSize: this.workers.size,
306
+ reason
307
+ });
308
+ }
309
+ async workerLoop(workerId) {
310
+ const slot = this.workers.get(workerId);
311
+ while (slot.state !== "dead") {
312
+ const task = this.queue.dequeue();
313
+ if (!task) {
314
+ slot.state = "idle";
315
+ slot.idleSince = Date.now();
316
+ if (this.draining && this.allIdle() && this.queue.size === 0) {
317
+ this.drainingResolve?.();
318
+ return;
319
+ }
320
+ await new Promise((resolve) => {
321
+ slot.wakeResolve = resolve;
322
+ });
323
+ if (slot.state === "dead") return;
324
+ continue;
325
+ }
326
+ this.workStealCount++;
327
+ slot.state = "busy";
328
+ slot.currentTask = task;
329
+ this.emit({ type: "task:started", taskId: task.id, workerId });
330
+ const startMs = Date.now();
331
+ try {
332
+ const result = await this.executeWithTimeout(task, workerId);
333
+ const durationMs = Date.now() - startMs;
334
+ this.latencies.push(durationMs);
335
+ this.completionTimestamps.push(Date.now());
336
+ if (this.latencies.length > _WorkerPool.MAX_METRICS_ENTRIES) {
337
+ this.latencies.splice(0, this.latencies.length - _WorkerPool.MAX_METRICS_ENTRIES);
338
+ }
339
+ if (this.completionTimestamps.length > _WorkerPool.MAX_METRICS_ENTRIES) {
340
+ this.completionTimestamps.splice(0, this.completionTimestamps.length - _WorkerPool.MAX_METRICS_ENTRIES);
341
+ }
342
+ this.totalCompleted++;
343
+ this.emit({
344
+ type: "task:completed",
345
+ taskId: task.id,
346
+ result,
347
+ durationMs
348
+ });
349
+ task.resolve(result);
350
+ } catch (error) {
351
+ const durationMs = Date.now() - startMs;
352
+ this.latencies.push(durationMs);
353
+ this.totalFailed++;
354
+ const err = error instanceof Error ? error : new Error(String(error));
355
+ this.emit({
356
+ type: "task:failed",
357
+ taskId: task.id,
358
+ error: err,
359
+ durationMs
360
+ });
361
+ task.reject(err);
362
+ } finally {
363
+ slot.currentTask = null;
364
+ }
365
+ }
366
+ }
367
+ executeWithTimeout(task, workerId) {
368
+ return new Promise((resolve, reject) => {
369
+ let settled = false;
370
+ const timer = setTimeout(() => {
371
+ if (!settled) {
372
+ settled = true;
373
+ task.abortController.abort(
374
+ new Error(`Task timeout after ${this.config.taskTimeoutMs}ms`)
375
+ );
376
+ this.emit({
377
+ type: "task:timeout",
378
+ taskId: task.id,
379
+ workerId
380
+ });
381
+ reject(
382
+ new Error(`Task "${task.id}" timed out after ${this.config.taskTimeoutMs}ms`)
383
+ );
384
+ }
385
+ }, this.config.taskTimeoutMs);
386
+ this.executor(task.input, task.abortController.signal).then(
387
+ (result) => {
388
+ if (!settled) {
389
+ settled = true;
390
+ clearTimeout(timer);
391
+ resolve(result);
392
+ }
393
+ },
394
+ (error) => {
395
+ if (!settled) {
396
+ settled = true;
397
+ clearTimeout(timer);
398
+ reject(error);
399
+ }
400
+ }
401
+ );
402
+ });
403
+ }
404
+ // ── Autoscaling ────────────────────────────────────────────────────────────
405
+ autoscale() {
406
+ const now = Date.now();
407
+ let active = 0;
408
+ let idle = 0;
409
+ for (const slot of this.workers.values()) {
410
+ if (slot.state === "busy") active++;
411
+ else if (slot.state === "idle") idle++;
412
+ }
413
+ if (this.queue.size > this.config.growThreshold && idle === 0 && this.workers.size < this.config.maxSize) {
414
+ const toAdd = Math.min(
415
+ Math.ceil(this.queue.size / 2),
416
+ this.config.maxSize - this.workers.size
417
+ );
418
+ for (let i = 0; i < toAdd; i++) this.spawnWorker();
419
+ }
420
+ if (idle > 1 && this.workers.size > this.config.minSize) {
421
+ for (const [id, slot] of this.workers) {
422
+ if (slot.state === "idle" && now - slot.idleSince > this.config.idleShrinkMs && this.workers.size > this.config.minSize) {
423
+ this.removeWorker(id, "idle-timeout");
424
+ }
425
+ }
426
+ }
427
+ }
428
+ // ── Health monitoring ──────────────────────────────────────────────────────
429
+ startHeartbeatMonitor() {
430
+ this.heartbeatTimer = setInterval(() => {
431
+ this.autoscale();
432
+ }, this.config.heartbeatIntervalMs);
433
+ }
434
+ // ── Helpers ────────────────────────────────────────────────────────────────
435
+ wakeOneIdleWorker() {
436
+ for (const [, slot] of this.workers) {
437
+ if (slot.state === "idle" && slot.wakeResolve) {
438
+ slot.wakeResolve();
439
+ slot.wakeResolve = null;
440
+ return;
441
+ }
442
+ }
443
+ }
444
+ allIdle() {
445
+ for (const slot of this.workers.values()) {
446
+ if (slot.state === "busy") return false;
447
+ }
448
+ return true;
449
+ }
450
+ emit(event) {
451
+ this.onEvent?.(event);
452
+ }
453
+ cleanup() {
454
+ if (this.heartbeatTimer) {
455
+ clearInterval(this.heartbeatTimer);
456
+ this.heartbeatTimer = null;
457
+ }
458
+ for (const [id] of this.workers) {
459
+ const slot = this.workers.get(id);
460
+ slot.state = "dead";
461
+ if (slot.wakeResolve) {
462
+ slot.wakeResolve();
463
+ slot.wakeResolve = null;
464
+ }
465
+ }
466
+ }
467
+ };
468
+
469
+ // src/graph/async-channel.ts
470
+ var AsyncChannel = class {
471
+ buffer = [];
472
+ waiters = [];
473
+ closed = false;
474
+ push(value) {
475
+ if (this.closed) return;
476
+ if (this.waiters.length > 0) {
477
+ const waiter = this.waiters.shift();
478
+ waiter.resolve({ value, done: false });
479
+ } else {
480
+ this.buffer.push(value);
481
+ }
482
+ }
483
+ close() {
484
+ if (this.closed) return;
485
+ this.closed = true;
486
+ for (const waiter of this.waiters) {
487
+ waiter.resolve({ value: void 0, done: true });
488
+ }
489
+ this.waiters = [];
490
+ }
491
+ get isClosed() {
492
+ return this.closed;
493
+ }
494
+ [Symbol.asyncIterator]() {
495
+ return {
496
+ next: () => {
497
+ if (this.buffer.length > 0) {
498
+ return Promise.resolve({ value: this.buffer.shift(), done: false });
499
+ }
500
+ if (this.closed) {
501
+ return Promise.resolve({
502
+ value: void 0,
503
+ done: true
504
+ });
505
+ }
506
+ return new Promise((resolve) => {
507
+ this.waiters.push({ resolve });
508
+ });
509
+ }
510
+ };
511
+ }
512
+ };
513
+
514
+ // src/graph/incremental-ready-tracker.ts
515
+ var IncrementalReadyTracker = class {
516
+ /** nodeId → number of pending (uncompleted) dependencies */
517
+ pendingDeps;
518
+ /** nodeId → list of successor nodeIds (reverse edges) */
519
+ successors;
520
+ /** Callback invoked when a node becomes ready (all deps satisfied) */
521
+ onReady;
522
+ constructor(edges, allNodeIds, onReady) {
523
+ this.onReady = onReady;
524
+ this.pendingDeps = /* @__PURE__ */ new Map();
525
+ this.successors = /* @__PURE__ */ new Map();
526
+ for (const nodeId of allNodeIds) {
527
+ const deps = edges.get(nodeId) ?? [];
528
+ this.pendingDeps.set(nodeId, deps.length);
529
+ for (const dep of deps) {
530
+ let succ = this.successors.get(dep);
531
+ if (!succ) {
532
+ succ = [];
533
+ this.successors.set(dep, succ);
534
+ }
535
+ succ.push(nodeId);
536
+ }
537
+ }
538
+ }
539
+ /** Emit all nodes with zero dependencies */
540
+ seedInitialReady() {
541
+ for (const [nodeId, count] of this.pendingDeps) {
542
+ if (count === 0) {
543
+ this.onReady(nodeId);
544
+ }
545
+ }
546
+ }
547
+ /** Mark a node as completed; returns list of newly-ready successors */
548
+ markCompleted(nodeId) {
549
+ const newlyReady = [];
550
+ const succs = this.successors.get(nodeId) ?? [];
551
+ for (const succ of succs) {
552
+ const remaining = this.pendingDeps.get(succ) - 1;
553
+ this.pendingDeps.set(succ, remaining);
554
+ if (remaining === 0) {
555
+ newlyReady.push(succ);
556
+ this.onReady(succ);
557
+ }
558
+ }
559
+ return newlyReady;
560
+ }
561
+ /** Snapshot current pending-deps state for checkpoint */
562
+ snapshot() {
563
+ return new Map(this.pendingDeps);
564
+ }
565
+ /** Restore from a previously taken snapshot */
566
+ restoreFrom(snap) {
567
+ for (const [k, v] of snap) {
568
+ this.pendingDeps.set(k, v);
569
+ }
570
+ }
571
+ };
572
+
573
+ // src/graph/token-budget-controller.ts
574
+ var DEFAULT_BUDGET_CONFIG = {
575
+ softLimitRatio: 0.8,
576
+ hardLimitRatio: 0.95,
577
+ estimatedTokensPerNode: 5e3
578
+ };
579
+ var TokenBudgetController = class {
580
+ config;
581
+ reserved = 0;
582
+ consumed = 0;
583
+ recentUsages = [];
584
+ constructor(totalBudget, config) {
585
+ this.config = { ...DEFAULT_BUDGET_CONFIG, totalBudget, ...config };
586
+ }
587
+ /**
588
+ * Reserve budget BEFORE executing a node.
589
+ * Returns whether it was granted and an optional throttle delay.
590
+ */
591
+ acquire(_nodeId) {
592
+ const estimated = this.config.estimatedTokensPerNode;
593
+ const projected = this.consumed + this.reserved + estimated;
594
+ const ratio = projected / this.config.totalBudget;
595
+ if (ratio > this.config.hardLimitRatio) {
596
+ return { granted: false, delayMs: 0 };
597
+ }
598
+ if (ratio > this.config.softLimitRatio) {
599
+ const pressure = (ratio - this.config.softLimitRatio) / (this.config.hardLimitRatio - this.config.softLimitRatio);
600
+ const delayMs = Math.round(pressure * 5e3);
601
+ this.reserved += estimated;
602
+ return { granted: true, delayMs };
603
+ }
604
+ this.reserved += estimated;
605
+ return { granted: true, delayMs: 0 };
606
+ }
607
+ /**
608
+ * Finalize actual consumption. Moves tokens from reserved to consumed.
609
+ */
610
+ release(actual) {
611
+ this.reserved = Math.max(
612
+ 0,
613
+ this.reserved - this.config.estimatedTokensPerNode
614
+ );
615
+ this.consumed += actual.input + actual.output;
616
+ this.updateEstimate(actual.input + actual.output);
617
+ }
618
+ /** Check current budget status without reserving */
619
+ check(usage) {
620
+ const total = usage.input + usage.output;
621
+ const ratio = total / this.config.totalBudget;
622
+ if (ratio >= this.config.hardLimitRatio) return "hard-limit";
623
+ if (ratio >= this.config.softLimitRatio) return "soft-limit";
624
+ return "ok";
625
+ }
626
+ /** Remaining budget (total - consumed - reserved) */
627
+ remaining() {
628
+ return Math.max(
629
+ 0,
630
+ this.config.totalBudget - this.consumed - this.reserved
631
+ );
632
+ }
633
+ /** Estimated number of nodes that can still execute */
634
+ estimatedRemainingNodes() {
635
+ return Math.floor(this.remaining() / this.config.estimatedTokensPerNode);
636
+ }
637
+ /** Rolling average of last N executions to refine estimates */
638
+ updateEstimate(actual) {
639
+ this.recentUsages.push(actual);
640
+ if (this.recentUsages.length > 20) this.recentUsages.shift();
641
+ this.config.estimatedTokensPerNode = Math.ceil(
642
+ this.recentUsages.reduce((a, b) => a + b, 0) / this.recentUsages.length
643
+ );
644
+ }
645
+ };
646
+
647
+ // src/graph/fork-coordinator.ts
648
+ var ForkCoordinator = class {
649
+ constructor(forkId, nodeIds, timeoutMs, minResults, onPartial) {
650
+ this.forkId = forkId;
651
+ this.minResults = minResults;
652
+ this.onPartial = onPartial;
653
+ this.total = nodeIds.length;
654
+ this.promise = new Promise((resolve, reject) => {
655
+ this.resolveAll = resolve;
656
+ this.rejectAll = reject;
657
+ });
658
+ this.timeoutTimer = setTimeout(() => {
659
+ if (this.settled) return;
660
+ if (this.results.size >= this.minResults) {
661
+ this.settle();
662
+ this.resolveAll([...this.results.values()]);
663
+ } else {
664
+ this.settle();
665
+ this.rejectAll(
666
+ new Error(
667
+ `Fork "${forkId}" timeout: only ${this.results.size}/${this.total} completed (minimum: ${this.minResults})`
668
+ )
669
+ );
670
+ }
671
+ }, timeoutMs);
672
+ }
673
+ results = /* @__PURE__ */ new Map();
674
+ errors = /* @__PURE__ */ new Map();
675
+ total;
676
+ resolveAll;
677
+ rejectAll;
678
+ promise;
679
+ timeoutTimer;
680
+ settled = false;
681
+ onNodeComplete(nodeId, result) {
682
+ if (this.settled) return;
683
+ this.results.set(nodeId, result);
684
+ this.onPartial?.([...this.results.values()]);
685
+ if (this.results.size === this.total) {
686
+ this.settle();
687
+ this.resolveAll([...this.results.values()]);
688
+ } else {
689
+ this.tryEagerResolve();
690
+ }
691
+ }
692
+ onNodeError(nodeId, error) {
693
+ if (this.settled) return;
694
+ this.errors.set(nodeId, error);
695
+ if (this.errors.size > this.total - this.minResults) {
696
+ this.settle();
697
+ this.rejectAll(
698
+ new Error(
699
+ `Fork "${this.forkId}": too many failures (${this.errors.size}/${this.total})`
700
+ )
701
+ );
702
+ } else {
703
+ this.tryEagerResolve();
704
+ }
705
+ }
706
+ /** Eagerly resolve when all nodes reported and we have enough successes */
707
+ tryEagerResolve() {
708
+ if (this.settled) return;
709
+ if (this.results.size + this.errors.size === this.total && this.results.size >= this.minResults) {
710
+ this.settle();
711
+ this.resolveAll([...this.results.values()]);
712
+ }
713
+ }
714
+ dispose() {
715
+ this.settle();
716
+ }
717
+ settle() {
718
+ if (this.settled) return;
719
+ this.settled = true;
720
+ if (this.timeoutTimer) {
721
+ clearTimeout(this.timeoutTimer);
722
+ this.timeoutTimer = void 0;
723
+ }
724
+ }
725
+ };
726
+
727
+ // src/graph/graph-executor.ts
728
+ var GraphExecutor = class _GraphExecutor {
729
+ constructor(nodes, edges, forks, config, sharedContext, eventBus, telemetry) {
730
+ this.nodes = nodes;
731
+ this.edges = edges;
732
+ this.forks = forks;
733
+ this.config = config;
734
+ this.sharedContext = sharedContext;
735
+ this.eventBus = eventBus;
736
+ this.telemetry = telemetry;
737
+ }
738
+ static CHECKPOINT_INTERVAL = 5;
739
+ async execute(prompt) {
740
+ let result;
741
+ for await (const event of this.stream(prompt)) {
742
+ if (event.type === "graph:complete") {
743
+ result = event.result;
744
+ }
745
+ if (event.type === "graph:error") {
746
+ throw new Error(event.error);
747
+ }
748
+ }
749
+ if (!result) throw new Error("Graph execution produced no result");
750
+ return result;
751
+ }
752
+ async *stream(prompt) {
753
+ const start = Date.now();
754
+ const nodeResults = /* @__PURE__ */ new Map();
755
+ let totalInput = 0;
756
+ let totalOutput = 0;
757
+ let completedCount = 0;
758
+ const totalNodes = this.nodes.size;
759
+ let terminated = false;
760
+ const channel = new AsyncChannel();
761
+ const budgetCtrl = new TokenBudgetController(this.config.maxTokenBudget);
762
+ const pool = new WorkerPool(
763
+ async (task, signal) => {
764
+ const { nodeId } = task;
765
+ this.eventBus?.emit("node:start", { nodeId });
766
+ channel.push({ type: "node:start", nodeId });
767
+ const nodeSpan = this.telemetry?.startSpan(
768
+ `graph.node.${nodeId}`,
769
+ { "node.id": nodeId }
770
+ );
771
+ try {
772
+ const fork = this.forks.get(nodeId);
773
+ if (fork) {
774
+ const result2 = await this.executeForkTask(
775
+ nodeId,
776
+ prompt,
777
+ fork,
778
+ nodeResults,
779
+ channel
780
+ );
781
+ nodeSpan?.setAttribute("node.duration_ms", result2.durationMs);
782
+ nodeSpan?.setStatus("OK");
783
+ return result2;
784
+ }
785
+ const node = this.nodes.get(nodeId);
786
+ if (!node) throw new Error(`Node "${nodeId}" not found`);
787
+ const enrichedPrompt = this.buildNodePrompt(prompt, nodeId, nodeResults);
788
+ const result = await node.run(enrichedPrompt, this.sharedContext);
789
+ nodeSpan?.setAttribute("node.duration_ms", result.durationMs);
790
+ nodeSpan?.setStatus("OK");
791
+ return result;
792
+ } catch (error) {
793
+ const errorMsg = error instanceof Error ? error.message : String(error);
794
+ nodeSpan?.setStatus("ERROR", errorMsg);
795
+ throw error;
796
+ } finally {
797
+ nodeSpan?.end();
798
+ }
799
+ },
800
+ {
801
+ initialSize: this.config.maxConcurrency,
802
+ minSize: 1,
803
+ maxSize: this.config.maxConcurrency,
804
+ taskTimeoutMs: 6e5,
805
+ heartbeatIntervalMs: 6e4,
806
+ idleShrinkMs: 3e4,
807
+ growThreshold: 10
808
+ }
809
+ );
810
+ const emitError = (errorMsg) => {
811
+ if (terminated) return;
812
+ terminated = true;
813
+ const partialResults = {};
814
+ for (const [id, r] of nodeResults) {
815
+ partialResults[id] = r;
816
+ }
817
+ this.eventBus?.emit("graph:complete", {
818
+ totalDurationMs: Date.now() - start,
819
+ totalTokenUsage: { input: totalInput, output: totalOutput },
820
+ error: errorMsg
821
+ });
822
+ channel.push({ type: "graph:error", error: errorMsg, partialResults });
823
+ channel.close();
824
+ };
825
+ const emitCompletion = () => {
826
+ if (terminated) return;
827
+ terminated = true;
828
+ const lastNodeId = this.findTerminalNode();
829
+ const lastResult = nodeResults.get(lastNodeId);
830
+ const resultMap = {};
831
+ for (const [id, r] of nodeResults) {
832
+ resultMap[id] = r;
833
+ }
834
+ const result = {
835
+ output: lastResult.output,
836
+ nodeResults: resultMap,
837
+ totalDurationMs: Date.now() - start,
838
+ totalTokenUsage: { input: totalInput, output: totalOutput }
839
+ };
840
+ this.eventBus?.emit("graph:complete", {
841
+ totalDurationMs: result.totalDurationMs,
842
+ totalTokenUsage: result.totalTokenUsage
843
+ });
844
+ channel.push({ type: "graph:complete", result });
845
+ channel.close();
846
+ };
847
+ const tracker = new IncrementalReadyTracker(
848
+ this.edges,
849
+ this.nodes.keys(),
850
+ (nodeId) => {
851
+ if (nodeResults.has(nodeId) || terminated) return;
852
+ pool.submit(nodeId, { nodeId, prompt }, 0).then((result) => {
853
+ if (terminated) return;
854
+ nodeResults.set(result.nodeId, result);
855
+ completedCount++;
856
+ if (result.tokenUsage) {
857
+ totalInput += result.tokenUsage.input;
858
+ totalOutput += result.tokenUsage.output;
859
+ budgetCtrl.release(result.tokenUsage);
860
+ }
861
+ this.eventBus?.emit("node:complete", { nodeId, result });
862
+ channel.push({ type: "node:complete", nodeId, result });
863
+ if (totalInput + totalOutput > this.config.maxTokenBudget) {
864
+ emitError("Token budget exceeded");
865
+ return;
866
+ }
867
+ const budgetStatus = budgetCtrl.check({ input: totalInput, output: totalOutput });
868
+ if (budgetStatus === "soft-limit") {
869
+ channel.push({
870
+ type: "budget:warning",
871
+ remaining: budgetCtrl.remaining(),
872
+ used: totalInput + totalOutput,
873
+ threshold: "soft"
874
+ });
875
+ } else if (budgetStatus === "hard-limit") {
876
+ channel.push({
877
+ type: "budget:warning",
878
+ remaining: budgetCtrl.remaining(),
879
+ used: totalInput + totalOutput,
880
+ threshold: "hard"
881
+ });
882
+ }
883
+ if (completedCount % _GraphExecutor.CHECKPOINT_INTERVAL === 0 && completedCount < totalNodes) {
884
+ const cp = {
885
+ completedNodes: new Map(nodeResults),
886
+ pendingDepsSnapshot: tracker.snapshot(),
887
+ tokenUsage: { input: totalInput, output: totalOutput },
888
+ elapsedMs: Date.now() - start,
889
+ prompt
890
+ };
891
+ channel.push({
892
+ type: "checkpoint:saved",
893
+ checkpoint: JSON.stringify({
894
+ completedNodeIds: [...cp.completedNodes.keys()],
895
+ tokenUsage: cp.tokenUsage,
896
+ elapsedMs: cp.elapsedMs
897
+ }),
898
+ completedCount
899
+ });
900
+ }
901
+ tracker.markCompleted(nodeId);
902
+ if (completedCount === totalNodes) {
903
+ emitCompletion();
904
+ }
905
+ }).catch((error) => {
906
+ if (terminated) return;
907
+ const errorMsg = error instanceof Error ? error.message : String(error);
908
+ this.eventBus?.emit("node:complete", { nodeId, error: errorMsg });
909
+ channel.push({ type: "node:error", nodeId, error: errorMsg });
910
+ emitError(errorMsg);
911
+ });
912
+ }
913
+ );
914
+ this.eventBus?.emit("graph:start", { nodeCount: totalNodes });
915
+ yield { type: "graph:start", nodeCount: totalNodes };
916
+ tracker.seedInitialReady();
917
+ if (completedCount === 0 && totalNodes > 0 && terminated === false) {
918
+ let hasZeroDeps = false;
919
+ for (const nodeId of this.nodes.keys()) {
920
+ const deps = this.edges.get(nodeId) ?? [];
921
+ if (deps.length === 0) {
922
+ hasZeroDeps = true;
923
+ break;
924
+ }
925
+ }
926
+ if (!hasZeroDeps) {
927
+ emitError("Deadlock: no nodes ready but graph incomplete");
928
+ }
929
+ }
930
+ const timeoutTimer = setTimeout(() => {
931
+ emitError("Graph execution timed out");
932
+ }, this.config.timeoutMs);
933
+ try {
934
+ for await (const event of channel) {
935
+ yield event;
936
+ if (event.type === "graph:complete" || event.type === "graph:error") {
937
+ break;
938
+ }
939
+ }
940
+ } finally {
941
+ clearTimeout(timeoutTimer);
942
+ await pool.drain(5e3).catch(() => {
943
+ });
944
+ }
945
+ }
946
+ // ── Fork execution with ForkCoordinator ──
947
+ async executeForkTask(forkId, prompt, fork, previousResults, channel) {
948
+ const forkStart = Date.now();
949
+ const enrichedPrompt = this.buildNodePrompt(prompt, forkId, previousResults);
950
+ this.eventBus?.emit("fork:start", { forkId, agentCount: fork.nodes.length });
951
+ channel.push({ type: "fork:start", forkId, agentCount: fork.nodes.length });
952
+ const coordinator = new ForkCoordinator(
953
+ forkId,
954
+ fork.nodes.map((n) => n.id),
955
+ Math.max(this.config.timeoutMs / 2, 5e3),
956
+ Math.max(1, Math.ceil(fork.nodes.length / 2)),
957
+ (partial) => {
958
+ channel.push({
959
+ type: "fork:partial",
960
+ forkId,
961
+ completedCount: partial.length,
962
+ totalCount: fork.nodes.length,
963
+ partialResults: partial
964
+ });
965
+ }
966
+ );
967
+ const promises = fork.nodes.map(async (node) => {
968
+ try {
969
+ const result2 = await node.run(enrichedPrompt, this.sharedContext);
970
+ coordinator.onNodeComplete(node.id, result2);
971
+ } catch (error) {
972
+ coordinator.onNodeError(
973
+ node.id,
974
+ error instanceof Error ? error : new Error(String(error))
975
+ );
976
+ }
977
+ });
978
+ let results;
979
+ try {
980
+ results = await coordinator.promise;
981
+ await Promise.allSettled(promises);
982
+ } catch (error) {
983
+ await Promise.allSettled(promises);
984
+ coordinator.dispose();
985
+ this.eventBus?.emit("fork:complete", {
986
+ forkId,
987
+ error: error instanceof Error ? error.message : String(error)
988
+ });
989
+ channel.push({ type: "fork:complete", forkId, results: [] });
990
+ throw error;
991
+ }
992
+ this.eventBus?.emit("fork:complete", { forkId, resultCount: results.length });
993
+ channel.push({ type: "fork:complete", forkId, results });
994
+ let output;
995
+ let tokenUsage = { input: 0, output: 0 };
996
+ for (const r of results) {
997
+ if (r.tokenUsage) {
998
+ tokenUsage.input += r.tokenUsage.input;
999
+ tokenUsage.output += r.tokenUsage.output;
1000
+ }
1001
+ }
1002
+ if (fork.consensus) {
1003
+ this.eventBus?.emit("consensus:start", { forkId });
1004
+ channel.push({ type: "consensus:start", forkId });
1005
+ try {
1006
+ const consensusInput = results.map((r) => ({
1007
+ id: r.nodeId,
1008
+ output: r.output
1009
+ }));
1010
+ const consensusResult = await fork.consensus.evaluate(consensusInput);
1011
+ this.eventBus?.emit("consensus:result", {
1012
+ forkId,
1013
+ winnerId: consensusResult.winnerId,
1014
+ merged: !!consensusResult.merged
1015
+ });
1016
+ output = consensusResult.merged ?? consensusResult.winnerOutput;
1017
+ channel.push({ type: "consensus:result", forkId, output });
1018
+ } catch (error) {
1019
+ this.eventBus?.emit("consensus:result", {
1020
+ forkId,
1021
+ error: error instanceof Error ? error.message : String(error)
1022
+ });
1023
+ channel.push({ type: "consensus:result", forkId, output: "" });
1024
+ coordinator.dispose();
1025
+ throw error;
1026
+ }
1027
+ } else {
1028
+ output = results[0].output;
1029
+ }
1030
+ const result = {
1031
+ nodeId: forkId,
1032
+ output,
1033
+ tokenUsage,
1034
+ durationMs: Date.now() - forkStart
1035
+ };
1036
+ await this.sharedContext.setNodeResult(forkId, output);
1037
+ coordinator.dispose();
1038
+ return result;
1039
+ }
1040
+ // ── Helpers ──
1041
+ buildNodePrompt(basePrompt, nodeId, previousResults) {
1042
+ const deps = this.edges.get(nodeId) ?? [];
1043
+ if (deps.length === 0) return basePrompt;
1044
+ const context = deps.map((depId) => {
1045
+ const r = previousResults.get(depId);
1046
+ return r ? `[${depId}]: ${r.output}` : "";
1047
+ }).filter(Boolean).join("\n\n");
1048
+ return `${basePrompt}
1049
+
1050
+ --- Previous results ---
1051
+ ${context}`;
1052
+ }
1053
+ findTerminalNode() {
1054
+ const isDependency = /* @__PURE__ */ new Set();
1055
+ for (const deps of this.edges.values()) {
1056
+ for (const d of deps) isDependency.add(d);
1057
+ }
1058
+ for (const nodeId of this.nodes.keys()) {
1059
+ if (!isDependency.has(nodeId)) return nodeId;
1060
+ }
1061
+ return [...this.nodes.keys()].pop();
1062
+ }
1063
+ };
1064
+
1065
+ // src/graph/shared-context.ts
1066
+ var VersionConflictError = class extends Error {
1067
+ constructor(key, expected, actual) {
1068
+ super(
1069
+ `Version conflict on "${key}": expected ${expected}, actual ${actual}`
1070
+ );
1071
+ this.name = "VersionConflictError";
1072
+ }
1073
+ };
1074
+ var SharedContext = class _SharedContext {
1075
+ constructor(fs, namespace = "/.shared", parent) {
1076
+ this.fs = fs;
1077
+ this.namespace = namespace;
1078
+ this.parent = parent;
1079
+ }
1080
+ watchers = /* @__PURE__ */ new Map();
1081
+ versions = /* @__PURE__ */ new Map();
1082
+ parent;
1083
+ // ---- helpers ------------------------------------------------------------
1084
+ keyPath(key) {
1085
+ return `${this.namespace}/${key}`;
1086
+ }
1087
+ getVersion(key) {
1088
+ return this.versions.get(key) ?? 0;
1089
+ }
1090
+ bumpVersion(key) {
1091
+ const next = this.getVersion(key) + 1;
1092
+ this.versions.set(key, next);
1093
+ return next;
1094
+ }
1095
+ // ---- notify watchers ----------------------------------------------------
1096
+ notify(change) {
1097
+ const keyHandlers = this.watchers.get(change.key);
1098
+ const wildHandlers = this.watchers.get("*");
1099
+ if (keyHandlers) {
1100
+ for (const h of keyHandlers) h(change);
1101
+ }
1102
+ if (wildHandlers) {
1103
+ for (const h of wildHandlers) h(change);
1104
+ }
1105
+ if (this.parent) {
1106
+ this.parent.notify(change);
1107
+ }
1108
+ }
1109
+ // ---- original API (backward compatible) ---------------------------------
1110
+ async set(key, value) {
1111
+ const oldValue = await this.get(key);
1112
+ await this.fs.write(this.keyPath(key), JSON.stringify(value));
1113
+ const version = this.bumpVersion(key);
1114
+ this.notify({
1115
+ key,
1116
+ oldValue,
1117
+ newValue: value,
1118
+ version,
1119
+ source: this.namespace,
1120
+ timestamp: Date.now()
1121
+ });
1122
+ }
1123
+ async get(key) {
1124
+ const path = this.keyPath(key);
1125
+ if (!await this.fs.exists(path)) return null;
1126
+ const raw = await this.fs.read(path);
1127
+ return JSON.parse(raw);
1128
+ }
1129
+ async delete(key) {
1130
+ const path = this.keyPath(key);
1131
+ if (await this.fs.exists(path)) {
1132
+ const oldValue = await this.get(key);
1133
+ await this.fs.delete(path);
1134
+ const version = this.bumpVersion(key);
1135
+ this.notify({
1136
+ key,
1137
+ oldValue,
1138
+ newValue: void 0,
1139
+ version,
1140
+ source: this.namespace,
1141
+ timestamp: Date.now()
1142
+ });
1143
+ }
1144
+ }
1145
+ async list() {
1146
+ if (!await this.fs.exists(this.namespace)) return [];
1147
+ const entries = await this.fs.list(this.namespace);
1148
+ return entries.filter((e) => !e.isDirectory).map((e) => e.name);
1149
+ }
1150
+ async getNodeResult(nodeId) {
1151
+ return this.get(`results/${nodeId}`);
1152
+ }
1153
+ async setNodeResult(nodeId, result) {
1154
+ await this.set(`results/${nodeId}`, result);
1155
+ }
1156
+ // ---- watchers -----------------------------------------------------------
1157
+ /**
1158
+ * Subscribe to changes on a specific key, or use "*" for all changes.
1159
+ * Returns an unsubscribe function.
1160
+ */
1161
+ watch(key, handler) {
1162
+ let handlers = this.watchers.get(key);
1163
+ if (!handlers) {
1164
+ handlers = /* @__PURE__ */ new Set();
1165
+ this.watchers.set(key, handlers);
1166
+ }
1167
+ handlers.add(handler);
1168
+ return () => {
1169
+ handlers.delete(handler);
1170
+ if (handlers.size === 0) this.watchers.delete(key);
1171
+ };
1172
+ }
1173
+ // ---- versioning (optimistic locking) ------------------------------------
1174
+ async getVersioned(key) {
1175
+ const value = await this.get(key);
1176
+ if (value === null) return null;
1177
+ return { value, version: this.getVersion(key) };
1178
+ }
1179
+ async setVersioned(key, value, expectedVersion) {
1180
+ const actual = this.getVersion(key);
1181
+ if (actual !== expectedVersion) {
1182
+ throw new VersionConflictError(key, expectedVersion, actual);
1183
+ }
1184
+ this.bumpVersion(key);
1185
+ const oldValue = await this.get(key);
1186
+ await this.fs.write(this.keyPath(key), JSON.stringify(value));
1187
+ this.notify({
1188
+ key,
1189
+ oldValue,
1190
+ newValue: value,
1191
+ version: this.getVersion(key),
1192
+ source: this.namespace,
1193
+ timestamp: Date.now()
1194
+ });
1195
+ }
1196
+ // ---- CRDT merge ---------------------------------------------------------
1197
+ /**
1198
+ * Read-then-write with a merge function using optimistic locking.
1199
+ * Default mergeFn is Last-Writer-Wins (returns newValue).
1200
+ * Retries on version conflict (CAS pattern).
1201
+ */
1202
+ async merge(key, value, mergeFn = (_old, nw) => nw) {
1203
+ const maxRetries = 3;
1204
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
1205
+ const currentVersion = this.getVersion(key);
1206
+ const current = await this.get(key);
1207
+ const merged = mergeFn(current, value);
1208
+ try {
1209
+ await this.setVersioned(key, merged, currentVersion);
1210
+ return;
1211
+ } catch (err) {
1212
+ if (err instanceof VersionConflictError && attempt < maxRetries) {
1213
+ continue;
1214
+ }
1215
+ throw err;
1216
+ }
1217
+ }
1218
+ }
1219
+ // ---- scoping ------------------------------------------------------------
1220
+ createScoped(scope) {
1221
+ return new _SharedContext(this.fs, `${this.namespace}/${scope}`, this);
1222
+ }
1223
+ };
1224
+
1225
+ // src/graph/agent-graph.ts
1226
+ var AgentGraph = class {
1227
+ constructor(nodes, edges, forks, config, fs, eventBus, telemetry) {
1228
+ this.nodes = nodes;
1229
+ this.edges = edges;
1230
+ this.forks = forks;
1231
+ this.config = config;
1232
+ this.fs = fs;
1233
+ this.eventBus = eventBus;
1234
+ this.telemetry = telemetry;
1235
+ }
1236
+ getNodes() {
1237
+ return this.nodes;
1238
+ }
1239
+ getEdges() {
1240
+ return this.edges;
1241
+ }
1242
+ getForks() {
1243
+ return this.forks;
1244
+ }
1245
+ describe() {
1246
+ const nodes = [...this.nodes.values()].map((n) => ({
1247
+ id: n.id,
1248
+ type: n.type
1249
+ }));
1250
+ const edges = [];
1251
+ for (const [to, sources] of this.edges) {
1252
+ for (const from of sources) {
1253
+ edges.push({ from, to });
1254
+ }
1255
+ }
1256
+ const forks = [...this.forks.entries()].map(([id, f]) => ({
1257
+ id,
1258
+ nodeIds: f.nodes.map((n) => n.id)
1259
+ }));
1260
+ return { nodes, edges, forks };
1261
+ }
1262
+ visualize(format = "ascii") {
1263
+ const descriptor = this.describe();
1264
+ if (format === "mermaid") {
1265
+ return new MermaidGraphAdapter().toMermaid(descriptor);
1266
+ }
1267
+ return new AsciiGraphAdapter().toAscii(descriptor);
1268
+ }
1269
+ static create(config) {
1270
+ return new AgentGraphBuilder(config);
1271
+ }
1272
+ async run(prompt) {
1273
+ const sharedContext = new SharedContext(this.fs);
1274
+ const executor = new GraphExecutor(
1275
+ this.nodes,
1276
+ this.edges,
1277
+ this.forks,
1278
+ this.config,
1279
+ sharedContext,
1280
+ this.eventBus,
1281
+ this.telemetry
1282
+ );
1283
+ return executor.execute(prompt);
1284
+ }
1285
+ async *stream(prompt) {
1286
+ const sharedContext = new SharedContext(this.fs);
1287
+ const executor = new GraphExecutor(
1288
+ this.nodes,
1289
+ this.edges,
1290
+ this.forks,
1291
+ this.config,
1292
+ sharedContext,
1293
+ this.eventBus,
1294
+ this.telemetry
1295
+ );
1296
+ yield* executor.stream(prompt);
1297
+ }
1298
+ };
1299
+ var AgentGraphBuilder = class extends AbstractBuilder {
1300
+ nodeMap = /* @__PURE__ */ new Map();
1301
+ edgeMap = /* @__PURE__ */ new Map();
1302
+ forkMap = /* @__PURE__ */ new Map();
1303
+ config;
1304
+ fs;
1305
+ eventBus;
1306
+ telemetryAdapter;
1307
+ constructor(config) {
1308
+ super();
1309
+ this.config = GraphConfigSchema.parse(config ?? {});
1310
+ }
1311
+ node(id, config) {
1312
+ if (this.nodeMap.has(id)) {
1313
+ throw new Error(`Node "${id}" already exists`);
1314
+ }
1315
+ this.nodeMap.set(
1316
+ id,
1317
+ new AgentNode({ id, type: "agent", agentConfig: config })
1318
+ );
1319
+ return this;
1320
+ }
1321
+ edge(from, to) {
1322
+ const deps = this.edgeMap.get(to) ?? [];
1323
+ deps.push(from);
1324
+ this.edgeMap.set(to, deps);
1325
+ return this;
1326
+ }
1327
+ fork(id, configs) {
1328
+ if (configs.length < 2) {
1329
+ throw new Error(`Fork "${id}" requires at least 2 configs`);
1330
+ }
1331
+ if (this.nodeMap.has(id) || this.forkMap.has(id)) {
1332
+ throw new Error(`Node "${id}" already exists`);
1333
+ }
1334
+ const forkNodes = configs.map(
1335
+ (cfg, i) => new AgentNode({
1336
+ id: `${id}__fork_${i}`,
1337
+ type: "agent",
1338
+ agentConfig: cfg
1339
+ })
1340
+ );
1341
+ this.nodeMap.set(
1342
+ id,
1343
+ new AgentNode({ id, type: "agent" })
1344
+ );
1345
+ this.forkMap.set(id, { nodes: forkNodes });
1346
+ return this;
1347
+ }
1348
+ consensus(forkId, strategy) {
1349
+ const fork = this.forkMap.get(forkId);
1350
+ if (!fork) {
1351
+ throw new Error(
1352
+ `Cannot set consensus: "${forkId}" is not a fork node`
1353
+ );
1354
+ }
1355
+ fork.consensus = strategy;
1356
+ return this;
1357
+ }
1358
+ withFilesystem(fs) {
1359
+ this.fs = fs;
1360
+ return this;
1361
+ }
1362
+ withEventBus(eventBus) {
1363
+ this.eventBus = eventBus;
1364
+ return this;
1365
+ }
1366
+ withTelemetry(adapter) {
1367
+ this.telemetryAdapter = adapter;
1368
+ return this;
1369
+ }
1370
+ validate() {
1371
+ this.validateEdges();
1372
+ this.validateNoCycles();
1373
+ }
1374
+ construct() {
1375
+ return new AgentGraph(
1376
+ this.nodeMap,
1377
+ this.edgeMap,
1378
+ this.forkMap,
1379
+ this.config,
1380
+ this.fs ?? new VirtualFilesystem(),
1381
+ this.eventBus,
1382
+ this.telemetryAdapter
1383
+ );
1384
+ }
1385
+ validateEdges() {
1386
+ for (const [to, deps] of this.edgeMap) {
1387
+ if (!this.nodeMap.has(to)) {
1388
+ throw new Error(`Edge target "${to}" does not exist`);
1389
+ }
1390
+ for (const from of deps) {
1391
+ if (!this.nodeMap.has(from)) {
1392
+ throw new Error(`Edge source "${from}" does not exist`);
1393
+ }
1394
+ }
1395
+ }
1396
+ }
1397
+ validateNoCycles() {
1398
+ const visited = /* @__PURE__ */ new Set();
1399
+ const stack = /* @__PURE__ */ new Set();
1400
+ const visit = (nodeId) => {
1401
+ if (stack.has(nodeId)) {
1402
+ throw new Error(`Cycle detected involving node "${nodeId}"`);
1403
+ }
1404
+ if (visited.has(nodeId)) return;
1405
+ stack.add(nodeId);
1406
+ const deps = this.edgeMap.get(nodeId) ?? [];
1407
+ for (const dep of deps) {
1408
+ visit(dep);
1409
+ }
1410
+ stack.delete(nodeId);
1411
+ visited.add(nodeId);
1412
+ };
1413
+ for (const nodeId of this.nodeMap.keys()) {
1414
+ visit(nodeId);
1415
+ }
1416
+ }
1417
+ };
1418
+ export {
1419
+ AgentGraph,
1420
+ AgentGraphBuilder
1421
+ };
1422
+ //# sourceMappingURL=agent-graph-AMQYAWNF.js.map