@effect-uai/core 0.2.0 → 0.4.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 (209) hide show
  1. package/README.md +1 -1
  2. package/dist/{AiError-CqmYjXyx.d.mts → AiError-csR8Bhxx.d.mts} +26 -4
  3. package/dist/{AiError-CqmYjXyx.d.mts.map → AiError-csR8Bhxx.d.mts.map} +1 -1
  4. package/dist/Audio-BfCTGnH3.d.mts +61 -0
  5. package/dist/Audio-BfCTGnH3.d.mts.map +1 -0
  6. package/dist/Image-DxyXqzAM.d.mts +61 -0
  7. package/dist/Image-DxyXqzAM.d.mts.map +1 -0
  8. package/dist/{Items-D1C2686t.d.mts → Items-Hg5AsYxl.d.mts} +132 -80
  9. package/dist/Items-Hg5AsYxl.d.mts.map +1 -0
  10. package/dist/Media-D_CpcM1Z.d.mts +57 -0
  11. package/dist/Media-D_CpcM1Z.d.mts.map +1 -0
  12. package/dist/{StructuredFormat-B5ueioNr.d.mts → StructuredFormat-Cl41C56K.d.mts} +5 -5
  13. package/dist/StructuredFormat-Cl41C56K.d.mts.map +1 -0
  14. package/dist/{Tool-5wxOCuOh.d.mts → Tool-B8B5qVEy.d.mts} +13 -13
  15. package/dist/Tool-B8B5qVEy.d.mts.map +1 -0
  16. package/dist/{Turn-Bi83du4I.d.mts → Turn-7geUcKsf.d.mts} +5 -11
  17. package/dist/Turn-7geUcKsf.d.mts.map +1 -0
  18. package/dist/{chunk-CfYAbeIz.mjs → chunk-uyGKjUfl.mjs} +2 -1
  19. package/dist/dist-DV5ISja1.mjs +13782 -0
  20. package/dist/dist-DV5ISja1.mjs.map +1 -0
  21. package/dist/domain/AiError.d.mts +2 -2
  22. package/dist/domain/AiError.mjs +19 -3
  23. package/dist/domain/AiError.mjs.map +1 -1
  24. package/dist/domain/Audio.d.mts +2 -0
  25. package/dist/domain/Audio.mjs +14 -0
  26. package/dist/domain/Audio.mjs.map +1 -0
  27. package/dist/domain/Image.d.mts +2 -0
  28. package/dist/domain/Image.mjs +58 -0
  29. package/dist/domain/Image.mjs.map +1 -0
  30. package/dist/domain/Items.d.mts +2 -2
  31. package/dist/domain/Items.mjs +19 -42
  32. package/dist/domain/Items.mjs.map +1 -1
  33. package/dist/domain/Media.d.mts +2 -0
  34. package/dist/domain/Media.mjs +14 -0
  35. package/dist/domain/Media.mjs.map +1 -0
  36. package/dist/domain/Music.d.mts +116 -0
  37. package/dist/domain/Music.d.mts.map +1 -0
  38. package/dist/domain/Music.mjs +29 -0
  39. package/dist/domain/Music.mjs.map +1 -0
  40. package/dist/domain/Transcript.d.mts +95 -0
  41. package/dist/domain/Transcript.d.mts.map +1 -0
  42. package/dist/domain/Transcript.mjs +22 -0
  43. package/dist/domain/Transcript.mjs.map +1 -0
  44. package/dist/domain/Turn.d.mts +1 -1
  45. package/dist/domain/Turn.mjs +1 -1
  46. package/dist/embedding-model/Embedding.d.mts +107 -0
  47. package/dist/embedding-model/Embedding.d.mts.map +1 -0
  48. package/dist/embedding-model/Embedding.mjs +18 -0
  49. package/dist/embedding-model/Embedding.mjs.map +1 -0
  50. package/dist/embedding-model/EmbeddingModel.d.mts +97 -0
  51. package/dist/embedding-model/EmbeddingModel.d.mts.map +1 -0
  52. package/dist/embedding-model/EmbeddingModel.mjs +17 -0
  53. package/dist/embedding-model/EmbeddingModel.mjs.map +1 -0
  54. package/dist/index.d.mts +21 -7
  55. package/dist/index.mjs +16 -2
  56. package/dist/language-model/LanguageModel.d.mts +12 -20
  57. package/dist/language-model/LanguageModel.d.mts.map +1 -1
  58. package/dist/language-model/LanguageModel.mjs +3 -20
  59. package/dist/language-model/LanguageModel.mjs.map +1 -1
  60. package/dist/loop/Loop.d.mts +31 -7
  61. package/dist/loop/Loop.d.mts.map +1 -1
  62. package/dist/loop/Loop.mjs +39 -6
  63. package/dist/loop/Loop.mjs.map +1 -1
  64. package/dist/loop/Loop.test.d.mts +1 -0
  65. package/dist/loop/Loop.test.mjs +411 -0
  66. package/dist/loop/Loop.test.mjs.map +1 -0
  67. package/dist/magic-string.es-BgIV5Mu3.mjs +1013 -0
  68. package/dist/magic-string.es-BgIV5Mu3.mjs.map +1 -0
  69. package/dist/math/Vector.d.mts +47 -0
  70. package/dist/math/Vector.d.mts.map +1 -0
  71. package/dist/math/Vector.mjs +117 -0
  72. package/dist/math/Vector.mjs.map +1 -0
  73. package/dist/music-generator/MusicGenerator.d.mts +77 -0
  74. package/dist/music-generator/MusicGenerator.d.mts.map +1 -0
  75. package/dist/music-generator/MusicGenerator.mjs +51 -0
  76. package/dist/music-generator/MusicGenerator.mjs.map +1 -0
  77. package/dist/music-generator/MusicGenerator.test.d.mts +1 -0
  78. package/dist/music-generator/MusicGenerator.test.mjs +154 -0
  79. package/dist/music-generator/MusicGenerator.test.mjs.map +1 -0
  80. package/dist/observability/Metrics.d.mts +2 -2
  81. package/dist/observability/Metrics.d.mts.map +1 -1
  82. package/dist/observability/Metrics.mjs +1 -1
  83. package/dist/observability/Metrics.mjs.map +1 -1
  84. package/dist/speech-synthesizer/SpeechSynthesizer.d.mts +96 -0
  85. package/dist/speech-synthesizer/SpeechSynthesizer.d.mts.map +1 -0
  86. package/dist/speech-synthesizer/SpeechSynthesizer.mjs +48 -0
  87. package/dist/speech-synthesizer/SpeechSynthesizer.mjs.map +1 -0
  88. package/dist/speech-synthesizer/SpeechSynthesizer.test.d.mts +1 -0
  89. package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs +112 -0
  90. package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs.map +1 -0
  91. package/dist/streaming/JSONL.d.mts +10 -3
  92. package/dist/streaming/JSONL.d.mts.map +1 -1
  93. package/dist/streaming/JSONL.mjs +13 -2
  94. package/dist/streaming/JSONL.mjs.map +1 -1
  95. package/dist/streaming/JSONL.test.d.mts +1 -0
  96. package/dist/streaming/JSONL.test.mjs +70 -0
  97. package/dist/streaming/JSONL.test.mjs.map +1 -0
  98. package/dist/streaming/Lines.mjs +1 -1
  99. package/dist/streaming/SSE.d.mts +2 -2
  100. package/dist/streaming/SSE.d.mts.map +1 -1
  101. package/dist/streaming/SSE.mjs +1 -1
  102. package/dist/streaming/SSE.mjs.map +1 -1
  103. package/dist/streaming/SSE.test.d.mts +1 -0
  104. package/dist/streaming/SSE.test.mjs +72 -0
  105. package/dist/streaming/SSE.test.mjs.map +1 -0
  106. package/dist/structured-format/StructuredFormat.d.mts +1 -1
  107. package/dist/structured-format/StructuredFormat.mjs +1 -1
  108. package/dist/structured-format/StructuredFormat.mjs.map +1 -1
  109. package/dist/testing/MockMusicGenerator.d.mts +39 -0
  110. package/dist/testing/MockMusicGenerator.d.mts.map +1 -0
  111. package/dist/testing/MockMusicGenerator.mjs +96 -0
  112. package/dist/testing/MockMusicGenerator.mjs.map +1 -0
  113. package/dist/testing/MockProvider.d.mts +6 -6
  114. package/dist/testing/MockProvider.d.mts.map +1 -1
  115. package/dist/testing/MockProvider.mjs.map +1 -1
  116. package/dist/testing/MockSpeechSynthesizer.d.mts +37 -0
  117. package/dist/testing/MockSpeechSynthesizer.d.mts.map +1 -0
  118. package/dist/testing/MockSpeechSynthesizer.mjs +95 -0
  119. package/dist/testing/MockSpeechSynthesizer.mjs.map +1 -0
  120. package/dist/testing/MockTranscriber.d.mts +37 -0
  121. package/dist/testing/MockTranscriber.d.mts.map +1 -0
  122. package/dist/testing/MockTranscriber.mjs +77 -0
  123. package/dist/testing/MockTranscriber.mjs.map +1 -0
  124. package/dist/tool/HistoryCheck.d.mts +6 -3
  125. package/dist/tool/HistoryCheck.d.mts.map +1 -1
  126. package/dist/tool/HistoryCheck.mjs +7 -1
  127. package/dist/tool/HistoryCheck.mjs.map +1 -1
  128. package/dist/tool/Outcome.d.mts +138 -2
  129. package/dist/tool/Outcome.d.mts.map +1 -0
  130. package/dist/tool/Outcome.mjs +32 -10
  131. package/dist/tool/Outcome.mjs.map +1 -1
  132. package/dist/tool/Resolvers.d.mts +11 -8
  133. package/dist/tool/Resolvers.d.mts.map +1 -1
  134. package/dist/tool/Resolvers.mjs +10 -1
  135. package/dist/tool/Resolvers.mjs.map +1 -1
  136. package/dist/tool/Resolvers.test.d.mts +1 -0
  137. package/dist/tool/Resolvers.test.mjs +317 -0
  138. package/dist/tool/Resolvers.test.mjs.map +1 -0
  139. package/dist/tool/Tool.d.mts +1 -1
  140. package/dist/tool/Tool.mjs +1 -1
  141. package/dist/tool/Tool.mjs.map +1 -1
  142. package/dist/tool/ToolEvent.d.mts +151 -2
  143. package/dist/tool/ToolEvent.d.mts.map +1 -0
  144. package/dist/tool/ToolEvent.mjs +30 -4
  145. package/dist/tool/ToolEvent.mjs.map +1 -1
  146. package/dist/tool/Toolkit.d.mts +19 -10
  147. package/dist/tool/Toolkit.d.mts.map +1 -1
  148. package/dist/tool/Toolkit.mjs +5 -5
  149. package/dist/tool/Toolkit.mjs.map +1 -1
  150. package/dist/tool/Toolkit.test.d.mts +1 -0
  151. package/dist/tool/Toolkit.test.mjs +113 -0
  152. package/dist/tool/Toolkit.test.mjs.map +1 -0
  153. package/dist/transcriber/Transcriber.d.mts +101 -0
  154. package/dist/transcriber/Transcriber.d.mts.map +1 -0
  155. package/dist/transcriber/Transcriber.mjs +49 -0
  156. package/dist/transcriber/Transcriber.mjs.map +1 -0
  157. package/dist/transcriber/Transcriber.test.d.mts +1 -0
  158. package/dist/transcriber/Transcriber.test.mjs +130 -0
  159. package/dist/transcriber/Transcriber.test.mjs.map +1 -0
  160. package/package.json +65 -13
  161. package/src/domain/AiError.ts +21 -0
  162. package/src/domain/Audio.ts +88 -0
  163. package/src/domain/Image.ts +75 -0
  164. package/src/domain/Items.ts +18 -47
  165. package/src/domain/Media.ts +61 -0
  166. package/src/domain/Music.ts +121 -0
  167. package/src/domain/Transcript.ts +83 -0
  168. package/src/embedding-model/Embedding.ts +117 -0
  169. package/src/embedding-model/EmbeddingModel.ts +107 -0
  170. package/src/index.ts +15 -1
  171. package/src/language-model/LanguageModel.ts +2 -22
  172. package/src/loop/Loop.test.ts +114 -2
  173. package/src/loop/Loop.ts +69 -5
  174. package/src/math/Vector.ts +138 -0
  175. package/src/music-generator/MusicGenerator.test.ts +170 -0
  176. package/src/music-generator/MusicGenerator.ts +123 -0
  177. package/src/observability/Metrics.ts +1 -1
  178. package/src/speech-synthesizer/SpeechSynthesizer.test.ts +141 -0
  179. package/src/speech-synthesizer/SpeechSynthesizer.ts +131 -0
  180. package/src/streaming/JSONL.ts +12 -0
  181. package/src/streaming/SSE.ts +1 -1
  182. package/src/structured-format/StructuredFormat.ts +2 -2
  183. package/src/testing/MockMusicGenerator.ts +170 -0
  184. package/src/testing/MockProvider.ts +2 -2
  185. package/src/testing/MockSpeechSynthesizer.ts +165 -0
  186. package/src/testing/MockTranscriber.ts +139 -0
  187. package/src/tool/HistoryCheck.ts +2 -5
  188. package/src/tool/Outcome.ts +36 -36
  189. package/src/tool/Resolvers.test.ts +11 -35
  190. package/src/tool/Resolvers.ts +5 -14
  191. package/src/tool/Tool.ts +9 -9
  192. package/src/tool/ToolEvent.ts +28 -24
  193. package/src/tool/Toolkit.test.ts +97 -2
  194. package/src/tool/Toolkit.ts +57 -33
  195. package/src/transcriber/Transcriber.test.ts +125 -0
  196. package/src/transcriber/Transcriber.ts +127 -0
  197. package/dist/Items-D1C2686t.d.mts.map +0 -1
  198. package/dist/Outcome-GiaNvt7i.d.mts +0 -32
  199. package/dist/Outcome-GiaNvt7i.d.mts.map +0 -1
  200. package/dist/StructuredFormat-B5ueioNr.d.mts.map +0 -1
  201. package/dist/Tool-5wxOCuOh.d.mts.map +0 -1
  202. package/dist/ToolEvent-wTMgb2GO.d.mts +0 -29
  203. package/dist/ToolEvent-wTMgb2GO.d.mts.map +0 -1
  204. package/dist/Turn-Bi83du4I.d.mts.map +0 -1
  205. package/dist/match/Match.d.mts +0 -16
  206. package/dist/match/Match.d.mts.map +0 -1
  207. package/dist/match/Match.mjs +0 -15
  208. package/dist/match/Match.mjs.map +0 -1
  209. package/src/match/Match.ts +0 -9
@@ -1 +1 @@
1
- {"version":3,"file":"ToolEvent.mjs","names":[],"sources":["../../src/tool/ToolEvent.ts"],"sourcesContent":["/**\n * The event type emitted while handling tool calls.\n *\n * - ApprovalRequested : gated calls waiting for approval\n * - Intermediate : per-element passthrough from a streaming tool's run\n * - Output : terminal result (carries a structured ToolResult)\n *\n * Recipes thread `ToolEvent.Output.result` through `nextStateFrom` and apply\n * `toFunctionCallOutput` when appending to history.\n */\nimport type { ToolResult } from \"./Outcome.js\"\n\nexport type ToolEvent =\n | {\n readonly _tag: \"ApprovalRequested\"\n readonly call_id: string\n readonly tool: string\n readonly arguments: string\n }\n | {\n readonly _tag: \"Intermediate\"\n readonly call_id: string\n readonly tool: string\n readonly data: unknown\n }\n | { readonly _tag: \"Output\"; readonly result: ToolResult }\n\nexport const isApprovalRequested = (\n e: ToolEvent,\n): e is Extract<ToolEvent, { _tag: \"ApprovalRequested\" }> => e._tag === \"ApprovalRequested\"\n\nexport const isIntermediate = (\n e: ToolEvent,\n): e is Extract<ToolEvent, { _tag: \"Intermediate\" }> => e._tag === \"Intermediate\"\n\nexport const isOutput = (e: ToolEvent): e is Extract<ToolEvent, { _tag: \"Output\" }> =>\n e._tag === \"Output\"\n"],"mappings":";AA2BA,MAAa,uBACX,MAC2D,EAAE,SAAS;AAExE,MAAa,kBACX,MACsD,EAAE,SAAS;AAEnE,MAAa,YAAY,MACvB,EAAE,SAAS"}
1
+ {"version":3,"file":"ToolEvent.mjs","names":[],"sources":["../../src/tool/ToolEvent.ts"],"sourcesContent":["/**\n * The event type emitted while handling tool calls.\n *\n * - ApprovalRequested : gated calls waiting for approval\n * - Intermediate : per-element passthrough from a streaming tool's run\n * - Output : terminal result (carries a structured ToolResult)\n *\n * Recipes thread `ToolEvent.Output.result` through `continueWith` and apply\n * `toFunctionCallOutput` when appending to history.\n */\nimport { Data } from \"effect\"\nimport type { ToolResult } from \"./Outcome.js\"\n\nexport type ToolEvent = Data.TaggedEnum<{\n ApprovalRequested: {\n readonly call_id: string\n readonly tool: string\n readonly arguments: string\n }\n Intermediate: {\n readonly call_id: string\n readonly tool: string\n readonly data: unknown\n }\n Output: {\n readonly result: ToolResult\n }\n}>\n\n/**\n * Namespace of constructors, type guards, and matchers for `ToolEvent`,\n * provided by `Data.taggedEnum`. Use `ToolEvent.Output({ result })` to build\n * an event, `ToolEvent.$is(\"Output\")` for type narrowing,\n * `ToolEvent.$match({ ApprovalRequested, Intermediate, Output })` for\n * exhaustive pattern matching.\n */\nexport const ToolEvent = Data.taggedEnum<ToolEvent>()\n\nexport const isApprovalRequested = ToolEvent.$is(\"ApprovalRequested\")\nexport const isIntermediate = ToolEvent.$is(\"Intermediate\")\nexport const isOutput = ToolEvent.$is(\"Output\")\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,MAAa,YAAY,KAAK,YAAuB;AAErD,MAAa,sBAAsB,UAAU,IAAI,oBAAoB;AACrE,MAAa,iBAAiB,UAAU,IAAI,eAAe;AAC3D,MAAa,WAAW,UAAU,IAAI,SAAS"}
@@ -1,19 +1,25 @@
1
- import { o as FunctionCall } from "../Items-D1C2686t.mjs";
2
- import { a as Tool, o as ToolDescriptor, t as AnyKindTool } from "../Tool-5wxOCuOh.mjs";
1
+ import { o as FunctionCall } from "../Items-Hg5AsYxl.mjs";
2
+ import { a as Tool, i as StreamingTool, o as ToolDescriptor, t as AnyKindTool } from "../Tool-B8B5qVEy.mjs";
3
3
  import { Event } from "../loop/Loop.mjs";
4
- import { t as ToolResult } from "../Outcome-GiaNvt7i.mjs";
5
- import { t as ToolEvent } from "../ToolEvent-wTMgb2GO.mjs";
4
+ import { ToolResult } from "./Outcome.mjs";
5
+ import { ToolEvent } from "./ToolEvent.mjs";
6
6
  import { Stream } from "effect";
7
7
 
8
8
  //#region src/tool/Toolkit.d.ts
9
9
  declare namespace Toolkit_d_exports {
10
- export { AnyTool, ExecuteOptions, Toolkit, ToolsR, executeAll, make, nextStateFrom, outputEvent, outputEvents, toDescriptors };
10
+ export { AnyTool, ExecuteOptions, ToolKindR, Toolkit, ToolsR, continueWith, executeAll, make, outputEvent, outputEvents, toDescriptors };
11
11
  }
12
12
  type AnyTool = Tool<string, any, any, any>;
13
13
  type Toolkit<Tools extends ReadonlyArray<AnyTool>> = {
14
14
  readonly tools: Tools;
15
15
  };
16
16
  type ToolsR<Tools extends ReadonlyArray<AnyTool>> = Tools[number] extends Tool<any, any, any, infer R> ? R : never;
17
+ /**
18
+ * Union of every tool's `R` requirements in a mixed plain + streaming array.
19
+ * Used by `executeAll` to surface the services tools need at the recipe
20
+ * level, so the loop's stream type carries them through to `Effect.provide`.
21
+ */
22
+ type ToolKindR<Tools extends ReadonlyArray<AnyKindTool<any>>> = Tools[number] extends StreamingTool<any, any, any, any, infer R> ? R : Tools[number] extends Tool<any, any, any, infer R> ? R : never;
17
23
  declare const make: <const Tools extends ReadonlyArray<AnyTool>>(tools: Tools) => Toolkit<Tools>;
18
24
  /**
19
25
  * Render every tool in a toolkit to a provider-agnostic descriptor.
@@ -21,14 +27,17 @@ declare const make: <const Tools extends ReadonlyArray<AnyTool>>(tools: Tools) =
21
27
  * Standard Schema converter (draft 2020-12).
22
28
  */
23
29
  declare const toDescriptors: <Tools extends ReadonlyArray<AnyTool>>(toolkit: Toolkit<Tools>) => ReadonlyArray<ToolDescriptor>;
24
- interface ExecuteOptions {
30
+ type ExecuteOptions = {
25
31
  readonly concurrency?: number | "unbounded";
26
- }
32
+ };
27
33
  /** Execute every provided call. Approval/rejection policy belongs upstream. */
28
- declare const executeAll: (tools: ReadonlyArray<AnyKindTool>, calls: ReadonlyArray<FunctionCall>, options?: ExecuteOptions) => Stream.Stream<ToolEvent>;
34
+ declare const executeAll: <Tools extends ReadonlyArray<AnyKindTool<any>>>(tools: Tools, calls: ReadonlyArray<FunctionCall>, options?: ExecuteOptions) => Stream.Stream<ToolEvent, never, ToolKindR<Tools>>;
29
35
  declare const outputEvent: (result: ToolResult) => ToolEvent;
30
36
  declare const outputEvents: (results: ReadonlyArray<ToolResult>) => Stream.Stream<ToolEvent>;
31
- declare const nextStateFrom: <S>(stream: Stream.Stream<ToolEvent>, build: (results: ReadonlyArray<ToolResult>) => S) => Stream.Stream<Event<ToolEvent, S>>;
37
+ declare const continueWith: {
38
+ <S>(build: (results: ReadonlyArray<ToolResult>) => S): <R>(stream: Stream.Stream<ToolEvent, never, R>) => Stream.Stream<Event<ToolEvent, S>, never, R>;
39
+ <S, R>(stream: Stream.Stream<ToolEvent, never, R>, build: (results: ReadonlyArray<ToolResult>) => S): Stream.Stream<Event<ToolEvent, S>, never, R>;
40
+ };
32
41
  //#endregion
33
- export { AnyTool, ExecuteOptions, Toolkit, ToolsR, executeAll, make, nextStateFrom, outputEvent, outputEvents, Toolkit_d_exports as t, toDescriptors };
42
+ export { AnyTool, ExecuteOptions, ToolKindR, Toolkit, ToolsR, continueWith, executeAll, make, outputEvent, outputEvents, Toolkit_d_exports as t, toDescriptors };
34
43
  //# sourceMappingURL=Toolkit.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Toolkit.d.mts","names":[],"sources":["../../src/tool/Toolkit.ts"],"mappings":";;;;;;;;;;;KAmBY,OAAA,GAAU,IAAA;AAAA,KAEV,OAAA,eAAsB,aAAA,CAAc,OAAA;EAAA,SACrC,KAAA,EAAO,KAAA;AAAA;AAAA,KAGN,MAAA,eAAqB,aAAA,CAAc,OAAA,KAC7C,KAAA,iBAAsB,IAAA,2BAA+B,CAAA;AAAA,cAE1C,IAAA,uBAA4B,aAAA,CAAc,OAAA,GAAU,KAAA,EAAO,KAAA,KAAQ,OAAA,CAAQ,KAAA;;;;;;cAS3E,aAAA,iBAA+B,aAAA,CAAc,OAAA,GACxD,OAAA,EAAS,OAAA,CAAQ,KAAA,MAChB,aAAA,CAAc,cAAA;AAAA,UAgBA,cAAA;EAAA,SACN,WAAA;AAAA;AArCX;AAAA,cAyCa,UAAA,GACX,KAAA,EAAO,aAAA,CAAc,WAAA,GACrB,KAAA,EAAO,aAAA,CAAc,YAAA,GACrB,OAAA,GAAU,cAAA,KACT,MAAA,CAAO,MAAA,CAAO,SAAA;AAAA,cAOJ,WAAA,GAAe,MAAA,EAAQ,UAAA,KAAa,SAAA;AAAA,cAEpC,YAAA,GACX,OAAA,EAAS,aAAA,CAAc,UAAA,MACtB,MAAA,CAAO,MAAA,CAAO,SAAA;AAAA,cAqHJ,aAAA,MACX,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,SAAA,GACtB,KAAA,GAAQ,OAAA,EAAS,aAAA,CAAc,UAAA,MAAgB,CAAA,KAC9C,MAAA,CAAO,MAAA,CAAO,KAAA,CAAW,SAAA,EAAW,CAAA"}
1
+ {"version":3,"file":"Toolkit.d.mts","names":[],"sources":["../../src/tool/Toolkit.ts"],"mappings":";;;;;;;;;;;KAgBY,OAAA,GAAU,IAAA;AAAA,KAEV,OAAA,eAAsB,aAAA,CAAc,OAAA;EAAA,SACrC,KAAA,EAAO,KAAA;AAAA;AAAA,KAGN,MAAA,eAAqB,aAAA,CAAc,OAAA,KAC7C,KAAA,iBAAsB,IAAA,2BAA+B,CAAA;;;;;;KAO3C,SAAA,eAAwB,aAAA,CAAc,WAAA,UAChD,KAAA,iBAAsB,aAAA,gCAClB,CAAA,GACA,KAAA,iBAAsB,IAAA,2BACpB,CAAA;AAAA,cAGK,IAAA,uBAA4B,aAAA,CAAc,OAAA,GAAU,KAAA,EAAO,KAAA,KAAQ,OAAA,CAAQ,KAAA;;;;;AArBxF;cA8Ba,aAAA,iBAA+B,aAAA,CAAc,OAAA,GACxD,OAAA,EAAS,OAAA,CAAQ,KAAA,MAChB,aAAA,CAAc,cAAA;AAAA,KAgBL,cAAA;EAAA,SACD,WAAA;AAAA;AA/CX;AAAA,cAmDa,UAAA,iBAA4B,aAAA,CAAc,WAAA,QACrD,KAAA,EAAO,KAAA,EACP,KAAA,EAAO,aAAA,CAAc,YAAA,GACrB,OAAA,GAAU,cAAA,KACT,MAAA,CAAO,MAAA,CAAO,SAAA,SAAkB,SAAA,CAAU,KAAA;AAAA,cAOhC,WAAA,GAAe,MAAA,EAAQ,UAAA,KAAa,SAAA;AAAA,cAEpC,YAAA,GAAgB,OAAA,EAAS,aAAA,CAAc,UAAA,MAAc,MAAA,CAAO,MAAA,CAAO,SAAA;AAAA,cAyHnE,YAAA;EAAA,IAET,KAAA,GAAQ,OAAA,EAAS,aAAA,CAAc,UAAA,MAAgB,CAAA,OAE/C,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,SAAA,SAAkB,CAAA,MACrC,MAAA,CAAO,MAAA,CAAO,KAAA,CAAW,SAAA,EAAW,CAAA,UAAW,CAAA;EAAA,OAElD,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,SAAA,SAAkB,CAAA,GACxC,KAAA,GAAQ,OAAA,EAAS,aAAA,CAAc,UAAA,MAAgB,CAAA,GAC9C,MAAA,CAAO,MAAA,CAAO,KAAA,CAAW,SAAA,EAAW,CAAA,UAAW,CAAA;AAAA"}
@@ -1,14 +1,14 @@
1
- import { t as __exportAll } from "../chunk-CfYAbeIz.mjs";
1
+ import { n as __exportAll } from "../chunk-uyGKjUfl.mjs";
2
2
  import { nextAfterFold } from "../loop/Loop.mjs";
3
3
  import { isStreamingTool } from "./Tool.mjs";
4
4
  import { executionError, rejected } from "./Outcome.mjs";
5
5
  import { isOutput } from "./ToolEvent.mjs";
6
- import { Array, Effect, Ref, Stream } from "effect";
6
+ import { Array, Effect, Function, Ref, Stream } from "effect";
7
7
  //#region src/tool/Toolkit.ts
8
8
  var Toolkit_exports = /* @__PURE__ */ __exportAll({
9
+ continueWith: () => continueWith,
9
10
  executeAll: () => executeAll,
10
11
  make: () => make,
11
- nextStateFrom: () => nextStateFrom,
12
12
  outputEvent: () => outputEvent,
13
13
  outputEvents: () => outputEvents,
14
14
  toDescriptors: () => toDescriptors
@@ -99,8 +99,8 @@ const runStreaming = (tool, call) => Stream.unwrap(Effect.gen(function* () {
99
99
  _tag: "Output",
100
100
  result: executionError(call, "Tool execution failed")
101
101
  })));
102
- const nextStateFrom = (stream, build) => nextAfterFold(stream, [], (acc, e) => isOutput(e) ? Array.append(acc, e.result) : acc, build);
102
+ const continueWith = Function.dual(2, (stream, build) => nextAfterFold(stream, [], (acc, e) => isOutput(e) ? Array.append(acc, e.result) : acc, build));
103
103
  //#endregion
104
- export { executeAll, make, nextStateFrom, outputEvent, outputEvents, Toolkit_exports as t, toDescriptors };
104
+ export { continueWith, executeAll, make, outputEvent, outputEvents, Toolkit_exports as t, toDescriptors };
105
105
 
106
106
  //# sourceMappingURL=Toolkit.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Toolkit.mjs","names":["Arr","Loop.nextAfterFold"],"sources":["../../src/tool/Toolkit.ts"],"sourcesContent":["import { Array as Arr, Effect, Ref, Stream } from \"effect\"\nimport * as Loop from \"../loop/Loop.js\"\nimport type { FunctionCall } from \"../domain/Items.js\"\nimport {\n type AnyKindTool,\n type AnyPlainTool,\n type AnyStreamingTool,\n isStreamingTool,\n type Tool,\n type ToolDescriptor,\n} from \"./Tool.js\"\nimport {\n type ToolResult,\n executionError,\n rejected,\n} from \"./Outcome.js\"\nimport type { ToolEvent } from \"./ToolEvent.js\"\nimport { isOutput } from \"./ToolEvent.js\"\n\nexport type AnyTool = Tool<string, any, any, any>\n\nexport type Toolkit<Tools extends ReadonlyArray<AnyTool>> = {\n readonly tools: Tools\n}\n\nexport type ToolsR<Tools extends ReadonlyArray<AnyTool>> =\n Tools[number] extends Tool<any, any, any, infer R> ? R : never\n\nexport const make = <const Tools extends ReadonlyArray<AnyTool>>(tools: Tools): Toolkit<Tools> => ({\n tools,\n})\n\n/**\n * Render every tool in a toolkit to a provider-agnostic descriptor.\n * `inputSchema` is the JSON Schema document produced by the tool's\n * Standard Schema converter (draft 2020-12).\n */\nexport const toDescriptors = <Tools extends ReadonlyArray<AnyTool>>(\n toolkit: Toolkit<Tools>,\n): ReadonlyArray<ToolDescriptor> =>\n toolkit.tools.map((tool) => {\n const inputSchema = tool.inputSchema[\"~standard\"].jsonSchema.input({\n target: \"draft-2020-12\",\n })\n return tool.strict !== undefined\n ? { name: tool.name, description: tool.description, inputSchema, strict: tool.strict }\n : { name: tool.name, description: tool.description, inputSchema }\n })\n\n// ---------------------------------------------------------------------------\n// Tool executor. Streams `ToolEvent`s in real time and dispatches streaming\n// and plain tools uniformly. Policy stays outside this module: callers pass\n// only the calls they have already decided should run.\n// ---------------------------------------------------------------------------\n\nexport interface ExecuteOptions {\n readonly concurrency?: number | \"unbounded\"\n}\n\n/** Execute every provided call. Approval/rejection policy belongs upstream. */\nexport const executeAll = (\n tools: ReadonlyArray<AnyKindTool>,\n calls: ReadonlyArray<FunctionCall>,\n options?: ExecuteOptions,\n): Stream.Stream<ToolEvent> =>\n Stream.fromIterable(calls).pipe(\n Stream.flatMap((call) => runOne(tools, call), {\n concurrency: options?.concurrency ?? \"unbounded\",\n }),\n )\n\nexport const outputEvent = (result: ToolResult): ToolEvent => ({ _tag: \"Output\", result })\n\nexport const outputEvents = (\n results: ReadonlyArray<ToolResult>,\n): Stream.Stream<ToolEvent> => Stream.fromIterable(results.map(outputEvent))\n\nconst valueResult = (call: FunctionCall, tool: string, value: unknown): ToolResult => ({\n _tag: \"Value\",\n call_id: call.call_id,\n tool,\n value,\n})\n\nconst runOne = (\n tools: ReadonlyArray<AnyKindTool>,\n call: FunctionCall,\n): Stream.Stream<ToolEvent> => {\n const tool = tools.find((t) => t.name === call.name)\n if (tool === undefined) {\n // Graceful: emit a synthetic Failure so OTHER calls in this turn\n // still execute. LLMs hallucinate tool names; MCP tools come and go.\n return Stream.succeed<ToolEvent>({\n _tag: \"Output\",\n result: rejected(call, \"unknown_tool\", `No tool registered with name \"${call.name}\"`),\n })\n }\n if (isStreamingTool(tool)) return runStreaming(tool, call)\n return runPlain(tool, call)\n}\n\nconst runPlain = (\n tool: AnyPlainTool,\n call: FunctionCall,\n): Stream.Stream<ToolEvent> =>\n Stream.fromEffect(\n Effect.gen(function* () {\n const parsed = yield* Effect.try({\n try: () => JSON.parse(call.arguments) as unknown,\n catch: () => \"json_parse_error\" as const,\n })\n const validated = yield* Effect.tryPromise({\n try: () => Promise.resolve(tool.inputSchema[\"~standard\"].validate(parsed)),\n catch: () => \"validation_threw\" as const,\n })\n if (validated.issues !== undefined) {\n return executionError(call, \"Tool input failed schema validation\")\n }\n const output = yield* tool.run(validated.value)\n return valueResult(call, tool.name, output)\n }).pipe(\n Effect.catchCause(() => Effect.succeed(executionError(call, \"Tool execution failed\"))),\n Effect.map((result) => ({ _tag: \"Output\", result }) satisfies ToolEvent),\n ),\n )\n\nconst runStreaming = (\n tool: AnyStreamingTool,\n call: FunctionCall,\n): Stream.Stream<ToolEvent> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const parsed = yield* Effect.try({\n try: () => JSON.parse(call.arguments) as unknown,\n catch: () => \"json_parse_error\" as const,\n })\n const validated = yield* Effect.tryPromise({\n try: () => Promise.resolve(tool.inputSchema[\"~standard\"].validate(parsed)),\n catch: () => \"validation_threw\" as const,\n })\n if (validated.issues !== undefined) {\n return Stream.succeed<ToolEvent>({\n _tag: \"Output\",\n result: executionError(call, \"Tool input failed schema validation\"),\n })\n }\n\n // Real-time: tap each event into a Ref as it flows; emit one\n // Intermediate per event; then concat one synthetic Output element\n // built from the accumulated Ref via `finalize`.\n const ref = yield* Ref.make<Array<unknown>>([])\n const intermediates = tool.run(validated.value).pipe(\n Stream.tap((event) => Ref.update(ref, Arr.append(event))),\n Stream.map(\n (data) =>\n ({\n _tag: \"Intermediate\",\n call_id: call.call_id,\n tool: tool.name,\n data,\n }) satisfies ToolEvent,\n ),\n )\n const output = Stream.fromEffect(\n Ref.get(ref).pipe(\n Effect.map(\n (events) =>\n ({\n _tag: \"Output\",\n result: valueResult(call, tool.name, tool.finalize(events)),\n }) satisfies ToolEvent,\n ),\n ),\n )\n return intermediates.pipe(Stream.concat(output))\n }),\n ).pipe(\n Stream.catchCause(() =>\n Stream.succeed<ToolEvent>({\n _tag: \"Output\",\n result: executionError(call, \"Tool execution failed\"),\n }),\n ),\n )\n\n// ---------------------------------------------------------------------------\n// `nextStateFrom` - bridge from a `Stream<ToolEvent>` to the loop's emit\n// shape. Drains the stream to the consumer in real-time, taps every\n// `Output` into an internal Ref, and at end-of-stream emits\n// `Loop.next(build(results))`. Recipe never sees the Ref.\n// ---------------------------------------------------------------------------\n\nexport const nextStateFrom = <S>(\n stream: Stream.Stream<ToolEvent>,\n build: (results: ReadonlyArray<ToolResult>) => S,\n): Stream.Stream<Loop.Event<ToolEvent, S>> =>\n Loop.nextAfterFold(\n stream,\n [] as ReadonlyArray<ToolResult>,\n (acc, e) => (isOutput(e) ? Arr.append(acc, e.result) : acc),\n build,\n )\n"],"mappings":"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"}
1
+ {"version":3,"file":"Toolkit.mjs","names":["Arr","Loop.nextAfterFold"],"sources":["../../src/tool/Toolkit.ts"],"sourcesContent":["import { Array as Arr, Effect, Function, Ref, Stream } from \"effect\"\nimport * as Loop from \"../loop/Loop.js\"\nimport type { FunctionCall } from \"../domain/Items.js\"\nimport {\n type AnyKindTool,\n type AnyPlainTool,\n type AnyStreamingTool,\n isStreamingTool,\n type StreamingTool,\n type Tool,\n type ToolDescriptor,\n} from \"./Tool.js\"\nimport { type ToolResult, executionError, rejected } from \"./Outcome.js\"\nimport type { ToolEvent } from \"./ToolEvent.js\"\nimport { isOutput } from \"./ToolEvent.js\"\n\nexport type AnyTool = Tool<string, any, any, any>\n\nexport type Toolkit<Tools extends ReadonlyArray<AnyTool>> = {\n readonly tools: Tools\n}\n\nexport type ToolsR<Tools extends ReadonlyArray<AnyTool>> =\n Tools[number] extends Tool<any, any, any, infer R> ? R : never\n\n/**\n * Union of every tool's `R` requirements in a mixed plain + streaming array.\n * Used by `executeAll` to surface the services tools need at the recipe\n * level, so the loop's stream type carries them through to `Effect.provide`.\n */\nexport type ToolKindR<Tools extends ReadonlyArray<AnyKindTool<any>>> =\n Tools[number] extends StreamingTool<any, any, any, any, infer R>\n ? R\n : Tools[number] extends Tool<any, any, any, infer R>\n ? R\n : never\n\nexport const make = <const Tools extends ReadonlyArray<AnyTool>>(tools: Tools): Toolkit<Tools> => ({\n tools,\n})\n\n/**\n * Render every tool in a toolkit to a provider-agnostic descriptor.\n * `inputSchema` is the JSON Schema document produced by the tool's\n * Standard Schema converter (draft 2020-12).\n */\nexport const toDescriptors = <Tools extends ReadonlyArray<AnyTool>>(\n toolkit: Toolkit<Tools>,\n): ReadonlyArray<ToolDescriptor> =>\n toolkit.tools.map((tool) => {\n const inputSchema = tool.inputSchema[\"~standard\"].jsonSchema.input({\n target: \"draft-2020-12\",\n })\n return tool.strict !== undefined\n ? { name: tool.name, description: tool.description, inputSchema, strict: tool.strict }\n : { name: tool.name, description: tool.description, inputSchema }\n })\n\n// ---------------------------------------------------------------------------\n// Tool executor. Streams `ToolEvent`s in real time and dispatches streaming\n// and plain tools uniformly. Policy stays outside this module: callers pass\n// only the calls they have already decided should run.\n// ---------------------------------------------------------------------------\n\nexport type ExecuteOptions = {\n readonly concurrency?: number | \"unbounded\"\n}\n\n/** Execute every provided call. Approval/rejection policy belongs upstream. */\nexport const executeAll = <Tools extends ReadonlyArray<AnyKindTool<any>>>(\n tools: Tools,\n calls: ReadonlyArray<FunctionCall>,\n options?: ExecuteOptions,\n): Stream.Stream<ToolEvent, never, ToolKindR<Tools>> =>\n Stream.fromIterable(calls).pipe(\n Stream.flatMap((call) => runOne(tools, call), {\n concurrency: options?.concurrency ?? \"unbounded\",\n }),\n )\n\nexport const outputEvent = (result: ToolResult): ToolEvent => ({ _tag: \"Output\", result })\n\nexport const outputEvents = (results: ReadonlyArray<ToolResult>): Stream.Stream<ToolEvent> =>\n Stream.fromIterable(results.map(outputEvent))\n\nconst valueResult = (call: FunctionCall, tool: string, value: unknown): ToolResult => ({\n _tag: \"Value\",\n call_id: call.call_id,\n tool,\n value,\n})\n\nconst runOne = <R>(\n tools: ReadonlyArray<AnyKindTool<R>>,\n call: FunctionCall,\n): Stream.Stream<ToolEvent, never, R> => {\n const tool = tools.find((t) => t.name === call.name)\n if (tool === undefined) {\n // Graceful: emit a synthetic Failure so OTHER calls in this turn\n // still execute. LLMs hallucinate tool names; MCP tools come and go.\n return Stream.succeed<ToolEvent>({\n _tag: \"Output\",\n result: rejected(call, \"unknown_tool\", `No tool registered with name \"${call.name}\"`),\n })\n }\n if (isStreamingTool(tool)) return runStreaming(tool, call)\n return runPlain(tool, call)\n}\n\nconst runPlain = <R>(\n tool: AnyPlainTool<R>,\n call: FunctionCall,\n): Stream.Stream<ToolEvent, never, R> =>\n Stream.fromEffect(\n Effect.gen(function* () {\n const parsed = yield* Effect.try({\n try: () => JSON.parse(call.arguments) as unknown,\n catch: () => \"json_parse_error\" as const,\n })\n const validated = yield* Effect.tryPromise({\n try: () => Promise.resolve(tool.inputSchema[\"~standard\"].validate(parsed)),\n catch: () => \"validation_threw\" as const,\n })\n if (validated.issues !== undefined) {\n return executionError(call, \"Tool input failed schema validation\")\n }\n const output = yield* tool.run(validated.value)\n return valueResult(call, tool.name, output)\n }).pipe(\n Effect.catchCause(() => Effect.succeed(executionError(call, \"Tool execution failed\"))),\n Effect.map((result) => ({ _tag: \"Output\", result }) satisfies ToolEvent),\n ),\n )\n\nconst runStreaming = <R>(\n tool: AnyStreamingTool<R>,\n call: FunctionCall,\n): Stream.Stream<ToolEvent, never, R> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const parsed = yield* Effect.try({\n try: () => JSON.parse(call.arguments) as unknown,\n catch: () => \"json_parse_error\" as const,\n })\n const validated = yield* Effect.tryPromise({\n try: () => Promise.resolve(tool.inputSchema[\"~standard\"].validate(parsed)),\n catch: () => \"validation_threw\" as const,\n })\n if (validated.issues !== undefined) {\n return Stream.succeed<ToolEvent>({\n _tag: \"Output\",\n result: executionError(call, \"Tool input failed schema validation\"),\n })\n }\n\n // Real-time: tap each event into a Ref as it flows; emit one\n // Intermediate per event; then concat one synthetic Output element\n // built from the accumulated Ref via `finalize`.\n const ref = yield* Ref.make<Array<unknown>>([])\n const intermediates = tool.run(validated.value).pipe(\n Stream.tap((event) => Ref.update(ref, Arr.append(event))),\n Stream.map(\n (data) =>\n ({\n _tag: \"Intermediate\",\n call_id: call.call_id,\n tool: tool.name,\n data,\n }) satisfies ToolEvent,\n ),\n )\n const output = Stream.fromEffect(\n Ref.get(ref).pipe(\n Effect.map(\n (events) =>\n ({\n _tag: \"Output\",\n result: valueResult(call, tool.name, tool.finalize(events)),\n }) satisfies ToolEvent,\n ),\n ),\n )\n return intermediates.pipe(Stream.concat(output))\n }),\n ).pipe(\n Stream.catchCause(() =>\n Stream.succeed<ToolEvent>({\n _tag: \"Output\",\n result: executionError(call, \"Tool execution failed\"),\n }),\n ),\n )\n\n// ---------------------------------------------------------------------------\n// `continueWith` - bridge from a `Stream<ToolEvent>` to the loop's emit\n// shape. Drains the stream to the consumer in real-time, taps every\n// `Output` into an internal Ref, and at end-of-stream emits\n// `Loop.next(build(results))`. Recipe never sees the Ref.\n//\n// Dual: data-first `continueWith(stream, build)` and data-last\n// `stream.pipe(continueWith(build))` both work.\n// ---------------------------------------------------------------------------\n\nexport const continueWith: {\n <S>(\n build: (results: ReadonlyArray<ToolResult>) => S,\n ): <R>(\n stream: Stream.Stream<ToolEvent, never, R>,\n ) => Stream.Stream<Loop.Event<ToolEvent, S>, never, R>\n <S, R>(\n stream: Stream.Stream<ToolEvent, never, R>,\n build: (results: ReadonlyArray<ToolResult>) => S,\n ): Stream.Stream<Loop.Event<ToolEvent, S>, never, R>\n} = Function.dual(\n 2,\n <S, R>(\n stream: Stream.Stream<ToolEvent, never, R>,\n build: (results: ReadonlyArray<ToolResult>) => S,\n ): Stream.Stream<Loop.Event<ToolEvent, S>, never, R> =>\n Loop.nextAfterFold(\n stream,\n [] as ReadonlyArray<ToolResult>,\n (acc, e) => (isOutput(e) ? Arr.append(acc, e.result) : acc),\n build,\n ),\n)\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,113 @@
1
+ import { fromEffectSchema, make } from "./Tool.mjs";
2
+ import { isValue } from "./Outcome.mjs";
3
+ import { isOutput } from "./ToolEvent.mjs";
4
+ import { executeAll, make as make$1, toDescriptors } from "./Toolkit.mjs";
5
+ import { i as it, n as globalExpect, r as describe, t as import_dist } from "../dist-DV5ISja1.mjs";
6
+ import { Context, Effect, Layer, Schema, Stream } from "effect";
7
+ //#region src/tool/Toolkit.test.ts
8
+ describe("Toolkit.toDescriptors", () => {
9
+ const GetWeatherInput = Schema.Struct({ city: Schema.String });
10
+ const getWeather = make({
11
+ name: "get_weather",
12
+ description: "Look up the current temperature for a city.",
13
+ inputSchema: fromEffectSchema(GetWeatherInput),
14
+ run: ({ city }) => Effect.succeed({
15
+ city,
16
+ tempC: 18
17
+ })
18
+ });
19
+ it("renders the input schema as a JSON Schema document", () => {
20
+ const [desc] = toDescriptors(make$1([getWeather]));
21
+ globalExpect(desc?.name).toBe("get_weather");
22
+ globalExpect(desc?.description).toBe("Look up the current temperature for a city.");
23
+ globalExpect(desc?.inputSchema).toMatchObject({
24
+ type: "object",
25
+ properties: { city: { type: "string" } },
26
+ required: ["city"]
27
+ });
28
+ });
29
+ it("includes strict flag only when set on the tool", () => {
30
+ const [s, l] = toDescriptors(make$1([make({
31
+ name: "strict_one",
32
+ description: "",
33
+ inputSchema: fromEffectSchema(GetWeatherInput),
34
+ run: () => Effect.succeed({}),
35
+ strict: true
36
+ }), make({
37
+ name: "loose_one",
38
+ description: "",
39
+ inputSchema: fromEffectSchema(GetWeatherInput),
40
+ run: () => Effect.succeed({})
41
+ })]));
42
+ globalExpect(s?.strict).toBe(true);
43
+ globalExpect(l).not.toHaveProperty("strict");
44
+ });
45
+ });
46
+ describe("Toolkit.executeAll - tools with R requirements", () => {
47
+ class WeatherApiKey extends Context.Service()("test/WeatherApiKey") {}
48
+ class GeoApiKey extends Context.Service()("test/GeoApiKey") {}
49
+ const Empty = Schema.Struct({});
50
+ const getWeather = make({
51
+ name: "get_weather",
52
+ description: "",
53
+ inputSchema: fromEffectSchema(Empty),
54
+ run: () => Effect.gen(function* () {
55
+ const { key } = yield* WeatherApiKey;
56
+ return {
57
+ source: "weather",
58
+ key
59
+ };
60
+ })
61
+ });
62
+ const getCoords = make({
63
+ name: "get_coords",
64
+ description: "",
65
+ inputSchema: fromEffectSchema(Empty),
66
+ run: () => Effect.gen(function* () {
67
+ const { key } = yield* GeoApiKey;
68
+ return {
69
+ source: "geo",
70
+ key
71
+ };
72
+ })
73
+ });
74
+ const call = (name, id) => ({
75
+ type: "function_call",
76
+ call_id: id,
77
+ name,
78
+ arguments: "{}"
79
+ });
80
+ it("propagates each tool's R into the resulting Stream's requirements", () => {
81
+ (0, import_dist.expectTypeOf)(executeAll([getWeather, getCoords], [])).toEqualTypeOf();
82
+ });
83
+ it("runs each tool with its own service injected", async () => {
84
+ const layer = Layer.mergeAll(Layer.succeed(WeatherApiKey, { key: "weather-123" }), Layer.succeed(GeoApiKey, { key: "geo-456" }));
85
+ const program = executeAll([getWeather, getCoords], [call("get_weather", "c1"), call("get_coords", "c2")]).pipe(Stream.runCollect, Effect.provide(layer));
86
+ const events = await Effect.runPromise(program);
87
+ const outputs = Array.from(events).filter(isOutput);
88
+ const byCall = new Map(outputs.map((e) => [e.result.call_id, e.result]));
89
+ const w = byCall.get("c1");
90
+ const g = byCall.get("c2");
91
+ globalExpect(w !== void 0 && isValue(w) && w.value).toEqual({
92
+ source: "weather",
93
+ key: "weather-123"
94
+ });
95
+ globalExpect(g !== void 0 && isValue(g) && g.value).toEqual({
96
+ source: "geo",
97
+ key: "geo-456"
98
+ });
99
+ });
100
+ it("with no service-needing tools, R is never", () => {
101
+ const plain = make({
102
+ name: "plain",
103
+ description: "",
104
+ inputSchema: fromEffectSchema(Empty),
105
+ run: () => Effect.succeed(0)
106
+ });
107
+ (0, import_dist.expectTypeOf)(executeAll([plain], [])).toEqualTypeOf();
108
+ });
109
+ });
110
+ //#endregion
111
+ export {};
112
+
113
+ //# sourceMappingURL=Toolkit.test.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toolkit.test.mjs","names":["Tool.make","Tool.fromEffectSchema","Toolkit.toDescriptors","Toolkit.make","Toolkit.executeAll"],"sources":["../../src/tool/Toolkit.test.ts"],"sourcesContent":["import { Context, Effect, Layer, Schema, Stream } from \"effect\"\nimport { describe, expect, expectTypeOf, it } from \"vitest\"\nimport type { FunctionCall } from \"../domain/Items.js\"\nimport { isOutput } from \"./ToolEvent.js\"\nimport { isValue } from \"./Outcome.js\"\nimport * as Tool from \"./Tool.js\"\nimport * as Toolkit from \"./Toolkit.js\"\n\ndescribe(\"Toolkit.toDescriptors\", () => {\n const GetWeatherInput = Schema.Struct({ city: Schema.String })\n\n const getWeather = Tool.make({\n name: \"get_weather\",\n description: \"Look up the current temperature for a city.\",\n inputSchema: Tool.fromEffectSchema(GetWeatherInput),\n run: ({ city }) => Effect.succeed({ city, tempC: 18 }),\n })\n\n it(\"renders the input schema as a JSON Schema document\", () => {\n const [desc] = Toolkit.toDescriptors(Toolkit.make([getWeather]))\n expect(desc?.name).toBe(\"get_weather\")\n expect(desc?.description).toBe(\"Look up the current temperature for a city.\")\n expect(desc?.inputSchema).toMatchObject({\n type: \"object\",\n properties: { city: { type: \"string\" } },\n required: [\"city\"],\n })\n })\n\n it(\"includes strict flag only when set on the tool\", () => {\n const strictTool = Tool.make({\n name: \"strict_one\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(GetWeatherInput),\n run: () => Effect.succeed({}),\n strict: true,\n })\n const looseTool = Tool.make({\n name: \"loose_one\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(GetWeatherInput),\n run: () => Effect.succeed({}),\n })\n const [s, l] = Toolkit.toDescriptors(Toolkit.make([strictTool, looseTool]))\n expect(s?.strict).toBe(true)\n expect(l).not.toHaveProperty(\"strict\")\n })\n})\n\ndescribe(\"Toolkit.executeAll - tools with R requirements\", () => {\n // Two distinct services, modelling the \"typed per-tool context\" use case\n // (cf. AI SDK 7's `toolsContext`). In Effect each tool declares its R, the\n // compiler enforces it, and `executeAll` surfaces the union for the caller\n // to provide via Layer.\n type WeatherApiKeyShape = { readonly key: string }\n class WeatherApiKey extends Context.Service<WeatherApiKey, WeatherApiKeyShape>()(\n \"test/WeatherApiKey\",\n ) {}\n\n type GeoApiKeyShape = { readonly key: string }\n class GeoApiKey extends Context.Service<GeoApiKey, GeoApiKeyShape>()(\"test/GeoApiKey\") {}\n\n const Empty = Schema.Struct({})\n\n const getWeather = Tool.make({\n name: \"get_weather\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () =>\n Effect.gen(function* () {\n const { key } = yield* WeatherApiKey\n return { source: \"weather\", key }\n }),\n })\n\n const getCoords = Tool.make({\n name: \"get_coords\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () =>\n Effect.gen(function* () {\n const { key } = yield* GeoApiKey\n return { source: \"geo\", key }\n }),\n })\n\n const call = (name: string, id: string): FunctionCall => ({\n type: \"function_call\",\n call_id: id,\n name,\n arguments: \"{}\",\n })\n\n it(\"propagates each tool's R into the resulting Stream's requirements\", () => {\n const stream = Toolkit.executeAll([getWeather, getCoords], [])\n expectTypeOf(stream).toEqualTypeOf<\n Stream.Stream<import(\"./ToolEvent.js\").ToolEvent, never, WeatherApiKey | GeoApiKey>\n >()\n })\n\n it(\"runs each tool with its own service injected\", async () => {\n const layer = Layer.mergeAll(\n Layer.succeed(WeatherApiKey, { key: \"weather-123\" }),\n Layer.succeed(GeoApiKey, { key: \"geo-456\" }),\n )\n\n const program = Toolkit.executeAll(\n [getWeather, getCoords],\n [call(\"get_weather\", \"c1\"), call(\"get_coords\", \"c2\")],\n ).pipe(Stream.runCollect, Effect.provide(layer))\n\n const events = await Effect.runPromise(program)\n const outputs = Array.from(events).filter(isOutput)\n const byCall = new Map(outputs.map((e) => [e.result.call_id, e.result]))\n\n const w = byCall.get(\"c1\")\n const g = byCall.get(\"c2\")\n expect(w !== undefined && isValue(w) && w.value).toEqual({\n source: \"weather\",\n key: \"weather-123\",\n })\n expect(g !== undefined && isValue(g) && g.value).toEqual({\n source: \"geo\",\n key: \"geo-456\",\n })\n })\n\n it(\"with no service-needing tools, R is never\", () => {\n const plain = Tool.make({\n name: \"plain\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () => Effect.succeed(0),\n })\n const stream = Toolkit.executeAll([plain], [])\n expectTypeOf(stream).toEqualTypeOf<\n Stream.Stream<import(\"./ToolEvent.js\").ToolEvent, never, never>\n >()\n })\n})\n"],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ import { t as AiError } from "../AiError-csR8Bhxx.mjs";
2
+ import { a as AudioSource, r as AudioFormat } from "../Audio-BfCTGnH3.mjs";
3
+ import { TranscriptEvent, TranscriptResult } from "../domain/Transcript.mjs";
4
+ import { Context, Effect, Stream } from "effect";
5
+
6
+ //#region src/transcriber/Transcriber.d.ts
7
+ declare namespace Transcriber_d_exports {
8
+ export { CommonStreamTranscribeRequest, CommonTranscribeRequest, SttStreaming, Transcriber, TranscriberService, streamTranscriptionFrom, transcribe };
9
+ }
10
+ /**
11
+ * Cross-provider sync transcription request. Provider-specific
12
+ * extensions (Deepgram `keyterm[]`, ElevenLabs `diarize`, Google
13
+ * `adaptation`, …) live on each provider's typed request which extends
14
+ * this and narrows `model`.
15
+ */
16
+ type CommonTranscribeRequest = {
17
+ readonly audio: AudioSource; /** Model identifier. Each provider narrows to its typed literal union. */
18
+ readonly model: string; /** ISO-639-1 / BCP-47. Omit for autodetection (where supported). */
19
+ readonly language?: string;
20
+ /**
21
+ * Vocab biasing. Single-string covers OpenAI/Whisper-style prompts;
22
+ * `terms[]` covers Deepgram `keyterm`, Google adaptation phrases, AWS
23
+ * `vocabularyName`. Providers ignore what they don't support.
24
+ */
25
+ readonly prompt?: string | {
26
+ readonly terms: ReadonlyArray<string>;
27
+ };
28
+ readonly diarization?: boolean;
29
+ readonly wordTimestamps?: boolean;
30
+ };
31
+ /**
32
+ * Streaming-transcription request. `inputFormat` declares what the
33
+ * bytes in the input stream will look like — providers reject
34
+ * mismatches at stream startup with `AiError.InvalidRequest`.
35
+ */
36
+ type CommonStreamTranscribeRequest = Omit<CommonTranscribeRequest, "audio"> & {
37
+ readonly inputFormat: AudioFormat;
38
+ readonly interimResults?: boolean;
39
+ readonly vadEvents?: boolean;
40
+ };
41
+ type TranscriberService = {
42
+ /**
43
+ * One-shot transcription. Universal — AWS Transcribe (which has no
44
+ * native sync endpoint) emulates this by draining a streaming session
45
+ * internally.
46
+ */
47
+ readonly transcribe: (request: CommonTranscribeRequest) => Effect.Effect<TranscriptResult, AiError>;
48
+ /**
49
+ * Live transcription as a Stream transformer. Consumes audio bytes
50
+ * from `audioIn`; emits `TranscriptEvent`s as they arrive. The
51
+ * underlying WS / gRPC connection is acquired on first pull and
52
+ * released when the output stream is finalized (success, failure, or
53
+ * interruption) via `Stream.scoped` — no explicit Scope handling at
54
+ * the call site.
55
+ *
56
+ * Gated by the `SttStreaming` capability marker on the top-level
57
+ * helper — providers without streaming-STT support don't ship the
58
+ * marker, so calls fail at `Effect.provide` with a type error.
59
+ */
60
+ readonly streamTranscriptionFrom: <E, R>(audioIn: Stream.Stream<Uint8Array, E, R>, request: CommonStreamTranscribeRequest) => Stream.Stream<TranscriptEvent, AiError | E, R>;
61
+ };
62
+ declare const Transcriber_base: Context.ServiceClass<Transcriber, "@betalyra/effect-uai/Transcriber", TranscriberService>;
63
+ declare class Transcriber extends Transcriber_base {}
64
+ declare const SttStreaming_base: Context.ServiceClass<SttStreaming, "@betalyra/effect-uai/capability/SttStreaming", void>;
65
+ /**
66
+ * Capability marker — provided by provider layers whose
67
+ * `streamTranscriptionFrom` is wired up at the wire level. Azure does
68
+ * not ship it (streaming-STT is SDK-internal). Calling
69
+ * `streamTranscriptionFrom` while only Azure's Layer is in scope fails
70
+ * at `Effect.provide` with a type error, not at runtime.
71
+ *
72
+ * Phantom — the value is `void`; providers register with
73
+ * `Layer.succeed(SttStreaming, undefined)`.
74
+ */
75
+ declare class SttStreaming extends SttStreaming_base {}
76
+ /** One-shot transcription. */
77
+ declare const transcribe: (request: CommonTranscribeRequest) => Effect.Effect<TranscriptResult, AiError, Transcriber>;
78
+ /**
79
+ * Live transcription. Dual-arity: pipeable (data-last) and direct
80
+ * (data-first). Requires `SttStreaming` in R — providers without
81
+ * streaming support are a type error at provide time.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * // Pipeable — composes with other Stream operators
86
+ * mic.frames.pipe(
87
+ * Transcriber.streamTranscriptionFrom(req),
88
+ * Stream.filter((e) => e._tag === "final"),
89
+ * )
90
+ *
91
+ * // Direct
92
+ * Transcriber.streamTranscriptionFrom(mic.frames, req)
93
+ * ```
94
+ */
95
+ declare const streamTranscriptionFrom: {
96
+ (request: CommonStreamTranscribeRequest): <E, R>(audioIn: Stream.Stream<Uint8Array, E, R>) => Stream.Stream<TranscriptEvent, AiError | E, R | Transcriber | SttStreaming>;
97
+ <E, R>(audioIn: Stream.Stream<Uint8Array, E, R>, request: CommonStreamTranscribeRequest): Stream.Stream<TranscriptEvent, AiError | E, R | Transcriber | SttStreaming>;
98
+ };
99
+ //#endregion
100
+ export { CommonStreamTranscribeRequest, CommonTranscribeRequest, SttStreaming, Transcriber, TranscriberService, streamTranscriptionFrom, Transcriber_d_exports as t, transcribe };
101
+ //# sourceMappingURL=Transcriber.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Transcriber.d.mts","names":[],"sources":["../../src/transcriber/Transcriber.ts"],"mappings":";;;;;;;;;;;;;;;KAWY,uBAAA;EAAA,SACD,KAAA,EAAO,WAAA;WAEP,KAAA;WAEA,QAAA;EALC;;;;;EAAA,SAWD,MAAA;IAAA,SAA6B,KAAA,EAAO,aAAA;EAAA;EAAA,SACpC,WAAA;EAAA,SACA,cAAA;AAAA;;;;;AAQX;KAAY,6BAAA,GAAgC,IAAA,CAAK,uBAAA;EAAA,SACtC,WAAA,EAAa,WAAA;EAAA,SACb,cAAA;EAAA,SACA,SAAA;AAAA;AAAA,KAGC,kBAAA;EALuB;;;;;EAAA,SAWxB,UAAA,GACP,OAAA,EAAS,uBAAA,KACN,MAAA,CAAO,MAAA,CAAO,gBAAA,EAAkB,OAAA;EAX5B;;;AAGX;;;;;;;;;EAHW,SAwBA,uBAAA,SACP,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,CAAA,EAAG,CAAA,GACtC,OAAA,EAAS,6BAAA,KACN,MAAA,CAAO,MAAA,CAAO,eAAA,EAAiB,OAAA,GAAkB,CAAA,EAAG,CAAA;AAAA;AAAA,cAC1D,gBAAA;cAEY,WAAA,SAAoB,gBAAA;AAAA,cAE7B,iBAAA;;;;;;;;;;;cAYS,YAAA,SAAqB,iBAAA;;cAKrB,UAAA,GACX,OAAA,EAAS,uBAAA,KACR,MAAA,CAAO,MAAA,CAAO,gBAAA,EAAkB,OAAA,EAAiB,WAAA;;;;;;;;;;;;;;;;;;cAoBvC,uBAAA;EAAA,CAET,OAAA,EAAS,6BAAA,UAET,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,CAAA,EAAG,CAAA,MACnC,MAAA,CAAO,MAAA,CAAO,eAAA,EAAiB,OAAA,GAAkB,CAAA,EAAG,CAAA,GAAI,WAAA,GAAc,YAAA;EAAA,OAEzE,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,CAAA,EAAG,CAAA,GACtC,OAAA,EAAS,6BAAA,GACR,MAAA,CAAO,MAAA,CAAO,eAAA,EAAiB,OAAA,GAAkB,CAAA,EAAG,CAAA,GAAI,WAAA,GAAc,YAAA;AAAA"}
@@ -0,0 +1,49 @@
1
+ import { n as __exportAll } from "../chunk-uyGKjUfl.mjs";
2
+ import { Context, Effect, Function, Stream } from "effect";
3
+ //#region src/transcriber/Transcriber.ts
4
+ var Transcriber_exports = /* @__PURE__ */ __exportAll({
5
+ SttStreaming: () => SttStreaming,
6
+ Transcriber: () => Transcriber,
7
+ streamTranscriptionFrom: () => streamTranscriptionFrom,
8
+ transcribe: () => transcribe
9
+ });
10
+ var Transcriber = class extends Context.Service()("@betalyra/effect-uai/Transcriber") {};
11
+ /**
12
+ * Capability marker — provided by provider layers whose
13
+ * `streamTranscriptionFrom` is wired up at the wire level. Azure does
14
+ * not ship it (streaming-STT is SDK-internal). Calling
15
+ * `streamTranscriptionFrom` while only Azure's Layer is in scope fails
16
+ * at `Effect.provide` with a type error, not at runtime.
17
+ *
18
+ * Phantom — the value is `void`; providers register with
19
+ * `Layer.succeed(SttStreaming, undefined)`.
20
+ */
21
+ var SttStreaming = class extends Context.Service()("@betalyra/effect-uai/capability/SttStreaming") {};
22
+ /** One-shot transcription. */
23
+ const transcribe = (request) => Effect.flatMap(Transcriber.asEffect(), (t) => t.transcribe(request));
24
+ /**
25
+ * Live transcription. Dual-arity: pipeable (data-last) and direct
26
+ * (data-first). Requires `SttStreaming` in R — providers without
27
+ * streaming support are a type error at provide time.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * // Pipeable — composes with other Stream operators
32
+ * mic.frames.pipe(
33
+ * Transcriber.streamTranscriptionFrom(req),
34
+ * Stream.filter((e) => e._tag === "final"),
35
+ * )
36
+ *
37
+ * // Direct
38
+ * Transcriber.streamTranscriptionFrom(mic.frames, req)
39
+ * ```
40
+ */
41
+ const streamTranscriptionFrom = Function.dual(2, (audioIn, request) => Stream.unwrap(Effect.gen(function* () {
42
+ const t = yield* Transcriber.asEffect();
43
+ yield* SttStreaming.asEffect();
44
+ return t.streamTranscriptionFrom(audioIn, request);
45
+ })));
46
+ //#endregion
47
+ export { SttStreaming, Transcriber, streamTranscriptionFrom, Transcriber_exports as t, transcribe };
48
+
49
+ //# sourceMappingURL=Transcriber.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Transcriber.mjs","names":[],"sources":["../../src/transcriber/Transcriber.ts"],"sourcesContent":["import { Context, Effect, Function, Stream } from \"effect\"\nimport * as AiError from \"../domain/AiError.js\"\nimport type { AudioFormat, AudioSource } from \"../domain/Audio.js\"\nimport type { TranscriptEvent, TranscriptResult } from \"../domain/Transcript.js\"\n\n/**\n * Cross-provider sync transcription request. Provider-specific\n * extensions (Deepgram `keyterm[]`, ElevenLabs `diarize`, Google\n * `adaptation`, …) live on each provider's typed request which extends\n * this and narrows `model`.\n */\nexport type CommonTranscribeRequest = {\n readonly audio: AudioSource\n /** Model identifier. Each provider narrows to its typed literal union. */\n readonly model: string\n /** ISO-639-1 / BCP-47. Omit for autodetection (where supported). */\n readonly language?: string\n /**\n * Vocab biasing. Single-string covers OpenAI/Whisper-style prompts;\n * `terms[]` covers Deepgram `keyterm`, Google adaptation phrases, AWS\n * `vocabularyName`. Providers ignore what they don't support.\n */\n readonly prompt?: string | { readonly terms: ReadonlyArray<string> }\n readonly diarization?: boolean\n readonly wordTimestamps?: boolean\n}\n\n/**\n * Streaming-transcription request. `inputFormat` declares what the\n * bytes in the input stream will look like — providers reject\n * mismatches at stream startup with `AiError.InvalidRequest`.\n */\nexport type CommonStreamTranscribeRequest = Omit<CommonTranscribeRequest, \"audio\"> & {\n readonly inputFormat: AudioFormat\n readonly interimResults?: boolean\n readonly vadEvents?: boolean\n}\n\nexport type TranscriberService = {\n /**\n * One-shot transcription. Universal — AWS Transcribe (which has no\n * native sync endpoint) emulates this by draining a streaming session\n * internally.\n */\n readonly transcribe: (\n request: CommonTranscribeRequest,\n ) => Effect.Effect<TranscriptResult, AiError.AiError>\n /**\n * Live transcription as a Stream transformer. Consumes audio bytes\n * from `audioIn`; emits `TranscriptEvent`s as they arrive. The\n * underlying WS / gRPC connection is acquired on first pull and\n * released when the output stream is finalized (success, failure, or\n * interruption) via `Stream.scoped` — no explicit Scope handling at\n * the call site.\n *\n * Gated by the `SttStreaming` capability marker on the top-level\n * helper — providers without streaming-STT support don't ship the\n * marker, so calls fail at `Effect.provide` with a type error.\n */\n readonly streamTranscriptionFrom: <E, R>(\n audioIn: Stream.Stream<Uint8Array, E, R>,\n request: CommonStreamTranscribeRequest,\n ) => Stream.Stream<TranscriptEvent, AiError.AiError | E, R>\n}\n\nexport class Transcriber extends Context.Service<Transcriber, TranscriberService>()(\n \"@betalyra/effect-uai/Transcriber\",\n) {}\n\n/**\n * Capability marker — provided by provider layers whose\n * `streamTranscriptionFrom` is wired up at the wire level. Azure does\n * not ship it (streaming-STT is SDK-internal). Calling\n * `streamTranscriptionFrom` while only Azure's Layer is in scope fails\n * at `Effect.provide` with a type error, not at runtime.\n *\n * Phantom — the value is `void`; providers register with\n * `Layer.succeed(SttStreaming, undefined)`.\n */\nexport class SttStreaming extends Context.Service<SttStreaming, void>()(\n \"@betalyra/effect-uai/capability/SttStreaming\",\n) {}\n\n/** One-shot transcription. */\nexport const transcribe = (\n request: CommonTranscribeRequest,\n): Effect.Effect<TranscriptResult, AiError.AiError, Transcriber> =>\n Effect.flatMap(Transcriber.asEffect(), (t) => t.transcribe(request))\n\n/**\n * Live transcription. Dual-arity: pipeable (data-last) and direct\n * (data-first). Requires `SttStreaming` in R — providers without\n * streaming support are a type error at provide time.\n *\n * @example\n * ```ts\n * // Pipeable — composes with other Stream operators\n * mic.frames.pipe(\n * Transcriber.streamTranscriptionFrom(req),\n * Stream.filter((e) => e._tag === \"final\"),\n * )\n *\n * // Direct\n * Transcriber.streamTranscriptionFrom(mic.frames, req)\n * ```\n */\nexport const streamTranscriptionFrom: {\n (\n request: CommonStreamTranscribeRequest,\n ): <E, R>(\n audioIn: Stream.Stream<Uint8Array, E, R>,\n ) => Stream.Stream<TranscriptEvent, AiError.AiError | E, R | Transcriber | SttStreaming>\n <E, R>(\n audioIn: Stream.Stream<Uint8Array, E, R>,\n request: CommonStreamTranscribeRequest,\n ): Stream.Stream<TranscriptEvent, AiError.AiError | E, R | Transcriber | SttStreaming>\n} = Function.dual(\n 2,\n <E, R>(audioIn: Stream.Stream<Uint8Array, E, R>, request: CommonStreamTranscribeRequest) =>\n Stream.unwrap(\n Effect.gen(function* () {\n const t = yield* Transcriber.asEffect()\n yield* SttStreaming.asEffect()\n return t.streamTranscriptionFrom(audioIn, request)\n }),\n ),\n)\n"],"mappings":";;;;;;;;;AAiEA,IAAa,cAAb,cAAiC,QAAQ,SAA0C,CACjF,mCACD,CAAC;;;;;;;;;;;AAYF,IAAa,eAAb,cAAkC,QAAQ,SAA6B,CACrE,+CACD,CAAC;;AAGF,MAAa,cACX,YAEA,OAAO,QAAQ,YAAY,UAAU,GAAG,MAAM,EAAE,WAAW,QAAQ,CAAC;;;;;;;;;;;;;;;;;;AAmBtE,MAAa,0BAUT,SAAS,KACX,IACO,SAA0C,YAC/C,OAAO,OACL,OAAO,IAAI,aAAa;CACtB,MAAM,IAAI,OAAO,YAAY,UAAU;AACvC,QAAO,aAAa,UAAU;AAC9B,QAAO,EAAE,wBAAwB,SAAS,QAAQ;EAClD,CACH,CACJ"}
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,130 @@
1
+ import { streamTranscriptionFrom, transcribe } from "./Transcriber.mjs";
2
+ import { i as it, n as globalExpect, r as describe, t as import_dist } from "../dist-DV5ISja1.mjs";
3
+ import { layer, layerSyncOnly } from "../testing/MockTranscriber.mjs";
4
+ import { Effect, Stream } from "effect";
5
+ //#region src/transcriber/Transcriber.test.ts
6
+ describe("Transcriber.transcribe", () => {
7
+ it("returns the scripted TranscriptResult", async () => {
8
+ const mock = layer({ transcripts: [{
9
+ text: "hello world",
10
+ durationSeconds: 1.23
11
+ }] });
12
+ const program = transcribe({
13
+ audio: {
14
+ _tag: "bytes",
15
+ bytes: new Uint8Array([0]),
16
+ mimeType: "audio/wav"
17
+ },
18
+ model: "mock-stt"
19
+ });
20
+ const result = await Effect.runPromise(program.pipe(Effect.provide(mock.layer)));
21
+ globalExpect(result.text).toBe("hello world");
22
+ globalExpect(result.durationSeconds).toBe(1.23);
23
+ });
24
+ it("records each transcribe call", async () => {
25
+ const mock = layer({ transcripts: [{ text: "a" }, { text: "b" }] });
26
+ const program = Effect.gen(function* () {
27
+ yield* transcribe({
28
+ audio: {
29
+ _tag: "bytes",
30
+ bytes: new Uint8Array([1]),
31
+ mimeType: "audio/wav"
32
+ },
33
+ model: "m1"
34
+ });
35
+ yield* transcribe({
36
+ audio: {
37
+ _tag: "bytes",
38
+ bytes: new Uint8Array([2]),
39
+ mimeType: "audio/wav"
40
+ },
41
+ model: "m2"
42
+ });
43
+ return yield* mock.recorder;
44
+ });
45
+ globalExpect((await Effect.runPromise(program.pipe(Effect.provide(mock.layer)))).transcribeCalls.map((c) => c.model)).toEqual(["m1", "m2"]);
46
+ });
47
+ });
48
+ describe("Transcriber capability marker (compile-time)", () => {
49
+ const sttReq = {
50
+ model: "mock-stt",
51
+ inputFormat: {
52
+ container: "raw",
53
+ encoding: "pcm_s16le",
54
+ sampleRate: 16e3
55
+ }
56
+ };
57
+ it("requires `SttStreaming` on the R channel of streamTranscriptionFrom", () => {
58
+ (0, import_dist.expectTypeOf)(Stream.fromIterable([new Uint8Array([0])]).pipe(streamTranscriptionFrom(sttReq))).toEqualTypeOf();
59
+ });
60
+ it("does NOT require `SttStreaming` for sync `transcribe`", () => {
61
+ (0, import_dist.expectTypeOf)(transcribe({
62
+ audio: {
63
+ _tag: "bytes",
64
+ bytes: new Uint8Array([0]),
65
+ mimeType: "audio/wav"
66
+ },
67
+ model: "m"
68
+ })).toEqualTypeOf();
69
+ });
70
+ it("a sync-only layer leaves `SttStreaming` unsatisfied in R", () => {
71
+ const syncOnly = layerSyncOnly({});
72
+ const events = Stream.fromIterable([new Uint8Array([0])]).pipe(streamTranscriptionFrom(sttReq));
73
+ (0, import_dist.expectTypeOf)(Stream.runDrain(events).pipe(Effect.provide(syncOnly.layer))).toEqualTypeOf();
74
+ });
75
+ it("a full layer (with marker) clears R to never", () => {
76
+ const fullMock = layer({ streams: [[]] });
77
+ const events = Stream.fromIterable([new Uint8Array([0])]).pipe(streamTranscriptionFrom(sttReq));
78
+ (0, import_dist.expectTypeOf)(Stream.runDrain(events).pipe(Effect.provide(fullMock.layer))).toEqualTypeOf();
79
+ });
80
+ });
81
+ describe("Transcriber.streamTranscriptionFrom", () => {
82
+ const sttReq = {
83
+ model: "mock-stt",
84
+ inputFormat: {
85
+ container: "raw",
86
+ encoding: "pcm_s16le",
87
+ sampleRate: 16e3
88
+ }
89
+ };
90
+ it("emits scripted events after draining the input audio stream", async () => {
91
+ const mock = layer({ streams: [[{
92
+ _tag: "partial",
93
+ text: "hello"
94
+ }, {
95
+ _tag: "final",
96
+ text: "hello world"
97
+ }]] });
98
+ const events = Stream.fromIterable([new Uint8Array([
99
+ 0,
100
+ 1,
101
+ 2
102
+ ]), new Uint8Array([
103
+ 3,
104
+ 4,
105
+ 5
106
+ ])]).pipe(streamTranscriptionFrom(sttReq));
107
+ globalExpect(await Effect.runPromise(Stream.runCollect(events).pipe(Effect.provide(mock.layer)))).toEqual([{
108
+ _tag: "partial",
109
+ text: "hello"
110
+ }, {
111
+ _tag: "final",
112
+ text: "hello world"
113
+ }]);
114
+ });
115
+ it("works data-first (direct call) as well as pipeable (data-last)", async () => {
116
+ const mock = layer({ streams: [[{
117
+ _tag: "final",
118
+ text: "x"
119
+ }]] });
120
+ const events = streamTranscriptionFrom(Stream.fromIterable([new Uint8Array([0])]), sttReq);
121
+ globalExpect(await Effect.runPromise(Stream.runCollect(events).pipe(Effect.provide(mock.layer)))).toEqual([{
122
+ _tag: "final",
123
+ text: "x"
124
+ }]);
125
+ });
126
+ });
127
+ //#endregion
128
+ export {};
129
+
130
+ //# sourceMappingURL=Transcriber.test.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Transcriber.test.mjs","names":["MockTranscriber.layer","Transcriber.transcribe","Transcriber.streamTranscriptionFrom","MockTranscriber.layerSyncOnly"],"sources":["../../src/transcriber/Transcriber.test.ts"],"sourcesContent":["import { Effect, Stream } from \"effect\"\nimport { describe, expect, expectTypeOf, it } from \"vitest\"\nimport type * as AiError from \"../domain/AiError.js\"\nimport type { TranscriptEvent, TranscriptResult } from \"../domain/Transcript.js\"\nimport * as MockTranscriber from \"../testing/MockTranscriber.js\"\nimport * as Transcriber from \"./Transcriber.js\"\n\ndescribe(\"Transcriber.transcribe\", () => {\n it(\"returns the scripted TranscriptResult\", async () => {\n const mock = MockTranscriber.layer({\n transcripts: [{ text: \"hello world\", durationSeconds: 1.23 }],\n })\n const program = Transcriber.transcribe({\n audio: { _tag: \"bytes\", bytes: new Uint8Array([0]), mimeType: \"audio/wav\" },\n model: \"mock-stt\",\n })\n const result = await Effect.runPromise(program.pipe(Effect.provide(mock.layer)))\n expect(result.text).toBe(\"hello world\")\n expect(result.durationSeconds).toBe(1.23)\n })\n\n it(\"records each transcribe call\", async () => {\n const mock = MockTranscriber.layer({\n transcripts: [{ text: \"a\" }, { text: \"b\" }],\n })\n const program = Effect.gen(function* () {\n yield* Transcriber.transcribe({\n audio: { _tag: \"bytes\", bytes: new Uint8Array([1]), mimeType: \"audio/wav\" },\n model: \"m1\",\n })\n yield* Transcriber.transcribe({\n audio: { _tag: \"bytes\", bytes: new Uint8Array([2]), mimeType: \"audio/wav\" },\n model: \"m2\",\n })\n return yield* mock.recorder\n })\n const rec = await Effect.runPromise(program.pipe(Effect.provide(mock.layer)))\n expect(rec.transcribeCalls.map((c) => c.model)).toEqual([\"m1\", \"m2\"])\n })\n})\n\ndescribe(\"Transcriber capability marker (compile-time)\", () => {\n const sttReq: Transcriber.CommonStreamTranscribeRequest = {\n model: \"mock-stt\",\n inputFormat: { container: \"raw\", encoding: \"pcm_s16le\", sampleRate: 16000 },\n }\n\n it(\"requires `SttStreaming` on the R channel of streamTranscriptionFrom\", () => {\n const audio: Stream.Stream<Uint8Array> = Stream.fromIterable([new Uint8Array([0])])\n const events = audio.pipe(Transcriber.streamTranscriptionFrom(sttReq))\n expectTypeOf(events).toEqualTypeOf<\n Stream.Stream<\n TranscriptEvent,\n AiError.AiError,\n Transcriber.Transcriber | Transcriber.SttStreaming\n >\n >()\n })\n\n it(\"does NOT require `SttStreaming` for sync `transcribe`\", () => {\n const eff = Transcriber.transcribe({\n audio: { _tag: \"bytes\", bytes: new Uint8Array([0]), mimeType: \"audio/wav\" },\n model: \"m\",\n })\n expectTypeOf(eff).toEqualTypeOf<\n Effect.Effect<TranscriptResult, AiError.AiError, Transcriber.Transcriber>\n >()\n })\n\n it(\"a sync-only layer leaves `SttStreaming` unsatisfied in R\", () => {\n const syncOnly = MockTranscriber.layerSyncOnly({})\n const audio: Stream.Stream<Uint8Array> = Stream.fromIterable([new Uint8Array([0])])\n const events = audio.pipe(Transcriber.streamTranscriptionFrom(sttReq))\n const program = Stream.runDrain(events).pipe(Effect.provide(syncOnly.layer))\n // `Transcriber` is provided by syncOnly.layer; `SttStreaming` is not.\n expectTypeOf(program).toEqualTypeOf<\n Effect.Effect<void, AiError.AiError, Transcriber.SttStreaming>\n >()\n })\n\n it(\"a full layer (with marker) clears R to never\", () => {\n const fullMock = MockTranscriber.layer({ streams: [[]] })\n const audio: Stream.Stream<Uint8Array> = Stream.fromIterable([new Uint8Array([0])])\n const events = audio.pipe(Transcriber.streamTranscriptionFrom(sttReq))\n const program = Stream.runDrain(events).pipe(Effect.provide(fullMock.layer))\n expectTypeOf(program).toEqualTypeOf<Effect.Effect<void, AiError.AiError, never>>()\n })\n})\n\ndescribe(\"Transcriber.streamTranscriptionFrom\", () => {\n const sttReq: Transcriber.CommonStreamTranscribeRequest = {\n model: \"mock-stt\",\n inputFormat: { container: \"raw\", encoding: \"pcm_s16le\", sampleRate: 16000 },\n }\n\n it(\"emits scripted events after draining the input audio stream\", async () => {\n const mock = MockTranscriber.layer({\n streams: [\n [\n { _tag: \"partial\", text: \"hello\" },\n { _tag: \"final\", text: \"hello world\" },\n ],\n ],\n })\n const audio = Stream.fromIterable([new Uint8Array([0, 1, 2]), new Uint8Array([3, 4, 5])])\n const events = audio.pipe(Transcriber.streamTranscriptionFrom(sttReq))\n const collected = await Effect.runPromise(\n Stream.runCollect(events).pipe(Effect.provide(mock.layer)),\n )\n expect(collected).toEqual([\n { _tag: \"partial\", text: \"hello\" },\n { _tag: \"final\", text: \"hello world\" },\n ])\n })\n\n it(\"works data-first (direct call) as well as pipeable (data-last)\", async () => {\n const mock = MockTranscriber.layer({\n streams: [[{ _tag: \"final\", text: \"x\" }]],\n })\n const audio = Stream.fromIterable([new Uint8Array([0])])\n const events = Transcriber.streamTranscriptionFrom(audio, sttReq)\n const out = await Effect.runPromise(Stream.runCollect(events).pipe(Effect.provide(mock.layer)))\n expect(out).toEqual([{ _tag: \"final\", text: \"x\" }])\n })\n})\n"],"mappings":";;;;;AAOA,SAAS,gCAAgC;AACvC,IAAG,yCAAyC,YAAY;EACtD,MAAM,OAAOA,MAAsB,EACjC,aAAa,CAAC;GAAE,MAAM;GAAe,iBAAiB;GAAM,CAAC,EAC9D,CAAC;EACF,MAAM,UAAUC,WAAuB;GACrC,OAAO;IAAE,MAAM;IAAS,OAAO,IAAI,WAAW,CAAC,EAAE,CAAC;IAAE,UAAU;IAAa;GAC3E,OAAO;GACR,CAAC;EACF,MAAM,SAAS,MAAM,OAAO,WAAW,QAAQ,KAAK,OAAO,QAAQ,KAAK,MAAM,CAAC,CAAC;AAChF,eAAO,OAAO,KAAK,CAAC,KAAK,cAAc;AACvC,eAAO,OAAO,gBAAgB,CAAC,KAAK,KAAK;GACzC;AAEF,IAAG,gCAAgC,YAAY;EAC7C,MAAM,OAAOD,MAAsB,EACjC,aAAa,CAAC,EAAE,MAAM,KAAK,EAAE,EAAE,MAAM,KAAK,CAAC,EAC5C,CAAC;EACF,MAAM,UAAU,OAAO,IAAI,aAAa;AACtC,UAAOC,WAAuB;IAC5B,OAAO;KAAE,MAAM;KAAS,OAAO,IAAI,WAAW,CAAC,EAAE,CAAC;KAAE,UAAU;KAAa;IAC3E,OAAO;IACR,CAAC;AACF,UAAOA,WAAuB;IAC5B,OAAO;KAAE,MAAM;KAAS,OAAO,IAAI,WAAW,CAAC,EAAE,CAAC;KAAE,UAAU;KAAa;IAC3E,OAAO;IACR,CAAC;AACF,UAAO,OAAO,KAAK;IACnB;AAEF,gBAAO,MADW,OAAO,WAAW,QAAQ,KAAK,OAAO,QAAQ,KAAK,MAAM,CAAC,CAAC,EAClE,gBAAgB,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;GACrE;EACF;AAEF,SAAS,sDAAsD;CAC7D,MAAM,SAAoD;EACxD,OAAO;EACP,aAAa;GAAE,WAAW;GAAO,UAAU;GAAa,YAAY;GAAO;EAC5E;AAED,IAAG,6EAA6E;AAG9E,GAAA,GAAA,YAAA,cAFyC,OAAO,aAAa,CAAC,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC,CAC9D,CAAC,KAAKC,wBAAoC,OAAO,CAClD,CAAC,CAAC,eAMlB;GACH;AAEF,IAAG,+DAA+D;AAKhE,GAAA,GAAA,YAAA,cAJYD,WAAuB;GACjC,OAAO;IAAE,MAAM;IAAS,OAAO,IAAI,WAAW,CAAC,EAAE,CAAC;IAAE,UAAU;IAAa;GAC3E,OAAO;GACR,CACe,CAAC,CAAC,eAEf;GACH;AAEF,IAAG,kEAAkE;EACnE,MAAM,WAAWE,cAA8B,EAAE,CAAC;EAElD,MAAM,SADmC,OAAO,aAAa,CAAC,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC,CAC9D,CAAC,KAAKD,wBAAoC,OAAO,CAAC;AAGtE,GAAA,GAAA,YAAA,cAFgB,OAAO,SAAS,OAAO,CAAC,KAAK,OAAO,QAAQ,SAAS,MAAM,CAEvD,CAAC,CAAC,eAEnB;GACH;AAEF,IAAG,sDAAsD;EACvD,MAAM,WAAWF,MAAsB,EAAE,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC;EAEzD,MAAM,SADmC,OAAO,aAAa,CAAC,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC,CAC9D,CAAC,KAAKE,wBAAoC,OAAO,CAAC;AAEtE,GAAA,GAAA,YAAA,cADgB,OAAO,SAAS,OAAO,CAAC,KAAK,OAAO,QAAQ,SAAS,MAAM,CACvD,CAAC,CAAC,eAA4D;GAClF;EACF;AAEF,SAAS,6CAA6C;CACpD,MAAM,SAAoD;EACxD,OAAO;EACP,aAAa;GAAE,WAAW;GAAO,UAAU;GAAa,YAAY;GAAO;EAC5E;AAED,IAAG,+DAA+D,YAAY;EAC5E,MAAM,OAAOF,MAAsB,EACjC,SAAS,CACP,CACE;GAAE,MAAM;GAAW,MAAM;GAAS,EAClC;GAAE,MAAM;GAAS,MAAM;GAAe,CACvC,CACF,EACF,CAAC;EAEF,MAAM,SADQ,OAAO,aAAa,CAAC,IAAI,WAAW;GAAC;GAAG;GAAG;GAAE,CAAC,EAAE,IAAI,WAAW;GAAC;GAAG;GAAG;GAAE,CAAC,CAAC,CACpE,CAAC,KAAKE,wBAAoC,OAAO,CAAC;AAItE,eAAO,MAHiB,OAAO,WAC7B,OAAO,WAAW,OAAO,CAAC,KAAK,OAAO,QAAQ,KAAK,MAAM,CAAC,CAC3D,CACgB,CAAC,QAAQ,CACxB;GAAE,MAAM;GAAW,MAAM;GAAS,EAClC;GAAE,MAAM;GAAS,MAAM;GAAe,CACvC,CAAC;GACF;AAEF,IAAG,kEAAkE,YAAY;EAC/E,MAAM,OAAOF,MAAsB,EACjC,SAAS,CAAC,CAAC;GAAE,MAAM;GAAS,MAAM;GAAK,CAAC,CAAC,EAC1C,CAAC;EAEF,MAAM,SAASE,wBADD,OAAO,aAAa,CAAC,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC,CACJ,EAAO,OAAO;AAEjE,eAAO,MADW,OAAO,WAAW,OAAO,WAAW,OAAO,CAAC,KAAK,OAAO,QAAQ,KAAK,MAAM,CAAC,CAAC,CACpF,CAAC,QAAQ,CAAC;GAAE,MAAM;GAAS,MAAM;GAAK,CAAC,CAAC;GACnD;EACF"}