@effect-uai/core 0.12.0 → 0.12.1

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 (284) hide show
  1. package/dist/{AiError-Bf1pq4BB.d.mts → AiError-eLV9t1lU.d.mts} +12 -16
  2. package/dist/AiError-eLV9t1lU.d.mts.map +1 -0
  3. package/dist/{Audio-CR7CSljJ.d.mts → Audio-60lKKHxS.d.mts} +4 -5
  4. package/dist/Audio-60lKKHxS.d.mts.map +1 -0
  5. package/dist/{Image-C4vuBmu0.d.mts → Image-BK8-4H6s.d.mts} +12 -14
  6. package/dist/Image-BK8-4H6s.d.mts.map +1 -0
  7. package/dist/{Items-BKQgqJ8A.d.mts → Items-SfUabNuB.d.mts} +74 -76
  8. package/dist/Items-SfUabNuB.d.mts.map +1 -0
  9. package/dist/{Loop-D8nWpowc.d.mts → Loop-B54AB1ME.d.mts} +19 -21
  10. package/dist/Loop-B54AB1ME.d.mts.map +1 -0
  11. package/dist/{Media-D_CpcM1Z.d.mts → Media-DwgpifPD.d.mts} +1 -1
  12. package/dist/Media-DwgpifPD.d.mts.map +1 -0
  13. package/dist/{SandboxError-CIrVDOMV.d.mts → SandboxError-BN8b28Bh.d.mts} +11 -15
  14. package/dist/SandboxError-BN8b28Bh.d.mts.map +1 -0
  15. package/dist/{StructuredFormat-DHaUJBdd.d.mts → StructuredFormat-BlZhyOsi.d.mts} +3 -7
  16. package/dist/StructuredFormat-BlZhyOsi.d.mts.map +1 -0
  17. package/dist/{Tool-u5bag8SO.d.mts → Tool-DE-rnvkw.d.mts} +5 -8
  18. package/dist/Tool-DE-rnvkw.d.mts.map +1 -0
  19. package/dist/{ToolEvent-BBfOdhF_.d.mts → ToolEvent-D99MGQYH.d.mts} +56 -63
  20. package/dist/ToolEvent-D99MGQYH.d.mts.map +1 -0
  21. package/dist/{ToolResult-CRpmkBXR.d.mts → ToolResult-Cj8ChodL.d.mts} +49 -54
  22. package/dist/ToolResult-Cj8ChodL.d.mts.map +1 -0
  23. package/dist/{Toolkit-D4mQvhjq.d.mts → Toolkit-BEZrNPTI.d.mts} +13 -16
  24. package/dist/Toolkit-BEZrNPTI.d.mts.map +1 -0
  25. package/dist/browser/Browser.d.mts +11 -7
  26. package/dist/browser/Browser.d.mts.map +1 -1
  27. package/dist/browser/Browser.mjs +1 -1
  28. package/dist/browser/Browser.mjs.map +1 -1
  29. package/dist/browser/BrowserError.d.mts +9 -13
  30. package/dist/browser/BrowserError.d.mts.map +1 -1
  31. package/dist/browser/BrowserError.mjs +1 -1
  32. package/dist/browser/BrowserError.mjs.map +1 -1
  33. package/dist/browser/BrowserTool.d.mts +33 -36
  34. package/dist/browser/BrowserTool.d.mts.map +1 -1
  35. package/dist/browser/BrowserTool.mjs +1 -1
  36. package/dist/browser/BrowserTool.mjs.map +1 -1
  37. package/dist/capabilities/Capabilities.d.mts +8 -6
  38. package/dist/capabilities/Capabilities.d.mts.map +1 -1
  39. package/dist/capabilities/Capabilities.mjs +1 -1
  40. package/dist/capabilities/Capabilities.mjs.map +1 -1
  41. package/dist/dist-BaenoU1A.mjs +145 -0
  42. package/dist/dist-BaenoU1A.mjs.map +1 -0
  43. package/dist/{dist-C0m0QnUP.mjs → dist-nohcnkD6.mjs} +16 -15
  44. package/dist/dist-nohcnkD6.mjs.map +1 -0
  45. package/dist/domain/AiError.d.mts +1 -1
  46. package/dist/domain/AiError.mjs +1 -1
  47. package/dist/domain/AiError.mjs.map +1 -1
  48. package/dist/domain/Audio.d.mts +1 -1
  49. package/dist/domain/Audio.mjs +1 -1
  50. package/dist/domain/Citation.d.mts +0 -2
  51. package/dist/domain/Citation.d.mts.map +1 -1
  52. package/dist/domain/Citation.mjs +1 -1
  53. package/dist/domain/Image.d.mts +1 -1
  54. package/dist/domain/Image.mjs +1 -1
  55. package/dist/domain/Image.mjs.map +1 -1
  56. package/dist/domain/Items.d.mts +1 -1
  57. package/dist/domain/Items.mjs +1 -1
  58. package/dist/domain/Items.mjs.map +1 -1
  59. package/dist/domain/Media.d.mts +1 -1
  60. package/dist/domain/Media.mjs +1 -1
  61. package/dist/domain/Music.d.mts +18 -11
  62. package/dist/domain/Music.d.mts.map +1 -1
  63. package/dist/domain/Music.mjs +1 -1
  64. package/dist/domain/Music.mjs.map +1 -1
  65. package/dist/domain/Research.d.mts +3 -4
  66. package/dist/domain/Research.d.mts.map +1 -1
  67. package/dist/domain/Research.mjs +1 -1
  68. package/dist/domain/Transcript.d.mts +2 -3
  69. package/dist/domain/Transcript.d.mts.map +1 -1
  70. package/dist/domain/Transcript.mjs +1 -1
  71. package/dist/domain/Turn.d.mts +143 -164
  72. package/dist/domain/Turn.d.mts.map +1 -1
  73. package/dist/domain/Turn.mjs +1 -1
  74. package/dist/domain/Turn.mjs.map +1 -1
  75. package/dist/domain/Turn.test.d.mts +1 -1
  76. package/dist/domain/Turn.test.mjs +28 -18
  77. package/dist/domain/Turn.test.mjs.map +1 -1
  78. package/dist/embedding-model/Embedding.d.mts +1 -3
  79. package/dist/embedding-model/Embedding.d.mts.map +1 -1
  80. package/dist/embedding-model/Embedding.mjs +1 -1
  81. package/dist/embedding-model/EmbeddingModel.d.mts +1 -3
  82. package/dist/embedding-model/EmbeddingModel.d.mts.map +1 -1
  83. package/dist/embedding-model/EmbeddingModel.mjs +1 -1
  84. package/dist/embedding-model/EmbeddingModel.mjs.map +1 -1
  85. package/dist/embedding-model/EmbeddingModel.test.d.mts +1 -1
  86. package/dist/embedding-model/EmbeddingModel.test.mjs +14 -9
  87. package/dist/embedding-model/EmbeddingModel.test.mjs.map +1 -1
  88. package/dist/index.d.mts +12 -12
  89. package/dist/job/Job.d.mts +4 -4
  90. package/dist/job/Job.d.mts.map +1 -1
  91. package/dist/job/Job.mjs +1 -1
  92. package/dist/job/Job.mjs.map +1 -1
  93. package/dist/language-model/LanguageModel.d.mts +4 -6
  94. package/dist/language-model/LanguageModel.d.mts.map +1 -1
  95. package/dist/language-model/LanguageModel.mjs +1 -1
  96. package/dist/language-model/LanguageModel.mjs.map +1 -1
  97. package/dist/language-model/LanguageModel.test.d.mts +1 -1
  98. package/dist/language-model/LanguageModel.test.mjs +6 -3
  99. package/dist/language-model/LanguageModel.test.mjs.map +1 -1
  100. package/dist/loop/Loop.d.mts +1 -1
  101. package/dist/loop/Loop.mjs +1 -1
  102. package/dist/loop/Loop.mjs.map +1 -1
  103. package/dist/loop/Loop.test.d.mts +1 -1
  104. package/dist/loop/Loop.test.mjs +60 -34
  105. package/dist/loop/Loop.test.mjs.map +1 -1
  106. package/dist/{magic-string.es-Dk-MMA0F.mjs → magic-string.es-CB2hOw9v.mjs} +14 -13
  107. package/dist/{magic-string.es-Dk-MMA0F.mjs.map → magic-string.es-CB2hOw9v.mjs.map} +1 -1
  108. package/dist/math/Vector.d.mts +0 -2
  109. package/dist/math/Vector.d.mts.map +1 -1
  110. package/dist/math/Vector.mjs +1 -1
  111. package/dist/math/Vector.mjs.map +1 -1
  112. package/dist/music-generator/MusicGenerator.d.mts +2 -4
  113. package/dist/music-generator/MusicGenerator.d.mts.map +1 -1
  114. package/dist/music-generator/MusicGenerator.mjs +1 -1
  115. package/dist/music-generator/MusicGenerator.mjs.map +1 -1
  116. package/dist/music-generator/MusicGenerator.test.d.mts +1 -1
  117. package/dist/music-generator/MusicGenerator.test.mjs +19 -10
  118. package/dist/music-generator/MusicGenerator.test.mjs.map +1 -1
  119. package/dist/observability/Metrics.d.mts +10 -7
  120. package/dist/observability/Metrics.d.mts.map +1 -1
  121. package/dist/observability/Metrics.mjs +1 -1
  122. package/dist/observability/Metrics.mjs.map +1 -1
  123. package/dist/observability/Metrics.test.d.mts +1 -1
  124. package/dist/observability/Metrics.test.mjs +50 -28
  125. package/dist/observability/Metrics.test.mjs.map +1 -1
  126. package/dist/observability/Telemetry.d.mts +2 -3
  127. package/dist/observability/Telemetry.d.mts.map +1 -1
  128. package/dist/observability/Telemetry.mjs +1 -1
  129. package/dist/observability/Telemetry.mjs.map +1 -1
  130. package/dist/observability/Telemetry.test.d.mts +1 -1
  131. package/dist/observability/Telemetry.test.mjs +15 -7
  132. package/dist/observability/Telemetry.test.mjs.map +1 -1
  133. package/dist/research/DeepResearch.d.mts +1 -3
  134. package/dist/research/DeepResearch.d.mts.map +1 -1
  135. package/dist/research/DeepResearch.mjs +1 -1
  136. package/dist/research/DeepResearch.mjs.map +1 -1
  137. package/dist/retry/Retry.d.mts +2 -6
  138. package/dist/retry/Retry.d.mts.map +1 -1
  139. package/dist/retry/Retry.mjs +1 -1
  140. package/dist/retry/Retry.mjs.map +1 -1
  141. package/dist/retry/Retry.test.d.mts +1 -1
  142. package/dist/retry/Retry.test.mjs +6 -3
  143. package/dist/retry/Retry.test.mjs.map +1 -1
  144. package/dist/sandbox/Memory.d.mts +0 -2
  145. package/dist/sandbox/Memory.d.mts.map +1 -1
  146. package/dist/sandbox/Memory.mjs +4 -4
  147. package/dist/sandbox/Memory.mjs.map +1 -1
  148. package/dist/sandbox/Sandbox.d.mts +144 -156
  149. package/dist/sandbox/Sandbox.d.mts.map +1 -1
  150. package/dist/sandbox/Sandbox.mjs +1 -1
  151. package/dist/sandbox/Sandbox.mjs.map +1 -1
  152. package/dist/sandbox/SandboxError.d.mts +1 -1
  153. package/dist/sandbox/SandboxError.mjs +1 -1
  154. package/dist/sandbox/SandboxError.mjs.map +1 -1
  155. package/dist/sandbox/SandboxImage.d.mts +0 -2
  156. package/dist/sandbox/SandboxImage.d.mts.map +1 -1
  157. package/dist/sandbox/SandboxImage.mjs +1 -1
  158. package/dist/sandbox/SandboxImage.mjs.map +1 -1
  159. package/dist/sandbox/SandboxNetwork.d.mts +0 -2
  160. package/dist/sandbox/SandboxNetwork.d.mts.map +1 -1
  161. package/dist/sandbox/SandboxNetwork.mjs +1 -1
  162. package/dist/sandbox/SandboxNetwork.mjs.map +1 -1
  163. package/dist/speech-synthesizer/SpeechSynthesizer.d.mts +8 -7
  164. package/dist/speech-synthesizer/SpeechSynthesizer.d.mts.map +1 -1
  165. package/dist/speech-synthesizer/SpeechSynthesizer.mjs +1 -1
  166. package/dist/speech-synthesizer/SpeechSynthesizer.mjs.map +1 -1
  167. package/dist/speech-synthesizer/SpeechSynthesizer.test.d.mts +1 -1
  168. package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs +31 -16
  169. package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs.map +1 -1
  170. package/dist/streaming/JSONL.d.mts +1 -5
  171. package/dist/streaming/JSONL.d.mts.map +1 -1
  172. package/dist/streaming/JSONL.mjs +1 -1
  173. package/dist/streaming/JSONL.mjs.map +1 -1
  174. package/dist/streaming/JSONL.test.d.mts +1 -1
  175. package/dist/streaming/JSONL.test.mjs +16 -8
  176. package/dist/streaming/JSONL.test.mjs.map +1 -1
  177. package/dist/streaming/Lines.d.mts +0 -2
  178. package/dist/streaming/Lines.d.mts.map +1 -1
  179. package/dist/streaming/Lines.mjs +1 -1
  180. package/dist/streaming/Lines.mjs.map +1 -1
  181. package/dist/streaming/SSE.d.mts +0 -2
  182. package/dist/streaming/SSE.d.mts.map +1 -1
  183. package/dist/streaming/SSE.mjs +1 -1
  184. package/dist/streaming/SSE.mjs.map +1 -1
  185. package/dist/streaming/SSE.test.d.mts +1 -1
  186. package/dist/streaming/SSE.test.mjs +34 -17
  187. package/dist/streaming/SSE.test.mjs.map +1 -1
  188. package/dist/structured-format/StructuredFormat.d.mts +1 -1
  189. package/dist/structured-format/StructuredFormat.mjs +1 -1
  190. package/dist/structured-format/StructuredFormat.mjs.map +1 -1
  191. package/dist/structured-format/StructuredFormat.test.d.mts +1 -1
  192. package/dist/structured-format/StructuredFormat.test.mjs +7 -4
  193. package/dist/structured-format/StructuredFormat.test.mjs.map +1 -1
  194. package/dist/{dist-CcRV3-A5.mjs → test.DNmyFkvJ-YPzDR0Co.mjs} +1644 -5172
  195. package/dist/test.DNmyFkvJ-YPzDR0Co.mjs.map +1 -0
  196. package/dist/testing/MockMusicGenerator.d.mts +4 -3
  197. package/dist/testing/MockMusicGenerator.d.mts.map +1 -1
  198. package/dist/testing/MockMusicGenerator.mjs.map +1 -1
  199. package/dist/testing/MockProvider.d.mts +1 -2
  200. package/dist/testing/MockProvider.d.mts.map +1 -1
  201. package/dist/testing/MockProvider.mjs.map +1 -1
  202. package/dist/testing/MockSandbox.d.mts +256 -290
  203. package/dist/testing/MockSandbox.d.mts.map +1 -1
  204. package/dist/testing/MockSandbox.mjs.map +1 -1
  205. package/dist/testing/MockSpeechSynthesizer.d.mts +10 -6
  206. package/dist/testing/MockSpeechSynthesizer.d.mts.map +1 -1
  207. package/dist/testing/MockSpeechSynthesizer.mjs.map +1 -1
  208. package/dist/testing/MockTranscriber.d.mts +3 -2
  209. package/dist/testing/MockTranscriber.d.mts.map +1 -1
  210. package/dist/testing/MockTranscriber.mjs.map +1 -1
  211. package/dist/tool/Approval.d.mts +31 -36
  212. package/dist/tool/Approval.d.mts.map +1 -1
  213. package/dist/tool/Approval.mjs +1 -1
  214. package/dist/tool/Approval.mjs.map +1 -1
  215. package/dist/tool/Approval.test.d.mts +1 -1
  216. package/dist/tool/Approval.test.mjs +37 -24
  217. package/dist/tool/Approval.test.mjs.map +1 -1
  218. package/dist/tool/HistoryCheck.d.mts +2 -4
  219. package/dist/tool/HistoryCheck.d.mts.map +1 -1
  220. package/dist/tool/HistoryCheck.mjs +1 -1
  221. package/dist/tool/HistoryCheck.mjs.map +1 -1
  222. package/dist/tool/Tool.d.mts +1 -1
  223. package/dist/tool/Tool.mjs +4 -4
  224. package/dist/tool/Tool.mjs.map +1 -1
  225. package/dist/tool/Tool.test.d.mts +1 -1
  226. package/dist/tool/Tool.test.mjs +23 -11
  227. package/dist/tool/Tool.test.mjs.map +1 -1
  228. package/dist/tool/ToolEvent.d.mts +1 -1
  229. package/dist/tool/ToolEvent.mjs +1 -1
  230. package/dist/tool/ToolEvent.mjs.map +1 -1
  231. package/dist/tool/ToolResult.d.mts +1 -1
  232. package/dist/tool/ToolResult.mjs +1 -1
  233. package/dist/tool/ToolResult.mjs.map +1 -1
  234. package/dist/tool/Toolkit.d.mts +1 -1
  235. package/dist/tool/Toolkit.mjs +4 -3
  236. package/dist/tool/Toolkit.mjs.map +1 -1
  237. package/dist/tool/Toolkit.test.d.mts +1 -1
  238. package/dist/tool/Toolkit.test.mjs +40 -21
  239. package/dist/tool/Toolkit.test.mjs.map +1 -1
  240. package/dist/transcriber/Transcriber.d.mts +6 -6
  241. package/dist/transcriber/Transcriber.d.mts.map +1 -1
  242. package/dist/transcriber/Transcriber.mjs +1 -1
  243. package/dist/transcriber/Transcriber.mjs.map +1 -1
  244. package/dist/transcriber/Transcriber.test.d.mts +1 -1
  245. package/dist/transcriber/Transcriber.test.mjs +20 -10
  246. package/dist/transcriber/Transcriber.test.mjs.map +1 -1
  247. package/dist/utils-CiH_DjFW.mjs +3918 -0
  248. package/dist/utils-CiH_DjFW.mjs.map +1 -0
  249. package/dist/web-read/WebRead.d.mts +15 -9
  250. package/dist/web-read/WebRead.d.mts.map +1 -1
  251. package/dist/web-read/WebRead.mjs +1 -1
  252. package/dist/web-read/WebRead.mjs.map +1 -1
  253. package/dist/web-read/WebReadTool.d.mts +4 -5
  254. package/dist/web-read/WebReadTool.d.mts.map +1 -1
  255. package/dist/web-read/WebReadTool.mjs +1 -1
  256. package/dist/web-read/WebReadTool.mjs.map +1 -1
  257. package/dist/web-search/WebSearch.d.mts +22 -13
  258. package/dist/web-search/WebSearch.d.mts.map +1 -1
  259. package/dist/web-search/WebSearch.mjs +1 -1
  260. package/dist/web-search/WebSearch.mjs.map +1 -1
  261. package/dist/web-search/WebSearchTool.d.mts +6 -6
  262. package/dist/web-search/WebSearchTool.d.mts.map +1 -1
  263. package/dist/web-search/WebSearchTool.mjs +1 -1
  264. package/dist/web-search/WebSearchTool.mjs.map +1 -1
  265. package/package.json +4 -4
  266. package/src/loop/Loop.test.ts +13 -14
  267. package/src/loop/Loop.ts +74 -76
  268. package/src/testing/MockProvider.ts +8 -9
  269. package/src/tool/Tool.ts +13 -13
  270. package/dist/AiError-Bf1pq4BB.d.mts.map +0 -1
  271. package/dist/Audio-CR7CSljJ.d.mts.map +0 -1
  272. package/dist/Image-C4vuBmu0.d.mts.map +0 -1
  273. package/dist/Items-BKQgqJ8A.d.mts.map +0 -1
  274. package/dist/Loop-D8nWpowc.d.mts.map +0 -1
  275. package/dist/Media-D_CpcM1Z.d.mts.map +0 -1
  276. package/dist/SandboxError-CIrVDOMV.d.mts.map +0 -1
  277. package/dist/StructuredFormat-DHaUJBdd.d.mts.map +0 -1
  278. package/dist/Tool-u5bag8SO.d.mts.map +0 -1
  279. package/dist/ToolEvent-BBfOdhF_.d.mts.map +0 -1
  280. package/dist/ToolResult-CRpmkBXR.d.mts.map +0 -1
  281. package/dist/Toolkit-D4mQvhjq.d.mts.map +0 -1
  282. package/dist/dist-C0m0QnUP.mjs.map +0 -1
  283. package/dist/dist-CcRV3-A5.mjs.map +0 -1
  284. /package/dist/{chunk-uyGKjUfl.mjs → rolldown-runtime-EAsCxrDo.mjs} +0 -0
@@ -1,7 +1,5 @@
1
- import { t as AiError } from "../AiError-Bf1pq4BB.mjs";
1
+ import { t as AiError } from "../AiError-eLV9t1lU.mjs";
2
2
  import { Context, Duration, Effect } from "effect";
3
-
4
- //#region src/web-read/WebRead.d.ts
5
3
  declare namespace WebRead_d_exports {
6
4
  export { CommonReadRequest, ReadFormat, ReadResponse, WebRead, WebReadService, read };
7
5
  }
@@ -12,16 +10,24 @@ type ReadFormat = "markdown" | "html";
12
10
  * knobs live on the provider-typed request.
13
11
  */
14
12
  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. */
13
+ /** The page to read. */
14
+ readonly url: string;
15
+ /** Output representation. Defaults to `markdown`. See {@link ReadFormat}. */
16
+ readonly format?: ReadFormat;
17
+ /** Upper bound on time spent fetching the page. */
17
18
  readonly timeout?: Duration.Duration;
18
19
  };
19
20
  /** One normalized read result. */
20
21
  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. */
22
+ /** The URL that was read. */
23
+ readonly url: string;
24
+ /** Extracted content in the requested {@link ReadFormat}. */
25
+ readonly content: string;
26
+ /** Page title, when reported. */
27
+ readonly title?: string;
28
+ /** Links discovered on the page, when returned. */
29
+ readonly links?: ReadonlyArray<string>;
30
+ /** The provider-native response. */
25
31
  readonly raw: unknown;
26
32
  };
27
33
  /**
@@ -1 +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"}
1
+ {"version":3,"file":"WebRead.d.mts","names":[],"sources":["../../src/web-read/WebRead.ts"],"mappings":";;;;;;KAQY;;;;;KAUA;;WAED;;WAEA,SAAS;;WAET,UAAU,SAAS;;;KAQlB;;WAED;;WAEA;;WAEA;;WAEA,QAAQ;;WAER;;;;;;KAWC;WACD,OAAO,SAAS,sBAAsB,OAAO,OAAO,cAAc;;;;;;;cAOhE,gBAAgB;;cAKhB,OAAI,SACN,sBACR,OAAO,OAAO,cAAc,SAAiB"}
@@ -1,4 +1,4 @@
1
- import { n as __exportAll } from "../chunk-uyGKjUfl.mjs";
1
+ import { n as __exportAll } from "../rolldown-runtime-EAsCxrDo.mjs";
2
2
  import { Context, Effect } from "effect";
3
3
  //#region src/web-read/WebRead.ts
4
4
  var WebRead_exports = /* @__PURE__ */ __exportAll({
@@ -1 +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"}
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,QAAiC,CAAC,CACrE,8BACF,CAAC,CAAC,CAAC;;AAGH,MAAa,QACX,YAEA,OAAO,QAAQ,UAAU,MAAM,EAAE,KAAK,OAAO,CAAC"}
@@ -1,9 +1,7 @@
1
- import { l as Tool } from "../Tool-u5bag8SO.mjs";
2
- import { t as AiError } from "../AiError-Bf1pq4BB.mjs";
1
+ import { l as Tool } from "../Tool-DE-rnvkw.mjs";
2
+ import { t as AiError } from "../AiError-eLV9t1lU.mjs";
3
3
  import { ReadFormat, ReadResponse, WebRead } from "./WebRead.mjs";
4
4
  import { Schema } from "effect";
5
-
6
- //#region src/web-read/WebReadTool.d.ts
7
5
  declare namespace WebReadTool_d_exports {
8
6
  export { WebReadToolArgs, WebReadToolOptions, webReadTool };
9
7
  }
@@ -18,7 +16,8 @@ declare const WebReadToolArgs: Schema.Struct<{
18
16
  }>;
19
17
  type WebReadToolArgs = typeof WebReadToolArgs.Type;
20
18
  type WebReadToolOptions = {
21
- /** Tool name the model sees. Default `"web_read"`. */readonly name?: string;
19
+ /** Tool name the model sees. Default `"web_read"`. */
20
+ readonly name?: string;
22
21
  /**
23
22
  * App-fixed representation for every read - a policy choice, not a model
24
23
  * knob. Default `"markdown"` (what models read best).
@@ -1 +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"}
1
+ {"version":3,"file":"WebReadTool.d.mts","names":[],"sources":["../../src/web-read/WebReadTool.ts"],"mappings":";;;;;;;;;;;;;cAWM,iBAAe,OAAA;gBAAf,OAAA;;KAMM,yBAAyB,gBAAgB;KAYzC;;WAED;;;;;WAKA,SAAS;;;;;WAKT;;;;;WAKA,UAAU,UAAU;;;;;;;;;;;;;;;;;;cAmBlB,cAAW,UACZ,uBACT,aAAkB,gCAAgC,SAAiB"}
@@ -1,4 +1,4 @@
1
- import { n as __exportAll } from "../chunk-uyGKjUfl.mjs";
1
+ import { n as __exportAll } from "../rolldown-runtime-EAsCxrDo.mjs";
2
2
  import { fromEffectSchema, make } from "../tool/Tool.mjs";
3
3
  import { read } from "./WebRead.mjs";
4
4
  import { Effect, Schema } from "effect";
@@ -1 +1 @@
1
- {"version":3,"file":"WebReadTool.mjs","names":["Tool.make","Tool.fromEffectSchema"],"sources":["../../src/web-read/WebReadTool.ts"],"sourcesContent":["import { Effect, Schema } from \"effect\"\nimport type * as AiError from \"../domain/AiError.js\"\nimport * as Tool from \"../tool/Tool.js\"\nimport { read, type ReadFormat, type ReadResponse, WebRead } from \"./WebRead.js\"\n\n/**\n * Model-facing argument schema. Deliberately narrow: the URL is the only\n * thing that is genuinely the model's call. Output format and the content\n * cost ceiling are app policy, pinned on the constructor instead, so they\n * are guaranteed rather than left to the model to remember each call.\n */\nconst WebReadToolArgs = Schema.Struct({\n url: Schema.String.annotate({\n description: \"Absolute URL of the page to read.\",\n }),\n})\n\nexport type WebReadToolArgs = typeof WebReadToolArgs.Type\n\n/** `title / url` header plus the extracted content - what a model reads best. */\nconst defaultRender = (response: ReadResponse, maxChars: number): string => {\n const header = response.title === undefined ? response.url : `${response.title}\\n${response.url}`\n const body =\n response.content.length > maxChars\n ? `${response.content.slice(0, maxChars)}\\n[content truncated at ${maxChars} characters]`\n : response.content\n return `${header}\\n\\n${body}`\n}\n\nexport type WebReadToolOptions = {\n /** Tool name the model sees. Default `\"web_read\"`. */\n readonly name?: string\n /**\n * App-fixed representation for every read - a policy choice, not a model\n * knob. Default `\"markdown\"` (what models read best).\n */\n readonly format?: ReadFormat\n /**\n * App-fixed ceiling on rendered content characters per call - a context\n * cost guard, not exposed to the model. Default `20000`.\n */\n readonly maxChars?: number\n /**\n * Override how a read response is rendered into the model-facing string.\n * Default: `title / url` header plus the content, truncated at `maxChars`.\n */\n readonly render?: (response: ReadResponse) => string\n}\n\n/**\n * The canonical web-read tool. Its `R` is just `WebRead`, so providing any\n * read-provider Layer satisfies it and the model-facing contract (name,\n * description, schema) is identical no matter which backend answers - swap\n * `FirecrawlRead.layer` for `JinaRead.layer` and the tool the model sees\n * does not change. Drops straight into a `Toolkit` next to `webSearchTool`\n * (search finds the URLs, read fetches the ones worth reading in full).\n *\n * `Output` is the rendered page; failures stay typed on the `AiError`\n * channel. To let the model recover from a failed read, wrap the toolkit in\n * `Toolkit.describeFailures(AiError.describe)`.\n *\n * This is a simple default implementation for quick use. For more elaborate\n * cases (a different output contract, more model-facing knobs), build your\n * own tool with `Tool.make` over the same `read` helper.\n */\nexport const webReadTool = (\n options?: WebReadToolOptions,\n): Tool.Tool<string, WebReadToolArgs, never, string, AiError.AiError, WebRead> => {\n const name = options?.name ?? \"web_read\"\n const format = options?.format ?? \"markdown\"\n const maxChars = options?.maxChars ?? 20_000\n const render = options?.render ?? ((response: ReadResponse) => defaultRender(response, maxChars))\n return Tool.make({\n name,\n description:\n \"Read a web page and return its content as clean text. Use it to read a promising URL in full (e.g. one found via search).\",\n inputSchema: Tool.fromEffectSchema(WebReadToolArgs),\n // The call is wrapped in a tracing span so agent traces show the tool\n // invocation (url, format, content length) nested under the model turn.\n // `withSpan` is a no-op until a Tracer is installed, so this is free by\n // default and adds nothing to the requirements.\n run: (args) =>\n read({ url: args.url, format }).pipe(\n Effect.tap((r) => Effect.annotateCurrentSpan(\"web_read.content_chars\", r.content.length)),\n Effect.map(render),\n Effect.withSpan(name, {\n kind: \"client\",\n attributes: {\n \"web_read.url\": args.url,\n \"web_read.format\": format,\n \"web_read.max_chars\": maxChars,\n },\n }),\n ),\n })\n}\n"],"mappings":";;;;;;;;;;;;AAWA,MAAM,kBAAkB,OAAO,OAAO,EACpC,KAAK,OAAO,OAAO,SAAS,EAC1B,aAAa,qCACd,CAAC,EACH,CAAC;;AAKF,MAAM,iBAAiB,UAAwB,aAA6B;AAM1E,QAAO,GALQ,SAAS,UAAU,KAAA,IAAY,SAAS,MAAM,GAAG,SAAS,MAAM,IAAI,SAAS,MAK3E,MAHf,SAAS,QAAQ,SAAS,WACtB,GAAG,SAAS,QAAQ,MAAM,GAAG,SAAS,CAAC,0BAA0B,SAAS,gBAC1E,SAAS;;;;;;;;;;;;;;;;;;AAwCjB,MAAa,eACX,YACgF;CAChF,MAAM,OAAO,SAAS,QAAQ;CAC9B,MAAM,SAAS,SAAS,UAAU;CAClC,MAAM,WAAW,SAAS,YAAY;CACtC,MAAM,SAAS,SAAS,YAAY,aAA2B,cAAc,UAAU,SAAS;AAChG,QAAOA,KAAU;EACf;EACA,aACE;EACF,aAAaC,iBAAsB,gBAAgB;EAKnD,MAAM,SACJ,KAAK;GAAE,KAAK,KAAK;GAAK;GAAQ,CAAC,CAAC,KAC9B,OAAO,KAAK,MAAM,OAAO,oBAAoB,0BAA0B,EAAE,QAAQ,OAAO,CAAC,EACzF,OAAO,IAAI,OAAO,EAClB,OAAO,SAAS,MAAM;GACpB,MAAM;GACN,YAAY;IACV,gBAAgB,KAAK;IACrB,mBAAmB;IACnB,sBAAsB;IACvB;GACF,CAAC,CACH;EACJ,CAAC"}
1
+ {"version":3,"file":"WebReadTool.mjs","names":["Tool.make","Tool.fromEffectSchema"],"sources":["../../src/web-read/WebReadTool.ts"],"sourcesContent":["import { Effect, Schema } from \"effect\"\nimport type * as AiError from \"../domain/AiError.js\"\nimport * as Tool from \"../tool/Tool.js\"\nimport { read, type ReadFormat, type ReadResponse, WebRead } from \"./WebRead.js\"\n\n/**\n * Model-facing argument schema. Deliberately narrow: the URL is the only\n * thing that is genuinely the model's call. Output format and the content\n * cost ceiling are app policy, pinned on the constructor instead, so they\n * are guaranteed rather than left to the model to remember each call.\n */\nconst WebReadToolArgs = Schema.Struct({\n url: Schema.String.annotate({\n description: \"Absolute URL of the page to read.\",\n }),\n})\n\nexport type WebReadToolArgs = typeof WebReadToolArgs.Type\n\n/** `title / url` header plus the extracted content - what a model reads best. */\nconst defaultRender = (response: ReadResponse, maxChars: number): string => {\n const header = response.title === undefined ? response.url : `${response.title}\\n${response.url}`\n const body =\n response.content.length > maxChars\n ? `${response.content.slice(0, maxChars)}\\n[content truncated at ${maxChars} characters]`\n : response.content\n return `${header}\\n\\n${body}`\n}\n\nexport type WebReadToolOptions = {\n /** Tool name the model sees. Default `\"web_read\"`. */\n readonly name?: string\n /**\n * App-fixed representation for every read - a policy choice, not a model\n * knob. Default `\"markdown\"` (what models read best).\n */\n readonly format?: ReadFormat\n /**\n * App-fixed ceiling on rendered content characters per call - a context\n * cost guard, not exposed to the model. Default `20000`.\n */\n readonly maxChars?: number\n /**\n * Override how a read response is rendered into the model-facing string.\n * Default: `title / url` header plus the content, truncated at `maxChars`.\n */\n readonly render?: (response: ReadResponse) => string\n}\n\n/**\n * The canonical web-read tool. Its `R` is just `WebRead`, so providing any\n * read-provider Layer satisfies it and the model-facing contract (name,\n * description, schema) is identical no matter which backend answers - swap\n * `FirecrawlRead.layer` for `JinaRead.layer` and the tool the model sees\n * does not change. Drops straight into a `Toolkit` next to `webSearchTool`\n * (search finds the URLs, read fetches the ones worth reading in full).\n *\n * `Output` is the rendered page; failures stay typed on the `AiError`\n * channel. To let the model recover from a failed read, wrap the toolkit in\n * `Toolkit.describeFailures(AiError.describe)`.\n *\n * This is a simple default implementation for quick use. For more elaborate\n * cases (a different output contract, more model-facing knobs), build your\n * own tool with `Tool.make` over the same `read` helper.\n */\nexport const webReadTool = (\n options?: WebReadToolOptions,\n): Tool.Tool<string, WebReadToolArgs, never, string, AiError.AiError, WebRead> => {\n const name = options?.name ?? \"web_read\"\n const format = options?.format ?? \"markdown\"\n const maxChars = options?.maxChars ?? 20_000\n const render = options?.render ?? ((response: ReadResponse) => defaultRender(response, maxChars))\n return Tool.make({\n name,\n description:\n \"Read a web page and return its content as clean text. Use it to read a promising URL in full (e.g. one found via search).\",\n inputSchema: Tool.fromEffectSchema(WebReadToolArgs),\n // The call is wrapped in a tracing span so agent traces show the tool\n // invocation (url, format, content length) nested under the model turn.\n // `withSpan` is a no-op until a Tracer is installed, so this is free by\n // default and adds nothing to the requirements.\n run: (args) =>\n read({ url: args.url, format }).pipe(\n Effect.tap((r) => Effect.annotateCurrentSpan(\"web_read.content_chars\", r.content.length)),\n Effect.map(render),\n Effect.withSpan(name, {\n kind: \"client\",\n attributes: {\n \"web_read.url\": args.url,\n \"web_read.format\": format,\n \"web_read.max_chars\": maxChars,\n },\n }),\n ),\n })\n}\n"],"mappings":";;;;;;;;;;;;AAWA,MAAM,kBAAkB,OAAO,OAAO,EACpC,KAAK,OAAO,OAAO,SAAS,EAC1B,aAAa,oCACf,CAAC,EACH,CAAC;;AAKD,MAAM,iBAAiB,UAAwB,aAA6B;CAM1E,OAAO,GALQ,SAAS,UAAU,KAAA,IAAY,SAAS,MAAM,GAAG,SAAS,MAAM,IAAI,SAAS,MAK3E,MAHf,SAAS,QAAQ,SAAS,WACtB,GAAG,SAAS,QAAQ,MAAM,GAAG,QAAQ,EAAE,0BAA0B,SAAS,gBAC1E,SAAS;AAEjB;;;;;;;;;;;;;;;;;AAsCA,MAAa,eACX,YACgF;CAChF,MAAM,OAAO,SAAS,QAAQ;CAC9B,MAAM,SAAS,SAAS,UAAU;CAClC,MAAM,WAAW,SAAS,YAAY;CACtC,MAAM,SAAS,SAAS,YAAY,aAA2B,cAAc,UAAU,QAAQ;CAC/F,OAAOA,KAAU;EACf;EACA,aACE;EACF,aAAaC,iBAAsB,eAAe;EAKlD,MAAM,SACJ,KAAK;GAAE,KAAK,KAAK;GAAK;EAAO,CAAC,CAAC,CAAC,KAC9B,OAAO,KAAK,MAAM,OAAO,oBAAoB,0BAA0B,EAAE,QAAQ,MAAM,CAAC,GACxF,OAAO,IAAI,MAAM,GACjB,OAAO,SAAS,MAAM;GACpB,MAAM;GACN,YAAY;IACV,gBAAgB,KAAK;IACrB,mBAAmB;IACnB,sBAAsB;GACxB;EACF,CAAC,CACH;CACJ,CAAC;AACH"}
@@ -1,7 +1,5 @@
1
- import { t as AiError } from "../AiError-Bf1pq4BB.mjs";
1
+ import { t as AiError } from "../AiError-eLV9t1lU.mjs";
2
2
  import { Context, DateTime, Effect, Schema } from "effect";
3
-
4
- //#region src/web-search/WebSearch.d.ts
5
3
  declare namespace WebSearch_d_exports {
6
4
  export { CommonSearchRequest, SearchRecency, SearchResponse, SearchResult, WebSearch, WebSearchService, search };
7
5
  }
@@ -35,7 +33,8 @@ type SearchRecency = typeof SearchRecency.Type;
35
33
  * `searchDepth`) is a mode knob, so it stays on the provider-typed request.
36
34
  */
37
35
  type CommonSearchRequest = {
38
- /** The search query. The one field every provider requires. */readonly query: string;
36
+ /** The search query. The one field every provider requires. */
37
+ readonly query: string;
39
38
  /**
40
39
  * Upper bound on the number of results to return in this one call.
41
40
  * Providers cap differently (Perplexity / Tavily / Brave at ~20, Exa /
@@ -43,18 +42,24 @@ type CommonSearchRequest = {
43
42
  * provider. There is no common pagination - only two providers paginate
44
43
  * and only shallowly, so `offset` is provider-typed.
45
44
  */
46
- readonly maxResults?: number; /** Restrict results to these domains (e.g. `["docs.foo.com"]`). */
47
- readonly includeDomains?: ReadonlyArray<string>; /** Drop results from these domains. */
45
+ readonly maxResults?: number;
46
+ /** Restrict results to these domains (e.g. `["docs.foo.com"]`). */
47
+ readonly includeDomains?: ReadonlyArray<string>;
48
+ /** Drop results from these domains. */
48
49
  readonly excludeDomains?: ReadonlyArray<string>;
49
50
  /**
50
51
  * Coarse freshness filter - see {@link SearchRecency}. Sugar over an
51
52
  * explicit `startDate`; ignored where {@link startDate} is also set and
52
53
  * the provider takes only one.
53
54
  */
54
- readonly recency?: SearchRecency; /** Published-after bound. The precise alternative to {@link recency}. */
55
- readonly startDate?: DateTime.DateTime; /** Published-before bound. */
56
- readonly endDate?: DateTime.DateTime; /** ISO 3166-1 alpha-2 country code to localize results (e.g. `"us"`). */
57
- readonly country?: string; /** ISO 639-1 language code to bias results toward (e.g. `"en"`). */
55
+ readonly recency?: SearchRecency;
56
+ /** Published-after bound. The precise alternative to {@link recency}. */
57
+ readonly startDate?: DateTime.DateTime;
58
+ /** Published-before bound. */
59
+ readonly endDate?: DateTime.DateTime;
60
+ /** ISO 3166-1 alpha-2 country code to localize results (e.g. `"us"`). */
61
+ readonly country?: string;
62
+ /** ISO 639-1 language code to bias results toward (e.g. `"en"`). */
58
63
  readonly language?: string;
59
64
  };
60
65
  /**
@@ -65,7 +70,9 @@ type CommonSearchRequest = {
65
70
  * here (`author`, `favicon`, multi-chunk `snippets[]`, …).
66
71
  */
67
72
  type SearchResult = {
68
- /** Canonical result URL. Always present. */readonly url: string; /** Result title / headline, when the provider returns one. */
73
+ /** Canonical result URL. Always present. */
74
+ readonly url: string;
75
+ /** Result title / headline, when the provider returns one. */
69
76
  readonly title?: string;
70
77
  /**
71
78
  * Primary short excerpt - the one text field all providers return (under
@@ -73,7 +80,8 @@ type SearchResult = {
73
80
  * extract fields (`text`, `highlights`, `summary`) belong to the
74
81
  * out-of-scope extract feature and stay on the provider-typed result.
75
82
  */
76
- readonly snippet?: string; /** Publication date, when the provider reports one. */
83
+ readonly snippet?: string;
84
+ /** Publication date, when the provider reports one. */
77
85
  readonly publishedDate?: DateTime.DateTime;
78
86
  /**
79
87
  * Relevance score, only from providers that rank (Exa, Tavily);
@@ -81,7 +89,8 @@ type SearchResult = {
81
89
  * being non-universal because ranking is core to what a "search result"
82
90
  * means - and `undefined` cleanly says "this backend doesn't score."
83
91
  */
84
- readonly score?: number; /** The provider-native result object, never lossy. */
92
+ readonly score?: number;
93
+ /** The provider-native result object, never lossy. */
85
94
  readonly raw: unknown;
86
95
  };
87
96
  type SearchResponse = {
@@ -1 +1 @@
1
- {"version":3,"file":"WebSearch.d.mts","names":[],"sources":["../../src/web-search/WebSearch.ts"],"mappings":";;;;;;;;;;;;;;;;;;;AAsBA;;;cAAa,aAAA,EAAa,MAAA,CAAA,QAAA;AAAA,KAEd,aAAA,UAAuB,aAAA,CAAc,IAAA;AAAjD;;;;;AAkBA;;;;;;;AAlBA,KAkBY,mBAAA;EAwB0B,wEAtB3B,KAAA;EAAA;;;;;;;EAAA,SAQA,UAAA,WAYA;EAAA,SAVA,cAAA,GAAiB,aAAA,UAUI;EAAA,SARrB,cAAA,GAAiB,aAAA;EAUP;;;;;EAAA,SAJV,OAAA,GAAU,aAAA,EAsBT;EAAA,SApBD,SAAA,GAAY,QAAA,CAAS,QAAA;WAErB,OAAA,GAAU,QAAA,CAAS,QAAA,EAoBnB;EAAA,SAlBA,OAAA,WA2BA;EAAA,SAzBA,QAAA;AAAA;;;;;;AAuCX;;KAzBY,YAAA;EA0BqB,qDAxBtB,GAAA,UAwBS;EAAA,SAtBT,KAAA;EA+BA;;;AAaX;;;EAbW,SAxBA,OAAA,WAsCwD;EAAA,SApCxD,aAAA,GAAgB,QAAA,CAAS,QAAA;EAoCiB;;;;;;EAAA,SA7B1C,KAAA,WA6BiD;EAAA,SA3BjD,GAAA;AAAA;AAAA,KAGC,cAAA;EAAA,SACD,OAAA,EAAS,aAAA,CAAc,YAAA;EAuBgE;AACjG;;;;;;;EADiG,SAdvF,GAAA;AAAA;;;;;;AAsBX;KATY,gBAAA;EAAA,SACD,MAAA,GAAS,OAAA,EAAS,mBAAA,KAAwB,MAAA,CAAO,MAAA,CAAO,cAAA,EAAgB,OAAA;AAAA;AAAA,cAClF,cAAA;AAYD;;;;;AAAA,cALa,SAAA,SAAkB,cAAA;;cAKlB,MAAA,GACX,OAAA,EAAS,mBAAA,KACR,MAAA,CAAO,MAAA,CAAO,cAAA,EAAgB,OAAA,EAAiB,SAAA"}
1
+ {"version":3,"file":"WebSearch.d.mts","names":[],"sources":["../../src/web-search/WebSearch.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;cAsBa,eAAa,OAAA;KAEd,uBAAuB,cAAc;;;;;;;;;;;;;KAkBrC;;WAED;;;;;;;;WAQA;;WAEA,iBAAiB;;WAEjB,iBAAiB;;;;;;WAMjB,UAAU;;WAEV,YAAY,SAAS;;WAErB,UAAU,SAAS;;WAEnB;;WAEA;;;;;;;;;KAcC;;WAED;;WAEA;;;;;;;WAOA;;WAEA,gBAAgB,SAAS;;;;;;;WAOzB;;WAEA;;KAGC;WACD,SAAS,cAAc;;;;;;;;;WASvB;;;;;;;;KAaC;WACD,SAAS,SAAS,wBAAwB,OAAO,OAAO,gBAAgB;;;;;;;;cAQtE,kBAAkB;;cAKlB,SAAM,SACR,wBACR,OAAO,OAAO,gBAAgB,SAAiB"}
@@ -1,4 +1,4 @@
1
- import { n as __exportAll } from "../chunk-uyGKjUfl.mjs";
1
+ import { n as __exportAll } from "../rolldown-runtime-EAsCxrDo.mjs";
2
2
  import { Context, Effect, Schema } from "effect";
3
3
  //#region src/web-search/WebSearch.ts
4
4
  var WebSearch_exports = /* @__PURE__ */ __exportAll({
@@ -1 +1 @@
1
- {"version":3,"file":"WebSearch.mjs","names":[],"sources":["../../src/web-search/WebSearch.ts"],"sourcesContent":["import { Context, type DateTime, Effect, Schema } from \"effect\"\nimport type * as AiError from \"../domain/AiError.js\"\n\n// ---------------------------------------------------------------------------\n// Recency\n// ---------------------------------------------------------------------------\n\n/**\n * Convenience freshness enum shared by every provider. A coarse \"published\n * within the last …\" filter that maps onto each provider's native recency\n * knob (Perplexity `search_recency_filter`, Brave `freshness`, Tavily\n * `time_range`, You.com `freshness`), or onto a computed published-date\n * range where a provider has no enum (Exa).\n *\n * For a precise window use {@link CommonSearchRequest.startDate} /\n * {@link CommonSearchRequest.endDate} instead; `recency` is the sugar for\n * the common \"past week / past month\" case.\n *\n * Exposed as a `Schema` so {@link \"../web-search/WebSearchTool\".webSearchTool}\n * can hand it straight to a model as a tool parameter; the\n * {@link SearchRecency} type is derived from it.\n */\nexport const SearchRecency = Schema.Literals([\"hour\", \"day\", \"week\", \"month\", \"year\"])\n\nexport type SearchRecency = typeof SearchRecency.Type\n\n// ---------------------------------------------------------------------------\n// Request\n// ---------------------------------------------------------------------------\n\n/**\n * Cross-provider web-search request. A field earns a place here only if\n * most of the supported providers honor it and a developer would expect it\n * from a generic search interface; everything provider-specific (Exa\n * `type`, Tavily `searchDepth`, Brave `goggles`, pagination `offset`,\n * `safeSearch`, `topic`, …) lives on that provider's typed request.\n *\n * Note the one structural difference from `EmbeddingModel` /\n * `Transcriber`: there is no `model`. None of the pure-`/search` endpoints\n * take one - what looks model-shaped on a provider (Exa `type`, Tavily\n * `searchDepth`) is a mode knob, so it stays on the provider-typed request.\n */\nexport type CommonSearchRequest = {\n /** The search query. The one field every provider requires. */\n readonly query: string\n /**\n * Upper bound on the number of results to return in this one call.\n * Providers cap differently (Perplexity / Tavily / Brave at ~20, Exa /\n * You.com at ~100); a value above a provider's cap is clamped by that\n * provider. There is no common pagination - only two providers paginate\n * and only shallowly, so `offset` is provider-typed.\n */\n readonly maxResults?: number\n /** Restrict results to these domains (e.g. `[\"docs.foo.com\"]`). */\n readonly includeDomains?: ReadonlyArray<string>\n /** Drop results from these domains. */\n readonly excludeDomains?: ReadonlyArray<string>\n /**\n * Coarse freshness filter - see {@link SearchRecency}. Sugar over an\n * explicit `startDate`; ignored where {@link startDate} is also set and\n * the provider takes only one.\n */\n readonly recency?: SearchRecency\n /** Published-after bound. The precise alternative to {@link recency}. */\n readonly startDate?: DateTime.DateTime\n /** Published-before bound. */\n readonly endDate?: DateTime.DateTime\n /** ISO 3166-1 alpha-2 country code to localize results (e.g. `\"us\"`). */\n readonly country?: string\n /** ISO 639-1 language code to bias results toward (e.g. `\"en\"`). */\n readonly language?: string\n}\n\n// ---------------------------------------------------------------------------\n// Response\n// ---------------------------------------------------------------------------\n\n/**\n * One normalized web-search hit. A flat record with optionals rather than a\n * tagged union: the providers differ by *which fields are present*, not by\n * *kind*. The provider's untouched result object is always on `raw`, so a\n * caller holding a typed provider tag can recover anything not promoted\n * here (`author`, `favicon`, multi-chunk `snippets[]`, …).\n */\nexport type SearchResult = {\n /** Canonical result URL. Always present. */\n readonly url: string\n /** Result title / headline, when the provider returns one. */\n readonly title?: string\n /**\n * Primary short excerpt - the one text field all providers return (under\n * various wire names: `snippet`, `content`, `description`). The richer\n * extract fields (`text`, `highlights`, `summary`) belong to the\n * out-of-scope extract feature and stay on the provider-typed result.\n */\n readonly snippet?: string\n /** Publication date, when the provider reports one. */\n readonly publishedDate?: DateTime.DateTime\n /**\n * Relevance score, only from providers that rank (Exa, Tavily);\n * `undefined` for providers that return an unscored list. Kept despite\n * being non-universal because ranking is core to what a \"search result\"\n * means - and `undefined` cleanly says \"this backend doesn't score.\"\n */\n readonly score?: number\n /** The provider-native result object, never lossy. */\n readonly raw: unknown\n}\n\nexport type SearchResponse = {\n readonly results: ReadonlyArray<SearchResult>\n /**\n * The provider-native top-level response object. Cost / usage reporting\n * is deliberately not modeled on this surface yet: providers disagree on\n * both what (Exa returns USD, Tavily credits, Brave nothing in-body) and\n * where (Brave reports cost in response headers), so it is deferred to the\n * unified usage design (see plans/usage-tracking.md). Anything a provider\n * reports survives here on `raw`.\n */\n readonly raw: unknown\n}\n\n// ---------------------------------------------------------------------------\n// Service + helper\n// ---------------------------------------------------------------------------\n\n/**\n * The portable web-search surface: one operation, `search`. Pure search is\n * the one thing every provider does, so - unlike `SpeechSynthesizer` /\n * `Transcriber` - this capability needs no marker tags; every provider\n * Layer can answer.\n */\nexport type WebSearchService = {\n readonly search: (request: CommonSearchRequest) => Effect.Effect<SearchResponse, AiError.AiError>\n}\n\n/**\n * Generic web-search service tag. Yield this for provider-portable code;\n * yield a provider tag (`PerplexitySearch`, `ExaSearch`, …) when you need\n * that provider's own knobs. A provider's `layer` registers both.\n */\nexport class WebSearch extends Context.Service<WebSearch, WebSearchService>()(\n \"@betalyra/effect-uai/WebSearch\",\n) {}\n\n/** Run one web search against whichever provider Layer is in scope. */\nexport const search = (\n request: CommonSearchRequest,\n): Effect.Effect<SearchResponse, AiError.AiError, WebSearch> =>\n Effect.flatMap(WebSearch, (s) => s.search(request))\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsBA,MAAa,gBAAgB,OAAO,SAAS;CAAC;CAAQ;CAAO;CAAQ;CAAS;CAAO,CAAC;;;;;;AAuHtF,IAAa,YAAb,cAA+B,QAAQ,SAAsC,CAC3E,iCACD,CAAC;;AAGF,MAAa,UACX,YAEA,OAAO,QAAQ,YAAY,MAAM,EAAE,OAAO,QAAQ,CAAC"}
1
+ {"version":3,"file":"WebSearch.mjs","names":[],"sources":["../../src/web-search/WebSearch.ts"],"sourcesContent":["import { Context, type DateTime, Effect, Schema } from \"effect\"\nimport type * as AiError from \"../domain/AiError.js\"\n\n// ---------------------------------------------------------------------------\n// Recency\n// ---------------------------------------------------------------------------\n\n/**\n * Convenience freshness enum shared by every provider. A coarse \"published\n * within the last …\" filter that maps onto each provider's native recency\n * knob (Perplexity `search_recency_filter`, Brave `freshness`, Tavily\n * `time_range`, You.com `freshness`), or onto a computed published-date\n * range where a provider has no enum (Exa).\n *\n * For a precise window use {@link CommonSearchRequest.startDate} /\n * {@link CommonSearchRequest.endDate} instead; `recency` is the sugar for\n * the common \"past week / past month\" case.\n *\n * Exposed as a `Schema` so {@link \"../web-search/WebSearchTool\".webSearchTool}\n * can hand it straight to a model as a tool parameter; the\n * {@link SearchRecency} type is derived from it.\n */\nexport const SearchRecency = Schema.Literals([\"hour\", \"day\", \"week\", \"month\", \"year\"])\n\nexport type SearchRecency = typeof SearchRecency.Type\n\n// ---------------------------------------------------------------------------\n// Request\n// ---------------------------------------------------------------------------\n\n/**\n * Cross-provider web-search request. A field earns a place here only if\n * most of the supported providers honor it and a developer would expect it\n * from a generic search interface; everything provider-specific (Exa\n * `type`, Tavily `searchDepth`, Brave `goggles`, pagination `offset`,\n * `safeSearch`, `topic`, …) lives on that provider's typed request.\n *\n * Note the one structural difference from `EmbeddingModel` /\n * `Transcriber`: there is no `model`. None of the pure-`/search` endpoints\n * take one - what looks model-shaped on a provider (Exa `type`, Tavily\n * `searchDepth`) is a mode knob, so it stays on the provider-typed request.\n */\nexport type CommonSearchRequest = {\n /** The search query. The one field every provider requires. */\n readonly query: string\n /**\n * Upper bound on the number of results to return in this one call.\n * Providers cap differently (Perplexity / Tavily / Brave at ~20, Exa /\n * You.com at ~100); a value above a provider's cap is clamped by that\n * provider. There is no common pagination - only two providers paginate\n * and only shallowly, so `offset` is provider-typed.\n */\n readonly maxResults?: number\n /** Restrict results to these domains (e.g. `[\"docs.foo.com\"]`). */\n readonly includeDomains?: ReadonlyArray<string>\n /** Drop results from these domains. */\n readonly excludeDomains?: ReadonlyArray<string>\n /**\n * Coarse freshness filter - see {@link SearchRecency}. Sugar over an\n * explicit `startDate`; ignored where {@link startDate} is also set and\n * the provider takes only one.\n */\n readonly recency?: SearchRecency\n /** Published-after bound. The precise alternative to {@link recency}. */\n readonly startDate?: DateTime.DateTime\n /** Published-before bound. */\n readonly endDate?: DateTime.DateTime\n /** ISO 3166-1 alpha-2 country code to localize results (e.g. `\"us\"`). */\n readonly country?: string\n /** ISO 639-1 language code to bias results toward (e.g. `\"en\"`). */\n readonly language?: string\n}\n\n// ---------------------------------------------------------------------------\n// Response\n// ---------------------------------------------------------------------------\n\n/**\n * One normalized web-search hit. A flat record with optionals rather than a\n * tagged union: the providers differ by *which fields are present*, not by\n * *kind*. The provider's untouched result object is always on `raw`, so a\n * caller holding a typed provider tag can recover anything not promoted\n * here (`author`, `favicon`, multi-chunk `snippets[]`, …).\n */\nexport type SearchResult = {\n /** Canonical result URL. Always present. */\n readonly url: string\n /** Result title / headline, when the provider returns one. */\n readonly title?: string\n /**\n * Primary short excerpt - the one text field all providers return (under\n * various wire names: `snippet`, `content`, `description`). The richer\n * extract fields (`text`, `highlights`, `summary`) belong to the\n * out-of-scope extract feature and stay on the provider-typed result.\n */\n readonly snippet?: string\n /** Publication date, when the provider reports one. */\n readonly publishedDate?: DateTime.DateTime\n /**\n * Relevance score, only from providers that rank (Exa, Tavily);\n * `undefined` for providers that return an unscored list. Kept despite\n * being non-universal because ranking is core to what a \"search result\"\n * means - and `undefined` cleanly says \"this backend doesn't score.\"\n */\n readonly score?: number\n /** The provider-native result object, never lossy. */\n readonly raw: unknown\n}\n\nexport type SearchResponse = {\n readonly results: ReadonlyArray<SearchResult>\n /**\n * The provider-native top-level response object. Cost / usage reporting\n * is deliberately not modeled on this surface yet: providers disagree on\n * both what (Exa returns USD, Tavily credits, Brave nothing in-body) and\n * where (Brave reports cost in response headers), so it is deferred to the\n * unified usage design (see plans/usage-tracking.md). Anything a provider\n * reports survives here on `raw`.\n */\n readonly raw: unknown\n}\n\n// ---------------------------------------------------------------------------\n// Service + helper\n// ---------------------------------------------------------------------------\n\n/**\n * The portable web-search surface: one operation, `search`. Pure search is\n * the one thing every provider does, so - unlike `SpeechSynthesizer` /\n * `Transcriber` - this capability needs no marker tags; every provider\n * Layer can answer.\n */\nexport type WebSearchService = {\n readonly search: (request: CommonSearchRequest) => Effect.Effect<SearchResponse, AiError.AiError>\n}\n\n/**\n * Generic web-search service tag. Yield this for provider-portable code;\n * yield a provider tag (`PerplexitySearch`, `ExaSearch`, …) when you need\n * that provider's own knobs. A provider's `layer` registers both.\n */\nexport class WebSearch extends Context.Service<WebSearch, WebSearchService>()(\n \"@betalyra/effect-uai/WebSearch\",\n) {}\n\n/** Run one web search against whichever provider Layer is in scope. */\nexport const search = (\n request: CommonSearchRequest,\n): Effect.Effect<SearchResponse, AiError.AiError, WebSearch> =>\n Effect.flatMap(WebSearch, (s) => s.search(request))\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsBA,MAAa,gBAAgB,OAAO,SAAS;CAAC;CAAQ;CAAO;CAAQ;CAAS;AAAM,CAAC;;;;;;AAuHrF,IAAa,YAAb,cAA+B,QAAQ,QAAqC,CAAC,CAC3E,gCACF,CAAC,CAAC,CAAC;;AAGH,MAAa,UACX,YAEA,OAAO,QAAQ,YAAY,MAAM,EAAE,OAAO,OAAO,CAAC"}
@@ -1,9 +1,7 @@
1
- import { l as Tool } from "../Tool-u5bag8SO.mjs";
2
- import { t as AiError } from "../AiError-Bf1pq4BB.mjs";
1
+ import { l as Tool } from "../Tool-DE-rnvkw.mjs";
2
+ import { t as AiError } from "../AiError-eLV9t1lU.mjs";
3
3
  import { SearchResult, WebSearch } from "./WebSearch.mjs";
4
4
  import { Schema } from "effect";
5
-
6
- //#region src/web-search/WebSearchTool.d.ts
7
5
  declare namespace WebSearchTool_d_exports {
8
6
  export { WebSearchToolArgs, WebSearchToolOptions, webSearchTool };
9
7
  }
@@ -21,7 +19,8 @@ declare const WebSearchToolArgs: Schema.Struct<{
21
19
  }>;
22
20
  type WebSearchToolArgs = typeof WebSearchToolArgs.Type;
23
21
  type WebSearchToolOptions = {
24
- /** Tool name the model sees. Default `"web_search"`. */readonly name?: string;
22
+ /** Tool name the model sees. Default `"web_search"`. */
23
+ readonly name?: string;
25
24
  /**
26
25
  * App-fixed ceiling on results per call - a cost guard, not exposed to
27
26
  * the model. Default `5`.
@@ -31,7 +30,8 @@ type WebSearchToolOptions = {
31
30
  * App-fixed allowlist applied to every search. A policy scope ("only
32
31
  * search our docs"), not a model knob - so it is enforced, not requested.
33
32
  */
34
- readonly includeDomains?: ReadonlyArray<string>; /** App-fixed denylist applied to every search ("never return X"). */
33
+ readonly includeDomains?: ReadonlyArray<string>;
34
+ /** App-fixed denylist applied to every search ("never return X"). */
35
35
  readonly excludeDomains?: ReadonlyArray<string>;
36
36
  /**
37
37
  * Override how results are rendered into the model-facing string.
@@ -1 +1 @@
1
- {"version":3,"file":"WebSearchTool.d.mts","names":[],"sources":["../../src/web-search/WebSearchTool.ts"],"mappings":";;;;;;;;;;;;;;;;;cAaM,iBAAA,EAAiB,MAAA,CAAA,MAAA;EAAA;;;KAKX,iBAAA,UAA2B,iBAAA,CAAkB,IAAA;AAAA,KAa7C,oBAAA;EAlBW,iEAoBZ,IAAA;EApBY;;;;EAAA,SAyBZ,UAAA;;;;;WAKA,cAAA,GAAiB,aAAA;WAEjB,cAAA,GAAiB,aAAA;;AA3B5B;;;WAgCW,MAAA,IAAU,OAAA,EAAS,aAAA,CAAc,YAAA;AAAA;AAnB5C;;;;;;;;;;;;;;;;;;;AAAA,cAyCa,aAAA,GACX,OAAA,GAAU,oBAAA,KACT,IAAA,SAAkB,iBAAA,iBAAkC,OAAA,EAAiB,SAAA"}
1
+ {"version":3,"file":"WebSearchTool.d.mts","names":[],"sources":["../../src/web-search/WebSearchTool.ts"],"mappings":";;;;;;;;;;;;;;;cAaM,mBAAiB,OAAA;;;;KAKX,2BAA2B,kBAAkB;KAa7C;;WAED;;;;;WAKA;;;;;WAKA,iBAAiB;;WAEjB,iBAAiB;;;;;WAKjB,UAAU,SAAS,cAAc;;;;;;;;;;;;;;;;;;;;;cAsB/B,gBAAa,UACd,yBACT,aAAkB,kCAAkC,SAAiB"}
@@ -1,4 +1,4 @@
1
- import { n as __exportAll } from "../chunk-uyGKjUfl.mjs";
1
+ import { n as __exportAll } from "../rolldown-runtime-EAsCxrDo.mjs";
2
2
  import { fromEffectSchema, make } from "../tool/Tool.mjs";
3
3
  import { SearchRecency, search } from "./WebSearch.mjs";
4
4
  import { Effect, Schema } from "effect";
@@ -1 +1 @@
1
- {"version":3,"file":"WebSearchTool.mjs","names":["Tool.make","Tool.fromEffectSchema"],"sources":["../../src/web-search/WebSearchTool.ts"],"sourcesContent":["import { Effect, Schema } from \"effect\"\nimport type * as AiError from \"../domain/AiError.js\"\nimport * as Tool from \"../tool/Tool.js\"\nimport { search, SearchRecency, type SearchResult, WebSearch } from \"./WebSearch.js\"\n\n/**\n * Model-facing argument schema. Deliberately narrow: `query` plus the one\n * filter that is genuinely the model's call - `recency` (it knows whether a\n * question is about current events or evergreen). App-policy scoping\n * (`includeDomains` / `excludeDomains`) and the `maxResults` cost ceiling\n * are pinned on the constructor instead, so they are guaranteed rather than\n * left to the model to remember each call.\n */\nconst WebSearchToolArgs = Schema.Struct({\n query: Schema.String,\n recency: Schema.optional(SearchRecency),\n})\n\nexport type WebSearchToolArgs = typeof WebSearchToolArgs.Type\n\n/** Numbered `title / url / snippet` list - what a model reads best. */\nconst defaultRender = (results: ReadonlyArray<SearchResult>): string =>\n results.length === 0\n ? \"No results found.\"\n : results\n .map((r, i) => {\n const head = `${i + 1}. ${r.title ?? r.url}\\n ${r.url}`\n return r.snippet === undefined ? head : `${head}\\n ${r.snippet}`\n })\n .join(\"\\n\\n\")\n\nexport type WebSearchToolOptions = {\n /** Tool name the model sees. Default `\"web_search\"`. */\n readonly name?: string\n /**\n * App-fixed ceiling on results per call - a cost guard, not exposed to\n * the model. Default `5`.\n */\n readonly maxResults?: number\n /**\n * App-fixed allowlist applied to every search. A policy scope (\"only\n * search our docs\"), not a model knob - so it is enforced, not requested.\n */\n readonly includeDomains?: ReadonlyArray<string>\n /** App-fixed denylist applied to every search (\"never return X\"). */\n readonly excludeDomains?: ReadonlyArray<string>\n /**\n * Override how results are rendered into the model-facing string.\n * Default: a numbered `title / url / snippet` list.\n */\n readonly render?: (results: ReadonlyArray<SearchResult>) => string\n}\n\n/**\n * The canonical web-search tool. Its `R` is just `WebSearch`, so providing\n * any search-provider Layer satisfies it and the model-facing contract\n * (name, description, schema) is identical no matter which backend answers\n * - swap `PerplexitySearch.layer` for `ExaSearch.layer` and the tool the\n * model sees does not change. Drops straight into a `Toolkit` and the\n * `LanguageModel` tool-calling loop.\n *\n * The model controls only `query` and `recency`; domain scoping and the\n * result cap are app policy, fixed here on the constructor. `Output` is the\n * rendered text (the model reads a numbered list better than raw\n * `SearchResult[]`; pass `render` to change the format); failures stay typed\n * on the `AiError` channel. To let the model recover from a failed search,\n * wrap the toolkit in `Toolkit.describeFailures(AiError.describe)`.\n *\n * This is a simple default implementation for quick use. For more elaborate\n * cases (a different output contract, more model-facing knobs), build your\n * own tool with `Tool.make` over the same `search` helper.\n */\nexport const webSearchTool = (\n options?: WebSearchToolOptions,\n): Tool.Tool<string, WebSearchToolArgs, never, string, AiError.AiError, WebSearch> => {\n const name = options?.name ?? \"web_search\"\n const render = options?.render ?? defaultRender\n const maxResults = options?.maxResults ?? 5\n const includeDomains = options?.includeDomains\n const excludeDomains = options?.excludeDomains\n return Tool.make({\n name,\n description:\n \"Search the web for current information. Returns ranked results with titles, URLs, and snippets.\",\n inputSchema: Tool.fromEffectSchema(WebSearchToolArgs),\n // The call is wrapped in a tracing span so agent traces show the tool\n // invocation (query, filters, result count) nested under the model turn.\n // `withSpan` is a no-op until a Tracer is installed, so this is free by\n // default and adds nothing to the requirements.\n run: (args) =>\n search({\n query: args.query,\n maxResults,\n ...(args.recency !== undefined && { recency: args.recency }),\n ...(includeDomains !== undefined && { includeDomains }),\n ...(excludeDomains !== undefined && { excludeDomains }),\n }).pipe(\n Effect.tap((r) => Effect.annotateCurrentSpan(\"web_search.result_count\", r.results.length)),\n Effect.map((r) => render(r.results)),\n Effect.withSpan(name, {\n kind: \"client\",\n attributes: {\n \"web_search.query\": args.query,\n \"web_search.max_results\": maxResults,\n ...(args.recency !== undefined && { \"web_search.recency\": args.recency }),\n ...(includeDomains !== undefined && { \"web_search.include_domains\": includeDomains }),\n ...(excludeDomains !== undefined && { \"web_search.exclude_domains\": excludeDomains }),\n },\n }),\n ),\n })\n}\n"],"mappings":";;;;;;;;;;;;;;AAaA,MAAM,oBAAoB,OAAO,OAAO;CACtC,OAAO,OAAO;CACd,SAAS,OAAO,SAAS,cAAc;CACxC,CAAC;;AAKF,MAAM,iBAAiB,YACrB,QAAQ,WAAW,IACf,sBACA,QACG,KAAK,GAAG,MAAM;CACb,MAAM,OAAO,GAAG,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,OAAO,EAAE;AACpD,QAAO,EAAE,YAAY,KAAA,IAAY,OAAO,GAAG,KAAK,OAAO,EAAE;EACzD,CACD,KAAK,OAAO;;;;;;;;;;;;;;;;;;;;AA2CrB,MAAa,iBACX,YACoF;CACpF,MAAM,OAAO,SAAS,QAAQ;CAC9B,MAAM,SAAS,SAAS,UAAU;CAClC,MAAM,aAAa,SAAS,cAAc;CAC1C,MAAM,iBAAiB,SAAS;CAChC,MAAM,iBAAiB,SAAS;AAChC,QAAOA,KAAU;EACf;EACA,aACE;EACF,aAAaC,iBAAsB,kBAAkB;EAKrD,MAAM,SACJ,OAAO;GACL,OAAO,KAAK;GACZ;GACA,GAAI,KAAK,YAAY,KAAA,KAAa,EAAE,SAAS,KAAK,SAAS;GAC3D,GAAI,mBAAmB,KAAA,KAAa,EAAE,gBAAgB;GACtD,GAAI,mBAAmB,KAAA,KAAa,EAAE,gBAAgB;GACvD,CAAC,CAAC,KACD,OAAO,KAAK,MAAM,OAAO,oBAAoB,2BAA2B,EAAE,QAAQ,OAAO,CAAC,EAC1F,OAAO,KAAK,MAAM,OAAO,EAAE,QAAQ,CAAC,EACpC,OAAO,SAAS,MAAM;GACpB,MAAM;GACN,YAAY;IACV,oBAAoB,KAAK;IACzB,0BAA0B;IAC1B,GAAI,KAAK,YAAY,KAAA,KAAa,EAAE,sBAAsB,KAAK,SAAS;IACxE,GAAI,mBAAmB,KAAA,KAAa,EAAE,8BAA8B,gBAAgB;IACpF,GAAI,mBAAmB,KAAA,KAAa,EAAE,8BAA8B,gBAAgB;IACrF;GACF,CAAC,CACH;EACJ,CAAC"}
1
+ {"version":3,"file":"WebSearchTool.mjs","names":["Tool.make","Tool.fromEffectSchema"],"sources":["../../src/web-search/WebSearchTool.ts"],"sourcesContent":["import { Effect, Schema } from \"effect\"\nimport type * as AiError from \"../domain/AiError.js\"\nimport * as Tool from \"../tool/Tool.js\"\nimport { search, SearchRecency, type SearchResult, WebSearch } from \"./WebSearch.js\"\n\n/**\n * Model-facing argument schema. Deliberately narrow: `query` plus the one\n * filter that is genuinely the model's call - `recency` (it knows whether a\n * question is about current events or evergreen). App-policy scoping\n * (`includeDomains` / `excludeDomains`) and the `maxResults` cost ceiling\n * are pinned on the constructor instead, so they are guaranteed rather than\n * left to the model to remember each call.\n */\nconst WebSearchToolArgs = Schema.Struct({\n query: Schema.String,\n recency: Schema.optional(SearchRecency),\n})\n\nexport type WebSearchToolArgs = typeof WebSearchToolArgs.Type\n\n/** Numbered `title / url / snippet` list - what a model reads best. */\nconst defaultRender = (results: ReadonlyArray<SearchResult>): string =>\n results.length === 0\n ? \"No results found.\"\n : results\n .map((r, i) => {\n const head = `${i + 1}. ${r.title ?? r.url}\\n ${r.url}`\n return r.snippet === undefined ? head : `${head}\\n ${r.snippet}`\n })\n .join(\"\\n\\n\")\n\nexport type WebSearchToolOptions = {\n /** Tool name the model sees. Default `\"web_search\"`. */\n readonly name?: string\n /**\n * App-fixed ceiling on results per call - a cost guard, not exposed to\n * the model. Default `5`.\n */\n readonly maxResults?: number\n /**\n * App-fixed allowlist applied to every search. A policy scope (\"only\n * search our docs\"), not a model knob - so it is enforced, not requested.\n */\n readonly includeDomains?: ReadonlyArray<string>\n /** App-fixed denylist applied to every search (\"never return X\"). */\n readonly excludeDomains?: ReadonlyArray<string>\n /**\n * Override how results are rendered into the model-facing string.\n * Default: a numbered `title / url / snippet` list.\n */\n readonly render?: (results: ReadonlyArray<SearchResult>) => string\n}\n\n/**\n * The canonical web-search tool. Its `R` is just `WebSearch`, so providing\n * any search-provider Layer satisfies it and the model-facing contract\n * (name, description, schema) is identical no matter which backend answers\n * - swap `PerplexitySearch.layer` for `ExaSearch.layer` and the tool the\n * model sees does not change. Drops straight into a `Toolkit` and the\n * `LanguageModel` tool-calling loop.\n *\n * The model controls only `query` and `recency`; domain scoping and the\n * result cap are app policy, fixed here on the constructor. `Output` is the\n * rendered text (the model reads a numbered list better than raw\n * `SearchResult[]`; pass `render` to change the format); failures stay typed\n * on the `AiError` channel. To let the model recover from a failed search,\n * wrap the toolkit in `Toolkit.describeFailures(AiError.describe)`.\n *\n * This is a simple default implementation for quick use. For more elaborate\n * cases (a different output contract, more model-facing knobs), build your\n * own tool with `Tool.make` over the same `search` helper.\n */\nexport const webSearchTool = (\n options?: WebSearchToolOptions,\n): Tool.Tool<string, WebSearchToolArgs, never, string, AiError.AiError, WebSearch> => {\n const name = options?.name ?? \"web_search\"\n const render = options?.render ?? defaultRender\n const maxResults = options?.maxResults ?? 5\n const includeDomains = options?.includeDomains\n const excludeDomains = options?.excludeDomains\n return Tool.make({\n name,\n description:\n \"Search the web for current information. Returns ranked results with titles, URLs, and snippets.\",\n inputSchema: Tool.fromEffectSchema(WebSearchToolArgs),\n // The call is wrapped in a tracing span so agent traces show the tool\n // invocation (query, filters, result count) nested under the model turn.\n // `withSpan` is a no-op until a Tracer is installed, so this is free by\n // default and adds nothing to the requirements.\n run: (args) =>\n search({\n query: args.query,\n maxResults,\n ...(args.recency !== undefined && { recency: args.recency }),\n ...(includeDomains !== undefined && { includeDomains }),\n ...(excludeDomains !== undefined && { excludeDomains }),\n }).pipe(\n Effect.tap((r) => Effect.annotateCurrentSpan(\"web_search.result_count\", r.results.length)),\n Effect.map((r) => render(r.results)),\n Effect.withSpan(name, {\n kind: \"client\",\n attributes: {\n \"web_search.query\": args.query,\n \"web_search.max_results\": maxResults,\n ...(args.recency !== undefined && { \"web_search.recency\": args.recency }),\n ...(includeDomains !== undefined && { \"web_search.include_domains\": includeDomains }),\n ...(excludeDomains !== undefined && { \"web_search.exclude_domains\": excludeDomains }),\n },\n }),\n ),\n })\n}\n"],"mappings":";;;;;;;;;;;;;;AAaA,MAAM,oBAAoB,OAAO,OAAO;CACtC,OAAO,OAAO;CACd,SAAS,OAAO,SAAS,aAAa;AACxC,CAAC;;AAKD,MAAM,iBAAiB,YACrB,QAAQ,WAAW,IACf,sBACA,QACG,KAAK,GAAG,MAAM;CACb,MAAM,OAAO,GAAG,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,OAAO,EAAE;CACpD,OAAO,EAAE,YAAY,KAAA,IAAY,OAAO,GAAG,KAAK,OAAO,EAAE;AAC3D,CAAC,CAAC,CACD,KAAK,MAAM;;;;;;;;;;;;;;;;;;;;AA2CpB,MAAa,iBACX,YACoF;CACpF,MAAM,OAAO,SAAS,QAAQ;CAC9B,MAAM,SAAS,SAAS,UAAU;CAClC,MAAM,aAAa,SAAS,cAAc;CAC1C,MAAM,iBAAiB,SAAS;CAChC,MAAM,iBAAiB,SAAS;CAChC,OAAOA,KAAU;EACf;EACA,aACE;EACF,aAAaC,iBAAsB,iBAAiB;EAKpD,MAAM,SACJ,OAAO;GACL,OAAO,KAAK;GACZ;GACA,GAAI,KAAK,YAAY,KAAA,KAAa,EAAE,SAAS,KAAK,QAAQ;GAC1D,GAAI,mBAAmB,KAAA,KAAa,EAAE,eAAe;GACrD,GAAI,mBAAmB,KAAA,KAAa,EAAE,eAAe;EACvD,CAAC,CAAC,CAAC,KACD,OAAO,KAAK,MAAM,OAAO,oBAAoB,2BAA2B,EAAE,QAAQ,MAAM,CAAC,GACzF,OAAO,KAAK,MAAM,OAAO,EAAE,OAAO,CAAC,GACnC,OAAO,SAAS,MAAM;GACpB,MAAM;GACN,YAAY;IACV,oBAAoB,KAAK;IACzB,0BAA0B;IAC1B,GAAI,KAAK,YAAY,KAAA,KAAa,EAAE,sBAAsB,KAAK,QAAQ;IACvE,GAAI,mBAAmB,KAAA,KAAa,EAAE,8BAA8B,eAAe;IACnF,GAAI,mBAAmB,KAAA,KAAa,EAAE,8BAA8B,eAAe;GACrF;EACF,CAAC,CACH;CACJ,CAAC;AACH"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-uai/core",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Low-level primitives (loop, conversation, items, tools, streaming codecs) for building AI agents with Effect.",
5
5
  "keywords": [
6
6
  "agents",
@@ -242,11 +242,11 @@
242
242
  "@standard-schema/spec": "^1.1.0"
243
243
  },
244
244
  "devDependencies": {
245
- "effect": "4.0.0-beta.94",
246
- "typescript": "^6.0.3"
245
+ "effect": "4.0.0-rc.111",
246
+ "typescript": "^7.0.2"
247
247
  },
248
248
  "peerDependencies": {
249
- "effect": ">=4.0.0-beta.94 <5.0.0"
249
+ "effect": ">=4.0.0-rc.111 <5.0.0"
250
250
  },
251
251
  "scripts": {
252
252
  "build": "tsdown",
@@ -68,10 +68,8 @@ describe("Loop.loop", () => {
68
68
 
69
69
  it("propagates errors from the body's stream", async () => {
70
70
  const boom = new Error("boom")
71
- const stream = loop(
72
- 0,
73
- (n: number): Stream.Stream<Step<number, number>, Error> =>
74
- n === 2 ? Stream.fail(boom) : Stream.succeed(value(n)).pipe(Stream.concat(next(n + 1))),
71
+ const stream = loop(0, (n: number): Stream.Stream<Step<number, number>, Error> =>
72
+ n === 2 ? Stream.fail(boom) : Stream.succeed(value(n)).pipe(Stream.concat(next(n + 1))),
75
73
  )
76
74
 
77
75
  const result = await Effect.runPromiseExit(Stream.runCollect(stream))
@@ -293,13 +291,12 @@ const conversationLoop = (initial: State, runTool: ToolRunner) =>
293
291
  ? Ref.update(textsRef, (t) => [...t, d.text])
294
292
  : Ref.update(toolCallsRef, (t) => [...t, { id: d.id, name: d.name }]),
295
293
  ),
296
- Stream.flatMap(
297
- (d): Stream.Stream<Step<UiEvent, State>> =>
298
- d.type === "text"
299
- ? Stream.fromIterable([value<UiEvent>({ type: "text", text: d.text })])
300
- : Stream.fromIterable([
301
- value<UiEvent>({ type: "tool_started", id: d.id, name: d.name }),
302
- ]),
294
+ Stream.flatMap((d): Stream.Stream<Step<UiEvent, State>> =>
295
+ d.type === "text"
296
+ ? Stream.fromIterable([value<UiEvent>({ type: "text", text: d.text })])
297
+ : Stream.fromIterable([
298
+ value<UiEvent>({ type: "tool_started", id: d.id, name: d.name }),
299
+ ]),
303
300
  ),
304
301
  )
305
302
 
@@ -314,9 +311,11 @@ const conversationLoop = (initial: State, runTool: ToolRunner) =>
314
311
 
315
312
  const turnItems: ReadonlyArray<HistoryItem> = [
316
313
  ...(texts.length > 0 ? [{ type: "assistant" as const, text: texts.join("") }] : []),
317
- ...toolCalls.map(
318
- (tc): HistoryItem => ({ type: "tool_call", id: tc.id, name: tc.name }),
319
- ),
314
+ ...toolCalls.map((tc): HistoryItem => ({
315
+ type: "tool_call",
316
+ id: tc.id,
317
+ name: tc.name,
318
+ })),
320
319
  ]
321
320
 
322
321
  const outcomes = toolCalls.map((call) => ({ call, outcome: runTool(call) }))
package/src/loop/Loop.ts CHANGED
@@ -229,91 +229,89 @@ type LoopBody<S, A, E, R> = (
229
229
  export const loop: {
230
230
  <S, A, E, R>(body: LoopBody<S, A, E, R>): (initial: S) => Stream.Stream<A, E, R>
231
231
  <S, A, E, R>(initial: S, body: LoopBody<S, A, E, R>): Stream.Stream<A, E, R>
232
- } = Function.dual(
233
- 2,
234
- <S, A, E, R>(initial: S, body: LoopBody<S, A, E, R>): Stream.Stream<A, E, R> =>
235
- Stream.scoped(
236
- Stream.fromPull(
237
- Effect.gen(function* () {
238
- const outerScope = yield* Effect.scope
239
- let state = initial
240
- let current: CurrentBody<S, A, E, R> | undefined
241
- let done = false
242
-
243
- const closeActive = (
244
- active: CurrentBody<S, A, E, R>,
245
- exit: Exit.Exit<unknown, unknown>,
246
- ) => {
247
- const isActive = current === active
248
- if (isActive) current = undefined
249
- // Scope.close is idempotent. Multiple paths can race to close the
250
- // active body during cancellation/failure, so closing twice is safe.
251
- return closeBody(active, exit)
252
- }
232
+ } = Function.dual(2, <S, A, E, R>(initial: S, body: LoopBody<S, A, E, R>): Stream.Stream<A, E, R> =>
233
+ Stream.scoped(
234
+ Stream.fromPull(
235
+ Effect.gen(function* () {
236
+ const outerScope = yield* Effect.scope
237
+ let state = initial
238
+ let current: CurrentBody<S, A, E, R> | undefined
239
+ let done = false
240
+
241
+ const closeActive = (
242
+ active: CurrentBody<S, A, E, R>,
243
+ exit: Exit.Exit<unknown, unknown>,
244
+ ) => {
245
+ const isActive = current === active
246
+ if (isActive) current = undefined
247
+ // Scope.close is idempotent. Multiple paths can race to close the
248
+ // active body during cancellation/failure, so closing twice is safe.
249
+ return closeBody(active, exit)
250
+ }
251
+
252
+ yield* Scope.addFinalizerExit(outerScope, (exit) =>
253
+ current === undefined ? Effect.void : closeActive(current, exit),
254
+ )
253
255
 
254
- yield* Scope.addFinalizerExit(outerScope, (exit) =>
255
- current === undefined ? Effect.void : closeActive(current, exit),
256
- )
257
-
258
- const pull = Effect.gen(function* () {
259
- while (true) {
260
- if (done) return yield* Cause.done()
261
-
262
- if (current === undefined) {
263
- const result = body(state)
264
- const stream = Effect.isEffect(result) ? Stream.unwrap(result) : result
265
- const bodyScope = yield* Scope.fork(outerScope)
266
- const bodyPull = yield* Channel.toPullScoped(
267
- Stream.toChannel(stream),
268
- bodyScope,
269
- ).pipe(Effect.onError((cause) => Scope.close(bodyScope, Exit.failCause(cause))))
270
- current = { scope: bodyScope, pull: bodyPull }
271
- }
256
+ const pull = Effect.gen(function* () {
257
+ while (true) {
258
+ if (done) return yield* Cause.done()
259
+
260
+ if (current === undefined) {
261
+ const result = body(state)
262
+ const stream = Effect.isEffect(result) ? Stream.unwrap(result) : result
263
+ const bodyScope = yield* Scope.fork(outerScope)
264
+ const bodyPull = yield* Channel.toPullScoped(
265
+ Stream.toChannel(stream),
266
+ bodyScope,
267
+ ).pipe(Effect.onError((cause) => Scope.close(bodyScope, Exit.failCause(cause))))
268
+ current = { scope: bodyScope, pull: bodyPull }
269
+ }
272
270
 
273
- const active = current
274
- const chunk = yield* active.pull.pipe(
275
- Effect.catchIf(Cause.isDone, () =>
276
- closeActive(active, Exit.void).pipe(
277
- Effect.as(undefined as ReadonlyArray<Step<A, S>> | undefined),
278
- ),
271
+ const active = current
272
+ const chunk = yield* active.pull.pipe(
273
+ Effect.catchIf(Cause.isDone, () =>
274
+ closeActive(active, Exit.void).pipe(
275
+ Effect.as(undefined as ReadonlyArray<Step<A, S>> | undefined),
279
276
  ),
280
- Effect.onError((cause) => closeActive(active, Exit.failCause(cause))),
281
- )
277
+ ),
278
+ Effect.onError((cause) => closeActive(active, Exit.failCause(cause))),
279
+ )
280
+
281
+ if (chunk === undefined) {
282
+ done = true
283
+ return yield* Cause.done()
284
+ }
285
+
286
+ const { values, decision } = partitionChunk(chunk)
282
287
 
283
- if (chunk === undefined) {
288
+ if (Option.isSome(decision)) {
289
+ yield* closeActive(active, Exit.void)
290
+ if (decision.value._tag === "Stop" || decision.value._tag === "StopWith") {
291
+ // `loop` has no next iteration to apply StopWith's state to;
292
+ // the state lands in `loopOver`'s outer ref or
293
+ // `loopWithState`'s SubscriptionRef via their taps.
284
294
  done = true
285
- return yield* Cause.done()
295
+ } else if (decision.value._tag === "Next") {
296
+ state = decision.value.state
286
297
  }
298
+ }
287
299
 
288
- const { values, decision } = partitionChunk(chunk)
289
-
290
- if (Option.isSome(decision)) {
291
- yield* closeActive(active, Exit.void)
292
- if (decision.value._tag === "Stop" || decision.value._tag === "StopWith") {
293
- // `loop` has no next iteration to apply StopWith's state to;
294
- // the state lands in `loopOver`'s outer ref or
295
- // `loopWithState`'s SubscriptionRef via their taps.
296
- done = true
297
- } else if (decision.value._tag === "Next") {
298
- state = decision.value.state
299
- }
300
- }
300
+ // Emit the values seen so far if any. Chunks from a Stream pull
301
+ // are non-empty, so when `decision` is `None` every step was
302
+ // a `Value` and `values` is non-empty here. With a decision and
303
+ // no preceding values, fall through to the next iteration.
304
+ if (isNonEmpty(values)) return values
305
+ }
306
+ })
301
307
 
302
- // Emit the values seen so far if any. Chunks from a Stream pull
303
- // are non-empty, so when `decision` is `None` every step was
304
- // a `Value` and `values` is non-empty here. With a decision and
305
- // no preceding values, fall through to the next iteration.
306
- if (isNonEmpty(values)) return values
307
- }
308
- })
309
-
310
- // `Stream.fromPull` expects the generator to RETURN the pull effect,
311
- // not run it; `return yield* pull` would execute a pull and break it.
312
- // @effect-diagnostics-next-line effect/returnEffectInGen:off
313
- return pull
314
- }),
315
- ),
308
+ // `Stream.fromPull` expects the generator to RETURN the pull effect,
309
+ // not run it; `return yield* pull` would execute a pull and break it.
310
+ // @effect-diagnostics-next-line effect/returnEffectInGen:off
311
+ return pull
312
+ }),
316
313
  ),
314
+ ),
317
315
  )
318
316
 
319
317
  // ---------------------------------------------------------------------------