@effect-uai/core 0.5.2 → 0.7.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 (175) hide show
  1. package/README.md +1 -1
  2. package/dist/{Audio-BfCTGnH3.d.mts → Audio-DPlTsNdz.d.mts} +3 -2
  3. package/dist/Audio-DPlTsNdz.d.mts.map +1 -0
  4. package/dist/{Items-BH8xUkoR.d.mts → Items-D8UaXQx_.d.mts} +15 -15
  5. package/dist/Items-D8UaXQx_.d.mts.map +1 -0
  6. package/dist/SandboxError-BvKypkJm.d.mts +158 -0
  7. package/dist/SandboxError-BvKypkJm.d.mts.map +1 -0
  8. package/dist/{Tool-87ViKCCO.d.mts → Tool-CiFXYjmR.d.mts} +11 -11
  9. package/dist/{Tool-87ViKCCO.d.mts.map → Tool-CiFXYjmR.d.mts.map} +1 -1
  10. package/dist/capabilities/Capabilities.d.mts +78 -0
  11. package/dist/capabilities/Capabilities.d.mts.map +1 -0
  12. package/dist/capabilities/Capabilities.mjs +65 -0
  13. package/dist/capabilities/Capabilities.mjs.map +1 -0
  14. package/dist/domain/Audio.d.mts +1 -1
  15. package/dist/domain/Audio.mjs.map +1 -1
  16. package/dist/domain/Items.d.mts +2 -2
  17. package/dist/domain/Items.mjs +15 -15
  18. package/dist/domain/Items.mjs.map +1 -1
  19. package/dist/domain/Music.d.mts +131 -72
  20. package/dist/domain/Music.d.mts.map +1 -1
  21. package/dist/domain/Music.mjs +36 -9
  22. package/dist/domain/Music.mjs.map +1 -1
  23. package/dist/domain/Transcript.d.mts +8 -2
  24. package/dist/domain/Transcript.d.mts.map +1 -1
  25. package/dist/domain/Transcript.mjs.map +1 -1
  26. package/dist/domain/Turn.d.mts +388 -2
  27. package/dist/domain/Turn.d.mts.map +1 -0
  28. package/dist/domain/Turn.mjs +13 -13
  29. package/dist/domain/Turn.mjs.map +1 -1
  30. package/dist/embedding-model/Embedding.d.mts +12 -2
  31. package/dist/embedding-model/Embedding.d.mts.map +1 -1
  32. package/dist/embedding-model/Embedding.mjs.map +1 -1
  33. package/dist/embedding-model/EmbeddingModel.d.mts +36 -23
  34. package/dist/embedding-model/EmbeddingModel.d.mts.map +1 -1
  35. package/dist/embedding-model/EmbeddingModel.mjs +20 -1
  36. package/dist/embedding-model/EmbeddingModel.mjs.map +1 -1
  37. package/dist/embedding-model/EmbeddingModel.test.mjs +15 -3
  38. package/dist/embedding-model/EmbeddingModel.test.mjs.map +1 -1
  39. package/dist/index.d.mts +13 -7
  40. package/dist/index.mjs +9 -3
  41. package/dist/language-model/LanguageModel.d.mts +5 -5
  42. package/dist/language-model/LanguageModel.d.mts.map +1 -1
  43. package/dist/language-model/LanguageModel.mjs.map +1 -1
  44. package/dist/loop/Loop.d.mts +37 -90
  45. package/dist/loop/Loop.d.mts.map +1 -1
  46. package/dist/loop/Loop.mjs +39 -93
  47. package/dist/loop/Loop.mjs.map +1 -1
  48. package/dist/loop/Loop.test.mjs +46 -54
  49. package/dist/loop/Loop.test.mjs.map +1 -1
  50. package/dist/music-generator/MusicGenerator.d.mts +48 -25
  51. package/dist/music-generator/MusicGenerator.d.mts.map +1 -1
  52. package/dist/music-generator/MusicGenerator.mjs +17 -9
  53. package/dist/music-generator/MusicGenerator.mjs.map +1 -1
  54. package/dist/music-generator/MusicGenerator.test.mjs +81 -56
  55. package/dist/music-generator/MusicGenerator.test.mjs.map +1 -1
  56. package/dist/sandbox/Memory.d.mts +53 -0
  57. package/dist/sandbox/Memory.d.mts.map +1 -0
  58. package/dist/sandbox/Memory.mjs +68 -0
  59. package/dist/sandbox/Memory.mjs.map +1 -0
  60. package/dist/sandbox/Sandbox.d.mts +717 -0
  61. package/dist/sandbox/Sandbox.d.mts.map +1 -0
  62. package/dist/sandbox/Sandbox.mjs +192 -0
  63. package/dist/sandbox/Sandbox.mjs.map +1 -0
  64. package/dist/sandbox/SandboxError.d.mts +2 -0
  65. package/dist/sandbox/SandboxError.mjs +89 -0
  66. package/dist/sandbox/SandboxError.mjs.map +1 -0
  67. package/dist/sandbox/SandboxImage.d.mts +28 -0
  68. package/dist/sandbox/SandboxImage.d.mts.map +1 -0
  69. package/dist/sandbox/SandboxImage.mjs +32 -0
  70. package/dist/sandbox/SandboxImage.mjs.map +1 -0
  71. package/dist/sandbox/SandboxNetwork.d.mts +34 -0
  72. package/dist/sandbox/SandboxNetwork.d.mts.map +1 -0
  73. package/dist/sandbox/SandboxNetwork.mjs +36 -0
  74. package/dist/sandbox/SandboxNetwork.mjs.map +1 -0
  75. package/dist/speech-synthesizer/SpeechSynthesizer.d.mts +84 -3
  76. package/dist/speech-synthesizer/SpeechSynthesizer.d.mts.map +1 -1
  77. package/dist/speech-synthesizer/SpeechSynthesizer.mjs +32 -2
  78. package/dist/speech-synthesizer/SpeechSynthesizer.mjs.map +1 -1
  79. package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs +59 -5
  80. package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs.map +1 -1
  81. package/dist/testing/MockMusicGenerator.d.mts +12 -7
  82. package/dist/testing/MockMusicGenerator.d.mts.map +1 -1
  83. package/dist/testing/MockMusicGenerator.mjs +4 -3
  84. package/dist/testing/MockMusicGenerator.mjs.map +1 -1
  85. package/dist/testing/MockProvider.d.mts +3 -3
  86. package/dist/testing/MockProvider.d.mts.map +1 -1
  87. package/dist/testing/MockProvider.mjs.map +1 -1
  88. package/dist/testing/MockSandbox.d.mts +604 -0
  89. package/dist/testing/MockSandbox.d.mts.map +1 -0
  90. package/dist/testing/MockSandbox.mjs +160 -0
  91. package/dist/testing/MockSandbox.mjs.map +1 -0
  92. package/dist/testing/MockSpeechSynthesizer.d.mts +27 -12
  93. package/dist/testing/MockSpeechSynthesizer.d.mts.map +1 -1
  94. package/dist/testing/MockSpeechSynthesizer.mjs +75 -51
  95. package/dist/testing/MockSpeechSynthesizer.mjs.map +1 -1
  96. package/dist/tool/{Resolvers.d.mts → Approval.d.mts} +27 -27
  97. package/dist/tool/Approval.d.mts.map +1 -0
  98. package/dist/tool/{Resolvers.mjs → Approval.mjs} +18 -18
  99. package/dist/tool/Approval.mjs.map +1 -0
  100. package/dist/tool/{Resolvers.test.mjs → Approval.test.mjs} +40 -40
  101. package/dist/tool/Approval.test.mjs.map +1 -0
  102. package/dist/tool/HistoryCheck.d.mts +6 -6
  103. package/dist/tool/HistoryCheck.d.mts.map +1 -1
  104. package/dist/tool/HistoryCheck.mjs +5 -5
  105. package/dist/tool/HistoryCheck.mjs.map +1 -1
  106. package/dist/tool/Tool.d.mts +2 -2
  107. package/dist/tool/Tool.mjs +4 -4
  108. package/dist/tool/Tool.mjs.map +1 -1
  109. package/dist/tool/ToolEvent.d.mts +19 -19
  110. package/dist/tool/ToolEvent.d.mts.map +1 -1
  111. package/dist/tool/ToolEvent.mjs +8 -8
  112. package/dist/tool/ToolEvent.mjs.map +1 -1
  113. package/dist/tool/{Outcome.d.mts → ToolResult.d.mts} +29 -29
  114. package/dist/tool/ToolResult.d.mts.map +1 -0
  115. package/dist/tool/ToolResult.mjs +61 -0
  116. package/dist/tool/ToolResult.mjs.map +1 -0
  117. package/dist/tool/Toolkit.d.mts +58 -26
  118. package/dist/tool/Toolkit.d.mts.map +1 -1
  119. package/dist/tool/Toolkit.mjs +62 -34
  120. package/dist/tool/Toolkit.mjs.map +1 -1
  121. package/dist/tool/Toolkit.test.mjs +13 -13
  122. package/dist/tool/Toolkit.test.mjs.map +1 -1
  123. package/dist/transcriber/Transcriber.d.mts +11 -10
  124. package/dist/transcriber/Transcriber.d.mts.map +1 -1
  125. package/dist/transcriber/Transcriber.mjs.map +1 -1
  126. package/dist/transcriber/Transcriber.test.mjs +3 -3
  127. package/dist/transcriber/Transcriber.test.mjs.map +1 -1
  128. package/package.json +35 -7
  129. package/src/capabilities/Capabilities.ts +81 -0
  130. package/src/domain/Audio.ts +2 -1
  131. package/src/domain/Items.ts +9 -9
  132. package/src/domain/Music.ts +142 -68
  133. package/src/domain/Transcript.ts +7 -1
  134. package/src/domain/Turn.ts +16 -16
  135. package/src/embedding-model/Embedding.ts +11 -0
  136. package/src/embedding-model/EmbeddingModel.test.ts +15 -4
  137. package/src/embedding-model/EmbeddingModel.ts +48 -21
  138. package/src/index.ts +8 -2
  139. package/src/language-model/LanguageModel.ts +3 -3
  140. package/src/loop/Loop.test.ts +93 -91
  141. package/src/loop/Loop.ts +72 -170
  142. package/src/music-generator/MusicGenerator.test.ts +78 -53
  143. package/src/music-generator/MusicGenerator.ts +65 -24
  144. package/src/sandbox/Memory.ts +128 -0
  145. package/src/sandbox/Sandbox.ts +639 -0
  146. package/src/sandbox/SandboxError.ts +140 -0
  147. package/src/sandbox/SandboxImage.ts +26 -0
  148. package/src/sandbox/SandboxNetwork.ts +34 -0
  149. package/src/speech-synthesizer/SpeechSynthesizer.test.ts +92 -3
  150. package/src/speech-synthesizer/SpeechSynthesizer.ts +109 -0
  151. package/src/testing/MockMusicGenerator.ts +28 -18
  152. package/src/testing/MockProvider.ts +21 -20
  153. package/src/testing/MockSandbox.ts +342 -0
  154. package/src/testing/MockSpeechSynthesizer.ts +137 -77
  155. package/src/tool/{Resolvers.test.ts → Approval.test.ts} +45 -54
  156. package/src/tool/{Resolvers.ts → Approval.ts} +25 -25
  157. package/src/tool/HistoryCheck.ts +10 -13
  158. package/src/tool/Tool.ts +13 -15
  159. package/src/tool/ToolEvent.ts +7 -7
  160. package/src/tool/{Outcome.ts → ToolResult.ts} +20 -20
  161. package/src/tool/Toolkit.test.ts +13 -13
  162. package/src/tool/Toolkit.ts +97 -73
  163. package/src/transcriber/Transcriber.test.ts +3 -3
  164. package/src/transcriber/Transcriber.ts +10 -7
  165. package/dist/Audio-BfCTGnH3.d.mts.map +0 -1
  166. package/dist/Items-BH8xUkoR.d.mts.map +0 -1
  167. package/dist/Turn-0CwCAyVe.d.mts +0 -388
  168. package/dist/Turn-0CwCAyVe.d.mts.map +0 -1
  169. package/dist/tool/Outcome.d.mts.map +0 -1
  170. package/dist/tool/Outcome.mjs +0 -61
  171. package/dist/tool/Outcome.mjs.map +0 -1
  172. package/dist/tool/Resolvers.d.mts.map +0 -1
  173. package/dist/tool/Resolvers.mjs.map +0 -1
  174. package/dist/tool/Resolvers.test.mjs.map +0 -1
  175. /package/dist/tool/{Resolvers.test.d.mts → Approval.test.d.mts} +0 -0
package/src/loop/Loop.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Pull-based `loop` for state-threaded sub-streams.
3
3
  *
4
- * Each iteration runs a body that returns a `Stream<Event<A, S>>`. The body
4
+ * Each iteration runs a body that returns a `Stream<Step<A, S>>`. The body
5
5
  * emits values via `Loop.value(a)` and signals iteration control via
6
- * `Loop.next(state)` (continue with new state) or `Loop.stop` (terminate).
7
- * The loop unwraps `Value` events back to `A` for downstream consumers, so
6
+ * `Loop.next(state)` (continue with new state) or `Loop.stop()` (terminate).
7
+ * The loop unwraps `Value` steps back to `A` for downstream consumers, so
8
8
  * the resulting stream is a plain `Stream<A>`.
9
9
  *
10
10
  * The next body stream is only pulled when downstream pulls the outer
@@ -12,10 +12,11 @@
12
12
  * scoped resources, and backpressure stay aligned with normal Stream
13
13
  * semantics.
14
14
  *
15
- * Convention: a `Next` or `Stop` event is the terminal element of a body's
15
+ * Convention: a `Next` or `Stop` step is the terminal element of a body's
16
16
  * iteration. Values emitted in the same chunk after one are discarded
17
- * (their producing side effects may already have run). Prefer the
18
- * `Loop.nextAfter` / `Loop.stopAfter` helpers to terminate cleanly.
17
+ * (their producing side effects may already have run). The `Loop.next` /
18
+ * `Loop.stop` helpers each emit a single terminal step, so concatenate
19
+ * your values before them (`values.pipe(Stream.concat(Loop.next(state)))`).
19
20
  */
20
21
  import {
21
22
  Array as Arr,
@@ -28,7 +29,6 @@ import {
28
29
  Match,
29
30
  Option,
30
31
  Ref,
31
- Result,
32
32
  Scope,
33
33
  Stream,
34
34
  SubscriptionRef,
@@ -37,165 +37,67 @@ import { IncompleteTurn } from "../domain/AiError.js"
37
37
  import { isTurnComplete, type Turn, type TurnEvent } from "../domain/Turn.js"
38
38
 
39
39
  // ---------------------------------------------------------------------------
40
- // Event type - the body's emit shape
40
+ // Step type - the body's emit shape
41
41
  // ---------------------------------------------------------------------------
42
42
 
43
43
  /**
44
44
  * The tagged union a body emits per pull. `Value` carries a payload that
45
45
  * flows downstream. `Next` ends the current iteration and continues with a
46
46
  * new state. `Stop` ends the loop entirely with no carried state.
47
- * `StopWith` also ends the loop but carries a final state that `loopFrom`
47
+ * `StopWith` also ends the loop but carries a final state that `loopOver`
48
48
  * will thread to the next input and `loopWithState` will write to its
49
49
  * `SubscriptionRef` before the loop ends. Plain `loop` has no next
50
50
  * iteration to apply it to and treats `StopWith` like `Stop`.
51
51
  *
52
- * `Stop` is intentionally `{}` so the bare `stopEvent` / `stop` helpers
53
- * don't constrain `S` from a body's stream type — every body has a `Stop`
52
+ * `Stop` is intentionally `{}` so the bare `stop()` helper doesn't
53
+ * constrain `S` from a body's stream type — every body has a `Stop`
54
54
  * variant in its union, and forcing `S` to flow through it would break
55
- * inference whenever the body never uses `next` / `stopWith`.
55
+ * inference whenever the body never uses `next` / `stop(state)`.
56
56
  */
57
- export type Event<A, S> = Data.TaggedEnum<{
57
+ export type Step<A, S> = Data.TaggedEnum<{
58
58
  Value: { readonly value: A }
59
59
  Next: { readonly state: S }
60
60
  Stop: {}
61
61
  StopWith: { readonly state: S }
62
62
  }>
63
63
 
64
- interface EventDef extends Data.TaggedEnum.WithGenerics<2> {
65
- readonly taggedEnum: Event<this["A"], this["B"]>
64
+ interface StepDef extends Data.TaggedEnum.WithGenerics<2> {
65
+ readonly taggedEnum: Step<this["A"], this["B"]>
66
66
  }
67
67
 
68
- const Event = Data.taggedEnum<EventDef>()
68
+ const Step = Data.taggedEnum<StepDef>()
69
69
 
70
70
  /** Wrap a value so it flows through the loop to downstream consumers. */
71
- export const value = <A>(a: A): Event<A, never> => Event.Value({ value: a })
72
-
73
- /** End the current iteration and continue with a new state. */
74
- export const next = <S>(state: S): Event<never, S> => Event.Next({ state })
75
-
76
- /**
77
- * The terminal `Stop` event with no carried state. Use `stop` (the Stream)
78
- * to end a loop body without communicating a final state.
79
- */
80
- export const stopEvent: Event<never, never> = Event.Stop()
81
-
82
- /**
83
- * Terminal event that ends the loop AND carries a final state. For
84
- * `loopFrom` this is the natural "this input is done, here's the state to
85
- * carry forward to the next input" signal — symmetric with `next(s)` but
86
- * ending the inner loop instead of continuing it. For `loopWithState` the
87
- * carried state is written to the `SubscriptionRef` before the loop ends.
88
- */
89
- export const stopWith = <S>(state: S): Event<never, S> => Event.StopWith({ state })
90
-
91
- /**
92
- * A single-element stream that ends the loop. Return this from a body when
93
- * there's nothing else to emit; equivalent to `stopAfter(Stream.empty)` but
94
- * named for the common case.
95
- */
96
- export const stop: Stream.Stream<Event<never, never>> = Stream.succeed(stopEvent)
97
-
98
- /**
99
- * Pipe a raw `Stream<A>` into the loop's emit shape, then terminate the
100
- * iteration with `next(state)`. Common shape for "stream this turn's
101
- * deltas, then continue with updated history."
102
- *
103
- * Dual: data-first `nextAfter(stream, state)` and data-last
104
- * `stream.pipe(nextAfter(state))` both work.
105
- */
106
- export const nextAfter: {
107
- <S>(state: S): <A, E, R>(stream: Stream.Stream<A, E, R>) => Stream.Stream<Event<A, S>, E, R>
108
- <S, A, E, R>(stream: Stream.Stream<A, E, R>, state: S): Stream.Stream<Event<A, S>, E, R>
109
- } = Function.dual(
110
- 2,
111
- <S, A, E, R>(stream: Stream.Stream<A, E, R>, state: S): Stream.Stream<Event<A, S>, E, R> =>
112
- Stream.concat(Stream.map(stream, value), Stream.fromIterable([next(state)])),
113
- )
114
-
115
- /**
116
- * Pipe a raw `Stream<A>` into the loop's emit shape, then terminate the
117
- * loop. Common shape for "stream this turn's deltas, then we're done."
118
- *
119
- * Unary on the stream — already pipe-compatible via `stream.pipe(stopAfter)`.
120
- */
121
- export const stopAfter = <A, E, R>(
122
- stream: Stream.Stream<A, E, R>,
123
- ): Stream.Stream<Event<A, never>, E, R> =>
124
- Stream.concat(Stream.map(stream, value), Stream.fromIterable([stopEvent]))
71
+ export const value = <A>(a: A): Step<A, never> => Step.Value({ value: a })
125
72
 
126
73
  /**
127
- * Pipe a raw `Stream<A>` into the loop's emit shape, then terminate with
128
- * `stopWith(state)`. The natural "emit final outputs, advance state, end
129
- * this input's inner loop" shape for `loopFrom`.
130
- *
131
- * Dual: data-first `stopWithAfter(stream, state)` and data-last
132
- * `stream.pipe(stopWithAfter(state))` both work.
74
+ * End the current iteration and continue with a new state. Emits a single
75
+ * terminal `Next` step as a one-element stream, so it slots directly into a
76
+ * loop body or after a run of values: `values.pipe(Stream.concat(next(s)))`.
133
77
  */
134
- export const stopWithAfter: {
135
- <S>(state: S): <A, E, R>(stream: Stream.Stream<A, E, R>) => Stream.Stream<Event<A, S>, E, R>
136
- <S, A, E, R>(stream: Stream.Stream<A, E, R>, state: S): Stream.Stream<Event<A, S>, E, R>
137
- } = Function.dual(
138
- 2,
139
- <S, A, E, R>(stream: Stream.Stream<A, E, R>, state: S): Stream.Stream<Event<A, S>, E, R> =>
140
- Stream.concat(Stream.map(stream, value), Stream.fromIterable([stopWith(state)])),
141
- )
78
+ export const next = <S>(state: S): Stream.Stream<Step<never, S>> =>
79
+ Stream.succeed(Step.Next({ state }))
142
80
 
143
81
  /**
144
- * General `nextAfter` variant: drain `stream` to the consumer, fold elements
145
- * into an accumulator, and at end-of-stream emit one `next(build(finalAcc))`.
146
- *
147
- * Subsumes `nextAfter` when state is constant (`reduce: (s, _) => s`,
148
- * `build: (s) => s`). Used by `Toolkit.continueWith` to collect tool
149
- * results and build next state without exposing a Ref to recipes.
150
- *
151
- * Dual: data-first `nextAfterFold(stream, initial, reduce, build)` and
152
- * data-last `stream.pipe(nextAfterFold(initial, reduce, build))` both work.
82
+ * End the loop. Called with no argument it emits a bare `Stop`; called with
83
+ * a state it emits `StopWith(state)` — `loopOver` threads that final state
84
+ * to the next input and `loopWithState` writes it to its `SubscriptionRef`
85
+ * before the loop ends. Either way it returns a single-element stream, so
86
+ * return it directly from a loop body.
153
87
  */
154
- export const nextAfterFold: {
155
- <A, B, S>(
156
- initial: B,
157
- reduce: (acc: B, a: A) => B,
158
- build: (b: B) => S,
159
- ): <E, R>(stream: Stream.Stream<A, E, R>) => Stream.Stream<Event<A, S>, E, R>
160
- <A, B, S, E, R>(
161
- stream: Stream.Stream<A, E, R>,
162
- initial: B,
163
- reduce: (acc: B, a: A) => B,
164
- build: (b: B) => S,
165
- ): Stream.Stream<Event<A, S>, E, R>
166
- } = Function.dual(
167
- 4,
168
- <A, B, S, E, R>(
169
- stream: Stream.Stream<A, E, R>,
170
- initial: B,
171
- reduce: (acc: B, a: A) => B,
172
- build: (b: B) => S,
173
- ): Stream.Stream<Event<A, S>, E, R> =>
174
- Stream.unwrap(
175
- Effect.gen(function* () {
176
- const ref = yield* Ref.make(initial)
177
- const tapped = stream.pipe(
178
- Stream.tap((a) => Ref.update(ref, (acc) => reduce(acc, a))),
179
- Stream.map(value),
180
- )
181
- const continuation = Stream.fromEffect(
182
- Ref.get(ref).pipe(Effect.map((acc) => next(build(acc)))),
183
- )
184
- return tapped.pipe(Stream.concat(continuation))
185
- }),
186
- ),
187
- )
88
+ export const stop = <S = never>(state?: S): Stream.Stream<Step<never, S>> =>
89
+ Stream.succeed<Step<never, S>>(state === undefined ? Step.Stop() : Step.StopWith({ state }))
188
90
 
189
91
  // ---------------------------------------------------------------------------
190
92
  // onTurnComplete - turn-aware stream operator for loop bodies
191
93
  // ---------------------------------------------------------------------------
192
94
 
193
95
  /**
194
- * Lift a provider's `Stream<TurnEvent>` into a loop body's `Stream<Event<TurnEvent | A, S>>`.
96
+ * Lift a provider's `Stream<TurnEvent>` into a loop body's `Stream<Step<TurnEvent | A, S>>`.
195
97
  * Each delta passes through as `value(delta)` (including the terminal
196
98
  * `TurnComplete`, so the consumer sees turn boundaries naturally). Once
197
99
  * the terminal arrives, `then(turn)` runs and its returned stream of loop
198
- * events (typically tool outputs followed by `next(state)` or `stop`) is
100
+ * steps (typically tool outputs followed by `next(state)` or `stop()`) is
199
101
  * concatenated.
200
102
  *
201
103
  * Pre-pipe transforms (`Stream.tap` / `Stream.map` / `Stream.filter`) on
@@ -210,25 +112,25 @@ export const nextAfterFold: {
210
112
  */
211
113
  export const onTurnComplete: {
212
114
  <S, A, E2 = never, R2 = never>(
213
- then: (turn: Turn) => Effect.Effect<Stream.Stream<Event<A, S>, E2, R2>, E2, R2>,
115
+ then: (turn: Turn) => Effect.Effect<Stream.Stream<Step<A, S>, E2, R2>, E2, R2>,
214
116
  ): <E, R>(
215
117
  deltas: Stream.Stream<TurnEvent, E, R>,
216
- ) => Stream.Stream<Event<TurnEvent | A, S>, E | E2 | IncompleteTurn, R | R2>
118
+ ) => Stream.Stream<Step<TurnEvent | A, S>, E | E2 | IncompleteTurn, R | R2>
217
119
  <S, A, E, R, E2 = never, R2 = never>(
218
120
  deltas: Stream.Stream<TurnEvent, E, R>,
219
- then: (turn: Turn) => Effect.Effect<Stream.Stream<Event<A, S>, E2, R2>, E2, R2>,
220
- ): Stream.Stream<Event<TurnEvent | A, S>, E | E2 | IncompleteTurn, R | R2>
121
+ then: (turn: Turn) => Effect.Effect<Stream.Stream<Step<A, S>, E2, R2>, E2, R2>,
122
+ ): Stream.Stream<Step<TurnEvent | A, S>, E | E2 | IncompleteTurn, R | R2>
221
123
  } = Function.dual(
222
124
  2,
223
125
  <S, A, E, R, E2, R2>(
224
126
  deltas: Stream.Stream<TurnEvent, E, R>,
225
- then: (turn: Turn) => Effect.Effect<Stream.Stream<Event<A, S>, E2, R2>, E2, R2>,
226
- ): Stream.Stream<Event<TurnEvent | A, S>, E | E2 | IncompleteTurn, R | R2> =>
127
+ then: (turn: Turn) => Effect.Effect<Stream.Stream<Step<A, S>, E2, R2>, E2, R2>,
128
+ ): Stream.Stream<Step<TurnEvent | A, S>, E | E2 | IncompleteTurn, R | R2> =>
227
129
  Stream.unwrap(
228
130
  Effect.gen(function* () {
229
131
  const turnRef = yield* Ref.make<Option.Option<Turn>>(Option.none())
230
132
 
231
- const events: Stream.Stream<Event<TurnEvent, S>, E, R> = deltas.pipe(
133
+ const events: Stream.Stream<Step<TurnEvent, S>, E, R> = deltas.pipe(
232
134
  Stream.tap((delta) =>
233
135
  isTurnComplete(delta) ? Ref.set(turnRef, Option.some(delta.turn)) : Effect.void,
234
136
  ),
@@ -257,7 +159,7 @@ const isNonEmpty = <A>(array: ReadonlyArray<A>): array is readonly [A, ...Array<
257
159
 
258
160
  type CurrentBody<S, A, E, R> = {
259
161
  readonly scope: Scope.Closeable
260
- readonly pull: Effect.Effect<ReadonlyArray<Event<A, S>>, E | Cause.Done<void>, R>
162
+ readonly pull: Effect.Effect<ReadonlyArray<Step<A, S>>, E | Cause.Done<void>, R>
261
163
  }
262
164
 
263
165
  const closeBody = <S, A, E, R>(
@@ -266,23 +168,23 @@ const closeBody = <S, A, E, R>(
266
168
  ) => Scope.close(current.scope, exit)
267
169
 
268
170
  /**
269
- * Walk a chunk of `Event<A, S>` until a terminal `Next` or `Stop` is found.
171
+ * Walk a chunk of `Step<A, S>` until a terminal `Next` or `Stop` is found.
270
172
  * Returns the unwrapped values seen so far and (optionally) the terminal
271
- * event. Anything in the chunk after the terminal is discarded - its
173
+ * step. Anything in the chunk after the terminal is discarded - its
272
174
  * producing side effects may have run, but downstream never sees it.
273
175
  */
274
176
  const partitionChunk = <A, S>(
275
- chunk: ReadonlyArray<Event<A, S>>,
177
+ chunk: ReadonlyArray<Step<A, S>>,
276
178
  ): {
277
179
  readonly values: ReadonlyArray<A>
278
- readonly decision: Option.Option<Event<A, S>>
180
+ readonly decision: Option.Option<Step<A, S>>
279
181
  } => {
280
- const [valueEvents, rest] = Arr.span(
182
+ const [valueSteps, rest] = Arr.span(
281
183
  chunk,
282
- (e): e is Event<A, S> & { _tag: "Value" } => e._tag === "Value",
184
+ (e): e is Step<A, S> & { _tag: "Value" } => e._tag === "Value",
283
185
  )
284
186
  return {
285
- values: valueEvents.map((e) => e.value),
187
+ values: valueSteps.map((e) => e.value),
286
188
  decision: Arr.head(rest),
287
189
  }
288
190
  }
@@ -293,12 +195,12 @@ const partitionChunk = <A, S>(
293
195
 
294
196
  type LoopBody<S, A, E, R> = (
295
197
  state: S,
296
- ) => Stream.Stream<Event<A, S>, E, R> | Effect.Effect<Stream.Stream<Event<A, S>, E, R>, E, R>
198
+ ) => Stream.Stream<Step<A, S>, E, R> | Effect.Effect<Stream.Stream<Step<A, S>, E, R>, E, R>
297
199
 
298
200
  /**
299
201
  * Drive a state-threaded loop body. Each iteration runs `body(state)` to get
300
- * a `Stream<Event<A, S>>`; values flow downstream, `next(s)` continues with
301
- * a new state, `stop` ends the loop. See the file header for the full
202
+ * a `Stream<Step<A, S>>`; values flow downstream, `next(s)` continues with
203
+ * a new state, `stop()` ends the loop. See the file header for the full
302
204
  * pull-based execution model.
303
205
  *
304
206
  * Dual: data-first `loop(initial, body)` and data-last `loop(body)(initial)`
@@ -352,7 +254,7 @@ export const loop: {
352
254
  const chunk = yield* active.pull.pipe(
353
255
  Effect.catchIf(Cause.isDone, () =>
354
256
  closeActive(active, Exit.void).pipe(
355
- Effect.as(undefined as ReadonlyArray<Event<A, S>> | undefined),
257
+ Effect.as(undefined as ReadonlyArray<Step<A, S>> | undefined),
356
258
  ),
357
259
  ),
358
260
  Effect.onError((cause) => closeActive(active, Exit.failCause(cause))),
@@ -369,7 +271,7 @@ export const loop: {
369
271
  yield* closeActive(active, Exit.void)
370
272
  if (decision.value._tag === "Stop" || decision.value._tag === "StopWith") {
371
273
  // `loop` has no next iteration to apply StopWith's state to;
372
- // the state lands in `loopFrom`'s outer ref or
274
+ // the state lands in `loopOver`'s outer ref or
373
275
  // `loopWithState`'s SubscriptionRef via their taps.
374
276
  done = true
375
277
  } else if (decision.value._tag === "Next") {
@@ -378,7 +280,7 @@ export const loop: {
378
280
  }
379
281
 
380
282
  // Emit the values seen so far if any. Chunks from a Stream pull
381
- // are non-empty, so when `decision` is `None` every event was
283
+ // are non-empty, so when `decision` is `None` every step was
382
284
  // a `Value` and `values` is non-empty here. With a decision and
383
285
  // no preceding values, fall through to the next iteration.
384
286
  if (isNonEmpty(values)) return values
@@ -392,54 +294,54 @@ export const loop: {
392
294
  )
393
295
 
394
296
  // ---------------------------------------------------------------------------
395
- // loopFrom - stream-driven sibling of loop. One input item runs a full
297
+ // loopOver - stream-driven sibling of loop. One input item runs a full
396
298
  // multi-turn inner loop.
397
299
  // ---------------------------------------------------------------------------
398
300
 
399
- type LoopFromBody<S, I, A, E, R> = (
301
+ type LoopOverBody<S, I, A, E, R> = (
400
302
  state: S,
401
303
  input: I,
402
- ) => Stream.Stream<Event<A, S>, E, R> | Effect.Effect<Stream.Stream<Event<A, S>, E, R>, E, R>
304
+ ) => Stream.Stream<Step<A, S>, E, R> | Effect.Effect<Stream.Stream<Step<A, S>, E, R>, E, R>
403
305
 
404
306
  /**
405
307
  * Input-driven sibling of `loop`. For each item pulled from the input
406
308
  * stream, runs an inner seed-driven `loop` whose body is
407
309
  * `(s) => body(s, item)`. State is threaded across input items.
408
310
  *
409
- * **Per-input semantics — the body emits standard `Event<A, S>`:**
311
+ * **Per-input semantics — the body emits standard `Step<A, S>`:**
410
312
  * - `value(a)`: emit `a` downstream
411
313
  * - `next(s)`: re-run the body with the SAME input and new state `s`
412
314
  * (multi-turn within one input — e.g. multiple model turns + tool
413
315
  * calls for one document)
414
- * - `stop`: end this input's inner loop, advance to the next input
316
+ * - `stop()`: end this input's inner loop, advance to the next input
415
317
  * (state preserved)
416
- * - body stream ending without a decision: same as `stop` (advance)
318
+ * - body stream ending without a decision: same as `stop()` (advance)
417
319
  *
418
320
  * **Outer termination:** the input stream ending. To halt programmatically
419
321
  * from within, end the input stream upstream (`Stream.takeWhile`, a
420
- * `SubscriptionRef` gate, etc.). Reserving `stop` for per-item
322
+ * `SubscriptionRef` gate, etc.). Reserving `stop()` for per-item
421
323
  * advancement is what makes the common "stream of documents, multi-turn
422
324
  * conversation per document" shape readable.
423
325
  *
424
- * Dual: data-first `loopFrom(input, initial, body)` and data-last
425
- * `input.pipe(loopFrom(initial, body))` both work.
326
+ * Dual: data-first `loopOver(input, initial, body)` and data-last
327
+ * `input.pipe(loopOver(initial, body))` both work.
426
328
  */
427
- export const loopFrom: {
329
+ export const loopOver: {
428
330
  <S, I, A, E, R>(
429
331
  initial: S,
430
- body: LoopFromBody<S, I, A, E, R>,
332
+ body: LoopOverBody<S, I, A, E, R>,
431
333
  ): <EI, RI>(input: Stream.Stream<I, EI, RI>) => Stream.Stream<A, E | EI, R | RI>
432
334
  <S, I, A, E, R, EI, RI>(
433
335
  input: Stream.Stream<I, EI, RI>,
434
336
  initial: S,
435
- body: LoopFromBody<S, I, A, E, R>,
337
+ body: LoopOverBody<S, I, A, E, R>,
436
338
  ): Stream.Stream<A, E | EI, R | RI>
437
339
  } = Function.dual(
438
340
  3,
439
341
  <S, I, A, E, R, EI, RI>(
440
342
  input: Stream.Stream<I, EI, RI>,
441
343
  initial: S,
442
- body: LoopFromBody<S, I, A, E, R>,
344
+ body: LoopOverBody<S, I, A, E, R>,
443
345
  ): Stream.Stream<A, E | EI, R | RI> =>
444
346
  Stream.unwrap(
445
347
  Effect.gen(function* () {
@@ -449,15 +351,15 @@ export const loopFrom: {
449
351
  Stream.unwrap(
450
352
  Effect.gen(function* () {
451
353
  const state = yield* Ref.get(stateRef)
452
- // Capture Next states (and stopWith's final state) into the
354
+ // Capture Next states (and stop(state)'s final state) into the
453
355
  // outer ref so the LAST state seen in this input's inner
454
356
  // loop is what the next input starts from.
455
357
  const wrappedBody = (s: S) => {
456
358
  const result = body(s, item)
457
359
  const stream = Effect.isEffect(result) ? Stream.unwrap(result) : result
458
360
  return stream.pipe(
459
- Stream.tap((event) =>
460
- Match.value(event).pipe(
361
+ Stream.tap((step) =>
362
+ Match.value(step).pipe(
461
363
  Match.tags({
462
364
  Next: (e) => Ref.set(stateRef, e.state),
463
365
  StopWith: (e) => Ref.set(stateRef, e.state),
@@ -485,7 +387,7 @@ export const loopFrom: {
485
387
  * alongside the value stream.
486
388
  *
487
389
  * Allocates one `SubscriptionRef<S>` seeded with `initial`, then runs the
488
- * loop with a wrapped body that taps every `Next(s)` event into the ref
390
+ * loop with a wrapped body that taps every `Next(s)` step into the ref
489
391
  * before forwarding it. The caller decides how to consume both channels:
490
392
  *
491
393
  * - **Final state**: drain the stream, then `SubscriptionRef.get(state)`
@@ -510,10 +412,10 @@ export const loopWithState = <S, A, E, R>(
510
412
  Effect.gen(function* () {
511
413
  const stateRef = yield* SubscriptionRef.make(initial)
512
414
 
513
- const tap = (stream: Stream.Stream<Event<A, S>, E, R>): Stream.Stream<Event<A, S>, E, R> =>
415
+ const tap = (stream: Stream.Stream<Step<A, S>, E, R>): Stream.Stream<Step<A, S>, E, R> =>
514
416
  stream.pipe(
515
- Stream.tap((event) =>
516
- Match.value(event).pipe(
417
+ Stream.tap((step) =>
418
+ Match.value(step).pipe(
517
419
  Match.tags({
518
420
  Next: (e) => SubscriptionRef.set(stateRef, e.state),
519
421
  StopWith: (e) => SubscriptionRef.set(stateRef, e.state),