@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.
- package/LICENSE +21 -0
- package/README.md +226 -0
- package/dist/agent/index.d.ts +28 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +28 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/openai-adapter.d.ts +15 -0
- package/dist/agent/openai-adapter.d.ts.map +1 -0
- package/dist/agent/openai-adapter.js +57 -0
- package/dist/agent/openai-adapter.js.map +1 -0
- package/dist/agent/parse-json.d.ts +12 -0
- package/dist/agent/parse-json.d.ts.map +1 -0
- package/dist/agent/parse-json.js +31 -0
- package/dist/agent/parse-json.js.map +1 -0
- package/dist/agent/retry.d.ts +15 -0
- package/dist/agent/retry.d.ts.map +1 -0
- package/dist/agent/retry.js +35 -0
- package/dist/agent/retry.js.map +1 -0
- package/dist/agent/runner.d.ts +25 -0
- package/dist/agent/runner.d.ts.map +1 -0
- package/dist/agent/runner.js +270 -0
- package/dist/agent/runner.js.map +1 -0
- package/dist/agent/stream-consumer.d.ts +57 -0
- package/dist/agent/stream-consumer.d.ts.map +1 -0
- package/dist/agent/stream-consumer.js +126 -0
- package/dist/agent/stream-consumer.js.map +1 -0
- package/dist/agent/types.d.ts +135 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +9 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/agent-runner.d.ts +10 -0
- package/dist/agent-runner.d.ts.map +1 -0
- package/dist/agent-runner.js +10 -0
- package/dist/agent-runner.js.map +1 -0
- package/dist/agents/capability.d.ts +36 -0
- package/dist/agents/capability.d.ts.map +1 -0
- package/dist/agents/capability.js +51 -0
- package/dist/agents/capability.js.map +1 -0
- package/dist/agents/event-bus.d.ts +20 -0
- package/dist/agents/event-bus.d.ts.map +1 -0
- package/dist/agents/event-bus.js +40 -0
- package/dist/agents/event-bus.js.map +1 -0
- package/dist/agents/index.d.ts +23 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +33 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/inference-adapter.d.ts +52 -0
- package/dist/agents/inference-adapter.d.ts.map +1 -0
- package/dist/agents/inference-adapter.js +209 -0
- package/dist/agents/inference-adapter.js.map +1 -0
- package/dist/agents/job-store-bridge.d.ts +44 -0
- package/dist/agents/job-store-bridge.d.ts.map +1 -0
- package/dist/agents/job-store-bridge.js +58 -0
- package/dist/agents/job-store-bridge.js.map +1 -0
- package/dist/agents/memory.d.ts +40 -0
- package/dist/agents/memory.d.ts.map +1 -0
- package/dist/agents/memory.js +14 -0
- package/dist/agents/memory.js.map +1 -0
- package/dist/agents/protocol.d.ts +302 -0
- package/dist/agents/protocol.d.ts.map +1 -0
- package/dist/agents/protocol.js +36 -0
- package/dist/agents/protocol.js.map +1 -0
- package/dist/agents/run-helpers.d.ts +70 -0
- package/dist/agents/run-helpers.d.ts.map +1 -0
- package/dist/agents/run-helpers.js +131 -0
- package/dist/agents/run-helpers.js.map +1 -0
- package/dist/agents/serialize-error.d.ts +18 -0
- package/dist/agents/serialize-error.d.ts.map +1 -0
- package/dist/agents/serialize-error.js +27 -0
- package/dist/agents/serialize-error.js.map +1 -0
- package/dist/agents/structured-output.d.ts +90 -0
- package/dist/agents/structured-output.d.ts.map +1 -0
- package/dist/agents/structured-output.js +101 -0
- package/dist/agents/structured-output.js.map +1 -0
- package/dist/agents/test-utils/conformance.d.ts +59 -0
- package/dist/agents/test-utils/conformance.d.ts.map +1 -0
- package/dist/agents/test-utils/conformance.js +207 -0
- package/dist/agents/test-utils/conformance.js.map +1 -0
- package/dist/agents/test-utils/index.d.ts +12 -0
- package/dist/agents/test-utils/index.d.ts.map +1 -0
- package/dist/agents/test-utils/index.js +12 -0
- package/dist/agents/test-utils/index.js.map +1 -0
- package/dist/agents/test-utils/mock-agent.d.ts +66 -0
- package/dist/agents/test-utils/mock-agent.d.ts.map +1 -0
- package/dist/agents/test-utils/mock-agent.js +244 -0
- package/dist/agents/test-utils/mock-agent.js.map +1 -0
- package/dist/agents/thread.d.ts +57 -0
- package/dist/agents/thread.d.ts.map +1 -0
- package/dist/agents/thread.js +128 -0
- package/dist/agents/thread.js.map +1 -0
- package/dist/agents/turn-accumulator.d.ts +94 -0
- package/dist/agents/turn-accumulator.d.ts.map +1 -0
- package/dist/agents/turn-accumulator.js +150 -0
- package/dist/agents/turn-accumulator.js.map +1 -0
- package/dist/agents/with-memory.d.ts +55 -0
- package/dist/agents/with-memory.d.ts.map +1 -0
- package/dist/agents/with-memory.js +155 -0
- package/dist/agents/with-memory.js.map +1 -0
- package/dist/agents/with-thread.d.ts +45 -0
- package/dist/agents/with-thread.d.ts.map +1 -0
- package/dist/agents/with-thread.js +70 -0
- package/dist/agents/with-thread.js.map +1 -0
- package/dist/cache.d.ts +47 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +81 -0
- package/dist/cache.js.map +1 -0
- package/dist/context/compressor.d.ts +36 -0
- package/dist/context/compressor.d.ts.map +1 -0
- package/dist/context/compressor.js +158 -0
- package/dist/context/compressor.js.map +1 -0
- package/dist/context/index.d.ts +4 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +4 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/result-capper.d.ts +32 -0
- package/dist/context/result-capper.d.ts.map +1 -0
- package/dist/context/result-capper.js +50 -0
- package/dist/context/result-capper.js.map +1 -0
- package/dist/context/token-budget.d.ts +81 -0
- package/dist/context/token-budget.d.ts.map +1 -0
- package/dist/context/token-budget.js +99 -0
- package/dist/context/token-budget.js.map +1 -0
- package/dist/helpers/caller.d.ts +18 -0
- package/dist/helpers/caller.d.ts.map +1 -0
- package/dist/helpers/caller.js +40 -0
- package/dist/helpers/caller.js.map +1 -0
- package/dist/helpers/hook.d.ts +73 -0
- package/dist/helpers/hook.d.ts.map +1 -0
- package/dist/helpers/hook.js +244 -0
- package/dist/helpers/hook.js.map +1 -0
- package/dist/helpers/index.d.ts +12 -0
- package/dist/helpers/index.d.ts.map +1 -0
- package/dist/helpers/index.js +11 -0
- package/dist/helpers/index.js.map +1 -0
- package/dist/helpers/one-shot.d.ts +27 -0
- package/dist/helpers/one-shot.d.ts.map +1 -0
- package/dist/helpers/one-shot.js +43 -0
- package/dist/helpers/one-shot.js.map +1 -0
- package/dist/helpers/schedule.d.ts +59 -0
- package/dist/helpers/schedule.d.ts.map +1 -0
- package/dist/helpers/schedule.js +118 -0
- package/dist/helpers/schedule.js.map +1 -0
- package/dist/helpers/types.d.ts +34 -0
- package/dist/helpers/types.d.ts.map +1 -0
- package/dist/helpers/types.js +11 -0
- package/dist/helpers/types.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/inference.d.ts +27 -0
- package/dist/inference.d.ts.map +1 -0
- package/dist/inference.js +34 -0
- package/dist/inference.js.map +1 -0
- package/dist/messages.d.ts +64 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +17 -0
- package/dist/messages.js.map +1 -0
- package/dist/orchestrator.d.ts +56 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +62 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/patterns/bounded-fanout-of.d.ts +61 -0
- package/dist/patterns/bounded-fanout-of.d.ts.map +1 -0
- package/dist/patterns/bounded-fanout-of.js +142 -0
- package/dist/patterns/bounded-fanout-of.js.map +1 -0
- package/dist/patterns/bounded-fanout.d.ts +111 -0
- package/dist/patterns/bounded-fanout.d.ts.map +1 -0
- package/dist/patterns/bounded-fanout.js +151 -0
- package/dist/patterns/bounded-fanout.js.map +1 -0
- package/dist/patterns/index.d.ts +14 -0
- package/dist/patterns/index.d.ts.map +1 -0
- package/dist/patterns/index.js +13 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/patterns/intent-gate.d.ts +27 -0
- package/dist/patterns/intent-gate.d.ts.map +1 -0
- package/dist/patterns/intent-gate.js +32 -0
- package/dist/patterns/intent-gate.js.map +1 -0
- package/dist/patterns/match.d.ts +30 -0
- package/dist/patterns/match.d.ts.map +1 -0
- package/dist/patterns/match.js +58 -0
- package/dist/patterns/match.js.map +1 -0
- package/dist/patterns/parallel-fanout.d.ts +28 -0
- package/dist/patterns/parallel-fanout.d.ts.map +1 -0
- package/dist/patterns/parallel-fanout.js +24 -0
- package/dist/patterns/parallel-fanout.js.map +1 -0
- package/dist/patterns/parallel-phases.d.ts +27 -0
- package/dist/patterns/parallel-phases.d.ts.map +1 -0
- package/dist/patterns/parallel-phases.js +77 -0
- package/dist/patterns/parallel-phases.js.map +1 -0
- package/dist/patterns/preflight-confidence.d.ts +20 -0
- package/dist/patterns/preflight-confidence.d.ts.map +1 -0
- package/dist/patterns/preflight-confidence.js +38 -0
- package/dist/patterns/preflight-confidence.js.map +1 -0
- package/dist/patterns/spot-check.d.ts +19 -0
- package/dist/patterns/spot-check.d.ts.map +1 -0
- package/dist/patterns/spot-check.js +33 -0
- package/dist/patterns/spot-check.js.map +1 -0
- package/dist/patterns/sub-pipeline.d.ts +84 -0
- package/dist/patterns/sub-pipeline.d.ts.map +1 -0
- package/dist/patterns/sub-pipeline.js +90 -0
- package/dist/patterns/sub-pipeline.js.map +1 -0
- package/dist/patterns/synthesize-with-followup.d.ts +35 -0
- package/dist/patterns/synthesize-with-followup.d.ts.map +1 -0
- package/dist/patterns/synthesize-with-followup.js +45 -0
- package/dist/patterns/synthesize-with-followup.js.map +1 -0
- package/dist/patterns/while-condition.d.ts +31 -0
- package/dist/patterns/while-condition.d.ts.map +1 -0
- package/dist/patterns/while-condition.js +59 -0
- package/dist/patterns/while-condition.js.map +1 -0
- package/dist/patterns/with-retry.d.ts +37 -0
- package/dist/patterns/with-retry.d.ts.map +1 -0
- package/dist/patterns/with-retry.js +73 -0
- package/dist/patterns/with-retry.js.map +1 -0
- package/dist/phase.d.ts +78 -0
- package/dist/phase.d.ts.map +1 -0
- package/dist/phase.js +36 -0
- package/dist/phase.js.map +1 -0
- package/dist/session/index.d.ts +5 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +4 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/job-runner.d.ts +67 -0
- package/dist/session/job-runner.d.ts.map +1 -0
- package/dist/session/job-runner.js +131 -0
- package/dist/session/job-runner.js.map +1 -0
- package/dist/session/job-store.d.ts +98 -0
- package/dist/session/job-store.d.ts.map +1 -0
- package/dist/session/job-store.js +37 -0
- package/dist/session/job-store.js.map +1 -0
- package/dist/session/sqlite-job-store.d.ts +40 -0
- package/dist/session/sqlite-job-store.d.ts.map +1 -0
- package/dist/session/sqlite-job-store.js +200 -0
- package/dist/session/sqlite-job-store.js.map +1 -0
- package/dist/session/sse.d.ts +60 -0
- package/dist/session/sse.d.ts.map +1 -0
- package/dist/session/sse.js +97 -0
- package/dist/session/sse.js.map +1 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/registry.d.ts +44 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +74 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/triggers/index.d.ts +15 -0
- package/dist/triggers/index.d.ts.map +1 -0
- package/dist/triggers/index.js +14 -0
- package/dist/triggers/index.js.map +1 -0
- package/dist/triggers/run-trigger.d.ts +86 -0
- package/dist/triggers/run-trigger.d.ts.map +1 -0
- package/dist/triggers/run-trigger.js +146 -0
- package/dist/triggers/run-trigger.js.map +1 -0
- package/dist/triggers/timer-trigger.d.ts +46 -0
- package/dist/triggers/timer-trigger.d.ts.map +1 -0
- package/dist/triggers/timer-trigger.js +74 -0
- package/dist/triggers/timer-trigger.js.map +1 -0
- package/dist/triggers/types.d.ts +61 -0
- package/dist/triggers/types.d.ts.map +1 -0
- package/dist/triggers/types.js +23 -0
- package/dist/triggers/types.js.map +1 -0
- 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"}
|