@effect-uai/core 0.9.0 → 0.11.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 (196) hide show
  1. package/dist/{AiError-CrdR1EQi.d.mts → AiError-Bf1pq4BB.d.mts} +8 -3
  2. package/dist/{AiError-CrdR1EQi.d.mts.map → AiError-Bf1pq4BB.d.mts.map} +1 -1
  3. package/dist/{Audio-DDSKCkSe.d.mts → Audio-CR7CSljJ.d.mts} +2 -2
  4. package/dist/{Audio-DDSKCkSe.d.mts.map → Audio-CR7CSljJ.d.mts.map} +1 -1
  5. package/dist/{Image-C_Zjpwhc.d.mts → Image-C4vuBmu0.d.mts} +12 -12
  6. package/dist/{Image-C_Zjpwhc.d.mts.map → Image-C4vuBmu0.d.mts.map} +1 -1
  7. package/dist/{Items-CgKD6Npw.d.mts → Items-BWNu6VGp.d.mts} +118 -92
  8. package/dist/Items-BWNu6VGp.d.mts.map +1 -0
  9. package/dist/{Loop-B5_cqumi.d.mts → Loop-D8nWpowc.d.mts} +2 -2
  10. package/dist/{Loop-B5_cqumi.d.mts.map → Loop-D8nWpowc.d.mts.map} +1 -1
  11. package/dist/{Media-DOLyaygI.d.mts → Media-D_CpcM1Z.d.mts} +1 -1
  12. package/dist/{Media-DOLyaygI.d.mts.map → Media-D_CpcM1Z.d.mts.map} +1 -1
  13. package/dist/{StructuredFormat-CMJFD3sn.d.mts → StructuredFormat-DHaUJBdd.d.mts} +1 -1
  14. package/dist/{StructuredFormat-CMJFD3sn.d.mts.map → StructuredFormat-DHaUJBdd.d.mts.map} +1 -1
  15. package/dist/{Tool-0XUIT2A2.d.mts → Tool-CXFHCQrT.d.mts} +101 -16
  16. package/dist/Tool-CXFHCQrT.d.mts.map +1 -0
  17. package/dist/{ToolEvent-DYrAUJGs.d.mts → ToolEvent-nVijCrvm.d.mts} +2 -2
  18. package/dist/ToolEvent-nVijCrvm.d.mts.map +1 -0
  19. package/dist/{ToolResult-BZd-cEWW.d.mts → ToolResult-CQqKkcDa.d.mts} +10 -4
  20. package/dist/ToolResult-CQqKkcDa.d.mts.map +1 -0
  21. package/dist/{Toolkit-BKC8b8Xo.d.mts → Toolkit-BYPwwu-j.d.mts} +65 -24
  22. package/dist/Toolkit-BYPwwu-j.d.mts.map +1 -0
  23. package/dist/browser/Browser.d.mts +190 -0
  24. package/dist/browser/Browser.d.mts.map +1 -0
  25. package/dist/browser/Browser.mjs +34 -0
  26. package/dist/browser/Browser.mjs.map +1 -0
  27. package/dist/browser/BrowserError.d.mts +141 -0
  28. package/dist/browser/BrowserError.d.mts.map +1 -0
  29. package/dist/browser/BrowserError.mjs +89 -0
  30. package/dist/browser/BrowserError.mjs.map +1 -0
  31. package/dist/browser/BrowserTool.d.mts +59 -0
  32. package/dist/browser/BrowserTool.d.mts.map +1 -0
  33. package/dist/browser/BrowserTool.mjs +86 -0
  34. package/dist/browser/BrowserTool.mjs.map +1 -0
  35. package/dist/{dist-DWgRbDN3.mjs → dist-C0m0QnUP.mjs} +71 -30
  36. package/dist/dist-C0m0QnUP.mjs.map +1 -0
  37. package/dist/{dist-B04dlFHg.mjs → dist-CcRV3-A5.mjs} +8 -8
  38. package/dist/{dist-B04dlFHg.mjs.map → dist-CcRV3-A5.mjs.map} +1 -1
  39. package/dist/domain/AiError.d.mts +2 -2
  40. package/dist/domain/AiError.mjs +22 -3
  41. package/dist/domain/AiError.mjs.map +1 -1
  42. package/dist/domain/Audio.d.mts +1 -1
  43. package/dist/domain/Citation.d.mts +60 -0
  44. package/dist/domain/Citation.d.mts.map +1 -0
  45. package/dist/domain/Citation.mjs +7 -0
  46. package/dist/domain/Citation.mjs.map +1 -0
  47. package/dist/domain/Image.d.mts +1 -1
  48. package/dist/domain/Items.d.mts +1 -1
  49. package/dist/domain/Items.mjs +13 -3
  50. package/dist/domain/Items.mjs.map +1 -1
  51. package/dist/domain/Media.d.mts +1 -1
  52. package/dist/domain/Music.d.mts +1 -1
  53. package/dist/domain/Research.d.mts +37 -0
  54. package/dist/domain/Research.d.mts.map +1 -0
  55. package/dist/domain/Research.mjs +7 -0
  56. package/dist/domain/Research.mjs.map +1 -0
  57. package/dist/domain/Turn.d.mts +92 -10
  58. package/dist/domain/Turn.d.mts.map +1 -1
  59. package/dist/domain/Turn.mjs +8 -1
  60. package/dist/domain/Turn.mjs.map +1 -1
  61. package/dist/domain/Turn.test.mjs +1 -1
  62. package/dist/embedding-model/Embedding.d.mts +1 -1
  63. package/dist/embedding-model/EmbeddingModel.d.mts +1 -1
  64. package/dist/embedding-model/EmbeddingModel.mjs +2 -2
  65. package/dist/embedding-model/EmbeddingModel.mjs.map +1 -1
  66. package/dist/embedding-model/EmbeddingModel.test.mjs +1 -1
  67. package/dist/index.d.mts +22 -13
  68. package/dist/index.mjs +18 -9
  69. package/dist/job/Job.d.mts +80 -0
  70. package/dist/job/Job.d.mts.map +1 -0
  71. package/dist/job/Job.mjs +49 -0
  72. package/dist/job/Job.mjs.map +1 -0
  73. package/dist/language-model/LanguageModel.d.mts +4 -4
  74. package/dist/language-model/LanguageModel.mjs +2 -2
  75. package/dist/language-model/LanguageModel.mjs.map +1 -1
  76. package/dist/language-model/LanguageModel.test.mjs +1 -1
  77. package/dist/loop/Loop.d.mts +1 -1
  78. package/dist/loop/Loop.test.mjs +1 -1
  79. package/dist/music-generator/MusicGenerator.d.mts +2 -2
  80. package/dist/music-generator/MusicGenerator.mjs +4 -4
  81. package/dist/music-generator/MusicGenerator.mjs.map +1 -1
  82. package/dist/music-generator/MusicGenerator.test.mjs +1 -1
  83. package/dist/observability/Metrics.d.mts +1 -1
  84. package/dist/observability/Metrics.test.mjs +2 -2
  85. package/dist/observability/Telemetry.test.mjs +2 -2
  86. package/dist/research/DeepResearch.d.mts +71 -0
  87. package/dist/research/DeepResearch.d.mts.map +1 -0
  88. package/dist/research/DeepResearch.mjs +61 -0
  89. package/dist/research/DeepResearch.mjs.map +1 -0
  90. package/dist/retry/Retry.d.mts +1 -1
  91. package/dist/retry/Retry.test.mjs +1 -1
  92. package/dist/sandbox/Sandbox.mjs +18 -18
  93. package/dist/sandbox/Sandbox.mjs.map +1 -1
  94. package/dist/speech-synthesizer/SpeechSynthesizer.d.mts +2 -2
  95. package/dist/speech-synthesizer/SpeechSynthesizer.mjs +8 -8
  96. package/dist/speech-synthesizer/SpeechSynthesizer.mjs.map +1 -1
  97. package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs +1 -1
  98. package/dist/streaming/JSONL.d.mts +3 -1
  99. package/dist/streaming/JSONL.d.mts.map +1 -1
  100. package/dist/streaming/JSONL.mjs +5 -11
  101. package/dist/streaming/JSONL.mjs.map +1 -1
  102. package/dist/streaming/JSONL.test.mjs +10 -1
  103. package/dist/streaming/JSONL.test.mjs.map +1 -1
  104. package/dist/streaming/SSE.d.mts +5 -3
  105. package/dist/streaming/SSE.d.mts.map +1 -1
  106. package/dist/streaming/SSE.mjs +28 -38
  107. package/dist/streaming/SSE.mjs.map +1 -1
  108. package/dist/streaming/SSE.test.mjs +54 -4
  109. package/dist/streaming/SSE.test.mjs.map +1 -1
  110. package/dist/structured-format/StructuredFormat.d.mts +1 -1
  111. package/dist/structured-format/StructuredFormat.test.mjs +1 -1
  112. package/dist/testing/MockMusicGenerator.d.mts +1 -1
  113. package/dist/testing/MockProvider.d.mts +1 -1
  114. package/dist/testing/MockSpeechSynthesizer.d.mts +1 -1
  115. package/dist/tool/Approval.d.mts +19 -7
  116. package/dist/tool/Approval.d.mts.map +1 -1
  117. package/dist/tool/Approval.mjs +18 -11
  118. package/dist/tool/Approval.mjs.map +1 -1
  119. package/dist/tool/Approval.test.mjs +47 -8
  120. package/dist/tool/Approval.test.mjs.map +1 -1
  121. package/dist/tool/HistoryCheck.d.mts +2 -2
  122. package/dist/tool/Tool.d.mts +2 -2
  123. package/dist/tool/Tool.mjs +112 -28
  124. package/dist/tool/Tool.mjs.map +1 -1
  125. package/dist/tool/Tool.test.mjs +127 -3
  126. package/dist/tool/Tool.test.mjs.map +1 -1
  127. package/dist/tool/ToolEvent.d.mts +1 -1
  128. package/dist/tool/ToolEvent.mjs +5 -0
  129. package/dist/tool/ToolEvent.mjs.map +1 -1
  130. package/dist/tool/ToolResult.d.mts +2 -2
  131. package/dist/tool/ToolResult.mjs +15 -6
  132. package/dist/tool/ToolResult.mjs.map +1 -1
  133. package/dist/tool/Toolkit.d.mts +2 -2
  134. package/dist/tool/Toolkit.mjs +62 -22
  135. package/dist/tool/Toolkit.mjs.map +1 -1
  136. package/dist/tool/Toolkit.test.mjs +207 -9
  137. package/dist/tool/Toolkit.test.mjs.map +1 -1
  138. package/dist/transcriber/Transcriber.d.mts +2 -2
  139. package/dist/transcriber/Transcriber.mjs +3 -3
  140. package/dist/transcriber/Transcriber.mjs.map +1 -1
  141. package/dist/transcriber/Transcriber.test.mjs +1 -1
  142. package/dist/web-read/WebRead.d.mts +44 -0
  143. package/dist/web-read/WebRead.d.mts.map +1 -0
  144. package/dist/web-read/WebRead.mjs +18 -0
  145. package/dist/web-read/WebRead.mjs.map +1 -0
  146. package/dist/web-read/WebReadTool.d.mts +57 -0
  147. package/dist/web-read/WebReadTool.d.mts.map +1 -0
  148. package/dist/web-read/WebReadTool.mjs +59 -0
  149. package/dist/web-read/WebReadTool.mjs.map +1 -0
  150. package/dist/web-search/WebSearch.d.mts +1 -1
  151. package/dist/web-search/WebSearch.mjs +1 -1
  152. package/dist/web-search/WebSearch.mjs.map +1 -1
  153. package/dist/web-search/WebSearchTool.d.mts +12 -6
  154. package/dist/web-search/WebSearchTool.d.mts.map +1 -1
  155. package/dist/web-search/WebSearchTool.mjs +10 -5
  156. package/dist/web-search/WebSearchTool.mjs.map +1 -1
  157. package/package.json +39 -3
  158. package/src/browser/Browser.ts +268 -0
  159. package/src/browser/BrowserError.ts +145 -0
  160. package/src/browser/BrowserTool.ts +161 -0
  161. package/src/domain/AiError.ts +27 -1
  162. package/src/domain/Citation.ts +64 -0
  163. package/src/domain/Items.ts +14 -4
  164. package/src/domain/Research.ts +42 -0
  165. package/src/domain/Turn.ts +26 -0
  166. package/src/embedding-model/EmbeddingModel.ts +2 -2
  167. package/src/index.ts +9 -0
  168. package/src/job/Job.ts +125 -0
  169. package/src/language-model/LanguageModel.ts +2 -2
  170. package/src/music-generator/MusicGenerator.ts +4 -4
  171. package/src/research/DeepResearch.ts +137 -0
  172. package/src/sandbox/Sandbox.ts +18 -18
  173. package/src/speech-synthesizer/SpeechSynthesizer.ts +8 -8
  174. package/src/streaming/JSONL.test.ts +19 -0
  175. package/src/streaming/JSONL.ts +6 -38
  176. package/src/streaming/SSE.test.ts +86 -3
  177. package/src/streaming/SSE.ts +36 -80
  178. package/src/tool/Approval.test.ts +55 -5
  179. package/src/tool/Approval.ts +72 -27
  180. package/src/tool/Tool.test.ts +151 -1
  181. package/src/tool/Tool.ts +263 -66
  182. package/src/tool/ToolEvent.ts +5 -0
  183. package/src/tool/ToolResult.ts +14 -8
  184. package/src/tool/Toolkit.test.ts +231 -2
  185. package/src/tool/Toolkit.ts +175 -62
  186. package/src/transcriber/Transcriber.ts +3 -3
  187. package/src/web-read/WebRead.ts +70 -0
  188. package/src/web-read/WebReadTool.ts +96 -0
  189. package/src/web-search/WebSearch.ts +1 -1
  190. package/src/web-search/WebSearchTool.ts +11 -5
  191. package/dist/Items-CgKD6Npw.d.mts.map +0 -1
  192. package/dist/Tool-0XUIT2A2.d.mts.map +0 -1
  193. package/dist/ToolEvent-DYrAUJGs.d.mts.map +0 -1
  194. package/dist/ToolResult-BZd-cEWW.d.mts.map +0 -1
  195. package/dist/Toolkit-BKC8b8Xo.d.mts.map +0 -1
  196. package/dist/dist-DWgRbDN3.mjs.map +0 -1
@@ -1,11 +1,20 @@
1
- import { fromEffectSchema, make, provider, signal, toDescriptors } from "./Tool.mjs";
2
- import { isOk } from "./ToolResult.mjs";
3
- import { isOutput } from "./ToolEvent.mjs";
4
- import { compose, fromArray, make as make$1, namespace, run, wrap } from "./Toolkit.mjs";
5
- import { a as describe, n as globalExpect, o as it, t as import_dist } from "../dist-B04dlFHg.mjs";
1
+ import { RateLimited, describe } from "../domain/AiError.mjs";
2
+ import { isFailure, isOk, toToolCallOutput } from "./ToolResult.mjs";
3
+ import { fail, fromEffectSchema, make, provider, signal, toDescriptors } from "./Tool.mjs";
4
+ import { isOutput, isProgress } from "./ToolEvent.mjs";
5
+ import { compose, describeFailures, fromArray, make as make$1, makeNamespaced, namespace, run, wrap } from "./Toolkit.mjs";
6
+ import { c as it, n as globalExpect, o as describe$1, t as import_dist } from "../dist-CcRV3-A5.mjs";
6
7
  import { Context, Effect, Layer, Schema, Stream, pipe } from "effect";
7
8
  //#region src/tool/Toolkit.test.ts
8
- describe("Tool.toDescriptors", () => {
9
+ const Empty = Schema.Struct({});
10
+ const toolCall = (name, id, args = "{}") => ({
11
+ type: "function_call",
12
+ call_id: id,
13
+ name,
14
+ arguments: args
15
+ });
16
+ const runToArray = (toolkit, calls, options) => run(toolkit, calls, options).pipe(Stream.runCollect, Effect.map((events) => Array.from(events)));
17
+ describe$1("Tool.toDescriptors", () => {
9
18
  const GetWeatherInput = Schema.Struct({ city: Schema.String });
10
19
  const getWeather = make({
11
20
  name: "get_weather",
@@ -43,7 +52,7 @@ describe("Tool.toDescriptors", () => {
43
52
  globalExpect(l).not.toHaveProperty("strict");
44
53
  });
45
54
  });
46
- describe("Toolkit.run - tools with R requirements", () => {
55
+ describe$1("Toolkit.run - tools with R requirements", () => {
47
56
  class WeatherApiKey extends Context.Service()("test/WeatherApiKey") {}
48
57
  class GeoApiKey extends Context.Service()("test/GeoApiKey") {}
49
58
  const Empty = Schema.Struct({});
@@ -132,7 +141,7 @@ describe("Toolkit.run - tools with R requirements", () => {
132
141
  (0, import_dist.expectTypeOf)(run(make$1(plain), [])).toEqualTypeOf();
133
142
  });
134
143
  });
135
- describe("Toolkit.make / compose / namespace - uniqueness", () => {
144
+ describe$1("Toolkit.make / compose / namespace - uniqueness", () => {
136
145
  const Empty = Schema.Struct({});
137
146
  const tool = (name) => make({
138
147
  name,
@@ -173,7 +182,51 @@ describe("Toolkit.make / compose / namespace - uniqueness", () => {
173
182
  })).toEqualTypeOf();
174
183
  });
175
184
  });
176
- describe("Toolkit.wrap - middleware", () => {
185
+ describe$1("Toolkit.namespace - typed toolkits", () => {
186
+ const Query = Schema.Struct({ q: Schema.String });
187
+ class Geo extends Context.Service()("test/Geo") {}
188
+ const search = make({
189
+ name: "search",
190
+ description: "",
191
+ inputSchema: fromEffectSchema(Query),
192
+ run: ({ q }) => Effect.gen(function* () {
193
+ const geo = yield* Geo;
194
+ if (q === "") return yield* Effect.fail("empty_query");
195
+ return yield* geo.lookup(q);
196
+ })
197
+ });
198
+ const kit = namespace("geo", make$1(search));
199
+ it("type: prefixes the name literal of a service-requiring tool", () => {
200
+ (0, import_dist.expectTypeOf)(kit.geo__search.name).toEqualTypeOf();
201
+ });
202
+ it("type: preserves E and R through namespace", () => {
203
+ (0, import_dist.expectTypeOf)().toEqualTypeOf();
204
+ (0, import_dist.expectTypeOf)().toEqualTypeOf();
205
+ });
206
+ it("type: preserves E and R through makeNamespaced", () => {
207
+ (0, import_dist.expectTypeOf)(makeNamespaced("geo", search).geo__search.name).toEqualTypeOf();
208
+ (0, import_dist.expectTypeOf)().toEqualTypeOf();
209
+ (0, import_dist.expectTypeOf)().toEqualTypeOf();
210
+ });
211
+ it("type: Toolkit.run surfaces the namespaced tool's R (string E is absorbed)", () => {
212
+ (0, import_dist.expectTypeOf)(run(kit, [])).toEqualTypeOf();
213
+ });
214
+ it("runtime: renames the tool and executes it under the prefixed name", async () => {
215
+ const outputs = (await Effect.runPromise(Stream.runCollect(run(kit, [{
216
+ type: "function_call",
217
+ call_id: "call_1",
218
+ name: "geo__search",
219
+ arguments: "{\"q\":\"lisbon\"}"
220
+ }])).pipe(Effect.provide(Layer.succeed(Geo, { lookup: (q) => Effect.succeed(`geo:${q}`) }))))).filter(isOutput).map((e) => e.result);
221
+ globalExpect(outputs).toHaveLength(1);
222
+ globalExpect(outputs[0]).toMatchObject({
223
+ _tag: "Ok",
224
+ tool: "geo__search",
225
+ value: "geo:lisbon"
226
+ });
227
+ });
228
+ });
229
+ describe$1("Toolkit.wrap - middleware", () => {
177
230
  const Empty = Schema.Struct({});
178
231
  class Audit extends Context.Service()("test/Audit") {}
179
232
  const getWeather = make({
@@ -213,6 +266,151 @@ describe("Toolkit.wrap - middleware", () => {
213
266
  globalExpect(s?._tag === "Failure" && s.kind).toBe("non_local_tool");
214
267
  });
215
268
  });
269
+ describe$1("Toolkit.run - executor outcomes", () => {
270
+ const plain = (name, out) => make({
271
+ name,
272
+ description: "",
273
+ inputSchema: fromEffectSchema(Empty),
274
+ run: () => Effect.succeed(out)
275
+ });
276
+ it("absorbs a bare string failure as a tool_failed result", async () => {
277
+ const t = make({
278
+ name: "t",
279
+ description: "",
280
+ inputSchema: fromEffectSchema(Empty),
281
+ run: () => Effect.fail("nope")
282
+ });
283
+ const result = (await Effect.runPromise(runToArray(make$1(t), [toolCall("t", "1")]))).filter(isOutput)[0]?.result;
284
+ globalExpect(result).toMatchObject({
285
+ _tag: "Failure",
286
+ kind: "tool_failed",
287
+ reason: "nope"
288
+ });
289
+ });
290
+ it("absorbs Tool.fail with a custom kind", async () => {
291
+ const t = make({
292
+ name: "t",
293
+ description: "",
294
+ inputSchema: fromEffectSchema(Empty),
295
+ run: () => fail("missing", { kind: "not_found" })
296
+ });
297
+ const result = (await Effect.runPromise(runToArray(make$1(t), [toolCall("t", "1")]))).filter(isOutput)[0]?.result;
298
+ globalExpect(result).toMatchObject({
299
+ _tag: "Failure",
300
+ kind: "not_found",
301
+ reason: "missing"
302
+ });
303
+ });
304
+ it("propagates a typed non-sentinel failure on the stream", async () => {
305
+ const t = make({
306
+ name: "t",
307
+ description: "",
308
+ inputSchema: fromEffectSchema(Empty),
309
+ run: () => Effect.fail(new RateLimited({
310
+ provider: "x",
311
+ raw: null
312
+ }))
313
+ });
314
+ globalExpect((await Effect.runPromiseExit(runToArray(make$1(t), [toolCall("t", "1")])))._tag).toBe("Failure");
315
+ });
316
+ it("dies on a defect instead of masking it as a result", async () => {
317
+ const t = make({
318
+ name: "t",
319
+ description: "",
320
+ inputSchema: fromEffectSchema(Empty),
321
+ run: () => Effect.die(/* @__PURE__ */ new Error("boom"))
322
+ });
323
+ globalExpect((await Effect.runPromiseExit(runToArray(make$1(t), [toolCall("t", "1")])))._tag).toBe("Failure");
324
+ });
325
+ it("streams progress events strictly before the terminal output", async () => {
326
+ const t = make({
327
+ name: "t",
328
+ description: "",
329
+ inputSchema: fromEffectSchema(Empty),
330
+ run: (_input, emit) => emit("a").pipe(Effect.andThen(emit("b")), Effect.andThen(Effect.succeed("done")))
331
+ });
332
+ const events = await Effect.runPromise(runToArray(make$1(t), [toolCall("t", "1")]));
333
+ globalExpect(events.map((e) => e._tag)).toEqual([
334
+ "Progress",
335
+ "Progress",
336
+ "Output"
337
+ ]);
338
+ globalExpect(events.filter(isProgress).map((p) => p.data)).toEqual(["a", "b"]);
339
+ });
340
+ it("reports input validation failures as a result carrying the issue detail", async () => {
341
+ const t = make({
342
+ name: "t",
343
+ description: "",
344
+ inputSchema: fromEffectSchema(Schema.Struct({ x: Schema.Number })),
345
+ run: () => Effect.succeed(1)
346
+ });
347
+ const result = (await Effect.runPromise(runToArray(make$1(t), [toolCall("t", "1", "{\"x\":\"nope\"}")]))).filter(isOutput)[0]?.result;
348
+ globalExpect(result).toMatchObject({
349
+ _tag: "Failure",
350
+ kind: "input_validation_error"
351
+ });
352
+ globalExpect(result !== void 0 && isFailure(result) && result.reason).toBeTruthy();
353
+ });
354
+ it("normalizes empty arguments to {} for a zero-arg tool", async () => {
355
+ const result = (await Effect.runPromise(runToArray(make$1(plain("t", "ok")), [toolCall("t", "1", "")]))).filter(isOutput)[0]?.result;
356
+ globalExpect(result).toMatchObject({
357
+ _tag: "Ok",
358
+ value: "ok"
359
+ });
360
+ });
361
+ it("reports unparseable arguments as input_validation_error", async () => {
362
+ const result = (await Effect.runPromise(runToArray(make$1(plain("t", "ok")), [toolCall("t", "1", "not json")]))).filter(isOutput)[0]?.result;
363
+ globalExpect(result).toMatchObject({
364
+ _tag: "Failure",
365
+ kind: "input_validation_error"
366
+ });
367
+ });
368
+ it("a call named constructor is unknown_tool, not non_local_tool", async () => {
369
+ const result = (await Effect.runPromise(runToArray(make$1(plain("t", "ok")), [toolCall("constructor", "1")]))).filter(isOutput)[0]?.result;
370
+ globalExpect(result).toMatchObject({
371
+ _tag: "Failure",
372
+ kind: "unknown_tool"
373
+ });
374
+ });
375
+ it("serializes an undefined output as \"null\" on the wire", async () => {
376
+ const t = make({
377
+ name: "t",
378
+ description: "",
379
+ inputSchema: fromEffectSchema(Empty),
380
+ run: () => Effect.void
381
+ });
382
+ const result = (await Effect.runPromise(runToArray(make$1(t), [toolCall("t", "1")]))).filter(isOutput)[0]?.result;
383
+ globalExpect(result !== void 0 && toToolCallOutput(result).output).toBe("null");
384
+ });
385
+ it("preserves call order with concurrency 1", async () => {
386
+ const kit = make$1(plain("a", "A"), plain("b", "B"));
387
+ globalExpect((await Effect.runPromise(runToArray(kit, [toolCall("a", "a1"), toolCall("b", "b1")], { concurrency: 1 }))).filter(isOutput).map((e) => e.result.call_id)).toEqual(["a1", "b1"]);
388
+ });
389
+ it("type: run of a describeFailures toolkit has no stream error", () => {
390
+ const kit = describeFailures(make$1(make({
391
+ name: "t",
392
+ description: "",
393
+ inputSchema: fromEffectSchema(Empty),
394
+ run: () => Effect.fail(new RateLimited({
395
+ provider: "x",
396
+ raw: null
397
+ }))
398
+ })), describe);
399
+ (0, import_dist.expectTypeOf)(run(kit, [])).toEqualTypeOf();
400
+ });
401
+ it("type: run of a typed toolkit propagates the tool's E", () => {
402
+ const t = make({
403
+ name: "t",
404
+ description: "",
405
+ inputSchema: fromEffectSchema(Empty),
406
+ run: () => Effect.fail(new RateLimited({
407
+ provider: "x",
408
+ raw: null
409
+ }))
410
+ });
411
+ (0, import_dist.expectTypeOf)(run(make$1(t), [])).toEqualTypeOf();
412
+ });
413
+ });
216
414
  //#endregion
217
415
  export {};
218
416
 
@@ -1 +1 @@
1
- {"version":3,"file":"Toolkit.test.mjs","names":["Tool.make","Tool.fromEffectSchema","Tool.toDescriptors","Toolkit.run","Toolkit.make","Tool.signal","Tool.provider","Toolkit.fromArray","Toolkit.compose","Toolkit.namespace","Toolkit.wrap"],"sources":["../../src/tool/Toolkit.test.ts"],"sourcesContent":["import { Context, Effect, Layer, pipe, Schema, Stream } from \"effect\"\nimport { describe, expect, expectTypeOf, it } from \"vitest\"\nimport type { ToolCall } from \"../domain/Items.js\"\nimport { isOutput } from \"./ToolEvent.js\"\nimport { isOk } from \"./ToolResult.js\"\nimport * as Tool from \"./Tool.js\"\nimport * as Toolkit from \"./Toolkit.js\"\n\ndescribe(\"Tool.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] = Tool.toDescriptors([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] = Tool.toDescriptors([strictTool, looseTool])\n expect(s?.strict).toBe(true)\n expect(l).not.toHaveProperty(\"strict\")\n })\n})\n\ndescribe(\"Toolkit.run - 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 `run` 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): ToolCall => ({\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.run(Toolkit.make(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.run(Toolkit.make(getWeather, getCoords), [\n call(\"get_weather\", \"c1\"),\n 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 && isOk(w) && w.value).toEqual({\n source: \"weather\",\n key: \"weather-123\",\n })\n expect(g !== undefined && isOk(g) && g.value).toEqual({\n source: \"geo\",\n key: \"geo-456\",\n })\n })\n\n it(\"reports non-local kinds as non_local_tool while local calls in the same turn still run\", async () => {\n const escalate = Tool.signal({\n name: \"escalate\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n })\n const localPlain = Tool.make({\n name: \"plain\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () => Effect.succeed({ ok: true }),\n })\n\n const events = await Effect.runPromise(\n Toolkit.run(Toolkit.make(localPlain, escalate), [\n call(\"escalate\", \"s1\"),\n call(\"plain\", \"p1\"),\n call(\"ghost\", \"g1\"),\n ]).pipe(Stream.runCollect),\n )\n const byCall = new Map(\n Array.from(events)\n .filter(isOutput)\n .map((e) => [e.result.call_id, e.result] as const),\n )\n\n // Signal tool: model-visible but no local executor.\n const s = byCall.get(\"s1\")\n expect(s?._tag === \"Failure\" && s.kind).toBe(\"non_local_tool\")\n // Unknown tool stays distinct from non-local.\n const g = byCall.get(\"g1\")\n expect(g?._tag === \"Failure\" && g.kind).toBe(\"unknown_tool\")\n // The local call still executed despite the non-local sibling.\n const p = byCall.get(\"p1\")\n expect(p !== undefined && isOk(p) && p.value).toEqual({ ok: true })\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.run(Toolkit.make(plain), [])\n expectTypeOf(stream).toEqualTypeOf<\n Stream.Stream<import(\"./ToolEvent.js\").ToolEvent, never, never>\n >()\n })\n})\n\ndescribe(\"Toolkit.make / compose / namespace - uniqueness\", () => {\n const Empty = Schema.Struct({})\n const tool = (name: string) =>\n Tool.make({\n name,\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () => Effect.succeed(0),\n })\n\n it(\"rejects a duplicate literal name at compile time\", () => {\n const a = tool(\"search\")\n const b = Tool.provider({\n name: \"search\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n provider: \"demo\",\n config: {},\n })\n // @ts-expect-error Duplicate tool name: search\n Toolkit.make(a, b)\n })\n\n it(\"fails compose with DuplicateToolName naming the colliding sources (dynamic)\", async () => {\n const github = Toolkit.fromArray([tool(\"search\")])\n const linear = Toolkit.fromArray([tool(\"search\")])\n const exit = await Effect.runPromiseExit(Toolkit.compose(github, linear))\n expect(exit._tag).toBe(\"Failure\")\n if (exit._tag === \"Failure\") {\n const json = JSON.stringify(exit.cause)\n expect(json).toContain(\"DuplicateToolName\")\n expect(json).toContain(\"toolkit-0\")\n expect(json).toContain(\"toolkit-1\")\n }\n })\n\n it(\"namespaces names so generic names from two sources compose cleanly\", async () => {\n const github = Toolkit.namespace(\"github\", Toolkit.fromArray([tool(\"search\")]))\n const linear = Toolkit.namespace(\"linear\", Toolkit.fromArray([tool(\"search\")]))\n const composed = await Effect.runPromise(Toolkit.compose(github, linear))\n expect(Object.keys(composed).sort()).toEqual([\"github__search\", \"linear__search\"])\n })\n\n it(\"preserves each tool's R through compose\", () => {\n const stream = Effect.gen(function* () {\n const composed = yield* Toolkit.compose(Toolkit.make(tool(\"a\")), Toolkit.make(tool(\"b\")))\n return Toolkit.run(composed, [])\n })\n // No service-needing tools here -> R stays never (compose didn't poison it).\n expectTypeOf(stream).toEqualTypeOf<\n Effect.Effect<\n Stream.Stream<import(\"./ToolEvent.js\").ToolEvent, never, never>,\n Toolkit.DuplicateToolName\n >\n >()\n })\n})\n\ndescribe(\"Toolkit.wrap - middleware\", () => {\n const Empty = Schema.Struct({})\n type AuditShape = { readonly record: (name: string) => Effect.Effect<void> }\n class Audit extends Context.Service<Audit, AuditShape>()(\"test/Audit\") {}\n\n const getWeather = Tool.make({\n name: \"get_weather\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () => Effect.succeed({ tempC: 18 }),\n })\n const escalate = Tool.signal({\n name: \"escalate\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n })\n\n // A middleware that needs the Audit service -> R2 = Audit.\n const audited: Toolkit.Middleware<Audit> = (run, name) => (input, emit) =>\n Effect.gen(function* () {\n const a = yield* Audit\n yield* a.record(name)\n return yield* run(input, emit)\n })\n\n const call = (name: string, id: string): ToolCall => ({\n type: \"function_call\",\n call_id: id,\n name,\n arguments: \"{}\",\n })\n\n it(\"unions the middleware's R2 into the toolkit's requirements\", () => {\n const wrapped = Toolkit.wrap(Toolkit.make(getWeather), audited)\n const stream = Toolkit.run(wrapped, [])\n expectTypeOf(stream).toEqualTypeOf<\n Stream.Stream<import(\"./ToolEvent.js\").ToolEvent, never, Audit>\n >()\n })\n\n it(\"runs the wrapped handler and leaves non-local kinds untouched\", async () => {\n const recorded: Array<string> = []\n const wrapped = pipe(Toolkit.make(getWeather, escalate), Toolkit.wrap(audited))\n\n const events = await Effect.runPromise(\n Toolkit.run(wrapped, [call(\"get_weather\", \"w1\"), call(\"escalate\", \"s1\")]).pipe(\n Stream.runCollect,\n Effect.provideService(Audit, { record: (n) => Effect.sync(() => void recorded.push(n)) }),\n ),\n )\n const byCall = new Map(\n Array.from(events)\n .filter(isOutput)\n .map((e) => [e.result.call_id, e.result] as const),\n )\n\n // Local tool ran through the middleware (audit fired).\n expect(recorded).toEqual([\"get_weather\"])\n const w = byCall.get(\"w1\")\n expect(w !== undefined && isOk(w) && w.value).toEqual({ tempC: 18 })\n // Signal kind is left alone by wrap -> still reported non-local.\n const s = byCall.get(\"s1\")\n expect(s?._tag === \"Failure\" && s.kind).toBe(\"non_local_tool\")\n })\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"Toolkit.test.mjs","names":["Toolkit.run","describe","Tool.make","Tool.fromEffectSchema","Tool.toDescriptors","Toolkit.make","Tool.signal","Tool.provider","Toolkit.fromArray","Toolkit.compose","Toolkit.namespace","Toolkit.makeNamespaced","Toolkit.wrap","Tool.fail","AiError.RateLimited","Toolkit.describeFailures","AiError.describe"],"sources":["../../src/tool/Toolkit.test.ts"],"sourcesContent":["import { Context, Effect, Layer, pipe, Schema, Stream } from \"effect\"\nimport { describe, expect, expectTypeOf, it } from \"vitest\"\nimport * as AiError from \"../domain/AiError.js\"\nimport type { ToolCall } from \"../domain/Items.js\"\nimport { type ToolEvent, isOutput, isProgress } from \"./ToolEvent.js\"\nimport { isFailure, isOk, toToolCallOutput } from \"./ToolResult.js\"\nimport * as Tool from \"./Tool.js\"\nimport * as Toolkit from \"./Toolkit.js\"\n\nconst Empty = Schema.Struct({})\nconst toolCall = (name: string, id: string, args = \"{}\"): ToolCall => ({\n type: \"function_call\",\n call_id: id,\n name,\n arguments: args,\n})\nconst runToArray = <T extends Toolkit.Toolkit>(\n toolkit: T,\n calls: ReadonlyArray<ToolCall>,\n options?: Toolkit.ExecuteOptions,\n) =>\n Toolkit.run(toolkit, calls, options).pipe(\n Stream.runCollect,\n Effect.map((events): ReadonlyArray<ToolEvent> => Array.from(events)),\n )\n\ndescribe(\"Tool.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] = Tool.toDescriptors([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] = Tool.toDescriptors([strictTool, looseTool])\n expect(s?.strict).toBe(true)\n expect(l).not.toHaveProperty(\"strict\")\n })\n})\n\ndescribe(\"Toolkit.run - 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 `run` 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): ToolCall => ({\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.run(Toolkit.make(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.run(Toolkit.make(getWeather, getCoords), [\n call(\"get_weather\", \"c1\"),\n 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 && isOk(w) && w.value).toEqual({\n source: \"weather\",\n key: \"weather-123\",\n })\n expect(g !== undefined && isOk(g) && g.value).toEqual({\n source: \"geo\",\n key: \"geo-456\",\n })\n })\n\n it(\"reports non-local kinds as non_local_tool while local calls in the same turn still run\", async () => {\n const escalate = Tool.signal({\n name: \"escalate\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n })\n const localPlain = Tool.make({\n name: \"plain\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () => Effect.succeed({ ok: true }),\n })\n\n const events = await Effect.runPromise(\n Toolkit.run(Toolkit.make(localPlain, escalate), [\n call(\"escalate\", \"s1\"),\n call(\"plain\", \"p1\"),\n call(\"ghost\", \"g1\"),\n ]).pipe(Stream.runCollect),\n )\n const byCall = new Map(\n Array.from(events)\n .filter(isOutput)\n .map((e) => [e.result.call_id, e.result] as const),\n )\n\n // Signal tool: model-visible but no local executor.\n const s = byCall.get(\"s1\")\n expect(s?._tag === \"Failure\" && s.kind).toBe(\"non_local_tool\")\n // Unknown tool stays distinct from non-local.\n const g = byCall.get(\"g1\")\n expect(g?._tag === \"Failure\" && g.kind).toBe(\"unknown_tool\")\n // The local call still executed despite the non-local sibling.\n const p = byCall.get(\"p1\")\n expect(p !== undefined && isOk(p) && p.value).toEqual({ ok: true })\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.run(Toolkit.make(plain), [])\n expectTypeOf(stream).toEqualTypeOf<\n Stream.Stream<import(\"./ToolEvent.js\").ToolEvent, never, never>\n >()\n })\n})\n\ndescribe(\"Toolkit.make / compose / namespace - uniqueness\", () => {\n const Empty = Schema.Struct({})\n const tool = (name: string) =>\n Tool.make({\n name,\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () => Effect.succeed(0),\n })\n\n it(\"rejects a duplicate literal name at compile time\", () => {\n const a = tool(\"search\")\n const b = Tool.provider({\n name: \"search\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n provider: \"demo\",\n config: {},\n })\n // @ts-expect-error Duplicate tool name: search\n Toolkit.make(a, b)\n })\n\n it(\"fails compose with DuplicateToolName naming the colliding sources (dynamic)\", async () => {\n const github = Toolkit.fromArray([tool(\"search\")])\n const linear = Toolkit.fromArray([tool(\"search\")])\n const exit = await Effect.runPromiseExit(Toolkit.compose(github, linear))\n expect(exit._tag).toBe(\"Failure\")\n if (exit._tag === \"Failure\") {\n const json = JSON.stringify(exit.cause)\n expect(json).toContain(\"DuplicateToolName\")\n expect(json).toContain(\"toolkit-0\")\n expect(json).toContain(\"toolkit-1\")\n }\n })\n\n it(\"namespaces names so generic names from two sources compose cleanly\", async () => {\n const github = Toolkit.namespace(\"github\", Toolkit.fromArray([tool(\"search\")]))\n const linear = Toolkit.namespace(\"linear\", Toolkit.fromArray([tool(\"search\")]))\n const composed = await Effect.runPromise(Toolkit.compose(github, linear))\n expect(Object.keys(composed).sort()).toEqual([\"github__search\", \"linear__search\"])\n })\n\n it(\"preserves each tool's R through compose\", () => {\n const stream = Effect.gen(function* () {\n const composed = yield* Toolkit.compose(Toolkit.make(tool(\"a\")), Toolkit.make(tool(\"b\")))\n return Toolkit.run(composed, [])\n })\n // No service-needing tools here -> R stays never (compose didn't poison it).\n expectTypeOf(stream).toEqualTypeOf<\n Effect.Effect<\n Stream.Stream<import(\"./ToolEvent.js\").ToolEvent, never, never>,\n Toolkit.DuplicateToolName\n >\n >()\n })\n})\n\ndescribe(\"Toolkit.namespace - typed toolkits\", () => {\n const Query = Schema.Struct({ q: Schema.String })\n type GeoShape = { readonly lookup: (q: string) => Effect.Effect<string> }\n class Geo extends Context.Service<Geo, GeoShape>()(\"test/Geo\") {}\n\n const search = Tool.make({\n name: \"search\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Query),\n run: ({ q }) =>\n Effect.gen(function* () {\n const geo = yield* Geo\n if (q === \"\") return yield* Effect.fail(\"empty_query\" as const)\n return yield* geo.lookup(q)\n }),\n })\n\n const kit = Toolkit.namespace(\"geo\", Toolkit.make(search))\n\n it(\"type: prefixes the name literal of a service-requiring tool\", () => {\n expectTypeOf(kit.geo__search.name).toEqualTypeOf<\"geo__search\">()\n })\n\n it(\"type: preserves E and R through namespace\", () => {\n expectTypeOf<Toolkit.ToolkitE<typeof kit>>().toEqualTypeOf<\"empty_query\">()\n expectTypeOf<Toolkit.ToolkitR<typeof kit>>().toEqualTypeOf<Geo>()\n })\n\n it(\"type: preserves E and R through makeNamespaced\", () => {\n const namespaced = Toolkit.makeNamespaced(\"geo\", search)\n expectTypeOf(namespaced.geo__search.name).toEqualTypeOf<\"geo__search\">()\n expectTypeOf<Toolkit.ToolkitE<typeof namespaced>>().toEqualTypeOf<\"empty_query\">()\n expectTypeOf<Toolkit.ToolkitR<typeof namespaced>>().toEqualTypeOf<Geo>()\n })\n\n it(\"type: Toolkit.run surfaces the namespaced tool's R (string E is absorbed)\", () => {\n const stream = Toolkit.run(kit, [])\n expectTypeOf(stream).toEqualTypeOf<\n Stream.Stream<import(\"./ToolEvent.js\").ToolEvent, never, Geo>\n >()\n })\n\n it(\"runtime: renames the tool and executes it under the prefixed name\", async () => {\n const call: ToolCall = {\n type: \"function_call\",\n call_id: \"call_1\",\n name: \"geo__search\",\n arguments: '{\"q\":\"lisbon\"}',\n }\n const events = await Effect.runPromise(\n Stream.runCollect(Toolkit.run(kit, [call])).pipe(\n Effect.provide(Layer.succeed(Geo, { lookup: (q) => Effect.succeed(`geo:${q}`) })),\n ),\n )\n const outputs = events.filter(isOutput).map((e) => e.result)\n expect(outputs).toHaveLength(1)\n expect(outputs[0]).toMatchObject({ _tag: \"Ok\", tool: \"geo__search\", value: \"geo:lisbon\" })\n })\n})\n\ndescribe(\"Toolkit.wrap - middleware\", () => {\n const Empty = Schema.Struct({})\n type AuditShape = { readonly record: (name: string) => Effect.Effect<void> }\n class Audit extends Context.Service<Audit, AuditShape>()(\"test/Audit\") {}\n\n const getWeather = Tool.make({\n name: \"get_weather\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () => Effect.succeed({ tempC: 18 }),\n })\n const escalate = Tool.signal({\n name: \"escalate\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n })\n\n // A middleware that needs the Audit service -> R2 = Audit.\n const audited: Toolkit.Middleware<Audit> = (run, name) => (input, emit) =>\n Effect.gen(function* () {\n const a = yield* Audit\n yield* a.record(name)\n return yield* run(input, emit)\n })\n\n const call = (name: string, id: string): ToolCall => ({\n type: \"function_call\",\n call_id: id,\n name,\n arguments: \"{}\",\n })\n\n it(\"unions the middleware's R2 into the toolkit's requirements\", () => {\n const wrapped = Toolkit.wrap(Toolkit.make(getWeather), audited)\n const stream = Toolkit.run(wrapped, [])\n expectTypeOf(stream).toEqualTypeOf<\n Stream.Stream<import(\"./ToolEvent.js\").ToolEvent, never, Audit>\n >()\n })\n\n it(\"runs the wrapped handler and leaves non-local kinds untouched\", async () => {\n const recorded: Array<string> = []\n const wrapped = pipe(Toolkit.make(getWeather, escalate), Toolkit.wrap(audited))\n\n const events = await Effect.runPromise(\n Toolkit.run(wrapped, [call(\"get_weather\", \"w1\"), call(\"escalate\", \"s1\")]).pipe(\n Stream.runCollect,\n Effect.provideService(Audit, { record: (n) => Effect.sync(() => void recorded.push(n)) }),\n ),\n )\n const byCall = new Map(\n Array.from(events)\n .filter(isOutput)\n .map((e) => [e.result.call_id, e.result] as const),\n )\n\n // Local tool ran through the middleware (audit fired).\n expect(recorded).toEqual([\"get_weather\"])\n const w = byCall.get(\"w1\")\n expect(w !== undefined && isOk(w) && w.value).toEqual({ tempC: 18 })\n // Signal kind is left alone by wrap -> still reported non-local.\n const s = byCall.get(\"s1\")\n expect(s?._tag === \"Failure\" && s.kind).toBe(\"non_local_tool\")\n })\n})\n\ndescribe(\"Toolkit.run - executor outcomes\", () => {\n const plain = <N extends string>(name: N, out: unknown) =>\n Tool.make({\n name,\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () => Effect.succeed(out),\n })\n\n it(\"absorbs a bare string failure as a tool_failed result\", async () => {\n const t = Tool.make({\n name: \"t\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () => Effect.fail(\"nope\"),\n })\n const events = await Effect.runPromise(runToArray(Toolkit.make(t), [toolCall(\"t\", \"1\")]))\n const result = events.filter(isOutput)[0]?.result\n expect(result).toMatchObject({ _tag: \"Failure\", kind: \"tool_failed\", reason: \"nope\" })\n })\n\n it(\"absorbs Tool.fail with a custom kind\", async () => {\n const t = Tool.make({\n name: \"t\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () => Tool.fail(\"missing\", { kind: \"not_found\" }),\n })\n const events = await Effect.runPromise(runToArray(Toolkit.make(t), [toolCall(\"t\", \"1\")]))\n const result = events.filter(isOutput)[0]?.result\n expect(result).toMatchObject({ _tag: \"Failure\", kind: \"not_found\", reason: \"missing\" })\n })\n\n it(\"propagates a typed non-sentinel failure on the stream\", async () => {\n const t = Tool.make({\n name: \"t\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () => Effect.fail(new AiError.RateLimited({ provider: \"x\", raw: null })),\n })\n const exit = await Effect.runPromiseExit(runToArray(Toolkit.make(t), [toolCall(\"t\", \"1\")]))\n expect(exit._tag).toBe(\"Failure\")\n })\n\n it(\"dies on a defect instead of masking it as a result\", async () => {\n const t = Tool.make({\n name: \"t\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () => Effect.die(new Error(\"boom\")),\n })\n const exit = await Effect.runPromiseExit(runToArray(Toolkit.make(t), [toolCall(\"t\", \"1\")]))\n expect(exit._tag).toBe(\"Failure\")\n })\n\n it(\"streams progress events strictly before the terminal output\", async () => {\n const t = Tool.make({\n name: \"t\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: (_input, emit) =>\n emit(\"a\").pipe(Effect.andThen(emit(\"b\")), Effect.andThen(Effect.succeed(\"done\"))),\n })\n const events = await Effect.runPromise(runToArray(Toolkit.make(t), [toolCall(\"t\", \"1\")]))\n expect(events.map((e) => e._tag)).toEqual([\"Progress\", \"Progress\", \"Output\"])\n expect(events.filter(isProgress).map((p) => p.data)).toEqual([\"a\", \"b\"])\n })\n\n it(\"reports input validation failures as a result carrying the issue detail\", async () => {\n const t = Tool.make({\n name: \"t\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Schema.Struct({ x: Schema.Number })),\n run: () => Effect.succeed(1),\n })\n const events = await Effect.runPromise(\n runToArray(Toolkit.make(t), [toolCall(\"t\", \"1\", '{\"x\":\"nope\"}')]),\n )\n const result = events.filter(isOutput)[0]?.result\n expect(result).toMatchObject({ _tag: \"Failure\", kind: \"input_validation_error\" })\n expect(result !== undefined && isFailure(result) && result.reason).toBeTruthy()\n })\n\n it(\"normalizes empty arguments to {} for a zero-arg tool\", async () => {\n const events = await Effect.runPromise(\n runToArray(Toolkit.make(plain(\"t\", \"ok\")), [toolCall(\"t\", \"1\", \"\")]),\n )\n const result = events.filter(isOutput)[0]?.result\n expect(result).toMatchObject({ _tag: \"Ok\", value: \"ok\" })\n })\n\n it(\"reports unparseable arguments as input_validation_error\", async () => {\n const events = await Effect.runPromise(\n runToArray(Toolkit.make(plain(\"t\", \"ok\")), [toolCall(\"t\", \"1\", \"not json\")]),\n )\n const result = events.filter(isOutput)[0]?.result\n expect(result).toMatchObject({ _tag: \"Failure\", kind: \"input_validation_error\" })\n })\n\n it(\"a call named constructor is unknown_tool, not non_local_tool\", async () => {\n const events = await Effect.runPromise(\n runToArray(Toolkit.make(plain(\"t\", \"ok\")), [toolCall(\"constructor\", \"1\")]),\n )\n const result = events.filter(isOutput)[0]?.result\n expect(result).toMatchObject({ _tag: \"Failure\", kind: \"unknown_tool\" })\n })\n\n it('serializes an undefined output as \"null\" on the wire', async () => {\n const t = Tool.make({\n name: \"t\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () => Effect.void,\n })\n const events = await Effect.runPromise(runToArray(Toolkit.make(t), [toolCall(\"t\", \"1\")]))\n const result = events.filter(isOutput)[0]?.result\n expect(result !== undefined && toToolCallOutput(result).output).toBe(\"null\")\n })\n\n it(\"preserves call order with concurrency 1\", async () => {\n const kit = Toolkit.make(plain(\"a\", \"A\"), plain(\"b\", \"B\"))\n const events = await Effect.runPromise(\n runToArray(kit, [toolCall(\"a\", \"a1\"), toolCall(\"b\", \"b1\")], { concurrency: 1 }),\n )\n expect(events.filter(isOutput).map((e) => e.result.call_id)).toEqual([\"a1\", \"b1\"])\n })\n\n it(\"type: run of a describeFailures toolkit has no stream error\", () => {\n const t = Tool.make({\n name: \"t\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () => Effect.fail(new AiError.RateLimited({ provider: \"x\", raw: null })),\n })\n const kit = Toolkit.describeFailures(Toolkit.make(t), AiError.describe)\n const stream = Toolkit.run(kit, [])\n expectTypeOf(stream).toEqualTypeOf<Stream.Stream<ToolEvent, never, never>>()\n })\n\n it(\"type: run of a typed toolkit propagates the tool's E\", () => {\n const t = Tool.make({\n name: \"t\",\n description: \"\",\n inputSchema: Tool.fromEffectSchema(Empty),\n run: () => Effect.fail(new AiError.RateLimited({ provider: \"x\", raw: null })),\n })\n const stream = Toolkit.run(Toolkit.make(t), [])\n expectTypeOf(stream).toEqualTypeOf<Stream.Stream<ToolEvent, AiError.RateLimited, never>>()\n })\n})\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { t as AiError } from "../AiError-CrdR1EQi.mjs";
2
- import { a as AudioSource, r as AudioFormat } from "../Audio-DDSKCkSe.mjs";
1
+ import { t as AiError } from "../AiError-Bf1pq4BB.mjs";
2
+ import { a as AudioSource, r as AudioFormat } from "../Audio-CR7CSljJ.mjs";
3
3
  import { TranscriptEvent, TranscriptResult } from "../domain/Transcript.mjs";
4
4
  import { Context, Effect, Stream } from "effect";
5
5
 
@@ -20,7 +20,7 @@ var Transcriber = class extends Context.Service()("@betalyra/effect-uai/Transcri
20
20
  */
21
21
  var SttStreaming = class extends Context.Service()("@betalyra/effect-uai/capability/SttStreaming") {};
22
22
  /** One-shot transcription. */
23
- const transcribe = (request) => Effect.flatMap(Transcriber.asEffect(), (t) => t.transcribe(request));
23
+ const transcribe = (request) => Effect.flatMap(Transcriber, (t) => t.transcribe(request));
24
24
  /**
25
25
  * Live transcription. Dual-arity: pipeable (data-last) and direct
26
26
  * (data-first). Requires `SttStreaming` in R — providers without
@@ -39,8 +39,8 @@ const transcribe = (request) => Effect.flatMap(Transcriber.asEffect(), (t) => t.
39
39
  * ```
40
40
  */
41
41
  const streamTranscriptionFrom = Function.dual(2, (audioIn, request) => Stream.unwrap(Effect.gen(function* () {
42
- const t = yield* Transcriber.asEffect();
43
- yield* SttStreaming.asEffect();
42
+ const t = yield* Transcriber;
43
+ yield* SttStreaming;
44
44
  return t.streamTranscriptionFrom(audioIn, request);
45
45
  })));
46
46
  //#endregion
@@ -1 +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 /** Free-form context / style hint (Whisper-style prose). OpenAI honors\n * it; providers without a prompt field `warnDropped`. */\n readonly prompt?: string\n /** Vocabulary biasing — discrete terms to boost (names, jargon). Maps to\n * Deepgram `keyterm`, ElevenLabs `keyterms`, Google `adaptation`,\n * Inworld `prompts`; others `warnDropped`. */\n readonly biasingTerms?: 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 * formats they can't ingest at stream startup with\n * `AiError.Unsupported` (a per-Layer capability gap, not a wire-shape\n * mismatch).\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":";;;;;;;;;AAoEA,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"}
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 /** Free-form context / style hint (Whisper-style prose). OpenAI honors\n * it; providers without a prompt field `warnDropped`. */\n readonly prompt?: string\n /** Vocabulary biasing — discrete terms to boost (names, jargon). Maps to\n * Deepgram `keyterm`, ElevenLabs `keyterms`, Google `adaptation`,\n * Inworld `prompts`; others `warnDropped`. */\n readonly biasingTerms?: 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 * formats they can't ingest at stream startup with\n * `AiError.Unsupported` (a per-Layer capability gap, not a wire-shape\n * mismatch).\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, (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\n yield* SttStreaming\n return t.streamTranscriptionFrom(audioIn, request)\n }),\n ),\n)\n"],"mappings":";;;;;;;;;AAoEA,IAAa,cAAb,cAAiC,QAAQ,SAA0C,CACjF,mCACD,CAAC;;;;;;;;;;;AAYF,IAAa,eAAb,cAAkC,QAAQ,SAA6B,CACrE,+CACD,CAAC;;AAGF,MAAa,cACX,YAEA,OAAO,QAAQ,cAAc,MAAM,EAAE,WAAW,QAAQ,CAAC;;;;;;;;;;;;;;;;;;AAmB3D,MAAa,0BAUT,SAAS,KACX,IACO,SAA0C,YAC/C,OAAO,OACL,OAAO,IAAI,aAAa;CACtB,MAAM,IAAI,OAAO;AACjB,QAAO;AACP,QAAO,EAAE,wBAAwB,SAAS,QAAQ;EAClD,CACH,CACJ"}
@@ -1,5 +1,5 @@
1
1
  import { streamTranscriptionFrom, transcribe } from "./Transcriber.mjs";
2
- import { a as describe, n as globalExpect, o as it, t as import_dist } from "../dist-B04dlFHg.mjs";
2
+ import { c as it, n as globalExpect, o as describe, t as import_dist } from "../dist-CcRV3-A5.mjs";
3
3
  import { layer, layerSyncOnly } from "../testing/MockTranscriber.mjs";
4
4
  import { Duration, Effect, Stream } from "effect";
5
5
  //#region src/transcriber/Transcriber.test.ts
@@ -0,0 +1,44 @@
1
+ import { t as AiError } from "../AiError-Bf1pq4BB.mjs";
2
+ import { Context, Duration, Effect } from "effect";
3
+
4
+ //#region src/web-read/WebRead.d.ts
5
+ declare namespace WebRead_d_exports {
6
+ export { CommonReadRequest, ReadFormat, ReadResponse, WebRead, WebReadService, read };
7
+ }
8
+ /** Representation to return for a page. `markdown` is the default. */
9
+ type ReadFormat = "markdown" | "html";
10
+ /**
11
+ * Cross-provider read request: one URL in, clean content out. Provider-specific
12
+ * knobs live on the provider-typed request.
13
+ */
14
+ type CommonReadRequest = {
15
+ /** The page to read. */readonly url: string; /** Output representation. Defaults to `markdown`. See {@link ReadFormat}. */
16
+ readonly format?: ReadFormat; /** Upper bound on time spent fetching the page. */
17
+ readonly timeout?: Duration.Duration;
18
+ };
19
+ /** One normalized read result. */
20
+ type ReadResponse = {
21
+ /** The URL that was read. */readonly url: string; /** Extracted content in the requested {@link ReadFormat}. */
22
+ readonly content: string; /** Page title, when reported. */
23
+ readonly title?: string; /** Links discovered on the page, when returned. */
24
+ readonly links?: ReadonlyArray<string>; /** The provider-native response. */
25
+ readonly raw: unknown;
26
+ };
27
+ /**
28
+ * The portable read surface: one operation, `read`. Every implementor can
29
+ * answer, so this capability needs no marker tags.
30
+ */
31
+ type WebReadService = {
32
+ readonly read: (request: CommonReadRequest) => Effect.Effect<ReadResponse, AiError>;
33
+ };
34
+ declare const WebRead_base: Context.ServiceClass<WebRead, "@betalyra/effect-uai/WebRead", WebReadService>;
35
+ /**
36
+ * Generic read service tag. Yield this for provider-portable code; yield a
37
+ * provider tag for provider-specific knobs. A provider `layer` registers both.
38
+ */
39
+ declare class WebRead extends WebRead_base {}
40
+ /** Read one URL against whichever provider Layer is in scope. */
41
+ declare const read: (request: CommonReadRequest) => Effect.Effect<ReadResponse, AiError, WebRead>;
42
+ //#endregion
43
+ export { CommonReadRequest, ReadFormat, ReadResponse, WebRead, WebReadService, read, WebRead_d_exports as t };
44
+ //# sourceMappingURL=WebRead.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebRead.d.mts","names":[],"sources":["../../src/web-read/WebRead.ts"],"mappings":";;;;;;;;KAQY,UAAA;;;;;KAUA,iBAAA;mCAED,GAAA;WAEA,MAAA,GAAS,UAAA,EAdR;EAAA,SAgBD,OAAA,GAAU,QAAA,CAAS,QAAA;AAAA;;KAQlB,YAAA;EAdA,sCAgBD,GAAA;WAEA,OAAA,UAhBA;EAAA,SAkBA,KAAA,WAhBS;EAAA,SAkBT,KAAA,GAAQ,aAAA,UAhBE;EAAA,SAkBV,GAAA;AAAA;;AAVX;;;KAqBY,cAAA;EAAA,SACD,IAAA,GAAO,OAAA,EAAS,iBAAA,KAAsB,MAAA,CAAO,MAAA,CAAO,YAAA,EAAc,OAAA;AAAA;AAAA,cAC5E,YAAA;;;;;cAMY,OAAA,SAAgB,YAAA;;cAKhB,IAAA,GACX,OAAA,EAAS,iBAAA,KACR,MAAA,CAAO,MAAA,CAAO,YAAA,EAAc,OAAA,EAAiB,OAAA"}
@@ -0,0 +1,18 @@
1
+ import { n as __exportAll } from "../chunk-uyGKjUfl.mjs";
2
+ import { Context, Effect } from "effect";
3
+ //#region src/web-read/WebRead.ts
4
+ var WebRead_exports = /* @__PURE__ */ __exportAll({
5
+ WebRead: () => WebRead,
6
+ read: () => read
7
+ });
8
+ /**
9
+ * Generic read service tag. Yield this for provider-portable code; yield a
10
+ * provider tag for provider-specific knobs. A provider `layer` registers both.
11
+ */
12
+ var WebRead = class extends Context.Service()("@betalyra/effect-uai/WebRead") {};
13
+ /** Read one URL against whichever provider Layer is in scope. */
14
+ const read = (request) => Effect.flatMap(WebRead, (s) => s.read(request));
15
+ //#endregion
16
+ export { WebRead, read, WebRead_exports as t };
17
+
18
+ //# sourceMappingURL=WebRead.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebRead.mjs","names":[],"sources":["../../src/web-read/WebRead.ts"],"sourcesContent":["import { Context, type Duration, Effect } from \"effect\"\nimport type * as AiError from \"../domain/AiError.js\"\n\n// ---------------------------------------------------------------------------\n// Format\n// ---------------------------------------------------------------------------\n\n/** Representation to return for a page. `markdown` is the default. */\nexport type ReadFormat = \"markdown\" | \"html\"\n\n// ---------------------------------------------------------------------------\n// Request\n// ---------------------------------------------------------------------------\n\n/**\n * Cross-provider read request: one URL in, clean content out. Provider-specific\n * knobs live on the provider-typed request.\n */\nexport type CommonReadRequest = {\n /** The page to read. */\n readonly url: string\n /** Output representation. Defaults to `markdown`. See {@link ReadFormat}. */\n readonly format?: ReadFormat\n /** Upper bound on time spent fetching the page. */\n readonly timeout?: Duration.Duration\n}\n\n// ---------------------------------------------------------------------------\n// Response\n// ---------------------------------------------------------------------------\n\n/** One normalized read result. */\nexport type ReadResponse = {\n /** The URL that was read. */\n readonly url: string\n /** Extracted content in the requested {@link ReadFormat}. */\n readonly content: string\n /** Page title, when reported. */\n readonly title?: string\n /** Links discovered on the page, when returned. */\n readonly links?: ReadonlyArray<string>\n /** The provider-native response. */\n readonly raw: unknown\n}\n\n// ---------------------------------------------------------------------------\n// Service + helper\n// ---------------------------------------------------------------------------\n\n/**\n * The portable read surface: one operation, `read`. Every implementor can\n * answer, so this capability needs no marker tags.\n */\nexport type WebReadService = {\n readonly read: (request: CommonReadRequest) => Effect.Effect<ReadResponse, AiError.AiError>\n}\n\n/**\n * Generic read service tag. Yield this for provider-portable code; yield a\n * provider tag for provider-specific knobs. A provider `layer` registers both.\n */\nexport class WebRead extends Context.Service<WebRead, WebReadService>()(\n \"@betalyra/effect-uai/WebRead\",\n) {}\n\n/** Read one URL against whichever provider Layer is in scope. */\nexport const read = (\n request: CommonReadRequest,\n): Effect.Effect<ReadResponse, AiError.AiError, WebRead> =>\n Effect.flatMap(WebRead, (s) => s.read(request))\n"],"mappings":";;;;;;;;;;;AA6DA,IAAa,UAAb,cAA6B,QAAQ,SAAkC,CACrE,+BACD,CAAC;;AAGF,MAAa,QACX,YAEA,OAAO,QAAQ,UAAU,MAAM,EAAE,KAAK,QAAQ,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { l as Tool } from "../Tool-CXFHCQrT.mjs";
2
+ import { t as AiError } from "../AiError-Bf1pq4BB.mjs";
3
+ import { ReadFormat, ReadResponse, WebRead } from "./WebRead.mjs";
4
+ import { Schema } from "effect";
5
+
6
+ //#region src/web-read/WebReadTool.d.ts
7
+ declare namespace WebReadTool_d_exports {
8
+ export { WebReadToolArgs, WebReadToolOptions, webReadTool };
9
+ }
10
+ /**
11
+ * Model-facing argument schema. Deliberately narrow: the URL is the only
12
+ * thing that is genuinely the model's call. Output format and the content
13
+ * cost ceiling are app policy, pinned on the constructor instead, so they
14
+ * are guaranteed rather than left to the model to remember each call.
15
+ */
16
+ declare const WebReadToolArgs: Schema.Struct<{
17
+ readonly url: Schema.String;
18
+ }>;
19
+ type WebReadToolArgs = typeof WebReadToolArgs.Type;
20
+ type WebReadToolOptions = {
21
+ /** Tool name the model sees. Default `"web_read"`. */readonly name?: string;
22
+ /**
23
+ * App-fixed representation for every read - a policy choice, not a model
24
+ * knob. Default `"markdown"` (what models read best).
25
+ */
26
+ readonly format?: ReadFormat;
27
+ /**
28
+ * App-fixed ceiling on rendered content characters per call - a context
29
+ * cost guard, not exposed to the model. Default `20000`.
30
+ */
31
+ readonly maxChars?: number;
32
+ /**
33
+ * Override how a read response is rendered into the model-facing string.
34
+ * Default: `title / url` header plus the content, truncated at `maxChars`.
35
+ */
36
+ readonly render?: (response: ReadResponse) => string;
37
+ };
38
+ /**
39
+ * The canonical web-read tool. Its `R` is just `WebRead`, so providing any
40
+ * read-provider Layer satisfies it and the model-facing contract (name,
41
+ * description, schema) is identical no matter which backend answers - swap
42
+ * `FirecrawlRead.layer` for `JinaRead.layer` and the tool the model sees
43
+ * does not change. Drops straight into a `Toolkit` next to `webSearchTool`
44
+ * (search finds the URLs, read fetches the ones worth reading in full).
45
+ *
46
+ * `Output` is the rendered page; failures stay typed on the `AiError`
47
+ * channel. To let the model recover from a failed read, wrap the toolkit in
48
+ * `Toolkit.describeFailures(AiError.describe)`.
49
+ *
50
+ * This is a simple default implementation for quick use. For more elaborate
51
+ * cases (a different output contract, more model-facing knobs), build your
52
+ * own tool with `Tool.make` over the same `read` helper.
53
+ */
54
+ declare const webReadTool: (options?: WebReadToolOptions) => Tool<string, WebReadToolArgs, never, string, AiError, WebRead>;
55
+ //#endregion
56
+ export { WebReadToolArgs, WebReadToolOptions, WebReadTool_d_exports as t, webReadTool };
57
+ //# sourceMappingURL=WebReadTool.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebReadTool.d.mts","names":[],"sources":["../../src/web-read/WebReadTool.ts"],"mappings":";;;;;;;;;;;;;;;cAWM,eAAA,EAAe,MAAA,CAAA,MAAA;EAAA,cAInB,MAAA,CAAA,MAAA;AAAA;AAAA,KAEU,eAAA,UAAyB,eAAA,CAAgB,IAAA;AAAA,KAYzC,kBAAA;EAlBS,+DAoBV,IAAA;EApBU;;;;EAAA,SAyBV,MAAA,GAAS,UAAA;;AAnBpB;;;WAwBW,QAAA;EAxB8C;AAYzD;;;EAZyD,SA6B9C,MAAA,IAAU,QAAA,EAAU,YAAA;AAAA;;;;;;;;;AAmB/B;;;;;;;;cAAa,WAAA,GACX,OAAA,GAAU,kBAAA,KACT,IAAA,SAAkB,eAAA,iBAAgC,OAAA,EAAiB,OAAA"}