@autonome-research/thread-phase 3.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 (263) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +226 -0
  3. package/dist/agent/index.d.ts +28 -0
  4. package/dist/agent/index.d.ts.map +1 -0
  5. package/dist/agent/index.js +28 -0
  6. package/dist/agent/index.js.map +1 -0
  7. package/dist/agent/openai-adapter.d.ts +15 -0
  8. package/dist/agent/openai-adapter.d.ts.map +1 -0
  9. package/dist/agent/openai-adapter.js +57 -0
  10. package/dist/agent/openai-adapter.js.map +1 -0
  11. package/dist/agent/parse-json.d.ts +12 -0
  12. package/dist/agent/parse-json.d.ts.map +1 -0
  13. package/dist/agent/parse-json.js +31 -0
  14. package/dist/agent/parse-json.js.map +1 -0
  15. package/dist/agent/retry.d.ts +15 -0
  16. package/dist/agent/retry.d.ts.map +1 -0
  17. package/dist/agent/retry.js +35 -0
  18. package/dist/agent/retry.js.map +1 -0
  19. package/dist/agent/runner.d.ts +25 -0
  20. package/dist/agent/runner.d.ts.map +1 -0
  21. package/dist/agent/runner.js +270 -0
  22. package/dist/agent/runner.js.map +1 -0
  23. package/dist/agent/stream-consumer.d.ts +57 -0
  24. package/dist/agent/stream-consumer.d.ts.map +1 -0
  25. package/dist/agent/stream-consumer.js +126 -0
  26. package/dist/agent/stream-consumer.js.map +1 -0
  27. package/dist/agent/types.d.ts +135 -0
  28. package/dist/agent/types.d.ts.map +1 -0
  29. package/dist/agent/types.js +9 -0
  30. package/dist/agent/types.js.map +1 -0
  31. package/dist/agent-runner.d.ts +10 -0
  32. package/dist/agent-runner.d.ts.map +1 -0
  33. package/dist/agent-runner.js +10 -0
  34. package/dist/agent-runner.js.map +1 -0
  35. package/dist/agents/capability.d.ts +36 -0
  36. package/dist/agents/capability.d.ts.map +1 -0
  37. package/dist/agents/capability.js +51 -0
  38. package/dist/agents/capability.js.map +1 -0
  39. package/dist/agents/event-bus.d.ts +20 -0
  40. package/dist/agents/event-bus.d.ts.map +1 -0
  41. package/dist/agents/event-bus.js +40 -0
  42. package/dist/agents/event-bus.js.map +1 -0
  43. package/dist/agents/index.d.ts +23 -0
  44. package/dist/agents/index.d.ts.map +1 -0
  45. package/dist/agents/index.js +33 -0
  46. package/dist/agents/index.js.map +1 -0
  47. package/dist/agents/inference-adapter.d.ts +52 -0
  48. package/dist/agents/inference-adapter.d.ts.map +1 -0
  49. package/dist/agents/inference-adapter.js +209 -0
  50. package/dist/agents/inference-adapter.js.map +1 -0
  51. package/dist/agents/job-store-bridge.d.ts +44 -0
  52. package/dist/agents/job-store-bridge.d.ts.map +1 -0
  53. package/dist/agents/job-store-bridge.js +58 -0
  54. package/dist/agents/job-store-bridge.js.map +1 -0
  55. package/dist/agents/memory.d.ts +40 -0
  56. package/dist/agents/memory.d.ts.map +1 -0
  57. package/dist/agents/memory.js +14 -0
  58. package/dist/agents/memory.js.map +1 -0
  59. package/dist/agents/protocol.d.ts +302 -0
  60. package/dist/agents/protocol.d.ts.map +1 -0
  61. package/dist/agents/protocol.js +36 -0
  62. package/dist/agents/protocol.js.map +1 -0
  63. package/dist/agents/run-helpers.d.ts +70 -0
  64. package/dist/agents/run-helpers.d.ts.map +1 -0
  65. package/dist/agents/run-helpers.js +131 -0
  66. package/dist/agents/run-helpers.js.map +1 -0
  67. package/dist/agents/serialize-error.d.ts +18 -0
  68. package/dist/agents/serialize-error.d.ts.map +1 -0
  69. package/dist/agents/serialize-error.js +27 -0
  70. package/dist/agents/serialize-error.js.map +1 -0
  71. package/dist/agents/structured-output.d.ts +90 -0
  72. package/dist/agents/structured-output.d.ts.map +1 -0
  73. package/dist/agents/structured-output.js +101 -0
  74. package/dist/agents/structured-output.js.map +1 -0
  75. package/dist/agents/test-utils/conformance.d.ts +59 -0
  76. package/dist/agents/test-utils/conformance.d.ts.map +1 -0
  77. package/dist/agents/test-utils/conformance.js +207 -0
  78. package/dist/agents/test-utils/conformance.js.map +1 -0
  79. package/dist/agents/test-utils/index.d.ts +12 -0
  80. package/dist/agents/test-utils/index.d.ts.map +1 -0
  81. package/dist/agents/test-utils/index.js +12 -0
  82. package/dist/agents/test-utils/index.js.map +1 -0
  83. package/dist/agents/test-utils/mock-agent.d.ts +66 -0
  84. package/dist/agents/test-utils/mock-agent.d.ts.map +1 -0
  85. package/dist/agents/test-utils/mock-agent.js +244 -0
  86. package/dist/agents/test-utils/mock-agent.js.map +1 -0
  87. package/dist/agents/thread.d.ts +57 -0
  88. package/dist/agents/thread.d.ts.map +1 -0
  89. package/dist/agents/thread.js +128 -0
  90. package/dist/agents/thread.js.map +1 -0
  91. package/dist/agents/turn-accumulator.d.ts +94 -0
  92. package/dist/agents/turn-accumulator.d.ts.map +1 -0
  93. package/dist/agents/turn-accumulator.js +150 -0
  94. package/dist/agents/turn-accumulator.js.map +1 -0
  95. package/dist/agents/with-memory.d.ts +55 -0
  96. package/dist/agents/with-memory.d.ts.map +1 -0
  97. package/dist/agents/with-memory.js +155 -0
  98. package/dist/agents/with-memory.js.map +1 -0
  99. package/dist/agents/with-thread.d.ts +45 -0
  100. package/dist/agents/with-thread.d.ts.map +1 -0
  101. package/dist/agents/with-thread.js +70 -0
  102. package/dist/agents/with-thread.js.map +1 -0
  103. package/dist/cache.d.ts +47 -0
  104. package/dist/cache.d.ts.map +1 -0
  105. package/dist/cache.js +81 -0
  106. package/dist/cache.js.map +1 -0
  107. package/dist/context/compressor.d.ts +36 -0
  108. package/dist/context/compressor.d.ts.map +1 -0
  109. package/dist/context/compressor.js +158 -0
  110. package/dist/context/compressor.js.map +1 -0
  111. package/dist/context/index.d.ts +4 -0
  112. package/dist/context/index.d.ts.map +1 -0
  113. package/dist/context/index.js +4 -0
  114. package/dist/context/index.js.map +1 -0
  115. package/dist/context/result-capper.d.ts +32 -0
  116. package/dist/context/result-capper.d.ts.map +1 -0
  117. package/dist/context/result-capper.js +50 -0
  118. package/dist/context/result-capper.js.map +1 -0
  119. package/dist/context/token-budget.d.ts +81 -0
  120. package/dist/context/token-budget.d.ts.map +1 -0
  121. package/dist/context/token-budget.js +99 -0
  122. package/dist/context/token-budget.js.map +1 -0
  123. package/dist/helpers/caller.d.ts +18 -0
  124. package/dist/helpers/caller.d.ts.map +1 -0
  125. package/dist/helpers/caller.js +40 -0
  126. package/dist/helpers/caller.js.map +1 -0
  127. package/dist/helpers/hook.d.ts +73 -0
  128. package/dist/helpers/hook.d.ts.map +1 -0
  129. package/dist/helpers/hook.js +244 -0
  130. package/dist/helpers/hook.js.map +1 -0
  131. package/dist/helpers/index.d.ts +12 -0
  132. package/dist/helpers/index.d.ts.map +1 -0
  133. package/dist/helpers/index.js +11 -0
  134. package/dist/helpers/index.js.map +1 -0
  135. package/dist/helpers/one-shot.d.ts +27 -0
  136. package/dist/helpers/one-shot.d.ts.map +1 -0
  137. package/dist/helpers/one-shot.js +43 -0
  138. package/dist/helpers/one-shot.js.map +1 -0
  139. package/dist/helpers/schedule.d.ts +59 -0
  140. package/dist/helpers/schedule.d.ts.map +1 -0
  141. package/dist/helpers/schedule.js +118 -0
  142. package/dist/helpers/schedule.js.map +1 -0
  143. package/dist/helpers/types.d.ts +34 -0
  144. package/dist/helpers/types.d.ts.map +1 -0
  145. package/dist/helpers/types.js +11 -0
  146. package/dist/helpers/types.js.map +1 -0
  147. package/dist/index.d.ts +26 -0
  148. package/dist/index.d.ts.map +1 -0
  149. package/dist/index.js +37 -0
  150. package/dist/index.js.map +1 -0
  151. package/dist/inference.d.ts +27 -0
  152. package/dist/inference.d.ts.map +1 -0
  153. package/dist/inference.js +34 -0
  154. package/dist/inference.js.map +1 -0
  155. package/dist/messages.d.ts +64 -0
  156. package/dist/messages.d.ts.map +1 -0
  157. package/dist/messages.js +17 -0
  158. package/dist/messages.js.map +1 -0
  159. package/dist/orchestrator.d.ts +56 -0
  160. package/dist/orchestrator.d.ts.map +1 -0
  161. package/dist/orchestrator.js +62 -0
  162. package/dist/orchestrator.js.map +1 -0
  163. package/dist/patterns/bounded-fanout-of.d.ts +61 -0
  164. package/dist/patterns/bounded-fanout-of.d.ts.map +1 -0
  165. package/dist/patterns/bounded-fanout-of.js +142 -0
  166. package/dist/patterns/bounded-fanout-of.js.map +1 -0
  167. package/dist/patterns/bounded-fanout.d.ts +111 -0
  168. package/dist/patterns/bounded-fanout.d.ts.map +1 -0
  169. package/dist/patterns/bounded-fanout.js +151 -0
  170. package/dist/patterns/bounded-fanout.js.map +1 -0
  171. package/dist/patterns/index.d.ts +14 -0
  172. package/dist/patterns/index.d.ts.map +1 -0
  173. package/dist/patterns/index.js +13 -0
  174. package/dist/patterns/index.js.map +1 -0
  175. package/dist/patterns/intent-gate.d.ts +27 -0
  176. package/dist/patterns/intent-gate.d.ts.map +1 -0
  177. package/dist/patterns/intent-gate.js +32 -0
  178. package/dist/patterns/intent-gate.js.map +1 -0
  179. package/dist/patterns/match.d.ts +30 -0
  180. package/dist/patterns/match.d.ts.map +1 -0
  181. package/dist/patterns/match.js +58 -0
  182. package/dist/patterns/match.js.map +1 -0
  183. package/dist/patterns/parallel-fanout.d.ts +28 -0
  184. package/dist/patterns/parallel-fanout.d.ts.map +1 -0
  185. package/dist/patterns/parallel-fanout.js +24 -0
  186. package/dist/patterns/parallel-fanout.js.map +1 -0
  187. package/dist/patterns/parallel-phases.d.ts +27 -0
  188. package/dist/patterns/parallel-phases.d.ts.map +1 -0
  189. package/dist/patterns/parallel-phases.js +77 -0
  190. package/dist/patterns/parallel-phases.js.map +1 -0
  191. package/dist/patterns/preflight-confidence.d.ts +20 -0
  192. package/dist/patterns/preflight-confidence.d.ts.map +1 -0
  193. package/dist/patterns/preflight-confidence.js +38 -0
  194. package/dist/patterns/preflight-confidence.js.map +1 -0
  195. package/dist/patterns/spot-check.d.ts +19 -0
  196. package/dist/patterns/spot-check.d.ts.map +1 -0
  197. package/dist/patterns/spot-check.js +33 -0
  198. package/dist/patterns/spot-check.js.map +1 -0
  199. package/dist/patterns/sub-pipeline.d.ts +84 -0
  200. package/dist/patterns/sub-pipeline.d.ts.map +1 -0
  201. package/dist/patterns/sub-pipeline.js +90 -0
  202. package/dist/patterns/sub-pipeline.js.map +1 -0
  203. package/dist/patterns/synthesize-with-followup.d.ts +35 -0
  204. package/dist/patterns/synthesize-with-followup.d.ts.map +1 -0
  205. package/dist/patterns/synthesize-with-followup.js +45 -0
  206. package/dist/patterns/synthesize-with-followup.js.map +1 -0
  207. package/dist/patterns/while-condition.d.ts +31 -0
  208. package/dist/patterns/while-condition.d.ts.map +1 -0
  209. package/dist/patterns/while-condition.js +59 -0
  210. package/dist/patterns/while-condition.js.map +1 -0
  211. package/dist/patterns/with-retry.d.ts +37 -0
  212. package/dist/patterns/with-retry.d.ts.map +1 -0
  213. package/dist/patterns/with-retry.js +73 -0
  214. package/dist/patterns/with-retry.js.map +1 -0
  215. package/dist/phase.d.ts +78 -0
  216. package/dist/phase.d.ts.map +1 -0
  217. package/dist/phase.js +36 -0
  218. package/dist/phase.js.map +1 -0
  219. package/dist/session/index.d.ts +5 -0
  220. package/dist/session/index.d.ts.map +1 -0
  221. package/dist/session/index.js +4 -0
  222. package/dist/session/index.js.map +1 -0
  223. package/dist/session/job-runner.d.ts +67 -0
  224. package/dist/session/job-runner.d.ts.map +1 -0
  225. package/dist/session/job-runner.js +131 -0
  226. package/dist/session/job-runner.js.map +1 -0
  227. package/dist/session/job-store.d.ts +98 -0
  228. package/dist/session/job-store.d.ts.map +1 -0
  229. package/dist/session/job-store.js +37 -0
  230. package/dist/session/job-store.js.map +1 -0
  231. package/dist/session/sqlite-job-store.d.ts +40 -0
  232. package/dist/session/sqlite-job-store.d.ts.map +1 -0
  233. package/dist/session/sqlite-job-store.js +200 -0
  234. package/dist/session/sqlite-job-store.js.map +1 -0
  235. package/dist/session/sse.d.ts +60 -0
  236. package/dist/session/sse.d.ts.map +1 -0
  237. package/dist/session/sse.js +97 -0
  238. package/dist/session/sse.js.map +1 -0
  239. package/dist/tools/index.d.ts +2 -0
  240. package/dist/tools/index.d.ts.map +1 -0
  241. package/dist/tools/index.js +2 -0
  242. package/dist/tools/index.js.map +1 -0
  243. package/dist/tools/registry.d.ts +44 -0
  244. package/dist/tools/registry.d.ts.map +1 -0
  245. package/dist/tools/registry.js +74 -0
  246. package/dist/tools/registry.js.map +1 -0
  247. package/dist/triggers/index.d.ts +15 -0
  248. package/dist/triggers/index.d.ts.map +1 -0
  249. package/dist/triggers/index.js +14 -0
  250. package/dist/triggers/index.js.map +1 -0
  251. package/dist/triggers/run-trigger.d.ts +86 -0
  252. package/dist/triggers/run-trigger.d.ts.map +1 -0
  253. package/dist/triggers/run-trigger.js +146 -0
  254. package/dist/triggers/run-trigger.js.map +1 -0
  255. package/dist/triggers/timer-trigger.d.ts +46 -0
  256. package/dist/triggers/timer-trigger.d.ts.map +1 -0
  257. package/dist/triggers/timer-trigger.js +74 -0
  258. package/dist/triggers/timer-trigger.js.map +1 -0
  259. package/dist/triggers/types.d.ts +61 -0
  260. package/dist/triggers/types.d.ts.map +1 -0
  261. package/dist/triggers/types.js +23 -0
  262. package/dist/triggers/types.js.map +1 -0
  263. package/package.json +64 -0
@@ -0,0 +1,111 @@
1
+ /**
2
+ * bounded-fanout — like parallelFanout, but caps in-flight runners.
3
+ *
4
+ * The reason this exists: most local inference setups have a hard concurrency
5
+ * cap (e.g. vLLM's `--max-num-seqs`). Sending 200 requests at once when the
6
+ * server only decodes 4 at a time gives you no extra throughput, no progress
7
+ * visibility, and head-of-line blocking. Bounded fanout matches concurrency
8
+ * to the real bottleneck and lets you observe per-item completion via the
9
+ * optional `onItemDone` callback.
10
+ *
11
+ * Result order matches input order, regardless of completion order.
12
+ *
13
+ * # Failure semantics
14
+ *
15
+ * Two modes via `options.mode`:
16
+ *
17
+ * - `'reject'` (default; backwards-compatible): if any runner throws, this
18
+ * rejects with the first thrown error. In-flight workers stop pulling new
19
+ * items but the runner already-in-flight on the failing path has already
20
+ * thrown. Other in-flight runners' resolved results are discarded.
21
+ *
22
+ * - `'collect'`: never reject due to a runner throw. Each result slot is
23
+ * `{ ok: true, value }` or `{ ok: false, error }`, in input order. Use
24
+ * this when partial-results-on-failure is what you want — common for
25
+ * batch agent runs where one item failing shouldn't drop the rest.
26
+ *
27
+ * `onItemError` fires regardless of mode, before the rejection in `'reject'`
28
+ * mode and once per failed item in `'collect'` mode. Use it for telemetry.
29
+ *
30
+ * # Cancellation
31
+ *
32
+ * Pass an `AbortSignal` via `options.signal`. Once aborted:
33
+ *
34
+ * - No new items are dispatched off the cursor.
35
+ * - The signal is forwarded to runners as the third argument
36
+ * (`runner(item, index, signal)`), so a runner that respects it can
37
+ * unwind early — e.g. by passing it into `runAgentWithTools({signal})`.
38
+ *
39
+ * Cancellation interacts with `mode`:
40
+ *
41
+ * - `'reject'`: hard-cancel. The fanout rejects with the abort reason.
42
+ * Partial results are discarded.
43
+ * - `'collect'`: soft-cancel. Returns a full-length, position-stable
44
+ * `FanOutResult<T>[]` — items that completed before the abort keep
45
+ * their `{ ok: true, value }` or `{ ok: false, error }`, items that
46
+ * were never started (or whose runner exited via the in-loop signal
47
+ * check) get a synthetic `{ ok: false, error: AbortError }`. The
48
+ * fanout does NOT reject. Use this when you want a soft deadline
49
+ * that returns work-in-progress for downstream phases to flush.
50
+ *
51
+ * For per-item progress as items complete, use `onItemDone` (it fires in
52
+ * completion order, before the final result array is returned).
53
+ */
54
+ export interface ItemDoneEvent<TItem, TResult> {
55
+ item: TItem;
56
+ index: number;
57
+ result: TResult;
58
+ }
59
+ export interface ItemErrorEvent<TItem> {
60
+ item: TItem;
61
+ index: number;
62
+ error: Error;
63
+ }
64
+ export type FanOutResult<TResult> = {
65
+ ok: true;
66
+ value: TResult;
67
+ } | {
68
+ ok: false;
69
+ error: Error;
70
+ };
71
+ export interface BoundedFanOutOptions<TItem, TResult> {
72
+ items: ReadonlyArray<TItem>;
73
+ /** Max concurrent runners. Default 4. Clamped to [1, items.length]. */
74
+ concurrency?: number;
75
+ /** If set, only the first `maxItems` items are processed. */
76
+ maxItems?: number;
77
+ /**
78
+ * Per-item runner. Receives the item, its index in the (capped) list, and
79
+ * the cancellation signal if one was passed. Forward `signal` into any
80
+ * abortable downstream call (HTTP, `runAgentWithTools`) for clean
81
+ * mid-flight cancellation.
82
+ */
83
+ runner: (item: TItem, index: number, signal?: AbortSignal) => Promise<TResult>;
84
+ /** Fires once per successfully-completed item, in completion order. */
85
+ onItemDone?: (event: ItemDoneEvent<TItem, TResult>) => void;
86
+ /**
87
+ * Failure mode:
88
+ * - `'reject'` (default): first throw rejects the whole call.
89
+ * - `'collect'`: never reject; each slot is FanOutResult.
90
+ */
91
+ mode?: 'reject' | 'collect';
92
+ /**
93
+ * Fires when a runner throws. Independent of mode; in `'reject'` mode it
94
+ * fires before the rejection propagates so you can record context for
95
+ * logging, in `'collect'` mode it fires per failed item.
96
+ */
97
+ onItemError?: (event: ItemErrorEvent<TItem>) => void;
98
+ /**
99
+ * Cancellation signal. When aborted, no new items are dispatched, the
100
+ * signal is forwarded to runners as the third argument, and the fanout
101
+ * rejects with the abort reason.
102
+ */
103
+ signal?: AbortSignal;
104
+ }
105
+ export declare function boundedFanout<TItem, TResult>(options: BoundedFanOutOptions<TItem, TResult> & {
106
+ mode: 'collect';
107
+ }): Promise<FanOutResult<TResult>[]>;
108
+ export declare function boundedFanout<TItem, TResult>(options: BoundedFanOutOptions<TItem, TResult> & {
109
+ mode?: 'reject';
110
+ }): Promise<TResult[]>;
111
+ //# sourceMappingURL=bounded-fanout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bounded-fanout.d.ts","sourceRoot":"","sources":["../../src/patterns/bounded-fanout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,MAAM,WAAW,aAAa,CAAC,KAAK,EAAE,OAAO;IAC3C,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,cAAc,CAAC,KAAK;IACnC,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;CACd;AAED,MAAM,MAAM,YAAY,CAAC,OAAO,IAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAC5B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAEhC,MAAM,WAAW,oBAAoB,CAAC,KAAK,EAAE,OAAO;IAClD,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAC5B,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/E,uEAAuE;IACvE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC5D;;;;OAIG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC5B;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;IACrD;;;;OAIG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAGD,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAC1C,OAAO,EAAE,oBAAoB,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GAClE,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AACpC,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAC1C,OAAO,EAAE,oBAAoB,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG;IAAE,IAAI,CAAC,EAAE,QAAQ,CAAA;CAAE,GAClE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * bounded-fanout — like parallelFanout, but caps in-flight runners.
3
+ *
4
+ * The reason this exists: most local inference setups have a hard concurrency
5
+ * cap (e.g. vLLM's `--max-num-seqs`). Sending 200 requests at once when the
6
+ * server only decodes 4 at a time gives you no extra throughput, no progress
7
+ * visibility, and head-of-line blocking. Bounded fanout matches concurrency
8
+ * to the real bottleneck and lets you observe per-item completion via the
9
+ * optional `onItemDone` callback.
10
+ *
11
+ * Result order matches input order, regardless of completion order.
12
+ *
13
+ * # Failure semantics
14
+ *
15
+ * Two modes via `options.mode`:
16
+ *
17
+ * - `'reject'` (default; backwards-compatible): if any runner throws, this
18
+ * rejects with the first thrown error. In-flight workers stop pulling new
19
+ * items but the runner already-in-flight on the failing path has already
20
+ * thrown. Other in-flight runners' resolved results are discarded.
21
+ *
22
+ * - `'collect'`: never reject due to a runner throw. Each result slot is
23
+ * `{ ok: true, value }` or `{ ok: false, error }`, in input order. Use
24
+ * this when partial-results-on-failure is what you want — common for
25
+ * batch agent runs where one item failing shouldn't drop the rest.
26
+ *
27
+ * `onItemError` fires regardless of mode, before the rejection in `'reject'`
28
+ * mode and once per failed item in `'collect'` mode. Use it for telemetry.
29
+ *
30
+ * # Cancellation
31
+ *
32
+ * Pass an `AbortSignal` via `options.signal`. Once aborted:
33
+ *
34
+ * - No new items are dispatched off the cursor.
35
+ * - The signal is forwarded to runners as the third argument
36
+ * (`runner(item, index, signal)`), so a runner that respects it can
37
+ * unwind early — e.g. by passing it into `runAgentWithTools({signal})`.
38
+ *
39
+ * Cancellation interacts with `mode`:
40
+ *
41
+ * - `'reject'`: hard-cancel. The fanout rejects with the abort reason.
42
+ * Partial results are discarded.
43
+ * - `'collect'`: soft-cancel. Returns a full-length, position-stable
44
+ * `FanOutResult<T>[]` — items that completed before the abort keep
45
+ * their `{ ok: true, value }` or `{ ok: false, error }`, items that
46
+ * were never started (or whose runner exited via the in-loop signal
47
+ * check) get a synthetic `{ ok: false, error: AbortError }`. The
48
+ * fanout does NOT reject. Use this when you want a soft deadline
49
+ * that returns work-in-progress for downstream phases to flush.
50
+ *
51
+ * For per-item progress as items complete, use `onItemDone` (it fires in
52
+ * completion order, before the final result array is returned).
53
+ */
54
+ export async function boundedFanout(options) {
55
+ const items = options.maxItems !== undefined ? options.items.slice(0, options.maxItems) : options.items;
56
+ if (items.length === 0)
57
+ return [];
58
+ const concurrency = Math.max(1, Math.min(options.concurrency ?? 4, items.length));
59
+ const collect = options.mode === 'collect';
60
+ const results = new Array(items.length);
61
+ let cursor = 0;
62
+ const signal = options.signal;
63
+ // Already aborted before any dispatch.
64
+ // - 'reject' mode: throw, matches HTTP-cancel semantics.
65
+ // - 'collect' mode: short-circuit with synthetic AbortError slots so
66
+ // consumers always get a full-length, position-stable array.
67
+ if (signal?.aborted) {
68
+ if (collect)
69
+ return fillAbortedSlots([], items.length, signal);
70
+ throw signalAbortError(signal);
71
+ }
72
+ const worker = async () => {
73
+ while (true) {
74
+ if (signal?.aborted)
75
+ return;
76
+ const i = cursor++;
77
+ if (i >= items.length)
78
+ return;
79
+ const item = items[i];
80
+ try {
81
+ const result = await options.runner(item, i, signal);
82
+ if (signal?.aborted)
83
+ return;
84
+ if (collect) {
85
+ results[i] = { ok: true, value: result };
86
+ }
87
+ else {
88
+ results[i] = result;
89
+ }
90
+ options.onItemDone?.({ item, index: i, result });
91
+ }
92
+ catch (rawErr) {
93
+ const error = toError(rawErr);
94
+ options.onItemError?.({ item, index: i, error });
95
+ if (collect) {
96
+ results[i] = { ok: false, error };
97
+ continue; // keep draining
98
+ }
99
+ throw error; // 'reject' mode: bubble out, Promise.all will reject
100
+ }
101
+ }
102
+ };
103
+ const workers = [];
104
+ for (let w = 0; w < concurrency; w++)
105
+ workers.push(worker());
106
+ await Promise.all(workers);
107
+ // Aborted at some point after dispatch began.
108
+ // - 'reject' mode: throw, partial results discarded (matches v1.0/1.1).
109
+ // - 'collect' mode: soft-cancel — return what completed, fill the slots
110
+ // of items that were never started (or whose runner exited via the
111
+ // in-loop signal check before writing a result) with synthetic
112
+ // AbortError FanOutResults. onItemError does NOT fire for these
113
+ // synthetic fills — the runner never ran for them.
114
+ if (signal?.aborted) {
115
+ if (collect) {
116
+ return fillAbortedSlots(results, items.length, signal);
117
+ }
118
+ throw signalAbortError(signal);
119
+ }
120
+ return results;
121
+ }
122
+ /**
123
+ * Soft-cancel helper: fills any undefined slots in a collect-mode results
124
+ * array with synthetic { ok: false, error } AbortError entries so the
125
+ * returned array stays position-stable with the input items array.
126
+ *
127
+ * Items that were already recorded (whether { ok: true } or { ok: false }
128
+ * from a real runner error) are preserved. Items that never ran — either
129
+ * because the cursor never reached them or because the runner exited via
130
+ * the in-loop signal check before writing — get a synthetic slot.
131
+ */
132
+ function fillAbortedSlots(partial, total, signal) {
133
+ const abortErr = signalAbortError(signal);
134
+ const out = new Array(total);
135
+ for (let i = 0; i < total; i++) {
136
+ out[i] = partial[i] ?? { ok: false, error: abortErr };
137
+ }
138
+ return out;
139
+ }
140
+ function toError(e) {
141
+ return e instanceof Error ? e : new Error(typeof e === 'string' ? e : JSON.stringify(e));
142
+ }
143
+ function signalAbortError(signal) {
144
+ const reason = signal.reason;
145
+ if (reason instanceof Error)
146
+ return reason;
147
+ const err = new Error(typeof reason === 'string' ? reason : 'aborted');
148
+ err.name = 'AbortError';
149
+ return err;
150
+ }
151
+ //# sourceMappingURL=bounded-fanout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bounded-fanout.js","sourceRoot":"","sources":["../../src/patterns/bounded-fanout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Reusable phase patterns. Each pattern is a small, opinionated helper that
3
+ * captures a recurring shape — not a black-box framework. Compose freely.
4
+ */
5
+ export { parallelPhases } from './parallel-phases.js';
6
+ export { boundedFanout, type BoundedFanOutOptions, type ItemDoneEvent, type ItemErrorEvent, type FanOutResult, } from './bounded-fanout.js';
7
+ export { boundedFanoutOf, BoundedFanoutOfError } from './bounded-fanout-of.js';
8
+ export type { BoundedFanoutOfOptions, BoundedFanoutOfMode } from './bounded-fanout-of.js';
9
+ export { intentGate, type IntentClassification, type IntentDecision, type IntentGateOptions, } from './intent-gate.js';
10
+ export { whileCondition, type WhileConditionOptions, } from './while-condition.js';
11
+ export { match, type MatchOptions, } from './match.js';
12
+ export { withRetry, type WithRetryOptions, } from './with-retry.js';
13
+ export { subPipeline, subPipelineOf, runSubPipeline, type SubPipelineOptions, type SubPipelineSource, } from './sub-pipeline.js';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/patterns/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EACL,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,YAAY,GAClB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC/E,YAAY,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE1F,OAAO,EACL,UAAU,EACV,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,iBAAiB,GACvB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,cAAc,EACd,KAAK,qBAAqB,GAC3B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,KAAK,EACL,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,SAAS,EACT,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,WAAW,EACX,aAAa,EACb,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,GACvB,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Reusable phase patterns. Each pattern is a small, opinionated helper that
3
+ * captures a recurring shape — not a black-box framework. Compose freely.
4
+ */
5
+ export { parallelPhases } from './parallel-phases.js';
6
+ export { boundedFanout, } from './bounded-fanout.js';
7
+ export { boundedFanoutOf, BoundedFanoutOfError } from './bounded-fanout-of.js';
8
+ export { intentGate, } from './intent-gate.js';
9
+ export { whileCondition, } from './while-condition.js';
10
+ export { match, } from './match.js';
11
+ export { withRetry, } from './with-retry.js';
12
+ export { subPipeline, subPipelineOf, runSubPipeline, } from './sub-pipeline.js';
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/patterns/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EACL,aAAa,GAKd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAG/E,OAAO,EACL,UAAU,GAIX,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,cAAc,GAEf,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,KAAK,GAEN,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,SAAS,GAEV,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,WAAW,EACX,aAAa,EACb,cAAc,GAGf,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * intent-gate — classify the input cheaply, route to a fast path or continue.
3
+ *
4
+ * Common cost-control pattern: a 1-call cheap classifier decides whether the
5
+ * pipeline should run end-to-end (`continue`) or short-circuit to a much
6
+ * cheaper handler (e.g. a one-shot direct answer). The handler may produce
7
+ * its own output before the pipeline halts.
8
+ */
9
+ import type { BasePipelineContext, Phase, PipelineEvent } from '../phase.js';
10
+ export interface IntentClassification<TIntent extends string> {
11
+ intent: TIntent;
12
+ /** Optional rationale surfaced in the activity log. */
13
+ rationale?: string;
14
+ }
15
+ export type IntentDecision<TCtx extends BasePipelineContext> = 'continue' | {
16
+ stop: string;
17
+ /** Optional generator that yields events before the pipeline halts. */
18
+ handler?: (ctx: TCtx) => AsyncGenerator<PipelineEvent, void, void>;
19
+ };
20
+ export interface IntentGateOptions<TCtx extends BasePipelineContext, TIntent extends string> {
21
+ /** Run the classifier (typically a cheap LLM call). */
22
+ classify: (ctx: TCtx) => Promise<IntentClassification<TIntent>>;
23
+ /** Map a classified intent to either 'continue' or a stop directive. */
24
+ route: (intent: TIntent, ctx: TCtx) => IntentDecision<TCtx>;
25
+ }
26
+ export declare function intentGate<TCtx extends BasePipelineContext, TIntent extends string>(phaseName: string, options: IntentGateOptions<TCtx, TIntent>): Phase<TCtx>;
27
+ //# sourceMappingURL=intent-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intent-gate.d.ts","sourceRoot":"","sources":["../../src/patterns/intent-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE7E,MAAM,WAAW,oBAAoB,CAAC,OAAO,SAAS,MAAM;IAC1D,MAAM,EAAE,OAAO,CAAC;IAChB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,cAAc,CAAC,IAAI,SAAS,mBAAmB,IACvD,UAAU,GACV;IACE,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,cAAc,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;CACpE,CAAC;AAEN,MAAM,WAAW,iBAAiB,CAAC,IAAI,SAAS,mBAAmB,EAAE,OAAO,SAAS,MAAM;IACzF,uDAAuD;IACvD,QAAQ,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,OAAO,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC;IAChE,wEAAwE;IACxE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,KAAK,cAAc,CAAC,IAAI,CAAC,CAAC;CAC7D;AAED,wBAAgB,UAAU,CAAC,IAAI,SAAS,mBAAmB,EAAE,OAAO,SAAS,MAAM,EACjF,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,GACxC,KAAK,CAAC,IAAI,CAAC,CAuBb"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * intent-gate — classify the input cheaply, route to a fast path or continue.
3
+ *
4
+ * Common cost-control pattern: a 1-call cheap classifier decides whether the
5
+ * pipeline should run end-to-end (`continue`) or short-circuit to a much
6
+ * cheaper handler (e.g. a one-shot direct answer). The handler may produce
7
+ * its own output before the pipeline halts.
8
+ */
9
+ export function intentGate(phaseName, options) {
10
+ return {
11
+ name: phaseName,
12
+ async *run(ctx) {
13
+ const classification = await options.classify(ctx);
14
+ yield {
15
+ type: 'agent_activity',
16
+ agent: phaseName,
17
+ action: 'classified',
18
+ detail: classification.rationale
19
+ ? `${classification.intent} — ${classification.rationale}`
20
+ : classification.intent,
21
+ };
22
+ const decision = options.route(classification.intent, ctx);
23
+ if (decision === 'continue')
24
+ return;
25
+ if (decision.handler) {
26
+ yield* decision.handler(ctx);
27
+ }
28
+ ctx.stop = { reason: decision.stop };
29
+ },
30
+ };
31
+ }
32
+ //# sourceMappingURL=intent-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intent-gate.js","sourceRoot":"","sources":["../../src/patterns/intent-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAyBH,MAAM,UAAU,UAAU,CACxB,SAAiB,EACjB,OAAyC;IAEzC,OAAO;QACL,IAAI,EAAE,SAAS;QACf,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG;YACZ,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YACnD,MAAM;gBACJ,IAAI,EAAE,gBAAgB;gBACtB,KAAK,EAAE,SAAS;gBAChB,MAAM,EAAE,YAAY;gBACpB,MAAM,EAAE,cAAc,CAAC,SAAS;oBAC9B,CAAC,CAAC,GAAG,cAAc,CAAC,MAAM,MAAM,cAAc,CAAC,SAAS,EAAE;oBAC1D,CAAC,CAAC,cAAc,CAAC,MAAM;aAC1B,CAAC;YAEF,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAC3D,IAAI,QAAQ,KAAK,UAAU;gBAAE,OAAO;YAEpC,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;gBACrB,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC/B,CAAC;YACD,GAAG,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;QACvC,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * match — keyed dispatch over phases.
3
+ *
4
+ * Routes to one of N phase lists based on a selector function. Generalizes
5
+ * if/else (use two cases) and replaces ad-hoc switch statements in pipeline
6
+ * code with a primitive the orchestrator can reason about.
7
+ *
8
+ * The selector returns one of three things:
9
+ * - a key present in `cases` → run that case's phases
10
+ * - a key missing from `cases` → run `default` if provided, else skip
11
+ * - `null` → skip silently (no case, no default)
12
+ *
13
+ * Emits a `data` event with key `${name}.taken` and value
14
+ * `{ taken: key | 'default' | 'skip' }` so downstream consumers can tell
15
+ * which arm ran without inspecting the selector themselves.
16
+ *
17
+ * Strict dispatch is the caller's responsibility — assert inside the
18
+ * selector if a missing key should be a bug.
19
+ */
20
+ import type { BasePipelineContext, Phase } from '../phase.js';
21
+ export interface MatchOptions<TCtx extends BasePipelineContext, K extends string> {
22
+ /** Returns the key of the case to run, or null to skip. */
23
+ selector: (ctx: TCtx) => K | null | Promise<K | null>;
24
+ /** Phase lists keyed by case. */
25
+ cases: Record<K, Phase<TCtx>[]>;
26
+ /** Fallback phases when selector returns a key not in `cases`. */
27
+ default?: Phase<TCtx>[];
28
+ }
29
+ export declare function match<TCtx extends BasePipelineContext, K extends string>(phaseName: string, options: MatchOptions<TCtx, K>): Phase<TCtx>;
30
+ //# sourceMappingURL=match.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.d.ts","sourceRoot":"","sources":["../../src/patterns/match.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAiB,MAAM,aAAa,CAAC;AAE7E,MAAM,WAAW,YAAY,CAAC,IAAI,SAAS,mBAAmB,EAAE,CAAC,SAAS,MAAM;IAC9E,2DAA2D;IAC3D,QAAQ,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACtD,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChC,kEAAkE;IAClE,OAAO,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;CACzB;AAED,wBAAgB,KAAK,CAAC,IAAI,SAAS,mBAAmB,EAAE,CAAC,SAAS,MAAM,EACtE,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,GAC7B,KAAK,CAAC,IAAI,CAAC,CAqCb"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * match — keyed dispatch over phases.
3
+ *
4
+ * Routes to one of N phase lists based on a selector function. Generalizes
5
+ * if/else (use two cases) and replaces ad-hoc switch statements in pipeline
6
+ * code with a primitive the orchestrator can reason about.
7
+ *
8
+ * The selector returns one of three things:
9
+ * - a key present in `cases` → run that case's phases
10
+ * - a key missing from `cases` → run `default` if provided, else skip
11
+ * - `null` → skip silently (no case, no default)
12
+ *
13
+ * Emits a `data` event with key `${name}.taken` and value
14
+ * `{ taken: key | 'default' | 'skip' }` so downstream consumers can tell
15
+ * which arm ran without inspecting the selector themselves.
16
+ *
17
+ * Strict dispatch is the caller's responsibility — assert inside the
18
+ * selector if a missing key should be a bug.
19
+ */
20
+ export function match(phaseName, options) {
21
+ return {
22
+ name: phaseName,
23
+ async *run(ctx) {
24
+ const key = await options.selector(ctx);
25
+ let chosen;
26
+ let taken;
27
+ if (key === null) {
28
+ chosen = undefined;
29
+ taken = 'skip';
30
+ }
31
+ else if (Object.prototype.hasOwnProperty.call(options.cases, key)) {
32
+ chosen = options.cases[key];
33
+ taken = key;
34
+ }
35
+ else if (options.default) {
36
+ chosen = options.default;
37
+ taken = 'default';
38
+ }
39
+ else {
40
+ chosen = undefined;
41
+ taken = 'skip';
42
+ }
43
+ yield {
44
+ type: 'data',
45
+ key: `${phaseName}.taken`,
46
+ value: { taken },
47
+ };
48
+ if (!chosen)
49
+ return;
50
+ for (const phase of chosen) {
51
+ yield* phase.run(ctx);
52
+ if (ctx.stop)
53
+ return;
54
+ }
55
+ },
56
+ };
57
+ }
58
+ //# sourceMappingURL=match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.js","sourceRoot":"","sources":["../../src/patterns/match.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAaH,MAAM,UAAU,KAAK,CACnB,SAAiB,EACjB,OAA8B;IAE9B,OAAO;QACL,IAAI,EAAE,SAAS;QACf,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG;YACZ,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAExC,IAAI,MAAiC,CAAC;YACtC,IAAI,KAAa,CAAC;YAElB,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBACjB,MAAM,GAAG,SAAS,CAAC;gBACnB,KAAK,GAAG,MAAM,CAAC;YACjB,CAAC;iBAAM,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;gBACpE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC5B,KAAK,GAAG,GAAG,CAAC;YACd,CAAC;iBAAM,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBAC3B,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;gBACzB,KAAK,GAAG,SAAS,CAAC;YACpB,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,SAAS,CAAC;gBACnB,KAAK,GAAG,MAAM,CAAC;YACjB,CAAC;YAED,MAAM;gBACJ,IAAI,EAAE,MAAM;gBACZ,GAAG,EAAE,GAAG,SAAS,QAAQ;gBACzB,KAAK,EAAE,EAAE,KAAK,EAAE;aACjB,CAAC;YAEF,IAAI,CAAC,MAAM;gBAAE,OAAO;YAEpB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACtB,IAAI,GAAG,CAAC,IAAI;oBAAE,OAAO;YACvB,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * parallel-fanout — N items, one async runner per item, results collected.
3
+ *
4
+ * The most common multi-agent pattern: "for each X, do Y." Caps concurrency
5
+ * optionally.
6
+ *
7
+ * Intentionally a helper, not a Phase. Compose inside your own phase:
8
+ *
9
+ * async *run(ctx) {
10
+ * const items = requireCtx(ctx, 'items', 'my-phase');
11
+ * yield { type: 'phase', phase: 'my-phase', detail: `${items.length} items` };
12
+ * const results = await parallelFanout({
13
+ * items,
14
+ * maxItems: 5,
15
+ * runner: (item) => runAgentWithTools(myConfig, [...], opts),
16
+ * });
17
+ * ctx.results = results;
18
+ * }
19
+ */
20
+ export interface FanOutOptions<TItem, TResult> {
21
+ items: ReadonlyArray<TItem>;
22
+ /** If set, only the first `maxItems` items are processed. */
23
+ maxItems?: number;
24
+ /** Per-item runner. Receives the item and its index in the (capped) list. */
25
+ runner: (item: TItem, index: number) => Promise<TResult>;
26
+ }
27
+ export declare function parallelFanout<TItem, TResult>(options: FanOutOptions<TItem, TResult>): Promise<TResult[]>;
28
+ //# sourceMappingURL=parallel-fanout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parallel-fanout.d.ts","sourceRoot":"","sources":["../../src/patterns/parallel-fanout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,aAAa,CAAC,KAAK,EAAE,OAAO;IAC3C,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAC5B,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1D;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,OAAO,EACjD,OAAO,EAAE,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,GACrC,OAAO,CAAC,OAAO,EAAE,CAAC,CAIpB"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * parallel-fanout — N items, one async runner per item, results collected.
3
+ *
4
+ * The most common multi-agent pattern: "for each X, do Y." Caps concurrency
5
+ * optionally.
6
+ *
7
+ * Intentionally a helper, not a Phase. Compose inside your own phase:
8
+ *
9
+ * async *run(ctx) {
10
+ * const items = requireCtx(ctx, 'items', 'my-phase');
11
+ * yield { type: 'phase', phase: 'my-phase', detail: `${items.length} items` };
12
+ * const results = await parallelFanout({
13
+ * items,
14
+ * maxItems: 5,
15
+ * runner: (item) => runAgentWithTools(myConfig, [...], opts),
16
+ * });
17
+ * ctx.results = results;
18
+ * }
19
+ */
20
+ export async function parallelFanout(options) {
21
+ const items = options.maxItems !== undefined ? options.items.slice(0, options.maxItems) : options.items;
22
+ return Promise.all(items.map((item, i) => options.runner(item, i)));
23
+ }
24
+ //# sourceMappingURL=parallel-fanout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parallel-fanout.js","sourceRoot":"","sources":["../../src/patterns/parallel-fanout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAUH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAsC;IAEtC,MAAM,KAAK,GACT,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IAC5F,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * parallel-phases — run several phases concurrently as one composite phase.
3
+ *
4
+ * The framework treats pipelines as an ordered array, which covers linear
5
+ * flow, conditional skip (`intentGate`), and self-iteration
6
+ * (`whileCondition`). The one DAG shape it doesn't natively express is
7
+ * "run two independent branches at the same time, then continue when
8
+ * both finish." That's what this pattern is for.
9
+ *
10
+ * Semantics:
11
+ * - Sub-phases share the parent `ctx`. If two branches both write to the
12
+ * same field, last-write-wins. Keep branches' ctx writes disjoint.
13
+ * - Events from all branches interleave into the composite phase's
14
+ * output stream in arrival order.
15
+ * - If a sub-phase throws, the composite re-throws (after letting other
16
+ * branches finish what they're doing — no in-flight cancellation).
17
+ * - If a sub-phase sets `ctx.stop`, sibling branches still run to
18
+ * completion. The orchestrator's stop check fires AFTER the composite
19
+ * phase returns, halting subsequent top-level phases.
20
+ *
21
+ * For data-dependent fan-in, write each branch's output to a distinct ctx
22
+ * field; a downstream phase reads them all via `requireCtx`. That's a
23
+ * complete DAG-edge expression without a graph framework.
24
+ */
25
+ import type { BasePipelineContext, Phase, PipelineEvent } from '../phase.js';
26
+ export declare function parallelPhases<TCtx extends BasePipelineContext, TEvent = PipelineEvent>(phaseName: string, phases: ReadonlyArray<Phase<TCtx, TEvent>>): Phase<TCtx, TEvent>;
27
+ //# sourceMappingURL=parallel-phases.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parallel-phases.d.ts","sourceRoot":"","sources":["../../src/patterns/parallel-phases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE7E,wBAAgB,cAAc,CAC5B,IAAI,SAAS,mBAAmB,EAChC,MAAM,GAAG,aAAa,EAEtB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,GACzC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAkDrB"}