@effect-uai/core 0.18.0 → 0.19.0-dev-20261110065930

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 (162) hide show
  1. package/README.md +4 -4
  2. package/dist/Content-D_Qfn8Ja.d.mts +48 -0
  3. package/dist/Content-D_Qfn8Ja.d.mts.map +1 -0
  4. package/dist/File-B923KvZ9.d.mts +46 -0
  5. package/dist/File-B923KvZ9.d.mts.map +1 -0
  6. package/dist/{Image-Cv6iBLTy.d.mts → Image-Bzc1H_UK.d.mts} +19 -8
  7. package/dist/Image-Bzc1H_UK.d.mts.map +1 -0
  8. package/dist/{Items-C7MyrYPX.d.mts → Items-Bvx8s9QH.d.mts} +109 -16
  9. package/dist/Items-Bvx8s9QH.d.mts.map +1 -0
  10. package/dist/{Loop-ChpaO-ya.d.mts → Loop-CeA0AelN.d.mts} +7 -6
  11. package/dist/Loop-CeA0AelN.d.mts.map +1 -0
  12. package/dist/Tool-Bkryw6-h.d.mts +206 -0
  13. package/dist/Tool-Bkryw6-h.d.mts.map +1 -0
  14. package/dist/ToolEvent-9inLx5cI.d.mts +22 -0
  15. package/dist/ToolEvent-9inLx5cI.d.mts.map +1 -0
  16. package/dist/ToolOutput-BNTIQgGB.d.mts +151 -0
  17. package/dist/ToolOutput-BNTIQgGB.d.mts.map +1 -0
  18. package/dist/Toolkit-D2VGeD5R.d.mts +212 -0
  19. package/dist/Toolkit-D2VGeD5R.d.mts.map +1 -0
  20. package/dist/browser/BrowserTool.d.mts +84 -22
  21. package/dist/browser/BrowserTool.d.mts.map +1 -1
  22. package/dist/browser/BrowserTool.mjs +5 -0
  23. package/dist/browser/BrowserTool.mjs.map +1 -1
  24. package/dist/capabilities/Capabilities.d.mts +1 -1
  25. package/dist/decision-model/Decision.test.mjs +1 -1
  26. package/dist/{dist-C8RmtoR8.mjs → dist-B5K-y4Be.mjs} +51 -32
  27. package/dist/dist-B5K-y4Be.mjs.map +1 -0
  28. package/dist/domain/File.d.mts +2 -0
  29. package/dist/domain/File.mjs +51 -0
  30. package/dist/domain/File.mjs.map +1 -0
  31. package/dist/domain/Image.d.mts +2 -2
  32. package/dist/domain/Image.mjs +12 -2
  33. package/dist/domain/Image.mjs.map +1 -1
  34. package/dist/domain/Items.d.mts +2 -2
  35. package/dist/domain/Items.mjs +65 -4
  36. package/dist/domain/Items.mjs.map +1 -1
  37. package/dist/domain/Realtime.d.mts +72 -490
  38. package/dist/domain/Realtime.d.mts.map +1 -1
  39. package/dist/domain/Research.d.mts +1 -1
  40. package/dist/domain/Transcript.test.mjs +1 -1
  41. package/dist/domain/Turn.d.mts +57 -262
  42. package/dist/domain/Turn.d.mts.map +1 -1
  43. package/dist/domain/Turn.mjs +1 -1
  44. package/dist/embedding-model/Embedding.d.mts +1 -1
  45. package/dist/image-generator/ImageGenerator.d.mts +10 -66
  46. package/dist/image-generator/ImageGenerator.d.mts.map +1 -1
  47. package/dist/index.d.mts +10 -9
  48. package/dist/index.mjs +7 -6
  49. package/dist/language-model/LanguageModel.d.mts +2 -2
  50. package/dist/loop/Loop.d.mts +1 -1
  51. package/dist/loop/Loop.mjs.map +1 -1
  52. package/dist/messenger/Messenger.d.mts +43 -289
  53. package/dist/messenger/Messenger.d.mts.map +1 -1
  54. package/dist/messenger/MessengerAdapter.test.mjs +1 -1
  55. package/dist/observability/Metrics.d.mts +1 -1
  56. package/dist/observability/Metrics.test.mjs +1 -1
  57. package/dist/observability/Telemetry.test.mjs +1 -1
  58. package/dist/realtime/RealtimeSession.d.mts +1 -1
  59. package/dist/realtime/RealtimeSession.test.mjs +1 -1
  60. package/dist/sandbox/Sandbox.d.mts +32 -237
  61. package/dist/sandbox/Sandbox.d.mts.map +1 -1
  62. package/dist/streaming/Multipart.mjs +2 -1
  63. package/dist/streaming/Multipart.mjs.map +1 -1
  64. package/dist/streaming/Multipart.test.mjs +28 -0
  65. package/dist/streaming/Multipart.test.mjs.map +1 -0
  66. package/dist/streaming/Settle.test.mjs +1 -1
  67. package/dist/streaming/WebSocketSession.test.mjs +1 -1
  68. package/dist/testing/MockMessenger.d.mts +19 -134
  69. package/dist/testing/MockMessenger.d.mts.map +1 -1
  70. package/dist/testing/MockProvider.d.mts +1 -1
  71. package/dist/testing/MockSandbox.d.mts +65 -446
  72. package/dist/testing/MockSandbox.d.mts.map +1 -1
  73. package/dist/tool/Content.d.mts +2 -0
  74. package/dist/tool/Content.mjs +46 -0
  75. package/dist/tool/Content.mjs.map +1 -0
  76. package/dist/tool/Content.test.d.mts +1 -0
  77. package/dist/tool/Content.test.mjs +48 -0
  78. package/dist/tool/Content.test.mjs.map +1 -0
  79. package/dist/tool/HistoryCheck.d.mts +6 -15
  80. package/dist/tool/HistoryCheck.d.mts.map +1 -1
  81. package/dist/tool/HistoryCheck.mjs +10 -24
  82. package/dist/tool/HistoryCheck.mjs.map +1 -1
  83. package/dist/tool/Tool.d.mts +2 -2
  84. package/dist/tool/Tool.mjs +55 -130
  85. package/dist/tool/Tool.mjs.map +1 -1
  86. package/dist/tool/Tool.test.mjs +220 -176
  87. package/dist/tool/Tool.test.mjs.map +1 -1
  88. package/dist/tool/ToolDecision.d.mts +164 -0
  89. package/dist/tool/ToolDecision.d.mts.map +1 -0
  90. package/dist/tool/ToolDecision.mjs +146 -0
  91. package/dist/tool/ToolDecision.mjs.map +1 -0
  92. package/dist/tool/ToolDecision.test.d.mts +1 -0
  93. package/dist/tool/ToolDecision.test.mjs +330 -0
  94. package/dist/tool/ToolDecision.test.mjs.map +1 -0
  95. package/dist/tool/ToolEvent.d.mts +2 -2
  96. package/dist/tool/ToolEvent.mjs +2 -34
  97. package/dist/tool/ToolEvent.mjs.map +1 -1
  98. package/dist/tool/ToolOutput.d.mts +2 -0
  99. package/dist/tool/ToolOutput.mjs +128 -0
  100. package/dist/tool/ToolOutput.mjs.map +1 -0
  101. package/dist/tool/ToolOutput.test.d.mts +1 -0
  102. package/dist/tool/ToolOutput.test.mjs +153 -0
  103. package/dist/tool/ToolOutput.test.mjs.map +1 -0
  104. package/dist/tool/Toolkit.d.mts +2 -2
  105. package/dist/tool/Toolkit.mjs +230 -165
  106. package/dist/tool/Toolkit.mjs.map +1 -1
  107. package/dist/tool/Toolkit.test.mjs +431 -389
  108. package/dist/tool/Toolkit.test.mjs.map +1 -1
  109. package/dist/web-read/WebReadTool.d.mts +2 -2
  110. package/dist/web-read/WebReadTool.mjs +1 -0
  111. package/dist/web-read/WebReadTool.mjs.map +1 -1
  112. package/dist/web-search/WebSearchTool.d.mts +2 -2
  113. package/dist/web-search/WebSearchTool.mjs +1 -0
  114. package/dist/web-search/WebSearchTool.mjs.map +1 -1
  115. package/package.json +17 -9
  116. package/src/browser/BrowserTool.ts +5 -0
  117. package/src/domain/File.ts +79 -0
  118. package/src/domain/Image.ts +14 -4
  119. package/src/domain/Items.ts +39 -3
  120. package/src/index.ts +3 -2
  121. package/src/loop/Loop.ts +24 -13
  122. package/src/streaming/Multipart.test.ts +26 -0
  123. package/src/streaming/Multipart.ts +5 -4
  124. package/src/tool/Content.test.ts +40 -0
  125. package/src/tool/Content.ts +38 -0
  126. package/src/tool/HistoryCheck.ts +21 -26
  127. package/src/tool/Tool.test.ts +240 -241
  128. package/src/tool/Tool.ts +203 -308
  129. package/src/tool/ToolDecision.test.ts +301 -0
  130. package/src/tool/ToolDecision.ts +360 -0
  131. package/src/tool/ToolEvent.ts +21 -41
  132. package/src/tool/ToolOutput.test.ts +132 -0
  133. package/src/tool/ToolOutput.ts +198 -0
  134. package/src/tool/Toolkit.test.ts +594 -454
  135. package/src/tool/Toolkit.ts +631 -356
  136. package/src/web-read/WebReadTool.ts +2 -1
  137. package/src/web-search/WebSearchTool.ts +2 -1
  138. package/dist/Image-Cv6iBLTy.d.mts.map +0 -1
  139. package/dist/Items-C7MyrYPX.d.mts.map +0 -1
  140. package/dist/Loop-ChpaO-ya.d.mts.map +0 -1
  141. package/dist/Tool-BF78QWtn.d.mts +0 -314
  142. package/dist/Tool-BF78QWtn.d.mts.map +0 -1
  143. package/dist/ToolEvent-Di4a723B.d.mts +0 -144
  144. package/dist/ToolEvent-Di4a723B.d.mts.map +0 -1
  145. package/dist/ToolResult-BsYQRjmW.d.mts +0 -152
  146. package/dist/ToolResult-BsYQRjmW.d.mts.map +0 -1
  147. package/dist/Toolkit-tlL0F2YR.d.mts +0 -193
  148. package/dist/Toolkit-tlL0F2YR.d.mts.map +0 -1
  149. package/dist/dist-C8RmtoR8.mjs.map +0 -1
  150. package/dist/tool/Approval.d.mts +0 -113
  151. package/dist/tool/Approval.d.mts.map +0 -1
  152. package/dist/tool/Approval.mjs +0 -80
  153. package/dist/tool/Approval.mjs.map +0 -1
  154. package/dist/tool/Approval.test.mjs +0 -371
  155. package/dist/tool/Approval.test.mjs.map +0 -1
  156. package/dist/tool/ToolResult.d.mts +0 -2
  157. package/dist/tool/ToolResult.mjs +0 -85
  158. package/dist/tool/ToolResult.mjs.map +0 -1
  159. package/src/tool/Approval.test.ts +0 -400
  160. package/src/tool/Approval.ts +0 -181
  161. package/src/tool/ToolResult.ts +0 -114
  162. /package/dist/{tool/Approval.test.d.mts → streaming/Multipart.test.d.mts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"Loop.mjs","names":["Arr"],"sources":["../../src/loop/Loop.ts"],"sourcesContent":["/**\n * Pull-based `loop` for state-threaded sub-streams.\n *\n * Each iteration runs a body that returns a `Stream<Step<A, S>>`. The body\n * emits values via `Loop.value(a)` and signals iteration control via\n * `Loop.next(state)` (continue with new state) or `Loop.stop()` (terminate).\n * The loop unwraps `Value` steps back to `A` for downstream consumers, so\n * the resulting stream is a plain `Stream<A>`.\n *\n * The next body stream is only pulled when downstream pulls the outer\n * stream - no producer fiber, no queue buffering. Cancellation, failures,\n * scoped resources, and backpressure stay aligned with normal Stream\n * semantics.\n *\n * Convention: a `Next` or `Stop` step is the terminal element of a body's\n * iteration. Values emitted in the same chunk after one are discarded\n * (their producing side effects may already have run). The `Loop.next` /\n * `Loop.stop` helpers each emit a single terminal step, so concatenate\n * your values before them (`values.pipe(Stream.concat(Loop.next(state)))`).\n */\nimport {\n Array as Arr,\n Cause,\n Channel,\n Data,\n Effect,\n Exit,\n Function,\n Match,\n Option,\n Ref,\n Scope,\n Stream,\n SubscriptionRef,\n} from \"effect\"\nimport { IncompleteTurn } from \"../domain/AiError.js\"\nimport { isTurnComplete, type Turn, type TurnEvent } from \"../domain/Turn.js\"\n\n// ---------------------------------------------------------------------------\n// Step type - the body's emit shape\n// ---------------------------------------------------------------------------\n\n/**\n * The tagged union a body emits per pull. `Value` carries a payload that\n * flows downstream. `Next` ends the current iteration and continues with a\n * new state. `Stop` ends the loop entirely with no carried state.\n * `StopWith` also ends the loop but carries a final state that `loopOver`\n * will thread to the next input and `loopWithState` will write to its\n * `SubscriptionRef` before the loop ends. Plain `loop` has no next\n * iteration to apply it to and treats `StopWith` like `Stop`.\n *\n * `Stop` is intentionally `{}` so the bare `stop()` helper doesn't\n * constrain `S` from a body's stream type — every body has a `Stop`\n * variant in its union, and forcing `S` to flow through it would break\n * inference whenever the body never uses `next` / `stop(state)`.\n */\nexport type Step<A, S> = Data.TaggedEnum<{\n Value: { readonly value: A }\n Next: { readonly state: S }\n Stop: {}\n StopWith: { readonly state: S }\n}>\n\ninterface StepDef extends Data.TaggedEnum.WithGenerics<2> {\n readonly taggedEnum: Step<this[\"A\"], this[\"B\"]>\n}\n\nconst Step = Data.taggedEnum<StepDef>()\n\n/**\n * Bare step constructors, so a loop body can emit `Value(...)`, `Next(...)`,\n * `Stop()`, `StopWith(...)` directly inside a `Stream.make(...)` without the\n * `Step.` prefix. (The `Step` object itself can't be exported under that name\n * because it collides with the exported `Step` type.) For the common cases\n * prefer the `value` / `next` / `stop` helpers, which also handle the\n * single-element-stream wrapping for `next` / `stop`.\n */\nexport const { Value, Next, Stop, StopWith } = Step\n\n/** Wrap a value so it flows through the loop to downstream consumers. */\nexport const value = <A>(a: A): Step<A, never> => Step.Value({ value: a })\n\n/**\n * End the current iteration and continue with a new state. Emits a single\n * terminal `Next` step as a one-element stream, so it slots directly into a\n * loop body or after a run of values: `values.pipe(Stream.concat(next(s)))`.\n */\nexport const next = <S>(state: S): Stream.Stream<Step<never, S>> =>\n Stream.succeed(Step.Next({ state }))\n\n/**\n * End the loop. Called with no argument it emits a bare `Stop`; called with\n * a state it emits `StopWith(state)` — `loopOver` threads that final state\n * to the next input and `loopWithState` writes it to its `SubscriptionRef`\n * before the loop ends. Either way it returns a single-element stream, so\n * return it directly from a loop body.\n */\nexport const stop = <S = never>(state?: S): Stream.Stream<Step<never, S>> =>\n Stream.succeed<Step<never, S>>(state === undefined ? Step.Stop() : Step.StopWith({ state }))\n\n// ---------------------------------------------------------------------------\n// onTurnComplete - turn-aware stream operator for loop bodies\n// ---------------------------------------------------------------------------\n\n/**\n * Lift a provider's `Stream<TurnEvent>` into a loop body's `Stream<Step<TurnEvent | A, S>>`.\n * Each delta passes through as `value(delta)` (including the terminal\n * `TurnComplete`, so the consumer sees turn boundaries naturally). Once\n * the terminal arrives, `then(turn)` runs and its returned stream of loop\n * steps (typically tool outputs followed by `next(state)` or `stop()`) is\n * concatenated.\n *\n * Pre-pipe transforms (`Stream.tap` / `Stream.map` / `Stream.filter`) on\n * the raw delta stream cover anything an `emit`-style callback would do.\n *\n * `then` may return the step stream directly, or an `Effect` that produces\n * it (for branches that need to read a `Ref`, decode tool args, log, etc.).\n * Mirrors `loop`'s body: return a bare `stop()` / `next(s)` where no effect\n * is needed, lift to `Effect` only where one is.\n *\n * If the upstream ends without a `TurnComplete`, the resulting stream\n * fails with `AiError.IncompleteTurn`. Catch it via `Stream.catchTag` if\n * you want to recover.\n *\n * Dual: data-first `onTurnComplete(deltas, then)` and data-last\n * `deltas.pipe(onTurnComplete(then))` both work.\n */\ntype TurnContinuation<S, A, E2, R2> =\n | Stream.Stream<Step<A, S>, E2, R2>\n | Effect.Effect<Stream.Stream<Step<A, S>, E2, R2>, E2, R2>\n\nexport const onTurnComplete: {\n <S, A, E2 = never, R2 = never>(\n then: (turn: Turn) => TurnContinuation<S, A, E2, R2>,\n ): <E, R>(\n deltas: Stream.Stream<TurnEvent, E, R>,\n ) => Stream.Stream<Step<TurnEvent | A, S>, E | E2 | IncompleteTurn, R | R2>\n <S, A, E, R, E2 = never, R2 = never>(\n deltas: Stream.Stream<TurnEvent, E, R>,\n then: (turn: Turn) => TurnContinuation<S, A, E2, R2>,\n ): Stream.Stream<Step<TurnEvent | A, S>, E | E2 | IncompleteTurn, R | R2>\n} = Function.dual(\n 2,\n <S, A, E, R, E2, R2>(\n deltas: Stream.Stream<TurnEvent, E, R>,\n then: (turn: Turn) => TurnContinuation<S, A, E2, R2>,\n ): Stream.Stream<Step<TurnEvent | A, S>, E | E2 | IncompleteTurn, R | R2> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const turnRef = yield* Ref.make<Option.Option<Turn>>(Option.none())\n\n const events: Stream.Stream<Step<TurnEvent, S>, E, R> = deltas.pipe(\n Stream.tap((delta) =>\n isTurnComplete(delta) ? Ref.set(turnRef, Option.some(delta.turn)) : Effect.void,\n ),\n Stream.map(value),\n )\n\n const continuation = Stream.unwrap(\n Effect.gen(function* () {\n const opt = yield* Ref.get(turnRef)\n if (Option.isNone(opt)) return yield* new IncompleteTurn({})\n const result = then(opt.value)\n return Effect.isEffect(result) ? yield* result : result\n }),\n )\n\n return Stream.concat(events, continuation)\n }),\n ),\n)\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nconst isNonEmpty = <A>(array: ReadonlyArray<A>): array is readonly [A, ...Array<A>] =>\n array.length > 0\n\ntype CurrentBody<S, A, E, R> = {\n readonly scope: Scope.Closeable\n readonly pull: Effect.Effect<ReadonlyArray<Step<A, S>>, E | Cause.Done<void>, R>\n}\n\nconst closeBody = <S, A, E, R>(\n current: CurrentBody<S, A, E, R>,\n exit: Exit.Exit<unknown, unknown>,\n) => Scope.close(current.scope, exit)\n\n/**\n * Walk a chunk of `Step<A, S>` until a terminal `Next` or `Stop` is found.\n * Returns the unwrapped values seen so far and (optionally) the terminal\n * step. Anything in the chunk after the terminal is discarded - its\n * producing side effects may have run, but downstream never sees it.\n */\nconst partitionChunk = <A, S>(\n chunk: ReadonlyArray<Step<A, S>>,\n): {\n readonly values: ReadonlyArray<A>\n readonly decision: Option.Option<Step<A, S>>\n} => {\n const [valueSteps, rest] = Arr.span(\n chunk,\n (e): e is Step<A, S> & { _tag: \"Value\" } => e._tag === \"Value\",\n )\n return {\n values: valueSteps.map((e) => e.value),\n decision: Arr.head(rest),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\ntype LoopBody<S, A, E, R> = (\n state: S,\n) => Stream.Stream<Step<A, S>, E, R> | Effect.Effect<Stream.Stream<Step<A, S>, E, R>, E, R>\n\n/**\n * Drive a state-threaded loop body. Each iteration runs `body(state)` to get\n * a `Stream<Step<A, S>>`; values flow downstream, `next(s)` continues with\n * a new state, `stop()` ends the loop. See the file header for the full\n * pull-based execution model.\n *\n * Dual: data-first `loop(initial, body)` and data-last `loop(body)(initial)`\n * (or `pipe(initial, loop(body))`) both work.\n */\nexport const loop: {\n <S, A, E, R>(body: LoopBody<S, A, E, R>): (initial: S) => Stream.Stream<A, E, R>\n <S, A, E, R>(initial: S, body: LoopBody<S, A, E, R>): Stream.Stream<A, E, R>\n} = Function.dual(2, <S, A, E, R>(initial: S, body: LoopBody<S, A, E, R>): Stream.Stream<A, E, R> =>\n Stream.scoped(\n Stream.fromPull(\n Effect.gen(function* () {\n const outerScope = yield* Effect.scope\n let state = initial\n let current: CurrentBody<S, A, E, R> | undefined\n let done = false\n\n const closeActive = (\n active: CurrentBody<S, A, E, R>,\n exit: Exit.Exit<unknown, unknown>,\n ) => {\n const isActive = current === active\n if (isActive) current = undefined\n // Scope.close is idempotent. Multiple paths can race to close the\n // active body during cancellation/failure, so closing twice is safe.\n return closeBody(active, exit)\n }\n\n yield* Scope.addFinalizerExit(outerScope, (exit) =>\n current === undefined ? Effect.void : closeActive(current, exit),\n )\n\n const pull = Effect.gen(function* () {\n while (true) {\n if (done) return yield* Cause.done()\n\n if (current === undefined) {\n const result = body(state)\n const stream = Effect.isEffect(result) ? Stream.unwrap(result) : result\n const bodyScope = yield* Scope.fork(outerScope)\n const bodyPull = yield* Channel.toPullScoped(\n Stream.toChannel(stream),\n bodyScope,\n ).pipe(Effect.onError((cause) => Scope.close(bodyScope, Exit.failCause(cause))))\n current = { scope: bodyScope, pull: bodyPull }\n }\n\n const active = current\n const chunk = yield* active.pull.pipe(\n Effect.catchIf(Cause.isDone, () =>\n closeActive(active, Exit.void).pipe(\n Effect.as(undefined as ReadonlyArray<Step<A, S>> | undefined),\n ),\n ),\n Effect.onError((cause) => closeActive(active, Exit.failCause(cause))),\n )\n\n if (chunk === undefined) {\n done = true\n return yield* Cause.done()\n }\n\n const { values, decision } = partitionChunk(chunk)\n\n if (Option.isSome(decision)) {\n yield* closeActive(active, Exit.void)\n if (decision.value._tag === \"Stop\" || decision.value._tag === \"StopWith\") {\n // `loop` has no next iteration to apply StopWith's state to;\n // the state lands in `loopOver`'s outer ref or\n // `loopWithState`'s SubscriptionRef via their taps.\n done = true\n } else if (decision.value._tag === \"Next\") {\n state = decision.value.state\n }\n }\n\n // Emit the values seen so far if any. Chunks from a Stream pull\n // are non-empty, so when `decision` is `None` every step was\n // a `Value` and `values` is non-empty here. With a decision and\n // no preceding values, fall through to the next iteration.\n if (isNonEmpty(values)) return values\n }\n })\n\n // `Stream.fromPull` expects the generator to RETURN the pull effect,\n // not run it; `return yield* pull` would execute a pull and break it.\n // @effect-diagnostics-next-line returnEffectInGen:off\n return pull\n }),\n ),\n ),\n)\n\n// ---------------------------------------------------------------------------\n// loopOver - stream-driven sibling of loop. One input item runs a full\n// multi-turn inner loop.\n// ---------------------------------------------------------------------------\n\ntype LoopOverBody<S, I, A, E, R> = (\n state: S,\n input: I,\n) => Stream.Stream<Step<A, S>, E, R> | Effect.Effect<Stream.Stream<Step<A, S>, E, R>, E, R>\n\n/**\n * Input-driven sibling of `loop`. For each item pulled from the input\n * stream, runs an inner seed-driven `loop` whose body is\n * `(s) => body(s, item)`. State is threaded across input items.\n *\n * **Per-input semantics — the body emits standard `Step<A, S>`:**\n * - `value(a)`: emit `a` downstream\n * - `next(s)`: re-run the body with the SAME input and new state `s`\n * (multi-turn within one input — e.g. multiple model turns + tool\n * calls for one document)\n * - `stop()`: end this input's inner loop, advance to the next input\n * (state preserved)\n * - body stream ending without a decision: same as `stop()` (advance)\n *\n * **Outer termination:** the input stream ending. To halt programmatically\n * from within, end the input stream upstream (`Stream.takeWhile`, a\n * `SubscriptionRef` gate, etc.). Reserving `stop()` for per-item\n * advancement is what makes the common \"stream of documents, multi-turn\n * conversation per document\" shape readable.\n *\n * Dual: data-first `loopOver(input, initial, body)` and data-last\n * `input.pipe(loopOver(initial, body))` both work.\n */\nexport const loopOver: {\n <S, I, A, E, R>(\n initial: S,\n body: LoopOverBody<S, I, A, E, R>,\n ): <EI, RI>(input: Stream.Stream<I, EI, RI>) => Stream.Stream<A, E | EI, R | RI>\n <S, I, A, E, R, EI, RI>(\n input: Stream.Stream<I, EI, RI>,\n initial: S,\n body: LoopOverBody<S, I, A, E, R>,\n ): Stream.Stream<A, E | EI, R | RI>\n} = Function.dual(\n 3,\n <S, I, A, E, R, EI, RI>(\n input: Stream.Stream<I, EI, RI>,\n initial: S,\n body: LoopOverBody<S, I, A, E, R>,\n ): Stream.Stream<A, E | EI, R | RI> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const stateRef = yield* Ref.make<S>(initial)\n return input.pipe(\n Stream.flatMap((item) =>\n Stream.unwrap(\n Effect.gen(function* () {\n const state = yield* Ref.get(stateRef)\n // Capture Next states (and stop(state)'s final state) into the\n // outer ref so the LAST state seen in this input's inner\n // loop is what the next input starts from.\n const wrappedBody = (s: S) => {\n const result = body(s, item)\n const stream = Effect.isEffect(result) ? Stream.unwrap(result) : result\n return stream.pipe(\n Stream.tap((step) =>\n Match.value(step).pipe(\n Match.tags({\n Next: (e) => Ref.set(stateRef, e.state),\n StopWith: (e) => Ref.set(stateRef, e.state),\n }),\n Match.orElse(() => Effect.void),\n ),\n ),\n )\n }\n return loop(state, wrappedBody)\n }),\n ),\n ),\n )\n }),\n ),\n)\n\n// ---------------------------------------------------------------------------\n// loopWithState - same body protocol, plus a live state observable.\n// ---------------------------------------------------------------------------\n\n/**\n * Like `loop`, but exposes the current loop state as a `SubscriptionRef`\n * alongside the value stream.\n *\n * Allocates one `SubscriptionRef<S>` seeded with `initial`, then runs the\n * loop with a wrapped body that taps every `Next(s)` step into the ref\n * before forwarding it. The caller decides how to consume both channels:\n *\n * - **Final state**: drain the stream, then `SubscriptionRef.get(state)`\n * - the ref holds the state from the last `Next` (or `initial` if the\n * loop ended without advancing).\n * - **Live transitions**: `SubscriptionRef.changes(state)` is a\n * `Stream<S>` of every state observed; subscribe alongside the value\n * stream.\n * - **Mid-iteration peek**: `SubscriptionRef.get(state)` at any time.\n *\n * The returned stream and ref are independent of each other - the ref\n * lives outside the stream's scope, so reading it after the stream\n * completes is safe.\n */\nexport const loopWithState = <S, A, E, R>(\n initial: S,\n body: LoopBody<S, A, E, R>,\n): Effect.Effect<{\n readonly stream: Stream.Stream<A, E, R>\n readonly state: SubscriptionRef.SubscriptionRef<S>\n}> =>\n Effect.gen(function* () {\n const stateRef = yield* SubscriptionRef.make(initial)\n\n const tap = (stream: Stream.Stream<Step<A, S>, E, R>): Stream.Stream<Step<A, S>, E, R> =>\n stream.pipe(\n Stream.tap((step) =>\n Match.value(step).pipe(\n Match.tags({\n Next: (e) => SubscriptionRef.set(stateRef, e.state),\n StopWith: (e) => SubscriptionRef.set(stateRef, e.state),\n }),\n Match.orElse(() => Effect.void),\n ),\n ),\n )\n\n const wrappedBody: LoopBody<S, A, E, R> = (s) => {\n const result = body(s)\n return Effect.isEffect(result) ? Effect.map(result, tap) : tap(result)\n }\n\n return {\n stream: loop(initial, wrappedBody),\n state: stateRef,\n }\n })\n"],"mappings":"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"}
1
+ {"version":3,"file":"Loop.mjs","names":["Arr"],"sources":["../../src/loop/Loop.ts"],"sourcesContent":["/**\n * Pull-based `loop` for state-threaded sub-streams.\n *\n * Each iteration runs a body that returns a `Stream<Step<A, S>>`. The body\n * emits values via `Loop.value(a)` and signals iteration control via\n * `Loop.next(state)` (continue with new state) or `Loop.stop()` (terminate).\n * The loop unwraps `Value` steps back to `A` for downstream consumers, so\n * the resulting stream is a plain `Stream<A>`.\n *\n * The next body stream is only pulled when downstream pulls the outer\n * stream - no producer fiber, no queue buffering. Cancellation, failures,\n * scoped resources, and backpressure stay aligned with normal Stream\n * semantics.\n *\n * Convention: a `Next` or `Stop` step is the terminal element of a body's\n * iteration. Values emitted in the same chunk after one are discarded\n * (their producing side effects may already have run). The `Loop.next` /\n * `Loop.stop` helpers each emit a single terminal step, so concatenate\n * your values before them (`values.pipe(Stream.concat(Loop.next(state)))`).\n */\nimport {\n Array as Arr,\n Cause,\n Channel,\n Data,\n Effect,\n Exit,\n Function,\n Match,\n Option,\n Ref,\n Scope,\n Stream,\n SubscriptionRef,\n} from \"effect\"\nimport { IncompleteTurn } from \"../domain/AiError.js\"\nimport { isTurnComplete, type Turn, type TurnEvent } from \"../domain/Turn.js\"\n\n// ---------------------------------------------------------------------------\n// Step type - the body's emit shape\n// ---------------------------------------------------------------------------\n\n/**\n * The tagged union a body emits per pull. `Value` carries a payload that\n * flows downstream. `Next` ends the current iteration and continues with a\n * new state. `Stop` ends the loop entirely with no carried state.\n * `StopWith` also ends the loop but carries a final state that `loopOver`\n * will thread to the next input and `loopWithState` will write to its\n * `SubscriptionRef` before the loop ends. Plain `loop` has no next\n * iteration to apply it to and treats `StopWith` like `Stop`.\n *\n * `Stop` is intentionally `{}` so the bare `stop()` helper doesn't\n * constrain `S` from a body's stream type — every body has a `Stop`\n * variant in its union, and forcing `S` to flow through it would break\n * inference whenever the body never uses `next` / `stop(state)`.\n */\nexport type Step<A, S> = Data.TaggedEnum<{\n Value: { readonly value: A }\n Next: { readonly state: S }\n Stop: {}\n StopWith: { readonly state: S }\n}>\n\ninterface StepDef extends Data.TaggedEnum.WithGenerics<2> {\n readonly taggedEnum: Step<this[\"A\"], this[\"B\"]>\n}\n\nconst Step = Data.taggedEnum<StepDef>()\n\n/**\n * Bare step constructors, so a loop body can emit `Value(...)`, `Next(...)`,\n * `Stop()`, `StopWith(...)` directly inside a `Stream.make(...)` without the\n * `Step.` prefix. (The `Step` object itself can't be exported under that name\n * because it collides with the exported `Step` type.) For the common cases\n * prefer the `value` / `next` / `stop` helpers, which also handle the\n * single-element-stream wrapping for `next` / `stop`.\n */\nexport const { Value, Next, Stop, StopWith } = Step\n\n/** Wrap a value so it flows through the loop to downstream consumers. */\nexport const value = <A>(a: A): Step<A, never> => Step.Value({ value: a })\n\n/**\n * End the current iteration and continue with a new state. Emits a single\n * terminal `Next` step as a one-element stream, so it slots directly into a\n * loop body or after a run of values: `values.pipe(Stream.concat(next(s)))`.\n */\nexport const next = <S>(state: S): Stream.Stream<Step<never, S>> =>\n Stream.succeed(Step.Next({ state }))\n\n/**\n * End the loop. Called with no argument it emits a bare `Stop`; called with\n * a state it emits `StopWith(state)` — `loopOver` threads that final state\n * to the next input and `loopWithState` writes it to its `SubscriptionRef`\n * before the loop ends. Either way it returns a single-element stream, so\n * return it directly from a loop body.\n */\nexport const stop = <S = never>(state?: S): Stream.Stream<Step<never, S>> =>\n Stream.succeed<Step<never, S>>(state === undefined ? Step.Stop() : Step.StopWith({ state }))\n\n// ---------------------------------------------------------------------------\n// onTurnComplete - turn-aware stream operator for loop bodies\n// ---------------------------------------------------------------------------\n\n/**\n * Lift a provider's `Stream<TurnEvent>` into a loop body's `Stream<Step<TurnEvent | A, S>>`.\n * Each delta passes through as `value(delta)` (including the terminal\n * `TurnComplete`, so the consumer sees turn boundaries naturally). Once\n * the terminal arrives, `then(turn)` runs and its returned stream of loop\n * steps (typically tool outputs followed by `next(state)` or `stop()`) is\n * concatenated.\n *\n * Pre-pipe transforms (`Stream.tap` / `Stream.map` / `Stream.filter`) on\n * the raw delta stream cover anything an `emit`-style callback would do.\n *\n * `then` may return the step stream directly, or an `Effect` that produces\n * it (for branches that need to read a `Ref`, decode tool args, log, etc.).\n * Mirrors `loop`'s body: return a bare `stop()` / `next(s)` where no effect\n * is needed, lift to `Effect` only where one is.\n *\n * If the upstream ends without a `TurnComplete`, the resulting stream\n * fails with `AiError.IncompleteTurn`. Catch it via `Stream.catchTag` if\n * you want to recover.\n *\n * Dual: data-first `onTurnComplete(deltas, then)` and data-last\n * `deltas.pipe(onTurnComplete(then))` both work.\n */\n// The Effect and the stream it returns infer their errors separately.\ntype TurnContinuation<S, A, E2, R2, E3, R3> =\n | Stream.Stream<Step<A, S>, E2, R2>\n | Effect.Effect<Stream.Stream<Step<A, S>, E2, R2>, E3, R3>\n\nexport const onTurnComplete: {\n <S, A, E2 = never, R2 = never, E3 = never, R3 = never>(\n then: (turn: Turn) => TurnContinuation<S, A, E2, R2, E3, R3>,\n ): <E, R>(\n deltas: Stream.Stream<TurnEvent, E, R>,\n ) => Stream.Stream<Step<TurnEvent | A, S>, E | E2 | E3 | IncompleteTurn, R | R2 | R3>\n <S, A, E, R, E2 = never, R2 = never, E3 = never, R3 = never>(\n deltas: Stream.Stream<TurnEvent, E, R>,\n then: (turn: Turn) => TurnContinuation<S, A, E2, R2, E3, R3>,\n ): Stream.Stream<Step<TurnEvent | A, S>, E | E2 | E3 | IncompleteTurn, R | R2 | R3>\n} = Function.dual(\n 2,\n <S, A, E, R, E2, R2, E3, R3>(\n deltas: Stream.Stream<TurnEvent, E, R>,\n then: (turn: Turn) => TurnContinuation<S, A, E2, R2, E3, R3>,\n ): Stream.Stream<Step<TurnEvent | A, S>, E | E2 | E3 | IncompleteTurn, R | R2 | R3> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const turnRef = yield* Ref.make<Option.Option<Turn>>(Option.none())\n\n const events: Stream.Stream<Step<TurnEvent, S>, E, R> = deltas.pipe(\n Stream.tap((delta) =>\n isTurnComplete(delta) ? Ref.set(turnRef, Option.some(delta.turn)) : Effect.void,\n ),\n Stream.map(value),\n )\n\n const continuation = Stream.unwrap(\n Effect.gen(function* () {\n const opt = yield* Ref.get(turnRef)\n if (Option.isNone(opt)) return yield* new IncompleteTurn({})\n const result = then(opt.value)\n return Effect.isEffect(result) ? yield* result : result\n }),\n )\n\n return Stream.concat(events, continuation)\n }),\n ),\n)\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nconst isNonEmpty = <A>(array: ReadonlyArray<A>): array is readonly [A, ...Array<A>] =>\n array.length > 0\n\ntype CurrentBody<S, A, E, R> = {\n readonly scope: Scope.Closeable\n readonly pull: Effect.Effect<ReadonlyArray<Step<A, S>>, E | Cause.Done<void>, R>\n}\n\nconst closeBody = <S, A, E, R>(\n current: CurrentBody<S, A, E, R>,\n exit: Exit.Exit<unknown, unknown>,\n) => Scope.close(current.scope, exit)\n\n/**\n * Walk a chunk of `Step<A, S>` until a terminal `Next` or `Stop` is found.\n * Returns the unwrapped values seen so far and (optionally) the terminal\n * step. Anything in the chunk after the terminal is discarded - its\n * producing side effects may have run, but downstream never sees it.\n */\nconst partitionChunk = <A, S>(\n chunk: ReadonlyArray<Step<A, S>>,\n): {\n readonly values: ReadonlyArray<A>\n readonly decision: Option.Option<Step<A, S>>\n} => {\n const [valueSteps, rest] = Arr.span(\n chunk,\n (e): e is Step<A, S> & { _tag: \"Value\" } => e._tag === \"Value\",\n )\n return {\n values: valueSteps.map((e) => e.value),\n decision: Arr.head(rest),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\ntype LoopBody<S, A, E, R> = (\n state: S,\n) => Stream.Stream<Step<A, S>, E, R> | Effect.Effect<Stream.Stream<Step<A, S>, E, R>, E, R>\n\n// What callers pass: the Effect and its stream infer errors and requirements separately.\ntype LoopBodyIn<S, A, E, R, E2, R2> = (\n state: S,\n) => Stream.Stream<Step<A, S>, E, R> | Effect.Effect<Stream.Stream<Step<A, S>, E, R>, E2, R2>\n\n/**\n * Drive a state-threaded loop body. Each iteration runs `body(state)` to get\n * a `Stream<Step<A, S>>`; values flow downstream, `next(s)` continues with\n * a new state, `stop()` ends the loop. See the file header for the full\n * pull-based execution model.\n *\n * Dual: data-first `loop(initial, body)` and data-last `loop(body)(initial)`\n * (or `pipe(initial, loop(body))`) both work.\n */\nexport const loop: {\n <S, A, E, R, E2 = never, R2 = never>(\n body: LoopBodyIn<S, A, E, R, E2, R2>,\n ): (initial: S) => Stream.Stream<A, E | E2, R | R2>\n <S, A, E, R, E2 = never, R2 = never>(\n initial: S,\n body: LoopBodyIn<S, A, E, R, E2, R2>,\n ): Stream.Stream<A, E | E2, R | R2>\n} = Function.dual(2, <S, A, E, R>(initial: S, body: LoopBody<S, A, E, R>): Stream.Stream<A, E, R> =>\n Stream.scoped(\n Stream.fromPull(\n Effect.gen(function* () {\n const outerScope = yield* Effect.scope\n let state = initial\n let current: CurrentBody<S, A, E, R> | undefined\n let done = false\n\n const closeActive = (\n active: CurrentBody<S, A, E, R>,\n exit: Exit.Exit<unknown, unknown>,\n ) => {\n const isActive = current === active\n if (isActive) current = undefined\n // Scope.close is idempotent. Multiple paths can race to close the\n // active body during cancellation/failure, so closing twice is safe.\n return closeBody(active, exit)\n }\n\n yield* Scope.addFinalizerExit(outerScope, (exit) =>\n current === undefined ? Effect.void : closeActive(current, exit),\n )\n\n const pull = Effect.gen(function* () {\n while (true) {\n if (done) return yield* Cause.done()\n\n if (current === undefined) {\n const result = body(state)\n const stream = Effect.isEffect(result) ? Stream.unwrap(result) : result\n const bodyScope = yield* Scope.fork(outerScope)\n const bodyPull = yield* Channel.toPullScoped(\n Stream.toChannel(stream),\n bodyScope,\n ).pipe(Effect.onError((cause) => Scope.close(bodyScope, Exit.failCause(cause))))\n current = { scope: bodyScope, pull: bodyPull }\n }\n\n const active = current\n const chunk = yield* active.pull.pipe(\n Effect.catchIf(Cause.isDone, () =>\n closeActive(active, Exit.void).pipe(\n Effect.as(undefined as ReadonlyArray<Step<A, S>> | undefined),\n ),\n ),\n Effect.onError((cause) => closeActive(active, Exit.failCause(cause))),\n )\n\n if (chunk === undefined) {\n done = true\n return yield* Cause.done()\n }\n\n const { values, decision } = partitionChunk(chunk)\n\n if (Option.isSome(decision)) {\n yield* closeActive(active, Exit.void)\n if (decision.value._tag === \"Stop\" || decision.value._tag === \"StopWith\") {\n // `loop` has no next iteration to apply StopWith's state to;\n // the state lands in `loopOver`'s outer ref or\n // `loopWithState`'s SubscriptionRef via their taps.\n done = true\n } else if (decision.value._tag === \"Next\") {\n state = decision.value.state\n }\n }\n\n // Emit the values seen so far if any. Chunks from a Stream pull\n // are non-empty, so when `decision` is `None` every step was\n // a `Value` and `values` is non-empty here. With a decision and\n // no preceding values, fall through to the next iteration.\n if (isNonEmpty(values)) return values\n }\n })\n\n // `Stream.fromPull` expects the generator to RETURN the pull effect,\n // not run it; `return yield* pull` would execute a pull and break it.\n // @effect-diagnostics-next-line returnEffectInGen:off\n return pull\n }),\n ),\n ),\n)\n\n// ---------------------------------------------------------------------------\n// loopOver - stream-driven sibling of loop. One input item runs a full\n// multi-turn inner loop.\n// ---------------------------------------------------------------------------\n\ntype LoopOverBody<S, I, A, E, R> = (\n state: S,\n input: I,\n) => Stream.Stream<Step<A, S>, E, R> | Effect.Effect<Stream.Stream<Step<A, S>, E, R>, E, R>\n\n/**\n * Input-driven sibling of `loop`. For each item pulled from the input\n * stream, runs an inner seed-driven `loop` whose body is\n * `(s) => body(s, item)`. State is threaded across input items.\n *\n * **Per-input semantics — the body emits standard `Step<A, S>`:**\n * - `value(a)`: emit `a` downstream\n * - `next(s)`: re-run the body with the SAME input and new state `s`\n * (multi-turn within one input — e.g. multiple model turns + tool\n * calls for one document)\n * - `stop()`: end this input's inner loop, advance to the next input\n * (state preserved)\n * - body stream ending without a decision: same as `stop()` (advance)\n *\n * **Outer termination:** the input stream ending. To halt programmatically\n * from within, end the input stream upstream (`Stream.takeWhile`, a\n * `SubscriptionRef` gate, etc.). Reserving `stop()` for per-item\n * advancement is what makes the common \"stream of documents, multi-turn\n * conversation per document\" shape readable.\n *\n * Dual: data-first `loopOver(input, initial, body)` and data-last\n * `input.pipe(loopOver(initial, body))` both work.\n */\nexport const loopOver: {\n <S, I, A, E, R>(\n initial: S,\n body: LoopOverBody<S, I, A, E, R>,\n ): <EI, RI>(input: Stream.Stream<I, EI, RI>) => Stream.Stream<A, E | EI, R | RI>\n <S, I, A, E, R, EI, RI>(\n input: Stream.Stream<I, EI, RI>,\n initial: S,\n body: LoopOverBody<S, I, A, E, R>,\n ): Stream.Stream<A, E | EI, R | RI>\n} = Function.dual(\n 3,\n <S, I, A, E, R, EI, RI>(\n input: Stream.Stream<I, EI, RI>,\n initial: S,\n body: LoopOverBody<S, I, A, E, R>,\n ): Stream.Stream<A, E | EI, R | RI> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const stateRef = yield* Ref.make<S>(initial)\n return input.pipe(\n Stream.flatMap((item) =>\n Stream.unwrap(\n Effect.gen(function* () {\n const state = yield* Ref.get(stateRef)\n // Capture Next states (and stop(state)'s final state) into the\n // outer ref so the LAST state seen in this input's inner\n // loop is what the next input starts from.\n const wrappedBody = (s: S) => {\n const result = body(s, item)\n const stream = Effect.isEffect(result) ? Stream.unwrap(result) : result\n return stream.pipe(\n Stream.tap((step) =>\n Match.value(step).pipe(\n Match.tags({\n Next: (e) => Ref.set(stateRef, e.state),\n StopWith: (e) => Ref.set(stateRef, e.state),\n }),\n Match.orElse(() => Effect.void),\n ),\n ),\n )\n }\n return loop(state, wrappedBody)\n }),\n ),\n ),\n )\n }),\n ),\n)\n\n// ---------------------------------------------------------------------------\n// loopWithState - same body protocol, plus a live state observable.\n// ---------------------------------------------------------------------------\n\n/**\n * Like `loop`, but exposes the current loop state as a `SubscriptionRef`\n * alongside the value stream.\n *\n * Allocates one `SubscriptionRef<S>` seeded with `initial`, then runs the\n * loop with a wrapped body that taps every `Next(s)` step into the ref\n * before forwarding it. The caller decides how to consume both channels:\n *\n * - **Final state**: drain the stream, then `SubscriptionRef.get(state)`\n * - the ref holds the state from the last `Next` (or `initial` if the\n * loop ended without advancing).\n * - **Live transitions**: `SubscriptionRef.changes(state)` is a\n * `Stream<S>` of every state observed; subscribe alongside the value\n * stream.\n * - **Mid-iteration peek**: `SubscriptionRef.get(state)` at any time.\n *\n * The returned stream and ref are independent of each other - the ref\n * lives outside the stream's scope, so reading it after the stream\n * completes is safe.\n */\nexport const loopWithState = <S, A, E, R>(\n initial: S,\n body: LoopBody<S, A, E, R>,\n): Effect.Effect<{\n readonly stream: Stream.Stream<A, E, R>\n readonly state: SubscriptionRef.SubscriptionRef<S>\n}> =>\n Effect.gen(function* () {\n const stateRef = yield* SubscriptionRef.make(initial)\n\n const tap = (stream: Stream.Stream<Step<A, S>, E, R>): Stream.Stream<Step<A, S>, E, R> =>\n stream.pipe(\n Stream.tap((step) =>\n Match.value(step).pipe(\n Match.tags({\n Next: (e) => SubscriptionRef.set(stateRef, e.state),\n StopWith: (e) => SubscriptionRef.set(stateRef, e.state),\n }),\n Match.orElse(() => Effect.void),\n ),\n ),\n )\n\n const wrappedBody: LoopBody<S, A, E, R> = (s) => {\n const result = body(s)\n return Effect.isEffect(result) ? Effect.map(result, tap) : tap(result)\n }\n\n return {\n stream: loop(initial, wrappedBody),\n state: stateRef,\n }\n })\n"],"mappings":"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"}
@@ -76,209 +76,37 @@ type InboundEvent = Data.TaggedEnum<{
76
76
  readonly raw: unknown;
77
77
  };
78
78
  }>;
79
- declare const InboundEvent: {
80
- readonly $is: <Tag extends "Action" | "Command" | "Message" | "Reaction">(tag: Tag) => (u: unknown) => u is Extract<{
81
- readonly _tag: "Action";
82
- readonly conversation: ConversationRef;
83
- readonly actionId: string;
84
- readonly value?: string;
85
- readonly author: UserId;
86
- readonly raw: unknown;
87
- }, {
88
- readonly _tag: Tag;
89
- }> | Extract<{
90
- readonly _tag: "Command";
91
- readonly conversation: ConversationRef;
92
- readonly name: string;
93
- readonly args: string;
94
- readonly author: UserId;
95
- readonly raw: unknown;
96
- }, {
97
- readonly _tag: Tag;
98
- }> | Extract<{
99
- readonly _tag: "Message";
100
- readonly conversation: ConversationRef;
101
- readonly id: MessageId;
102
- readonly author: UserId;
103
- readonly text: string;
104
- readonly addressed: boolean;
105
- readonly replyTo?: MessageId;
106
- readonly raw: unknown;
107
- }, {
108
- readonly _tag: Tag;
109
- }> | Extract<{
110
- readonly _tag: "Reaction";
111
- readonly conversation: ConversationRef;
112
- readonly message: MessageId;
113
- readonly emoji: string;
114
- readonly author: UserId;
115
- readonly raw: unknown;
116
- }, {
117
- readonly _tag: Tag;
118
- }>;
119
- readonly $match: {
120
- <Cases extends { readonly [Tag in "Action" | "Command" | "Message" | "Reaction"]: (args: Extract<{
121
- readonly _tag: "Action";
122
- readonly conversation: ConversationRef;
123
- readonly actionId: string;
124
- readonly value?: string;
125
- readonly author: UserId;
126
- readonly raw: unknown;
127
- } | {
128
- readonly _tag: "Command";
129
- readonly conversation: ConversationRef;
130
- readonly name: string;
131
- readonly args: string;
132
- readonly author: UserId;
133
- readonly raw: unknown;
134
- } | {
135
- readonly _tag: "Message";
136
- readonly conversation: ConversationRef;
137
- readonly id: MessageId;
138
- readonly author: UserId;
139
- readonly text: string;
140
- readonly addressed: boolean;
141
- readonly replyTo?: MessageId;
142
- readonly raw: unknown;
143
- } | {
144
- readonly _tag: "Reaction";
145
- readonly conversation: ConversationRef;
146
- readonly message: MessageId;
147
- readonly emoji: string;
148
- readonly author: UserId;
149
- readonly raw: unknown;
150
- }, {
151
- readonly _tag: Tag;
152
- }>) => any; }>(cases: Cases): (value: {
153
- readonly _tag: "Action";
154
- readonly conversation: ConversationRef;
155
- readonly actionId: string;
156
- readonly value?: string;
157
- readonly author: UserId;
158
- readonly raw: unknown;
159
- } | {
160
- readonly _tag: "Command";
161
- readonly conversation: ConversationRef;
162
- readonly name: string;
163
- readonly args: string;
164
- readonly author: UserId;
165
- readonly raw: unknown;
166
- } | {
167
- readonly _tag: "Message";
168
- readonly conversation: ConversationRef;
169
- readonly id: MessageId;
170
- readonly author: UserId;
171
- readonly text: string;
172
- readonly addressed: boolean;
173
- readonly replyTo?: MessageId;
174
- readonly raw: unknown;
175
- } | {
176
- readonly _tag: "Reaction";
177
- readonly conversation: ConversationRef;
178
- readonly message: MessageId;
179
- readonly emoji: string;
180
- readonly author: UserId;
181
- readonly raw: unknown;
182
- }) => import("effect/Unify").Unify<ReturnType<Cases["Action" | "Command" | "Message" | "Reaction"]>>;
183
- <Cases extends { readonly [Tag in "Action" | "Command" | "Message" | "Reaction"]: (args: Extract<{
184
- readonly _tag: "Action";
185
- readonly conversation: ConversationRef;
186
- readonly actionId: string;
187
- readonly value?: string;
188
- readonly author: UserId;
189
- readonly raw: unknown;
190
- } | {
191
- readonly _tag: "Command";
192
- readonly conversation: ConversationRef;
193
- readonly name: string;
194
- readonly args: string;
195
- readonly author: UserId;
196
- readonly raw: unknown;
197
- } | {
198
- readonly _tag: "Message";
199
- readonly conversation: ConversationRef;
200
- readonly id: MessageId;
201
- readonly author: UserId;
202
- readonly text: string;
203
- readonly addressed: boolean;
204
- readonly replyTo?: MessageId;
205
- readonly raw: unknown;
206
- } | {
207
- readonly _tag: "Reaction";
208
- readonly conversation: ConversationRef;
209
- readonly message: MessageId;
210
- readonly emoji: string;
211
- readonly author: UserId;
212
- readonly raw: unknown;
213
- }, {
214
- readonly _tag: Tag;
215
- }>) => any; }>(value: {
216
- readonly _tag: "Action";
217
- readonly conversation: ConversationRef;
218
- readonly actionId: string;
219
- readonly value?: string;
220
- readonly author: UserId;
221
- readonly raw: unknown;
222
- } | {
223
- readonly _tag: "Command";
224
- readonly conversation: ConversationRef;
225
- readonly name: string;
226
- readonly args: string;
227
- readonly author: UserId;
228
- readonly raw: unknown;
229
- } | {
230
- readonly _tag: "Message";
231
- readonly conversation: ConversationRef;
232
- readonly id: MessageId;
233
- readonly author: UserId;
234
- readonly text: string;
235
- readonly addressed: boolean;
236
- readonly replyTo?: MessageId;
237
- readonly raw: unknown;
238
- } | {
239
- readonly _tag: "Reaction";
240
- readonly conversation: ConversationRef;
241
- readonly message: MessageId;
242
- readonly emoji: string;
243
- readonly author: UserId;
244
- readonly raw: unknown;
245
- }, cases: Cases): import("effect/Unify").Unify<ReturnType<Cases["Action" | "Command" | "Message" | "Reaction"]>>;
246
- };
247
- readonly Action: Data.TaggedEnum.ConstructorFrom<{
248
- readonly _tag: "Action";
249
- readonly conversation: ConversationRef;
250
- readonly actionId: string;
251
- readonly value?: string;
252
- readonly author: UserId;
253
- readonly raw: unknown;
254
- }, "_tag">;
255
- readonly Command: Data.TaggedEnum.ConstructorFrom<{
256
- readonly _tag: "Command";
257
- readonly conversation: ConversationRef;
258
- readonly name: string;
259
- readonly args: string;
260
- readonly author: UserId;
261
- readonly raw: unknown;
262
- }, "_tag">;
263
- readonly Message: Data.TaggedEnum.ConstructorFrom<{
264
- readonly _tag: "Message";
265
- readonly conversation: ConversationRef;
266
- readonly id: MessageId;
267
- readonly author: UserId;
268
- readonly text: string;
269
- readonly addressed: boolean;
270
- readonly replyTo?: MessageId;
271
- readonly raw: unknown;
272
- }, "_tag">;
273
- readonly Reaction: Data.TaggedEnum.ConstructorFrom<{
274
- readonly _tag: "Reaction";
275
- readonly conversation: ConversationRef;
276
- readonly message: MessageId;
277
- readonly emoji: string;
278
- readonly author: UserId;
279
- readonly raw: unknown;
280
- }, "_tag">;
281
- };
79
+ declare const InboundEvent: Data.TaggedEnum.Constructor<{
80
+ readonly _tag: "Action";
81
+ readonly conversation: ConversationRef;
82
+ readonly actionId: string;
83
+ readonly value?: string;
84
+ readonly author: UserId;
85
+ readonly raw: unknown;
86
+ } | {
87
+ readonly _tag: "Command";
88
+ readonly conversation: ConversationRef;
89
+ readonly name: string;
90
+ readonly args: string;
91
+ readonly author: UserId;
92
+ readonly raw: unknown;
93
+ } | {
94
+ readonly _tag: "Message";
95
+ readonly conversation: ConversationRef;
96
+ readonly id: MessageId;
97
+ readonly author: UserId;
98
+ readonly text: string;
99
+ readonly addressed: boolean;
100
+ readonly replyTo?: MessageId;
101
+ readonly raw: unknown;
102
+ } | {
103
+ readonly _tag: "Reaction";
104
+ readonly conversation: ConversationRef;
105
+ readonly message: MessageId;
106
+ readonly emoji: string;
107
+ readonly author: UserId;
108
+ readonly raw: unknown;
109
+ }>;
282
110
  /**
283
111
  * What the agent says. `Text` is sent verbatim: each provider layer says
284
112
  * which markup it expects (Telegram HTML, Slack markdown), and the prompt is
@@ -303,92 +131,18 @@ type OutboundBody = Data.TaggedEnum<{
303
131
  readonly payload: unknown;
304
132
  };
305
133
  }>;
306
- declare const OutboundBody: {
307
- readonly $is: <Tag extends "Media" | "Raw" | "Text">(tag: Tag) => (u: unknown) => u is Extract<{
308
- readonly _tag: "Media";
309
- readonly media: MediaSource;
310
- readonly caption?: string;
311
- readonly filename?: string;
312
- }, {
313
- readonly _tag: Tag;
314
- }> | Extract<{
315
- readonly _tag: "Raw";
316
- readonly payload: unknown;
317
- }, {
318
- readonly _tag: Tag;
319
- }> | Extract<{
320
- readonly _tag: "Text";
321
- readonly text: string;
322
- }, {
323
- readonly _tag: Tag;
324
- }>;
325
- readonly $match: {
326
- <Cases extends { readonly [Tag in "Media" | "Raw" | "Text"]: (args: Extract<{
327
- readonly _tag: "Media";
328
- readonly media: MediaSource;
329
- readonly caption?: string;
330
- readonly filename?: string;
331
- } | {
332
- readonly _tag: "Raw";
333
- readonly payload: unknown;
334
- } | {
335
- readonly _tag: "Text";
336
- readonly text: string;
337
- }, {
338
- readonly _tag: Tag;
339
- }>) => any; }>(cases: Cases): (value: {
340
- readonly _tag: "Media";
341
- readonly media: MediaSource;
342
- readonly caption?: string;
343
- readonly filename?: string;
344
- } | {
345
- readonly _tag: "Raw";
346
- readonly payload: unknown;
347
- } | {
348
- readonly _tag: "Text";
349
- readonly text: string;
350
- }) => import("effect/Unify").Unify<ReturnType<Cases["Media" | "Raw" | "Text"]>>;
351
- <Cases extends { readonly [Tag in "Media" | "Raw" | "Text"]: (args: Extract<{
352
- readonly _tag: "Media";
353
- readonly media: MediaSource;
354
- readonly caption?: string;
355
- readonly filename?: string;
356
- } | {
357
- readonly _tag: "Raw";
358
- readonly payload: unknown;
359
- } | {
360
- readonly _tag: "Text";
361
- readonly text: string;
362
- }, {
363
- readonly _tag: Tag;
364
- }>) => any; }>(value: {
365
- readonly _tag: "Media";
366
- readonly media: MediaSource;
367
- readonly caption?: string;
368
- readonly filename?: string;
369
- } | {
370
- readonly _tag: "Raw";
371
- readonly payload: unknown;
372
- } | {
373
- readonly _tag: "Text";
374
- readonly text: string;
375
- }, cases: Cases): import("effect/Unify").Unify<ReturnType<Cases["Media" | "Raw" | "Text"]>>;
376
- };
377
- readonly Media: Data.TaggedEnum.ConstructorFrom<{
378
- readonly _tag: "Media";
379
- readonly media: MediaSource;
380
- readonly caption?: string;
381
- readonly filename?: string;
382
- }, "_tag">;
383
- readonly Raw: Data.TaggedEnum.ConstructorFrom<{
384
- readonly _tag: "Raw";
385
- readonly payload: unknown;
386
- }, "_tag">;
387
- readonly Text: Data.TaggedEnum.ConstructorFrom<{
388
- readonly _tag: "Text";
389
- readonly text: string;
390
- }, "_tag">;
391
- };
134
+ declare const OutboundBody: Data.TaggedEnum.Constructor<{
135
+ readonly _tag: "Media";
136
+ readonly media: MediaSource;
137
+ readonly caption?: string;
138
+ readonly filename?: string;
139
+ } | {
140
+ readonly _tag: "Raw";
141
+ readonly payload: unknown;
142
+ } | {
143
+ readonly _tag: "Text";
144
+ readonly text: string;
145
+ }>;
392
146
  /**
393
147
  * A body plus the envelope fields true of any message. `replyTo` is ignored
394
148
  * for a `Raw` body, which names its own wire fields.
@@ -1 +1 @@
1
- {"version":3,"file":"Messenger.d.mts","names":[],"sources":["../../src/messenger/Messenger.ts"],"mappings":"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"}
1
+ {"version":3,"file":"Messenger.d.mts","names":[],"sources":["../../src/messenger/Messenger.ts"],"mappings":";;;;;;;KASY,YAAY,MAAM;cACjB,WAAS,MAAA,YAAA;;KAGV,YAAY,MAAM;cACjB,WAAS,MAAA,YAAA;;KAGV,SAAS,MAAM;cACd,QAAM,MAAA,YAAA;;KAGP,WAAW,MAAM;cAChB,UAAQ,MAAA,YAAA;;;;;;KAOT;WACD,SAAS;WACT,SAAS;;KAGR;WACD,cAAc;WACd,IAAI;;;cAIF,kBAAe,KAAS;;;;;;;;;;;;;;KAoBzB,eAAe,KAAK;EAC9B;aACW,cAAc;aACd,IAAI;aACJ,QAAQ;aACR;aACA;aACA,UAAU;aACV;;EAEX;aACW,cAAc;aACd,SAAS;aACT;aACA,QAAQ;aACR;;EAEX;aACW,cAAc;aACd;aACA;aACA,QAAQ;aACR;;EAEX;aACW,cAAc;aACd;aACA;aACA,QAAQ;aACR;;;cAIA,cAAY,KAAA,WAAA;;WARE,cAAA;WACJ;WACF;WACA,QAAA;WACH;;;WAXS,cAAA;WACR;WACA;WACE,QAAA;WACH;;;WApBS,cAAA;WACV,IAAA;WACI,QAAA;WACF;WACK;WACD,UAAA;WACL;;;WAGS,cAAA;WACL,SAAA;WACF;WACC,QAAA;WACH;;;;;;;;;;;;;KAmCN,eAAe,KAAK;EAC9B;aAAiB;;EACjB;aACW,OAAO;aACP;aACA;;EAEX;aAAgB;;;cAGL,cAAY,KAAA,WAAA;;WAPL,OAAA;WACG;WACC;;;WAEG;;;WANF;;;;;;KAeb;WACD,MAAM;WACN,UAAU;;KAGT;WAA6B,UAAU;;;cAQtC,OAAI,cAAgB,UAAY,oBAAkB;;cAIlD,QAAK,QACR,aAAW,UACT;WAA6B;WAA2B;MACjE;;cAWU,MAAG,qBAAuB;;;;;;;;cAY1B,4BAA4B;;cAK5B,iBAAc,KACnB,qBACL,GAAG,GAAG,GAAC,QAAU,OAAO,OAAO,GAAG,GAAG,OAAK,OAAO,OAAO,GAAG,GAAG,QAAQ,GAAG;;KAQhE,gBAAgB;;KAGhB;;WAED;;WAEA;;;;;;;;;;;;;KAcC;WACD,QAAQ,OAAO,OAAO,cAAc;;WAGpC,OACP,KAAK,aACF,OAAO,OAAO,WAAW,gBAA+B;WAEpD,OACP,KAAK,YACL,MAAM,aACH,OAAO,aAAa;;;;;;WAOhB,QACP,KAAK,YACL,kBACG,OAAO,aAAa;;WAGhB,QAAQ,OAAO,aAEtB,gBACA,sBAAsB,MAAM;;;;;WAOrB,SAAS,GAAG,GACnB,QAAQ,OAAO,eAAe,GAAG,IACjC,UAAU,kBACP,OAAO,OACV,OAAO,OAAO,YACd,iBAAgC,GAChC,IAAI;WAGG,QAAQ;;;cAGN,kBAAkB;cAQlB,QAAQ,OAAO,OAAO,cAAc,gBAA+B;cAGnE,OAAI,KACV,aACJ,OAAO,OAAO,WAAW,gBAA+B,YAAY;cAG1D,OAAI,KACV,YAAU,MACT,aACL,OAAO,aAAa,gBAA+B;cAGzC,QAAK,KACX,YAAU,kBAEd,OAAO,aAAa,gBAA+B;cAGzC,QAAQ,OAAO,aAE1B,gBACA,YAAY,sBAAsB,MAAM;cAG7B,SAAU,GAAG,GAAC,QACjB,OAAO,eAAe,GAAG,IAAE,UACzB,kBACT,OAAO,OACR,OAAO,OAAO,YACd,iBAAgC,GAChC,IAAI,YAAY"}
@@ -3,7 +3,7 @@ import { splitForLimit } from "./MessengerAdapter.mjs";
3
3
  import { MessengerRateLimited } from "./MessengerError.mjs";
4
4
  import { m as describe } from "../dist-DzeSyeYF.mjs";
5
5
  import { n as globalExpect } from "../index.C4tKZ0yW-LuFnBtmu.mjs";
6
- import { t as it } from "../dist-C8RmtoR8.mjs";
6
+ import { t as it } from "../dist-B5K-y4Be.mjs";
7
7
  import { make } from "../testing/MockMessenger.mjs";
8
8
  import { Array, Duration, Effect, Option, Result, Stream } from "effect";
9
9
  import { TestClock } from "effect/testing";
@@ -1,4 +1,4 @@
1
- import { S as Usage } from "../Items-C7MyrYPX.mjs";
1
+ import { T as Usage } from "../Items-Bvx8s9QH.mjs";
2
2
  import { TurnEvent } from "../domain/Turn.mjs";
3
3
  import { Duration, Effect, Option, Stream } from "effect";
4
4
  declare namespace Metrics_d_exports {
@@ -2,7 +2,7 @@ import { TurnEvent } from "../domain/Turn.mjs";
2
2
  import { computeThroughputTick, isMetricEvent, makeEvent, metricEvents, throughput, timeToCompletion, timeToFirstToken, tokenTotals } from "./Metrics.mjs";
3
3
  import { m as describe } from "../dist-DzeSyeYF.mjs";
4
4
  import { n as globalExpect } from "../index.C4tKZ0yW-LuFnBtmu.mjs";
5
- import { t as it } from "../dist-C8RmtoR8.mjs";
5
+ import { t as it } from "../dist-B5K-y4Be.mjs";
6
6
  import { Array, Duration, Effect, Fiber, Option, Stream } from "effect";
7
7
  import * as TestClock from "effect/testing/TestClock";
8
8
  //#region src/observability/Metrics.test.ts
@@ -2,7 +2,7 @@ import { makeEvent } from "./Metrics.mjs";
2
2
  import { layerOtlp, record } from "./Telemetry.mjs";
3
3
  import { m as describe } from "../dist-DzeSyeYF.mjs";
4
4
  import { n as globalExpect } from "../index.C4tKZ0yW-LuFnBtmu.mjs";
5
- import { t as it } from "../dist-C8RmtoR8.mjs";
5
+ import { t as it } from "../dist-B5K-y4Be.mjs";
6
6
  import { Array, Duration, Effect, Layer, Metric, Option, Ref, Stream } from "effect";
7
7
  import { HttpClient, HttpClientResponse } from "effect/http";
8
8
  //#region src/observability/Telemetry.test.ts
@@ -1,4 +1,4 @@
1
- import { o as ImageSource } from "../Image-Cv6iBLTy.mjs";
1
+ import { o as ImageSource } from "../Image-Bzc1H_UK.mjs";
2
2
  import { t as AiError } from "../AiError-DvhLIbmd.mjs";
3
3
  import { CommonSessionRequest, RealtimeEvent, RealtimeInput } from "../domain/Realtime.mjs";
4
4
  import { Context, Effect, Scope, Stream } from "effect";
@@ -4,7 +4,7 @@ import { open, sendVideoFrame, toolCalls } from "./RealtimeSession.mjs";
4
4
  import { m as describe } from "../dist-DzeSyeYF.mjs";
5
5
  import { n as globalExpect } from "../index.C4tKZ0yW-LuFnBtmu.mjs";
6
6
  import { t as import_dist } from "../dist-DNeuh84d.mjs";
7
- import { t as it } from "../dist-C8RmtoR8.mjs";
7
+ import { t as it } from "../dist-B5K-y4Be.mjs";
8
8
  import { layer, layerAudioOnly } from "../testing/MockRealtimeSession.mjs";
9
9
  import { Effect, Stream } from "effect";
10
10
  //#region src/realtime/RealtimeSession.test.ts