@effect-uai/core 0.17.0 → 0.19.0-dev-20261109183959

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 (218) hide show
  1. package/README.md +5 -5
  2. package/dist/Content-D_Qfn8Ja.d.mts +48 -0
  3. package/dist/Content-D_Qfn8Ja.d.mts.map +1 -0
  4. package/dist/File-B923KvZ9.d.mts +46 -0
  5. package/dist/File-B923KvZ9.d.mts.map +1 -0
  6. package/dist/{Image-Cv6iBLTy.d.mts → Image-Bzc1H_UK.d.mts} +19 -8
  7. package/dist/Image-Bzc1H_UK.d.mts.map +1 -0
  8. package/dist/{Items-C7MyrYPX.d.mts → Items-Bvx8s9QH.d.mts} +109 -16
  9. package/dist/Items-Bvx8s9QH.d.mts.map +1 -0
  10. package/dist/{Loop-ChpaO-ya.d.mts → Loop-CeA0AelN.d.mts} +7 -6
  11. package/dist/Loop-CeA0AelN.d.mts.map +1 -0
  12. package/dist/Tool-Bkryw6-h.d.mts +206 -0
  13. package/dist/Tool-Bkryw6-h.d.mts.map +1 -0
  14. package/dist/ToolEvent-9inLx5cI.d.mts +22 -0
  15. package/dist/ToolEvent-9inLx5cI.d.mts.map +1 -0
  16. package/dist/ToolOutput-BNTIQgGB.d.mts +151 -0
  17. package/dist/ToolOutput-BNTIQgGB.d.mts.map +1 -0
  18. package/dist/Toolkit-D2VGeD5R.d.mts +212 -0
  19. package/dist/Toolkit-D2VGeD5R.d.mts.map +1 -0
  20. package/dist/browser/BrowserTool.d.mts +84 -22
  21. package/dist/browser/BrowserTool.d.mts.map +1 -1
  22. package/dist/browser/BrowserTool.mjs +5 -0
  23. package/dist/browser/BrowserTool.mjs.map +1 -1
  24. package/dist/capabilities/Capabilities.d.mts +1 -1
  25. package/dist/decision-model/Decision.test.mjs +4 -4
  26. package/dist/dist-B5K-y4Be.mjs +191 -0
  27. package/dist/dist-B5K-y4Be.mjs.map +1 -0
  28. package/dist/dist-CorQTQL-.mjs +1533 -0
  29. package/dist/dist-CorQTQL-.mjs.map +1 -0
  30. package/dist/dist-DNeuh84d.mjs +7 -0
  31. package/dist/dist-DNeuh84d.mjs.map +1 -0
  32. package/dist/dist-DzeSyeYF.mjs +10253 -0
  33. package/dist/dist-DzeSyeYF.mjs.map +1 -0
  34. package/dist/domain/File.d.mts +2 -0
  35. package/dist/domain/File.mjs +51 -0
  36. package/dist/domain/File.mjs.map +1 -0
  37. package/dist/domain/Image.d.mts +2 -2
  38. package/dist/domain/Image.mjs +12 -2
  39. package/dist/domain/Image.mjs.map +1 -1
  40. package/dist/domain/Items.d.mts +2 -2
  41. package/dist/domain/Items.mjs +65 -4
  42. package/dist/domain/Items.mjs.map +1 -1
  43. package/dist/domain/Realtime.d.mts +72 -490
  44. package/dist/domain/Realtime.d.mts.map +1 -1
  45. package/dist/domain/Research.d.mts +1 -1
  46. package/dist/domain/Transcript.test.mjs +3 -3
  47. package/dist/domain/Turn.d.mts +57 -262
  48. package/dist/domain/Turn.d.mts.map +1 -1
  49. package/dist/domain/Turn.mjs +1 -1
  50. package/dist/domain/Turn.test.mjs +2 -2
  51. package/dist/embedding-model/Embedding.d.mts +1 -1
  52. package/dist/embedding-model/EmbeddingModel.test.mjs +2 -2
  53. package/dist/embedding-model/EmbeddingModel.test.mjs.map +1 -1
  54. package/dist/image-generator/ImageGenerator.d.mts +10 -66
  55. package/dist/image-generator/ImageGenerator.d.mts.map +1 -1
  56. package/dist/index.C4tKZ0yW-LuFnBtmu.mjs +7042 -0
  57. package/dist/index.C4tKZ0yW-LuFnBtmu.mjs.map +1 -0
  58. package/dist/index.d.mts +10 -9
  59. package/dist/index.mjs +7 -6
  60. package/dist/language-model/LanguageModel.d.mts +2 -2
  61. package/dist/language-model/LanguageModel.test.mjs +2 -2
  62. package/dist/loop/Loop.d.mts +1 -1
  63. package/dist/loop/Loop.mjs.map +1 -1
  64. package/dist/loop/Loop.test.mjs +3 -3
  65. package/dist/math/Probability.test.mjs +2 -2
  66. package/dist/messenger/Messenger.d.mts +43 -289
  67. package/dist/messenger/Messenger.d.mts.map +1 -1
  68. package/dist/messenger/MessengerAdapter.test.mjs +3 -3
  69. package/dist/music-generator/MusicGenerator.test.mjs +3 -3
  70. package/dist/observability/Metrics.d.mts +1 -1
  71. package/dist/observability/Metrics.test.mjs +3 -3
  72. package/dist/observability/Telemetry.d.mts +1 -1
  73. package/dist/observability/Telemetry.mjs +1 -1
  74. package/dist/observability/Telemetry.mjs.map +1 -1
  75. package/dist/observability/Telemetry.test.mjs +4 -4
  76. package/dist/observability/Telemetry.test.mjs.map +1 -1
  77. package/dist/realtime/RealtimeSession.d.mts +1 -1
  78. package/dist/realtime/RealtimeSession.test.mjs +4 -4
  79. package/dist/retry/Retry.test.mjs +2 -2
  80. package/dist/sandbox/Sandbox.d.mts +32 -237
  81. package/dist/sandbox/Sandbox.d.mts.map +1 -1
  82. package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs +3 -3
  83. package/dist/streaming/JSONL.test.mjs +2 -2
  84. package/dist/streaming/Multipart.d.mts +1 -1
  85. package/dist/streaming/Multipart.mjs +3 -2
  86. package/dist/streaming/Multipart.mjs.map +1 -1
  87. package/dist/streaming/Multipart.test.mjs +28 -0
  88. package/dist/streaming/Multipart.test.mjs.map +1 -0
  89. package/dist/streaming/SSE.d.mts +1 -1
  90. package/dist/streaming/SSE.mjs +2 -2
  91. package/dist/streaming/SSE.mjs.map +1 -1
  92. package/dist/streaming/SSE.test.mjs +2 -2
  93. package/dist/streaming/Settle.test.mjs +3 -3
  94. package/dist/streaming/WebSocketSession.d.mts +5 -3
  95. package/dist/streaming/WebSocketSession.d.mts.map +1 -1
  96. package/dist/streaming/WebSocketSession.mjs +22 -10
  97. package/dist/streaming/WebSocketSession.mjs.map +1 -1
  98. package/dist/streaming/WebSocketSession.test.mjs +41 -5
  99. package/dist/streaming/WebSocketSession.test.mjs.map +1 -1
  100. package/dist/structured-format/StructuredFormat.mjs.map +1 -1
  101. package/dist/structured-format/StructuredFormat.test.mjs +2 -2
  102. package/dist/testing/FakeWebSocket.d.mts +5 -1
  103. package/dist/testing/FakeWebSocket.d.mts.map +1 -1
  104. package/dist/testing/FakeWebSocket.mjs +12 -6
  105. package/dist/testing/FakeWebSocket.mjs.map +1 -1
  106. package/dist/testing/MockMessenger.d.mts +19 -134
  107. package/dist/testing/MockMessenger.d.mts.map +1 -1
  108. package/dist/testing/MockProvider.d.mts +1 -1
  109. package/dist/testing/MockSandbox.d.mts +65 -446
  110. package/dist/testing/MockSandbox.d.mts.map +1 -1
  111. package/dist/tool/Content.d.mts +2 -0
  112. package/dist/tool/Content.mjs +46 -0
  113. package/dist/tool/Content.mjs.map +1 -0
  114. package/dist/tool/Content.test.d.mts +1 -0
  115. package/dist/tool/Content.test.mjs +48 -0
  116. package/dist/tool/Content.test.mjs.map +1 -0
  117. package/dist/tool/HistoryCheck.d.mts +6 -15
  118. package/dist/tool/HistoryCheck.d.mts.map +1 -1
  119. package/dist/tool/HistoryCheck.mjs +10 -24
  120. package/dist/tool/HistoryCheck.mjs.map +1 -1
  121. package/dist/tool/Tool.d.mts +2 -2
  122. package/dist/tool/Tool.mjs +55 -130
  123. package/dist/tool/Tool.mjs.map +1 -1
  124. package/dist/tool/Tool.test.mjs +222 -178
  125. package/dist/tool/Tool.test.mjs.map +1 -1
  126. package/dist/tool/ToolDecision.d.mts +164 -0
  127. package/dist/tool/ToolDecision.d.mts.map +1 -0
  128. package/dist/tool/ToolDecision.mjs +146 -0
  129. package/dist/tool/ToolDecision.mjs.map +1 -0
  130. package/dist/tool/ToolDecision.test.d.mts +1 -0
  131. package/dist/tool/ToolDecision.test.mjs +330 -0
  132. package/dist/tool/ToolDecision.test.mjs.map +1 -0
  133. package/dist/tool/ToolEvent.d.mts +2 -2
  134. package/dist/tool/ToolEvent.mjs +2 -34
  135. package/dist/tool/ToolEvent.mjs.map +1 -1
  136. package/dist/tool/ToolOutput.d.mts +2 -0
  137. package/dist/tool/ToolOutput.mjs +128 -0
  138. package/dist/tool/ToolOutput.mjs.map +1 -0
  139. package/dist/tool/ToolOutput.test.d.mts +1 -0
  140. package/dist/tool/ToolOutput.test.mjs +153 -0
  141. package/dist/tool/ToolOutput.test.mjs.map +1 -0
  142. package/dist/tool/Toolkit.d.mts +2 -2
  143. package/dist/tool/Toolkit.mjs +230 -165
  144. package/dist/tool/Toolkit.mjs.map +1 -1
  145. package/dist/tool/Toolkit.test.mjs +433 -391
  146. package/dist/tool/Toolkit.test.mjs.map +1 -1
  147. package/dist/transcriber/Transcriber.test.mjs +3 -3
  148. package/dist/web-read/WebReadTool.d.mts +2 -2
  149. package/dist/web-read/WebReadTool.mjs +1 -0
  150. package/dist/web-read/WebReadTool.mjs.map +1 -1
  151. package/dist/web-search/WebSearchTool.d.mts +2 -2
  152. package/dist/web-search/WebSearchTool.mjs +1 -0
  153. package/dist/web-search/WebSearchTool.mjs.map +1 -1
  154. package/package.json +18 -10
  155. package/src/browser/BrowserTool.ts +5 -0
  156. package/src/domain/File.ts +79 -0
  157. package/src/domain/Image.ts +14 -4
  158. package/src/domain/Items.ts +39 -3
  159. package/src/embedding-model/EmbeddingModel.test.ts +2 -2
  160. package/src/index.ts +3 -2
  161. package/src/loop/Loop.ts +25 -14
  162. package/src/observability/Telemetry.test.ts +1 -1
  163. package/src/observability/Telemetry.ts +2 -2
  164. package/src/streaming/Multipart.test.ts +26 -0
  165. package/src/streaming/Multipart.ts +6 -5
  166. package/src/streaming/SSE.ts +2 -2
  167. package/src/streaming/WebSocketSession.test.ts +54 -2
  168. package/src/streaming/WebSocketSession.ts +27 -6
  169. package/src/structured-format/StructuredFormat.ts +1 -1
  170. package/src/testing/FakeWebSocket.ts +21 -6
  171. package/src/tool/Content.test.ts +40 -0
  172. package/src/tool/Content.ts +38 -0
  173. package/src/tool/HistoryCheck.ts +21 -26
  174. package/src/tool/Tool.test.ts +240 -241
  175. package/src/tool/Tool.ts +204 -309
  176. package/src/tool/ToolDecision.test.ts +301 -0
  177. package/src/tool/ToolDecision.ts +360 -0
  178. package/src/tool/ToolEvent.ts +21 -41
  179. package/src/tool/ToolOutput.test.ts +132 -0
  180. package/src/tool/ToolOutput.ts +198 -0
  181. package/src/tool/Toolkit.test.ts +594 -454
  182. package/src/tool/Toolkit.ts +631 -356
  183. package/src/web-read/WebReadTool.ts +2 -1
  184. package/src/web-search/WebSearchTool.ts +2 -1
  185. package/dist/Image-Cv6iBLTy.d.mts.map +0 -1
  186. package/dist/Items-C7MyrYPX.d.mts.map +0 -1
  187. package/dist/Loop-ChpaO-ya.d.mts.map +0 -1
  188. package/dist/Tool-BF78QWtn.d.mts +0 -314
  189. package/dist/Tool-BF78QWtn.d.mts.map +0 -1
  190. package/dist/ToolEvent-Di4a723B.d.mts +0 -144
  191. package/dist/ToolEvent-Di4a723B.d.mts.map +0 -1
  192. package/dist/ToolResult-BsYQRjmW.d.mts +0 -152
  193. package/dist/ToolResult-BsYQRjmW.d.mts.map +0 -1
  194. package/dist/Toolkit-tlL0F2YR.d.mts +0 -193
  195. package/dist/Toolkit-tlL0F2YR.d.mts.map +0 -1
  196. package/dist/dist-BaenoU1A.mjs +0 -145
  197. package/dist/dist-BaenoU1A.mjs.map +0 -1
  198. package/dist/dist-nohcnkD6.mjs +0 -182
  199. package/dist/dist-nohcnkD6.mjs.map +0 -1
  200. package/dist/magic-string.es-CB2hOw9v.mjs +0 -1014
  201. package/dist/magic-string.es-CB2hOw9v.mjs.map +0 -1
  202. package/dist/test.DNmyFkvJ-YPzDR0Co.mjs +0 -10254
  203. package/dist/test.DNmyFkvJ-YPzDR0Co.mjs.map +0 -1
  204. package/dist/tool/Approval.d.mts +0 -113
  205. package/dist/tool/Approval.d.mts.map +0 -1
  206. package/dist/tool/Approval.mjs +0 -80
  207. package/dist/tool/Approval.mjs.map +0 -1
  208. package/dist/tool/Approval.test.mjs +0 -371
  209. package/dist/tool/Approval.test.mjs.map +0 -1
  210. package/dist/tool/ToolResult.d.mts +0 -2
  211. package/dist/tool/ToolResult.mjs +0 -85
  212. package/dist/tool/ToolResult.mjs.map +0 -1
  213. package/dist/utils-CiH_DjFW.mjs +0 -3918
  214. package/dist/utils-CiH_DjFW.mjs.map +0 -1
  215. package/src/tool/Approval.test.ts +0 -400
  216. package/src/tool/Approval.ts +0 -181
  217. package/src/tool/ToolResult.ts +0 -114
  218. /package/dist/{tool/Approval.test.d.mts → streaming/Multipart.test.d.mts} +0 -0
@@ -1 +1 @@
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
+ {"version":3,"file":"Toolkit.test.mjs","names":["Toolkit.run","Toolkit.isOutcome","Tool.make","Tool.declare","Tool.noInput","Toolkit.make","Toolkit.describeFailures","expect","ToolOutput.OutputInvalid","Toolkit.output","Toolkit.decode","Content.image","Content.Value","ToolOutput.Cancelled","ToolOutput.failure","ToolOutput.CoreError","Tool.withFailures","Toolkit.close","Toolkit.UndeclaredFailure","Toolkit.withFailures","Toolkit.split","ToolOutput.InputInvalid","Toolkit.complete","Toolkit.next","Toolkit.wrap","Tool.ToolFailed","Toolkit.compose","Toolkit.fromArray","Toolkit.DuplicateToolName","Toolkit.makeNamespaced","Toolkit.namespace"],"sources":["../../src/tool/Toolkit.test.ts"],"sourcesContent":["import { describe, expect, expectTypeOf, it } from \"@effect/vitest\"\nimport {\n Cause,\n Context,\n Deferred,\n Effect,\n Exit,\n Layer,\n Match,\n pipe,\n Result,\n Schema,\n Stream,\n} from \"effect\"\nimport { imageBytes } from \"../domain/Image.js\"\nimport type { HistoryItem, ToolCall } from \"../domain/Items.js\"\nimport type { Turn } from \"../domain/Turn.js\"\nimport * as Content from \"./Content.js\"\nimport * as Tool from \"./Tool.js\"\nimport * as Toolkit from \"./Toolkit.js\"\nimport * as ToolOutput from \"./ToolOutput.js\"\n\nconst call = (name: string, id: string, args = \"{}\"): ToolCall => ({\n type: \"function_call\",\n call_id: id,\n name,\n arguments: args,\n})\n\nconst collect = <T extends Toolkit.Toolkit>(\n toolkit: T,\n calls: ReadonlyArray<ToolCall>,\n options?: Toolkit.ExecuteOptions,\n) => Stream.runCollect(Toolkit.run(toolkit, calls, options))\n\n// In call order: concurrency 1.\nconst outcomes = <T extends Toolkit.Toolkit>(toolkit: T, calls: ReadonlyArray<ToolCall>) =>\n Toolkit.run(toolkit, calls, { concurrency: 1 }).pipe(\n Stream.filter(Toolkit.isOutcome),\n Stream.runCollect,\n )\n\nconst failureOf = <R extends Result.Result<unknown, unknown>>(\n r: R,\n): Extract<R, { readonly _tag: \"Failure\" }>[\"failure\"] | undefined =>\n r._tag === \"Failure\" ? r.failure : undefined\n\nclass CityNotFound extends Schema.TaggedError<CityNotFound>()(\"CityNotFound\", {\n city: Schema.String,\n}) {}\nclass ApiDown extends Schema.TaggedError<ApiDown>()(\"ApiDown\", {}) {}\n\nconst Weather = Schema.Struct({ city: Schema.String, at: Schema.DateFromString })\nconst at = new Date(\"2026-01-01T12:00:00.000Z\")\n\nconst weather = Tool.make({\n name: \"weather\",\n description: \"Weather for a city.\",\n inputSchema: Schema.Struct({ city: Schema.String }),\n outputSchema: Weather,\n failureSchema: CityNotFound,\n run: ({ city }) =>\n Effect.gen(function* () {\n if (city === \"Atlantis\") return yield* new CityNotFound({ city })\n if (city === \"down\") return yield* new ApiDown()\n if (city === \"bug\") return yield* Effect.die(\"defect\")\n return { city, at }\n }),\n})\n\nconst search = Tool.make({\n name: \"search\",\n description: \"Search, reporting hits as it reads pages.\",\n inputSchema: Schema.Struct({ query: Schema.String }),\n outputSchema: Schema.Struct({ hits: Schema.Number }),\n run: () => Stream.fromIterable([{ hits: 1 }, { hits: 3 }, { hits: 4 }]),\n})\n\n// A declared tool: the loop handles its calls.\nconst escalate = Tool.declare({ name: \"escalate\", description: \"\", inputSchema: Tool.noInput })\n\nconst kit = Toolkit.make(weather, search, escalate)\n\ndescribe(\"Toolkit.run\", () => {\n it.effect(\"emits each of a Stream tool's values as a partial, then the last as the result\", () =>\n Effect.gen(function* () {\n const events = yield* collect(kit, [call(\"search\", \"s1\", '{\"query\":\"x\"}')])\n expect(events.map((e) => (e._tag === \"Partial\" ? e.value : e.result))).toEqual([\n { hits: 1 },\n { hits: 3 },\n { hits: 4 },\n Result.succeed({ hits: 4 }),\n ])\n }),\n )\n\n it.effect(\"emits a partial as soon as the tool produces it, not when the next arrives\", () =>\n Effect.gen(function* () {\n const gate = yield* Deferred.make<void>()\n const slow = Tool.make({\n name: \"slow\",\n description: \"\",\n inputSchema: Tool.noInput,\n outputSchema: Schema.String,\n run: () =>\n Stream.concat(\n Stream.succeed(\"searching...\"),\n Stream.fromEffect(Effect.as(Deferred.await(gate), \"found\")),\n ),\n })\n // The second value waits for the first partial: a delayed partial deadlocks.\n const events = yield* Toolkit.run(Toolkit.make(slow), [call(\"slow\", \"1\")]).pipe(\n Stream.tap((e) =>\n e._tag === \"Partial\" && e.value === \"searching...\"\n ? Deferred.succeed(gate, undefined)\n : Effect.void,\n ),\n Stream.runCollect,\n )\n expect(events.map((e) => (e._tag === \"Partial\" ? e.value : e.result))).toEqual([\n \"searching...\",\n \"found\",\n Result.succeed(\"found\"),\n ])\n }),\n )\n\n it.effect(\"an Effect tool emits only its result, also after describeFailures\", () =>\n Effect.gen(function* () {\n const lisbon = [call(\"weather\", \"w1\", '{\"city\":\"Lisbon\"}')]\n const plain = yield* collect(kit, lisbon)\n const described = yield* collect(\n Toolkit.describeFailures(kit, () => \"failed\"),\n lisbon,\n )\n expect(plain.map((e) => e._tag)).toEqual([\"Output\"])\n expect(described.map((e) => e._tag)).toEqual([\"Output\"])\n }),\n )\n\n it.effect(\"hands on decoded values: a DateFromString field stays a Date\", () =>\n Effect.gen(function* () {\n const [event] = yield* outcomes(kit, [call(\"weather\", \"w1\", '{\"city\":\"Lisbon\"}')])\n expect(event?.result).toEqual(Result.succeed({ city: \"Lisbon\", at }))\n }),\n )\n\n it.effect(\"a declared error becomes a Failure; an undeclared one fails the stream\", () =>\n Effect.gen(function* () {\n const [event] = yield* outcomes(kit, [call(\"weather\", \"w1\", '{\"city\":\"Atlantis\"}')])\n expect(failureOf(event!.result)).toEqual(new CityNotFound({ city: \"Atlantis\" }))\n\n const down = yield* Effect.flip(collect(kit, [call(\"weather\", \"w2\", '{\"city\":\"down\"}')]))\n expect(down).toEqual(new ApiDown())\n\n const bug = yield* Effect.exit(collect(kit, [call(\"weather\", \"w3\", '{\"city\":\"bug\"}')]))\n expect(Exit.isFailure(bug) && Cause.hasDies(bug.cause)).toBe(true)\n }),\n )\n\n it.effect(\"reports what it could not run as core errors, without stopping other calls\", () =>\n Effect.gen(function* () {\n const events = yield* outcomes(kit, [\n call(\"weather\", \"1\", '{\"city\":7}'),\n call(\"weather\", \"2\", \"not json\"),\n call(\"nope\", \"3\"),\n call(\"escalate\", \"4\"),\n call(\"constructor\", \"5\"),\n call(\"search\", \"6\", '{\"query\":\"x\"}'),\n ])\n expect(events.map((e) => failureOf(e.result)?._tag)).toEqual([\n \"InputInvalid\",\n \"InputInvalid\",\n \"UnknownTool\",\n \"UnknownTool\",\n \"UnknownTool\",\n undefined,\n ])\n expect(failureOf(events[0]!.result)).toMatchObject({\n message: expect.stringContaining(\"city\"),\n })\n }),\n )\n\n it.effect(\"reports a value outputSchema rejects, or no value at all, as OutputInvalid\", () =>\n Effect.gen(function* () {\n const count = (values: ReadonlyArray<number>) =>\n Tool.make({\n name: \"count\",\n description: \"\",\n inputSchema: Tool.noInput,\n outputSchema: Schema.Int,\n run: () => Stream.fromIterable(values),\n })\n const [rejected] = yield* outcomes(Toolkit.make(count([1, 1.5])), [call(\"count\", \"1\")])\n const [empty] = yield* outcomes(Toolkit.make(count([])), [call(\"count\", \"2\")])\n expect(failureOf(rejected!.result)).toBeInstanceOf(ToolOutput.OutputInvalid)\n expect(failureOf(empty!.result)).toBeInstanceOf(ToolOutput.OutputInvalid)\n }),\n )\n\n it(\"type: events narrow per tool, the stream fails with each tool's undeclared errors\", () => {\n const stream = Toolkit.run(kit, [])\n expectTypeOf<Stream.Error<typeof stream>>().toEqualTypeOf<ApiDown>()\n type Done = Extract<\n Stream.Success<typeof stream>,\n { readonly _tag: \"Output\"; readonly tool: \"weather\" }\n >\n type Value = Extract<Done[\"result\"], { readonly _tag: \"Success\" }>[\"success\"]\n type Error = Extract<Done[\"result\"], { readonly _tag: \"Failure\" }>[\"failure\"]\n expectTypeOf<Value>().toEqualTypeOf<{ readonly city: string; readonly at: Date }>()\n expectTypeOf<Error>().toEqualTypeOf<CityNotFound | ToolOutput.RunError>()\n })\n\n it(\"type: an error one tool declares still fails the stream when another throws it\", () => {\n const loose = Tool.make({\n name: \"loose\",\n description: \"\",\n inputSchema: Tool.noInput,\n outputSchema: Schema.String,\n run: () => Effect.fail(new CityNotFound({ city: \"x\" })),\n })\n expectTypeOf<\n Toolkit.ToolkitE<ReturnType<typeof Toolkit.make<[typeof weather, typeof loose]>>>\n >().toEqualTypeOf<ApiDown | CityNotFound>()\n })\n\n it.effect(\"provides each tool's own requirements\", () =>\n Effect.gen(function* () {\n class Geo extends Context.Service<Geo, { readonly place: string }>()(\"test/Geo\") {}\n const where = Tool.make({\n name: \"where\",\n description: \"\",\n inputSchema: Tool.noInput,\n outputSchema: Schema.String,\n run: () =>\n Effect.gen(function* () {\n return (yield* Geo).place\n }),\n })\n const stream = Toolkit.run(Toolkit.make(where), [call(\"where\", \"1\")])\n expectTypeOf<Stream.Services<typeof stream>>().toEqualTypeOf<Geo>()\n const [event] = yield* stream.pipe(\n Stream.filter(Toolkit.isOutcome),\n Stream.runCollect,\n Effect.provide(Layer.succeed(Geo, { place: \"Lisbon\" })),\n )\n expect(event?.result).toEqual(Result.succeed(\"Lisbon\"))\n }),\n )\n})\n\ndescribe(\"Toolkit.output and Toolkit.decode\", () => {\n it.effect(\"encode with the tool's schemas and decode back to the same typed Result\", () =>\n Effect.gen(function* () {\n const events = yield* outcomes(kit, [\n call(\"weather\", \"1\", '{\"city\":\"Lisbon\"}'),\n call(\"weather\", \"2\", '{\"city\":\"Atlantis\"}'),\n ])\n const items = yield* Effect.forEach(events, Toolkit.output(kit))\n expect(items.map((i) => [i.output, i.isError])).toEqual([\n [[{ type: \"input_json\", value: { city: \"Lisbon\", at: at.toISOString() } }], undefined],\n [[{ type: \"input_json\", value: { _tag: \"CityNotFound\", city: \"Atlantis\" } }], true],\n ])\n\n const decoded = yield* Effect.forEach(items, (item) => Toolkit.decode(kit, \"weather\", item))\n expect(decoded).toEqual(events.map((e) => e.result))\n expectTypeOf(decoded[0]!).toEqualTypeOf<\n Result.Result<\n { readonly city: string; readonly at: Date },\n CityNotFound | ToolOutput.CoreError\n >\n >()\n }),\n )\n\n it.effect(\"with Content.Value, media gets its own part and reads back as a class\", () =>\n Effect.gen(function* () {\n const png = Content.image(imageBytes(new Uint8Array([1, 2]), \"image/png\"))\n const shot = Tool.make({\n name: \"shot\",\n description: \"\",\n inputSchema: Tool.noInput,\n outputSchema: Content.Value,\n run: () => Effect.succeed([{ title: \"Home\" }, png]),\n })\n const shots = Toolkit.make(shot)\n const [event] = yield* outcomes(shots, [call(\"shot\", \"1\")])\n const item = yield* Toolkit.output(shots, event!)\n expect(item.output.map((p) => p.type)).toEqual([\"input_json\", \"input_image\"])\n expect(yield* Toolkit.decode(shots, \"shot\", item)).toEqual(\n Result.succeed([{ title: \"Home\" }, png]),\n )\n }),\n )\n\n it.effect(\"decodes a call closed with core's Cancelled\", () =>\n Effect.gen(function* () {\n const cancelled = new ToolOutput.Cancelled({ message: \"user moved on\" })\n const item = yield* ToolOutput.failure({ call_id: \"1\" }, ToolOutput.CoreError, cancelled)\n expect(yield* Toolkit.decode(kit, \"weather\", item)).toEqual(Result.fail(cancelled))\n }),\n )\n})\n\ndescribe(\"Tool.withFailures and Toolkit.close\", () => {\n class Denied extends Schema.TaggedError<Denied>()(\"Denied\", { message: Schema.String }) {}\n\n // Only the tool that needs approval may be closed with `Denied`.\n const gated = Toolkit.make(Tool.withFailures(weather, Denied), search)\n const denied = new Denied({ message: \"not now\" })\n\n it.effect(\"a closing the tool declares round-trips through history\", () =>\n Effect.gen(function* () {\n const closed = yield* Toolkit.close(gated, call(\"weather\", \"1\"), denied)\n const item = yield* Toolkit.output(gated, closed)\n expect(item.isError).toBe(true)\n expect(yield* Toolkit.decode(gated, \"weather\", item)).toEqual(Result.fail(denied))\n }),\n )\n\n it.effect(\"closing with an error the call's tool doesn't declare fails at close\", () =>\n Effect.gen(function* () {\n const error = yield* Effect.flip(Toolkit.close(gated, call(\"search\", \"2\"), denied))\n expect(error).toBeInstanceOf(Toolkit.UndeclaredFailure)\n expect(error.tool).toBe(\"search\")\n }),\n )\n\n it.effect(\"with the tool's name, close checks the call belongs to that tool\", () =>\n Effect.gen(function* () {\n const closed = yield* Toolkit.close(gated, \"weather\", call(\"weather\", \"5\"), denied)\n expect(closed.tool).toBe(\"weather\")\n const error = yield* Effect.flip(Toolkit.close(gated, \"weather\", call(\"search\", \"6\"), denied))\n expect(error).toBeInstanceOf(Toolkit.UndeclaredFailure)\n }),\n )\n\n it(\"type: with the tool's name, the error must be that tool's\", () => {\n // @ts-expect-error search declares no Denied, though weather does\n Toolkit.close(gated, \"search\", call(\"search\", \"7\"), denied)\n })\n\n it.effect(\"core's errors close any call\", () =>\n Effect.gen(function* () {\n const cancelled = new ToolOutput.Cancelled({ message: \"moved on\" })\n const closed = yield* Toolkit.close(gated, call(\"search\", \"3\"), cancelled)\n expect(closed.result).toEqual(Result.fail(cancelled))\n }),\n )\n\n it.effect(\"Toolkit.withFailures declares the closing on every local tool\", () =>\n Effect.gen(function* () {\n const all = Toolkit.withFailures(kit, Denied)\n const closed = yield* Toolkit.close(all, call(\"search\", \"4\"), denied)\n const item = yield* Toolkit.output(all, closed)\n expect(yield* Toolkit.decode(all, \"search\", item)).toEqual(Result.fail(denied))\n }),\n )\n\n it.effect(\"keeps the tool's own failures declared\", () =>\n Effect.gen(function* () {\n const [event] = yield* outcomes(gated, [call(\"weather\", \"3\", '{\"city\":\"Atlantis\"}')])\n expect(failureOf(event!.result)).toEqual(new CityNotFound({ city: \"Atlantis\" }))\n }),\n )\n\n it(\"type: close takes only errors the toolkit declares\", () => {\n const decoded = Toolkit.decode(gated, \"weather\", {\n type: \"function_call_output\",\n call_id: \"1\",\n output: [],\n })\n expectTypeOf<Effect.Success<typeof decoded>>().toEqualTypeOf<\n Result.Result<\n { readonly city: string; readonly at: Date },\n CityNotFound | Denied | ToolOutput.CoreError\n >\n >()\n // @ts-expect-error ApiDown is no tool's declared failure\n Toolkit.close(gated, call(\"weather\", \"4\"), new ApiDown())\n })\n})\n\ndescribe(\"Toolkit.split and Toolkit.complete\", () => {\n const askUser = Tool.declare({\n name: \"ask_user\",\n description: \"\",\n inputSchema: Schema.Struct({ question: Schema.String }),\n outputSchema: Schema.String,\n })\n const finish = Tool.declare({\n name: \"finish\",\n description: \"\",\n inputSchema: Schema.Struct({ report: Schema.String }),\n })\n const agent = Toolkit.make(weather, askUser, finish)\n const turnOf = (...calls: ReadonlyArray<ToolCall>): Turn => ({\n items: calls,\n usage: {},\n stop_reason: \"tool_calls\",\n })\n\n it.effect(\"sorts a turn's calls: run, declared (decoded), invalid (closed)\", () =>\n Effect.gen(function* () {\n const { run, declared, invalid } = yield* Toolkit.split(\n agent,\n turnOf(\n call(\"weather\", \"1\", `{\"city\":\"Lisbon\"}`),\n call(\"ask_user\", \"2\", `{\"question\":\"Which city?\"}`),\n call(\"nope\", \"3\"),\n call(\"finish\", \"4\", `{}`),\n ),\n )\n expect(run.map((c) => c.call_id)).toEqual([\"1\", \"3\"])\n expect(declared).toEqual([\n {\n tool: \"ask_user\",\n call: call(\"ask_user\", \"2\", `{\"question\":\"Which city?\"}`),\n input: { question: \"Which city?\" },\n },\n ])\n expect(invalid).toHaveLength(1)\n expect(invalid[0]).toMatchObject({ call_id: \"4\", tool: \"finish\" })\n expect(failureOf(invalid[0]!.result)).toBeInstanceOf(ToolOutput.InputInvalid)\n }),\n )\n\n it.effect(\"declared calls are typed per tool: an exhaustive Match handles each\", () =>\n Effect.gen(function* () {\n const { declared } = yield* Toolkit.split(\n agent,\n turnOf(call(\"finish\", \"1\", `{\"report\":\"done\"}`), call(\"ask_user\", \"2\", `{\"question\":\"?\"}`)),\n )\n const route = Match.type<Toolkit.DeclaredCall<typeof agent>>().pipe(\n Match.discriminatorsExhaustive(\"tool\")({\n ask_user: (c) => `ask ${c.input.question}`,\n finish: (c) => `end ${c.input.report}`,\n }),\n )\n expect(declared.map(route)).toEqual([\"end done\", \"ask ?\"])\n Match.type<Toolkit.DeclaredCall<typeof agent>>().pipe(\n // @ts-expect-error finish is not handled\n Match.discriminatorsExhaustive(\"tool\")({ ask_user: () => \"ask\" }),\n )\n expectTypeOf<Toolkit.DeclaredCall<typeof agent>[\"tool\"]>().toEqualTypeOf<\n \"ask_user\" | \"finish\"\n >()\n }),\n )\n\n it.effect(\"complete answers a call with a value typed by outputSchema\", () =>\n Effect.gen(function* () {\n const answered = yield* Toolkit.complete(agent, \"ask_user\", call(\"ask_user\", \"1\"), \"Lisbon\")\n expect(answered).toEqual({\n _tag: \"Output\",\n call_id: \"1\",\n tool: \"ask_user\",\n result: Result.succeed(\"Lisbon\"),\n })\n const item = yield* Toolkit.output(agent, answered)\n expect(yield* Toolkit.decode(agent, \"ask_user\", item)).toEqual(Result.succeed(\"Lisbon\"))\n }),\n )\n\n it.effect(\"complete fails with UndeclaredFailure for another tool's call\", () =>\n Effect.gen(function* () {\n const error = yield* Effect.flip(\n Toolkit.complete(agent, \"ask_user\", call(\"finish\", \"1\"), \"Lisbon\"),\n )\n expect(error).toMatchObject({ _tag: \"UndeclaredFailure\", tool: \"ask_user\" })\n }),\n )\n\n it(\"type: complete's value is the tool's output\", () => {\n // @ts-expect-error ask_user's outputSchema is String\n Toolkit.complete(agent, \"ask_user\", call(\"ask_user\", \"1\"), 42)\n // @ts-expect-error finish has no outputSchema: nothing to complete with\n Toolkit.complete(agent, \"finish\", call(\"finish\", \"1\"), \"done\")\n })\n})\n\ndescribe(\"Toolkit.next\", () => {\n it.effect(\"forwards every event, then continues with the turn and encoded outputs appended\", () =>\n Effect.gen(function* () {\n const calls = [\n call(\"weather\", \"1\", '{\"city\":\"Lisbon\"}'),\n call(\"search\", \"2\", '{\"query\":\"x\"}'),\n ]\n const turn: Turn = { items: calls, usage: {}, stop_reason: \"tool_calls\" }\n const state = { history: [] as ReadonlyArray<HistoryItem>, round: 1 }\n\n const steps = yield* Toolkit.run(kit, calls, { concurrency: 1 }).pipe(\n Toolkit.next(kit, state, turn),\n Stream.runCollect,\n )\n // weather: Output; search: three partials and its Output.\n expect(steps.map((s) => s._tag)).toEqual([\n \"Value\",\n \"Value\",\n \"Value\",\n \"Value\",\n \"Value\",\n \"Next\",\n ])\n\n const last = steps.at(-1)\n expect(last?._tag === \"Next\" && last.state).toEqual({\n round: 1,\n history: [\n ...calls,\n {\n type: \"function_call_output\",\n call_id: \"1\",\n output: [{ type: \"input_json\", value: { city: \"Lisbon\", at: at.toISOString() } }],\n },\n {\n type: \"function_call_output\",\n call_id: \"2\",\n output: [{ type: \"input_json\", value: { hits: 4 } }],\n },\n ],\n })\n }),\n )\n})\n\ndescribe(\"Toolkit.wrap and Toolkit.describeFailures\", () => {\n class Audit extends Context.Service<\n Audit,\n { readonly record: (name: string) => Effect.Effect<void> }\n >()(\"test/Audit\") {}\n const audited: Toolkit.Middleware<Audit> = (run, name) => (input) =>\n Stream.unwrap(\n Effect.gen(function* () {\n yield* (yield* Audit).record(name)\n return run(input)\n }),\n )\n\n it.effect(\"wrap runs local tools through the middleware and tracks its requirement\", () =>\n Effect.gen(function* () {\n const recorded: Array<string> = []\n const wrapped = pipe(kit, Toolkit.wrap(audited))\n const stream = Toolkit.run(\n wrapped,\n [call(\"search\", \"1\", '{\"query\":\"x\"}'), call(\"escalate\", \"2\")],\n { concurrency: 1 },\n )\n expectTypeOf<Stream.Services<typeof stream>>().toEqualTypeOf<Audit>()\n\n const events = yield* stream.pipe(\n Stream.filter(Toolkit.isOutcome),\n Stream.runCollect,\n Effect.provideService(Audit, { record: (n) => Effect.sync(() => void recorded.push(n)) }),\n )\n expect(recorded).toEqual([\"search\"])\n expect(events.map((e) => e.result._tag)).toEqual([\"Success\", \"Failure\"])\n }),\n )\n\n it.effect(\"wrap keeps each tool's shape: an Effect tool emits no partials\", () =>\n Effect.gen(function* () {\n const wrapped = pipe(kit, Toolkit.wrap(audited))\n const events = yield* Toolkit.run(\n wrapped,\n [call(\"weather\", \"1\", '{\"city\":\"Lisbon\"}'), call(\"search\", \"2\", '{\"query\":\"x\"}')],\n { concurrency: 1 },\n ).pipe(Stream.runCollect, Effect.provideService(Audit, { record: () => Effect.void }))\n expect(events.map((e) => `${e.tool}:${e._tag}`)).toEqual([\n \"weather:Output\",\n \"search:Partial\",\n \"search:Partial\",\n \"search:Partial\",\n \"search:Output\",\n ])\n }),\n )\n\n it.effect(\n \"describeFailures turns undeclared errors into ToolFailed and keeps declared ones\",\n () =>\n Effect.gen(function* () {\n const described = Toolkit.describeFailures(kit, (e) => `upstream: ${e._tag}`)\n expectTypeOf<Toolkit.ToolkitE<typeof described>>().toEqualTypeOf<never>()\n\n const events = yield* outcomes(described, [\n call(\"weather\", \"1\", '{\"city\":\"down\"}'),\n call(\"weather\", \"2\", '{\"city\":\"Atlantis\"}'),\n ])\n expect(events.map((e) => failureOf(e.result))).toEqual([\n new Tool.ToolFailed({ message: \"upstream: ApiDown\" }),\n new CityNotFound({ city: \"Atlantis\" }),\n ])\n const item = yield* Toolkit.output(described, events[0]!)\n expect(item.output).toEqual([\n { type: \"input_json\", value: { _tag: \"ToolFailed\", message: \"upstream: ApiDown\" } },\n ])\n }),\n )\n\n it.effect(\"describeFailures keeps an error fatal when describe returns undefined\", () =>\n Effect.gen(function* () {\n class SessionGone extends Schema.TaggedError<SessionGone>()(\"SessionGone\", {}) {}\n const click = Tool.make({\n name: \"click\",\n description: \"\",\n inputSchema: Schema.Struct({ ref: Schema.String }),\n outputSchema: Schema.String,\n run: ({ ref }) =>\n Effect.gen(function* () {\n if (ref === \"gone\") return yield* new SessionGone()\n return yield* new ApiDown()\n }),\n })\n const kit = Toolkit.describeFailures(Toolkit.make(click), (e) =>\n e._tag === \"ApiDown\" ? \"the button did nothing\" : undefined,\n )\n expectTypeOf<Toolkit.ToolkitE<typeof kit>>().toEqualTypeOf<ApiDown | SessionGone>()\n\n const [stale] = yield* outcomes(kit, [call(\"click\", \"1\", '{\"ref\":\"b1\"}')])\n expect(failureOf(stale!.result)).toEqual(\n new Tool.ToolFailed({ message: \"the button did nothing\" }),\n )\n const gone = yield* Effect.flip(collect(kit, [call(\"click\", \"2\", '{\"ref\":\"gone\"}')]))\n expect(gone).toEqual(new SessionGone())\n }),\n )\n})\n\ndescribe(\"Toolkit.make, namespace and compose\", () => {\n const tool = <N extends string>(name: N) =>\n Tool.make({\n name,\n description: \"\",\n inputSchema: Tool.noInput,\n outputSchema: Schema.Number,\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.declare({ name: \"search\", description: \"\", inputSchema: Tool.noInput })\n // @ts-expect-error Duplicate tool name: search\n Toolkit.make(a, b)\n })\n\n it.effect(\"compose fails on a clash between dynamic toolkits, naming both sources\", () =>\n Effect.gen(function* () {\n const error = yield* Effect.flip(\n Toolkit.compose(Toolkit.fromArray([tool(\"search\")]), Toolkit.fromArray([tool(\"search\")])),\n )\n expect(error).toEqual(\n new Toolkit.DuplicateToolName({ name: \"search\", sources: [\"toolkit-0\", \"toolkit-1\"] }),\n )\n }),\n )\n\n it.effect(\"namespaced tools compose and run under their prefixed, typed names\", () =>\n Effect.gen(function* () {\n const github = Toolkit.makeNamespaced(\"github\", tool(\"search\"))\n const linear = Toolkit.namespace(\"linear\", Toolkit.make(tool(\"search\")))\n expectTypeOf(github.github__search.name).toEqualTypeOf<\"github__search\">()\n\n const both = yield* Toolkit.compose(github, linear)\n const [event] = yield* outcomes(both, [call(\"linear__search\", \"1\")])\n expect(event).toMatchObject({ tool: \"linear__search\", result: Result.succeed(0) })\n }),\n )\n})\n"],"mappings":";;;;;;;;;;;AAsBA,MAAM,QAAQ,MAAc,IAAY,OAAO,UAAoB;CACjE,MAAM;CACN,SAAS;CACT;CACA,WAAW;AACb;AAEA,MAAM,WACJ,SACA,OACA,YACG,OAAO,WAAWA,IAAY,SAAS,OAAO,OAAO,CAAC;AAG3D,MAAM,YAAuC,SAAY,UACvDA,IAAY,SAAS,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,KAC9C,OAAO,OAAOC,SAAiB,GAC/B,OAAO,UACT;AAEF,MAAM,aACJ,MAEA,EAAE,SAAS,YAAY,EAAE,UAAU,KAAA;AAErC,IAAM,eAAN,cAA2B,OAAO,YAA0B,CAAC,CAAC,gBAAgB,EAC5E,MAAM,OAAO,OACf,CAAC,CAAC,CAAC,CAAC;AACJ,IAAM,UAAN,cAAsB,OAAO,YAAqB,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpE,MAAM,UAAU,OAAO,OAAO;CAAE,MAAM,OAAO;CAAQ,IAAI,OAAO;AAAe,CAAC;AAChF,MAAM,qBAAK,IAAI,KAAK,0BAA0B;AAE9C,MAAM,UAAUC,KAAU;CACxB,MAAM;CACN,aAAa;CACb,aAAa,OAAO,OAAO,EAAE,MAAM,OAAO,OAAO,CAAC;CAClD,cAAc;CACd,eAAe;CACf,MAAM,EAAE,WACN,OAAO,IAAI,aAAa;EACtB,IAAI,SAAS,YAAY,OAAO,OAAO,IAAI,aAAa,EAAE,KAAK,CAAC;EAChE,IAAI,SAAS,QAAQ,OAAO,OAAO,IAAI,QAAQ;EAC/C,IAAI,SAAS,OAAO,OAAO,OAAO,OAAO,IAAI,QAAQ;EACrD,OAAO;GAAE;GAAM;EAAG;CACpB,CAAC;AACL,CAAC;AAED,MAAM,SAASA,KAAU;CACvB,MAAM;CACN,aAAa;CACb,aAAa,OAAO,OAAO,EAAE,OAAO,OAAO,OAAO,CAAC;CACnD,cAAc,OAAO,OAAO,EAAE,MAAM,OAAO,OAAO,CAAC;CACnD,WAAW,OAAO,aAAa;EAAC,EAAE,MAAM,EAAE;EAAG,EAAE,MAAM,EAAE;EAAG,EAAE,MAAM,EAAE;CAAC,CAAC;AACxE,CAAC;AAGD,MAAM,WAAWC,QAAa;CAAE,MAAM;CAAY,aAAa;CAAI,aAAaC;AAAa,CAAC;AAE9F,MAAM,MAAMC,OAAa,SAAS,QAAQ,QAAQ;AAElD,SAAS,qBAAqB;CAC5B,GAAG,OAAO,wFACR,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,OAAO,QAAQ,KAAK,CAAC,KAAK,UAAU,MAAM,mBAAe,CAAC,CAAC;EAC1E,aAAO,OAAO,KAAK,MAAO,EAAE,SAAS,YAAY,EAAE,QAAQ,EAAE,MAAO,CAAC,CAAC,CAAC,QAAQ;GAC7E,EAAE,MAAM,EAAE;GACV,EAAE,MAAM,EAAE;GACV,EAAE,MAAM,EAAE;GACV,OAAO,QAAQ,EAAE,MAAM,EAAE,CAAC;EAC5B,CAAC;CACH,CAAC,CACH;CAEA,GAAG,OAAO,oFACR,OAAO,IAAI,aAAa;EACtB,MAAM,OAAO,OAAO,SAAS,KAAW;EACxC,MAAM,OAAOH,KAAU;GACrB,MAAM;GACN,aAAa;GACb,aAAaE;GACb,cAAc,OAAO;GACrB,WACE,OAAO,OACL,OAAO,QAAQ,cAAc,GAC7B,OAAO,WAAW,OAAO,GAAG,SAAS,MAAM,IAAI,GAAG,OAAO,CAAC,CAC5D;EACJ,CAAC;EAED,MAAM,SAAS,OAAOJ,IAAYK,OAAa,IAAI,GAAG,CAAC,KAAK,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,KACzE,OAAO,KAAK,MACV,EAAE,SAAS,aAAa,EAAE,UAAU,iBAChC,SAAS,QAAQ,MAAM,KAAA,CAAS,IAChC,OAAO,IACb,GACA,OAAO,UACT;EACA,aAAO,OAAO,KAAK,MAAO,EAAE,SAAS,YAAY,EAAE,QAAQ,EAAE,MAAO,CAAC,CAAC,CAAC,QAAQ;GAC7E;GACA;GACA,OAAO,QAAQ,OAAO;EACxB,CAAC;CACH,CAAC,CACH;CAEA,GAAG,OAAO,2EACR,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,CAAC,KAAK,WAAW,MAAM,uBAAmB,CAAC;EAC1D,MAAM,QAAQ,OAAO,QAAQ,KAAK,MAAM;EACxC,MAAM,YAAY,OAAO,QACvBC,iBAAyB,WAAW,QAAQ,GAC5C,MACF;EACA,aAAO,MAAM,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;EACnD,aAAO,UAAU,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;CACzD,CAAC,CACH;CAEA,GAAG,OAAO,sEACR,OAAO,IAAI,aAAa;EACtB,MAAM,CAAC,SAAS,OAAO,SAAS,KAAK,CAAC,KAAK,WAAW,MAAM,uBAAmB,CAAC,CAAC;EACjF,aAAO,OAAO,MAAM,CAAC,CAAC,QAAQ,OAAO,QAAQ;GAAE,MAAM;GAAU;EAAG,CAAC,CAAC;CACtE,CAAC,CACH;CAEA,GAAG,OAAO,gFACR,OAAO,IAAI,aAAa;EACtB,MAAM,CAAC,SAAS,OAAO,SAAS,KAAK,CAAC,KAAK,WAAW,MAAM,yBAAqB,CAAC,CAAC;EACnF,aAAO,UAAU,MAAO,MAAM,CAAC,CAAC,CAAC,QAAQ,IAAI,aAAa,EAAE,MAAM,WAAW,CAAC,CAAC;EAE/E,MAAM,OAAO,OAAO,OAAO,KAAK,QAAQ,KAAK,CAAC,KAAK,WAAW,MAAM,qBAAiB,CAAC,CAAC,CAAC;EACxF,aAAO,IAAI,CAAC,CAAC,QAAQ,IAAI,QAAQ,CAAC;EAElC,MAAM,MAAM,OAAO,OAAO,KAAK,QAAQ,KAAK,CAAC,KAAK,WAAW,MAAM,oBAAgB,CAAC,CAAC,CAAC;EACtF,aAAO,KAAK,UAAU,GAAG,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;CACnE,CAAC,CACH;CAEA,GAAG,OAAO,oFACR,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,OAAO,SAAS,KAAK;GAClC,KAAK,WAAW,KAAK,cAAY;GACjC,KAAK,WAAW,KAAK,UAAU;GAC/B,KAAK,QAAQ,GAAG;GAChB,KAAK,YAAY,GAAG;GACpB,KAAK,eAAe,GAAG;GACvB,KAAK,UAAU,KAAK,mBAAe;EACrC,CAAC;EACD,aAAO,OAAO,KAAK,MAAM,UAAU,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ;GAC3D;GACA;GACA;GACA;GACA;GACA,KAAA;EACF,CAAC;EACD,aAAO,UAAU,OAAO,EAAE,CAAE,MAAM,CAAC,CAAC,CAAC,cAAc,EACjD,SAASC,aAAO,iBAAiB,MAAM,EACzC,CAAC;CACH,CAAC,CACH;CAEA,GAAG,OAAO,oFACR,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,WACbL,KAAU;GACR,MAAM;GACN,aAAa;GACb,aAAaE;GACb,cAAc,OAAO;GACrB,WAAW,OAAO,aAAa,MAAM;EACvC,CAAC;EACH,MAAM,CAAC,YAAY,OAAO,SAASC,OAAa,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,SAAS,GAAG,CAAC,CAAC;EACtF,MAAM,CAAC,SAAS,OAAO,SAASA,OAAa,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,SAAS,GAAG,CAAC,CAAC;EAC7E,aAAO,UAAU,SAAU,MAAM,CAAC,CAAC,CAAC,eAAeG,aAAwB;EAC3E,aAAO,UAAU,MAAO,MAAM,CAAC,CAAC,CAAC,eAAeA,aAAwB;CAC1E,CAAC,CACH;CAEA,GAAG,2FAA2F;EAC7E,IAAY,KAAK,CAAC,CAAC;EAClC,CAAA,GAAA,YAAA,aAAA,CAA0C,CAAC,CAAC,cAAuB;EAOnE,CAAA,GAAA,YAAA,aAAA,CAAoB,CAAC,CAAC,cAA4D;EAClF,CAAA,GAAA,YAAA,aAAA,CAAoB,CAAC,CAAC,cAAkD;CAC1E,CAAC;CAED,GAAG,wFAAwF;EAC3E,KAAU;GACtB,MAAM;GACN,aAAa;GACb,aAAaJ;GACb,cAAc,OAAO;GACrB,WAAW,OAAO,KAAK,IAAI,aAAa,EAAE,MAAM,IAAI,CAAC,CAAC;EACxD,CAAC;EACD,CAAA,GAAA,YAAA,aAAA,CAEE,CAAC,CAAC,cAAsC;CAC5C,CAAC;CAED,GAAG,OAAO,+CACR,OAAO,IAAI,aAAa;EACtB,MAAM,YAAY,QAAQ,QAAyC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;EAClF,MAAM,QAAQF,KAAU;GACtB,MAAM;GACN,aAAa;GACb,aAAaE;GACb,cAAc,OAAO;GACrB,WACE,OAAO,IAAI,aAAa;IACtB,QAAQ,OAAO,IAAA,CAAK;GACtB,CAAC;EACL,CAAC;EACD,MAAM,SAASJ,IAAYK,OAAa,KAAK,GAAG,CAAC,KAAK,SAAS,GAAG,CAAC,CAAC;EACpE,CAAA,GAAA,YAAA,aAAA,CAA6C,CAAC,CAAC,cAAmB;EAClE,MAAM,CAAC,SAAS,OAAO,OAAO,KAC5B,OAAO,OAAOJ,SAAiB,GAC/B,OAAO,YACP,OAAO,QAAQ,MAAM,QAAQ,KAAK,EAAE,OAAO,SAAS,CAAC,CAAC,CACxD;EACA,aAAO,OAAO,MAAM,CAAC,CAAC,QAAQ,OAAO,QAAQ,QAAQ,CAAC;CACxD,CAAC,CACH;AACF,CAAC;AAED,SAAS,2CAA2C;CAClD,GAAG,OAAO,iFACR,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,OAAO,SAAS,KAAK,CAClC,KAAK,WAAW,KAAK,uBAAmB,GACxC,KAAK,WAAW,KAAK,yBAAqB,CAC5C,CAAC;EACD,MAAM,QAAQ,OAAO,OAAO,QAAQ,QAAQQ,OAAe,GAAG,CAAC;EAC/D,aAAO,MAAM,KAAK,MAAM,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CACtD,CAAC,CAAC;GAAE,MAAM;GAAc,OAAO;IAAE,MAAM;IAAU,IAAI,GAAG,YAAY;GAAE;EAAE,CAAC,GAAG,KAAA,CAAS,GACrF,CAAC,CAAC;GAAE,MAAM;GAAc,OAAO;IAAE,MAAM;IAAgB,MAAM;GAAW;EAAE,CAAC,GAAG,IAAI,CACpF,CAAC;EAED,MAAM,UAAU,OAAO,OAAO,QAAQ,QAAQ,SAASC,OAAe,KAAK,WAAW,IAAI,CAAC;EAC3F,aAAO,OAAO,CAAC,CAAC,QAAQ,OAAO,KAAK,MAAM,EAAE,MAAM,CAAC;EACnD,CAAA,GAAA,YAAA,aAAA,CAAa,QAAQ,EAAG,CAAC,CAAC,cAKxB;CACJ,CAAC,CACH;CAEA,GAAG,OAAO,+EACR,OAAO,IAAI,aAAa;EACtB,MAAM,MAAMC,MAAc,WAAW,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC;EACzE,MAAM,OAAOT,KAAU;GACrB,MAAM;GACN,aAAa;GACb,aAAaE;GACb,cAAcQ;GACd,WAAW,OAAO,QAAQ,CAAC,EAAE,OAAO,OAAO,GAAG,GAAG,CAAC;EACpD,CAAC;EACD,MAAM,QAAQP,OAAa,IAAI;EAC/B,MAAM,CAAC,SAAS,OAAO,SAAS,OAAO,CAAC,KAAK,QAAQ,GAAG,CAAC,CAAC;EAC1D,MAAM,OAAO,OAAOI,OAAe,OAAO,KAAM;EAChD,aAAO,KAAK,OAAO,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,aAAa,CAAC;EAC5E,aAAO,OAAOC,OAAe,OAAO,QAAQ,IAAI,CAAC,CAAC,CAAC,QACjD,OAAO,QAAQ,CAAC,EAAE,OAAO,OAAO,GAAG,GAAG,CAAC,CACzC;CACF,CAAC,CACH;CAEA,GAAG,OAAO,qDACR,OAAO,IAAI,aAAa;EACtB,MAAM,YAAY,IAAIG,UAAqB,EAAE,SAAS,gBAAgB,CAAC;EACvE,MAAM,OAAO,OAAOC,QAAmB,EAAE,SAAS,IAAI,GAAGC,WAAsB,SAAS;EACxF,aAAO,OAAOL,OAAe,KAAK,WAAW,IAAI,CAAC,CAAC,CAAC,QAAQ,OAAO,KAAK,SAAS,CAAC;CACpF,CAAC,CACH;AACF,CAAC;AAED,SAAS,6CAA6C;CACpD,MAAM,eAAe,OAAO,YAAoB,CAAC,CAAC,UAAU,EAAE,SAAS,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;CAGzF,MAAM,QAAQL,OAAaW,aAAkB,SAAS,MAAM,GAAG,MAAM;CACrE,MAAM,SAAS,IAAI,OAAO,EAAE,SAAS,UAAU,CAAC;CAEhD,GAAG,OAAO,iEACR,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,OAAOC,MAAc,OAAO,KAAK,WAAW,GAAG,GAAG,MAAM;EACvE,MAAM,OAAO,OAAOR,OAAe,OAAO,MAAM;EAChD,aAAO,KAAK,OAAO,CAAC,CAAC,KAAK,IAAI;EAC9B,aAAO,OAAOC,OAAe,OAAO,WAAW,IAAI,CAAC,CAAC,CAAC,QAAQ,OAAO,KAAK,MAAM,CAAC;CACnF,CAAC,CACH;CAEA,GAAG,OAAO,8EACR,OAAO,IAAI,aAAa;EACtB,MAAM,QAAQ,OAAO,OAAO,KAAKO,MAAc,OAAO,KAAK,UAAU,GAAG,GAAG,MAAM,CAAC;EAClF,aAAO,KAAK,CAAC,CAAC,eAAeC,iBAAyB;EACtD,aAAO,MAAM,IAAI,CAAC,CAAC,KAAK,QAAQ;CAClC,CAAC,CACH;CAEA,GAAG,OAAO,0EACR,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,OAAOD,MAAc,OAAO,WAAW,KAAK,WAAW,GAAG,GAAG,MAAM;EAClF,aAAO,OAAO,IAAI,CAAC,CAAC,KAAK,SAAS;EAClC,MAAM,QAAQ,OAAO,OAAO,KAAKA,MAAc,OAAO,WAAW,KAAK,UAAU,GAAG,GAAG,MAAM,CAAC;EAC7F,aAAO,KAAK,CAAC,CAAC,eAAeC,iBAAyB;CACxD,CAAC,CACH;CAEA,GAAG,mEAAmE;EAEpE,MAAc,OAAO,UAAU,KAAK,UAAU,GAAG,GAAG,MAAM;CAC5D,CAAC;CAED,GAAG,OAAO,sCACR,OAAO,IAAI,aAAa;EACtB,MAAM,YAAY,IAAIL,UAAqB,EAAE,SAAS,WAAW,CAAC;EAClE,MAAM,SAAS,OAAOI,MAAc,OAAO,KAAK,UAAU,GAAG,GAAG,SAAS;EACzE,aAAO,OAAO,MAAM,CAAC,CAAC,QAAQ,OAAO,KAAK,SAAS,CAAC;CACtD,CAAC,CACH;CAEA,GAAG,OAAO,uEACR,OAAO,IAAI,aAAa;EACtB,MAAM,MAAME,eAAqB,KAAK,MAAM;EAC5C,MAAM,SAAS,OAAOF,MAAc,KAAK,KAAK,UAAU,GAAG,GAAG,MAAM;EACpE,MAAM,OAAO,OAAOR,OAAe,KAAK,MAAM;EAC9C,aAAO,OAAOC,OAAe,KAAK,UAAU,IAAI,CAAC,CAAC,CAAC,QAAQ,OAAO,KAAK,MAAM,CAAC;CAChF,CAAC,CACH;CAEA,GAAG,OAAO,gDACR,OAAO,IAAI,aAAa;EACtB,MAAM,CAAC,SAAS,OAAO,SAAS,OAAO,CAAC,KAAK,WAAW,KAAK,yBAAqB,CAAC,CAAC;EACpF,aAAO,UAAU,MAAO,MAAM,CAAC,CAAC,CAAC,QAAQ,IAAI,aAAa,EAAE,MAAM,WAAW,CAAC,CAAC;CACjF,CAAC,CACH;CAEA,GAAG,4DAA4D;EAC7C,OAAe,OAAO,WAAW;GAC/C,MAAM;GACN,SAAS;GACT,QAAQ,CAAC;EACX,CAAC;EACD,CAAA,GAAA,YAAA,aAAA,CAA6C,CAAC,CAAC,cAK7C;EAEF,MAAc,OAAO,KAAK,WAAW,GAAG,GAAG,IAAI,QAAQ,CAAC;CAC1D,CAAC;AACH,CAAC;AAED,SAAS,4CAA4C;CACnD,MAAM,UAAUP,QAAa;EAC3B,MAAM;EACN,aAAa;EACb,aAAa,OAAO,OAAO,EAAE,UAAU,OAAO,OAAO,CAAC;EACtD,cAAc,OAAO;CACvB,CAAC;CACD,MAAM,SAASA,QAAa;EAC1B,MAAM;EACN,aAAa;EACb,aAAa,OAAO,OAAO,EAAE,QAAQ,OAAO,OAAO,CAAC;CACtD,CAAC;CACD,MAAM,QAAQE,OAAa,SAAS,SAAS,MAAM;CACnD,MAAM,UAAU,GAAG,WAA0C;EAC3D,OAAO;EACP,OAAO,CAAC;EACR,aAAa;CACf;CAEA,GAAG,OAAO,yEACR,OAAO,IAAI,aAAa;EACtB,MAAM,EAAE,KAAK,UAAU,YAAY,OAAOe,MACxC,OACA,OACE,KAAK,WAAW,KAAK,mBAAmB,GACxC,KAAK,YAAY,KAAK,4BAA4B,GAClD,KAAK,QAAQ,GAAG,GAChB,KAAK,UAAU,KAAK,IAAI,CAC1B,CACF;EACA,aAAO,IAAI,KAAK,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC;EACpD,aAAO,QAAQ,CAAC,CAAC,QAAQ,CACvB;GACE,MAAM;GACN,MAAM,KAAK,YAAY,KAAK,4BAA4B;GACxD,OAAO,EAAE,UAAU,cAAc;EACnC,CACF,CAAC;EACD,aAAO,OAAO,CAAC,CAAC,aAAa,CAAC;EAC9B,aAAO,QAAQ,EAAE,CAAC,CAAC,cAAc;GAAE,SAAS;GAAK,MAAM;EAAS,CAAC;EACjE,aAAO,UAAU,QAAQ,EAAE,CAAE,MAAM,CAAC,CAAC,CAAC,eAAeC,YAAuB;CAC9E,CAAC,CACH;CAEA,GAAG,OAAO,6EACR,OAAO,IAAI,aAAa;EACtB,MAAM,EAAE,aAAa,OAAOD,MAC1B,OACA,OAAO,KAAK,UAAU,KAAK,mBAAmB,GAAG,KAAK,YAAY,KAAK,kBAAkB,CAAC,CAC5F;EACA,MAAM,QAAQ,MAAM,KAAyC,CAAC,CAAC,KAC7D,MAAM,yBAAyB,MAAM,CAAC,CAAC;GACrC,WAAW,MAAM,OAAO,EAAE,MAAM;GAChC,SAAS,MAAM,OAAO,EAAE,MAAM;EAChC,CAAC,CACH;EACA,aAAO,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,OAAO,CAAC;EACzD,MAAM,KAAyC,CAAC,CAAC,KAE/C,MAAM,yBAAyB,MAAM,CAAC,CAAC,EAAE,gBAAgB,MAAM,CAAC,CAClE;EACA,CAAA,GAAA,YAAA,aAAA,CAAyD,CAAC,CAAC,cAEzD;CACJ,CAAC,CACH;CAEA,GAAG,OAAO,oEACR,OAAO,IAAI,aAAa;EACtB,MAAM,WAAW,OAAOE,SAAiB,OAAO,YAAY,KAAK,YAAY,GAAG,GAAG,QAAQ;EAC3F,aAAO,QAAQ,CAAC,CAAC,QAAQ;GACvB,MAAM;GACN,SAAS;GACT,MAAM;GACN,QAAQ,OAAO,QAAQ,QAAQ;EACjC,CAAC;EACD,MAAM,OAAO,OAAOb,OAAe,OAAO,QAAQ;EAClD,aAAO,OAAOC,OAAe,OAAO,YAAY,IAAI,CAAC,CAAC,CAAC,QAAQ,OAAO,QAAQ,QAAQ,CAAC;CACzF,CAAC,CACH;CAEA,GAAG,OAAO,uEACR,OAAO,IAAI,aAAa;EACtB,MAAM,QAAQ,OAAO,OAAO,KAC1BY,SAAiB,OAAO,YAAY,KAAK,UAAU,GAAG,GAAG,QAAQ,CACnE;EACA,aAAO,KAAK,CAAC,CAAC,cAAc;GAAE,MAAM;GAAqB,MAAM;EAAW,CAAC;CAC7E,CAAC,CACH;CAEA,GAAG,qDAAqD;EAEtD,SAAiB,OAAO,YAAY,KAAK,YAAY,GAAG,GAAG,EAAE;EAE7D,SAAiB,OAAO,UAAU,KAAK,UAAU,GAAG,GAAG,MAAM;CAC/D,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB;CAC7B,GAAG,OAAO,yFACR,OAAO,IAAI,aAAa;EACtB,MAAM,QAAQ,CACZ,KAAK,WAAW,KAAK,uBAAmB,GACxC,KAAK,UAAU,KAAK,mBAAe,CACrC;EACA,MAAM,OAAa;GAAE,OAAO;GAAO,OAAO,CAAC;GAAG,aAAa;EAAa;EAGxE,MAAM,QAAQ,OAAOtB,IAAY,KAAK,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,KAC/DuB,KAAa,KAAK;GAHJ,SAAS,CAAC;GAAiC,OAAO;EAG1C,GAAG,IAAI,GAC7B,OAAO,UACT;EAEA,aAAO,MAAM,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ;GACvC;GACA;GACA;GACA;GACA;GACA;EACF,CAAC;EAED,MAAM,OAAO,MAAM,GAAG,EAAE;EACxB,aAAO,MAAM,SAAS,UAAU,KAAK,KAAK,CAAC,CAAC,QAAQ;GAClD,OAAO;GACP,SAAS;IACP,GAAG;IACH;KACE,MAAM;KACN,SAAS;KACT,QAAQ,CAAC;MAAE,MAAM;MAAc,OAAO;OAAE,MAAM;OAAU,IAAI,GAAG,YAAY;MAAE;KAAE,CAAC;IAClF;IACA;KACE,MAAM;KACN,SAAS;KACT,QAAQ,CAAC;MAAE,MAAM;MAAc,OAAO,EAAE,MAAM,EAAE;KAAE,CAAC;IACrD;GACF;EACF,CAAC;CACH,CAAC,CACH;AACF,CAAC;AAED,SAAS,mDAAmD;CAC1D,MAAM,cAAc,QAAQ,QAG1B,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;CACnB,MAAM,WAAsC,KAAK,UAAU,UACzD,OAAO,OACL,OAAO,IAAI,aAAa;EACtB,QAAQ,OAAO,MAAA,CAAO,OAAO,IAAI;EACjC,OAAO,IAAI,KAAK;CAClB,CAAC,CACH;CAEF,GAAG,OAAO,iFACR,OAAO,IAAI,aAAa;EACtB,MAAM,WAA0B,CAAC;EACjC,MAAM,UAAU,KAAK,KAAKC,KAAa,OAAO,CAAC;EAC/C,MAAM,SAASxB,IACb,SACA,CAAC,KAAK,UAAU,KAAK,mBAAe,GAAG,KAAK,YAAY,GAAG,CAAC,GAC5D,EAAE,aAAa,EAAE,CACnB;EACA,CAAA,GAAA,YAAA,aAAA,CAA6C,CAAC,CAAC,cAAqB;EAEpE,MAAM,SAAS,OAAO,OAAO,KAC3B,OAAO,OAAOC,SAAiB,GAC/B,OAAO,YACP,OAAO,eAAe,OAAO,EAAE,SAAS,MAAM,OAAO,WAAW,KAAK,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC,CAC1F;EACA,aAAO,QAAQ,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;EACnC,aAAO,OAAO,KAAK,MAAM,EAAE,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,SAAS,CAAC;CACzE,CAAC,CACH;CAEA,GAAG,OAAO,wEACR,OAAO,IAAI,aAAa;EACtB,MAAM,UAAU,KAAK,KAAKuB,KAAa,OAAO,CAAC;EAC/C,MAAM,SAAS,OAAOxB,IACpB,SACA,CAAC,KAAK,WAAW,KAAK,uBAAmB,GAAG,KAAK,UAAU,KAAK,mBAAe,CAAC,GAChF,EAAE,aAAa,EAAE,CACnB,CAAC,CAAC,KAAK,OAAO,YAAY,OAAO,eAAe,OAAO,EAAE,cAAc,OAAO,KAAK,CAAC,CAAC;EACrF,aAAO,OAAO,KAAK,MAAM,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ;GACvD;GACA;GACA;GACA;GACA;EACF,CAAC;CACH,CAAC,CACH;CAEA,GAAG,OACD,0FAEE,OAAO,IAAI,aAAa;EACtB,MAAM,YAAYM,iBAAyB,MAAM,MAAM,aAAa,EAAE,MAAM;EAC5E,CAAA,GAAA,YAAA,aAAA,CAAiD,CAAC,CAAC,cAAqB;EAExE,MAAM,SAAS,OAAO,SAAS,WAAW,CACxC,KAAK,WAAW,KAAK,qBAAiB,GACtC,KAAK,WAAW,KAAK,yBAAqB,CAC5C,CAAC;EACD,aAAO,OAAO,KAAK,MAAM,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CACrD,IAAImB,WAAgB,EAAE,SAAS,oBAAoB,CAAC,GACpD,IAAI,aAAa,EAAE,MAAM,WAAW,CAAC,CACvC,CAAC;EACD,MAAM,OAAO,OAAOhB,OAAe,WAAW,OAAO,EAAG;EACxD,aAAO,KAAK,MAAM,CAAC,CAAC,QAAQ,CAC1B;GAAE,MAAM;GAAc,OAAO;IAAE,MAAM;IAAc,SAAS;GAAoB;EAAE,CACpF,CAAC;CACH,CAAC,CACL;CAEA,GAAG,OAAO,+EACR,OAAO,IAAI,aAAa;EACtB,MAAM,oBAAoB,OAAO,YAAyB,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;EAChF,MAAM,QAAQP,KAAU;GACtB,MAAM;GACN,aAAa;GACb,aAAa,OAAO,OAAO,EAAE,KAAK,OAAO,OAAO,CAAC;GACjD,cAAc,OAAO;GACrB,MAAM,EAAE,UACN,OAAO,IAAI,aAAa;IACtB,IAAI,QAAQ,QAAQ,OAAO,OAAO,IAAI,YAAY;IAClD,OAAO,OAAO,IAAI,QAAQ;GAC5B,CAAC;EACL,CAAC;EACD,MAAM,MAAMI,iBAAyBD,OAAa,KAAK,IAAI,MACzD,EAAE,SAAS,YAAY,2BAA2B,KAAA,CACpD;EACA,CAAA,GAAA,YAAA,aAAA,CAA2C,CAAC,CAAC,cAAqC;EAElF,MAAM,CAAC,SAAS,OAAO,SAAS,KAAK,CAAC,KAAK,SAAS,KAAK,kBAAc,CAAC,CAAC;EACzE,aAAO,UAAU,MAAO,MAAM,CAAC,CAAC,CAAC,QAC/B,IAAIoB,WAAgB,EAAE,SAAS,yBAAyB,CAAC,CAC3D;EACA,MAAM,OAAO,OAAO,OAAO,KAAK,QAAQ,KAAK,CAAC,KAAK,SAAS,KAAK,oBAAgB,CAAC,CAAC,CAAC;EACpF,aAAO,IAAI,CAAC,CAAC,QAAQ,IAAI,YAAY,CAAC;CACxC,CAAC,CACH;AACF,CAAC;AAED,SAAS,6CAA6C;CACpD,MAAM,QAA0B,SAC9BvB,KAAU;EACR;EACA,aAAa;EACb,aAAaE;EACb,cAAc,OAAO;EACrB,WAAW,OAAO,QAAQ,CAAC;CAC7B,CAAC;CAEH,GAAG,0DAA0D;EAC3D,MAAM,IAAI,KAAK,QAAQ;EACvB,MAAM,IAAID,QAAa;GAAE,MAAM;GAAU,aAAa;GAAI,aAAaC;EAAa,CAAC;EAErF,OAAa,GAAG,CAAC;CACnB,CAAC;CAED,GAAG,OAAO,gFACR,OAAO,IAAI,aAAa;EACtB,MAAM,QAAQ,OAAO,OAAO,KAC1BsB,QAAgBC,UAAkB,CAAC,KAAK,QAAQ,CAAC,CAAC,GAAGA,UAAkB,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAC1F;EACA,aAAO,KAAK,CAAC,CAAC,QACZ,IAAIC,kBAA0B;GAAE,MAAM;GAAU,SAAS,CAAC,aAAa,WAAW;EAAE,CAAC,CACvF;CACF,CAAC,CACH;CAEA,GAAG,OAAO,4EACR,OAAO,IAAI,aAAa;EACtB,MAAM,SAASC,eAAuB,UAAU,KAAK,QAAQ,CAAC;EAC9D,MAAM,SAASC,UAAkB,UAAUzB,OAAa,KAAK,QAAQ,CAAC,CAAC;EACvE,CAAA,GAAA,YAAA,aAAA,CAAa,OAAO,eAAe,IAAI,CAAC,CAAC,cAAgC;EAEzE,MAAM,OAAO,OAAOqB,QAAgB,QAAQ,MAAM;EAClD,MAAM,CAAC,SAAS,OAAO,SAAS,MAAM,CAAC,KAAK,kBAAkB,GAAG,CAAC,CAAC;EACnE,aAAO,KAAK,CAAC,CAAC,cAAc;GAAE,MAAM;GAAkB,QAAQ,OAAO,QAAQ,CAAC;EAAE,CAAC;CACnF,CAAC,CACH;AACF,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { streamTranscriptionFrom, transcribe } from "./Transcriber.mjs";
2
- import { m as it, o as describe } from "../utils-CiH_DjFW.mjs";
3
- import { n as globalExpect } from "../test.DNmyFkvJ-YPzDR0Co.mjs";
4
- import { t as import_dist } from "../dist-BaenoU1A.mjs";
2
+ import { b as it, m as describe } from "../dist-DzeSyeYF.mjs";
3
+ import { n as globalExpect } from "../index.C4tKZ0yW-LuFnBtmu.mjs";
4
+ import { t as import_dist } from "../dist-DNeuh84d.mjs";
5
5
  import { layer, layerSyncOnly } from "../testing/MockTranscriber.mjs";
6
6
  import { Duration, Effect, Stream } from "effect";
7
7
  //#region src/transcriber/Transcriber.test.ts
@@ -1,4 +1,4 @@
1
- import { l as Tool } from "../Tool-BF78QWtn.mjs";
1
+ import { d as Tool } from "../Tool-Bkryw6-h.mjs";
2
2
  import { t as AiError } from "../AiError-DvhLIbmd.mjs";
3
3
  import { ReadFormat, ReadResponse, WebRead } from "./WebRead.mjs";
4
4
  import { Schema } from "effect";
@@ -50,7 +50,7 @@ type WebReadToolOptions = {
50
50
  * cases (a different output contract, more model-facing knobs), build your
51
51
  * own tool with `Tool.make` over the same `read` helper.
52
52
  */
53
- declare const webReadTool: (options?: WebReadToolOptions) => Tool<string, WebReadToolArgs, never, string, AiError, WebRead>;
53
+ declare const webReadTool: (options?: WebReadToolOptions) => Tool<string, WebReadToolArgs, string, never, AiError, WebRead>;
54
54
  //#endregion
55
55
  export { WebReadToolArgs, WebReadToolOptions, WebReadTool_d_exports as t, webReadTool };
56
56
  //# sourceMappingURL=WebReadTool.d.mts.map
@@ -40,6 +40,7 @@ const webReadTool = (options) => {
40
40
  name,
41
41
  description: "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).",
42
42
  inputSchema: fromEffectSchema(WebReadToolArgs),
43
+ outputSchema: Schema.String,
43
44
  run: (args) => read({
44
45
  url: args.url,
45
46
  format
@@ -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,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
+ {"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, string, never, 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 outputSchema: Schema.String,\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;EAClD,cAAc,OAAO;EAKrB,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,4 +1,4 @@
1
- import { l as Tool } from "../Tool-BF78QWtn.mjs";
1
+ import { d as Tool } from "../Tool-Bkryw6-h.mjs";
2
2
  import { t as AiError } from "../AiError-DvhLIbmd.mjs";
3
3
  import { SearchResult, WebSearch } from "./WebSearch.mjs";
4
4
  import { Schema } from "effect";
@@ -58,7 +58,7 @@ type WebSearchToolOptions = {
58
58
  * cases (a different output contract, more model-facing knobs), build your
59
59
  * own tool with `Tool.make` over the same `search` helper.
60
60
  */
61
- declare const webSearchTool: (options?: WebSearchToolOptions) => Tool<string, WebSearchToolArgs, never, string, AiError, WebSearch>;
61
+ declare const webSearchTool: (options?: WebSearchToolOptions) => Tool<string, WebSearchToolArgs, string, never, AiError, WebSearch>;
62
62
  //#endregion
63
63
  export { WebSearchToolArgs, WebSearchToolOptions, WebSearchTool_d_exports as t, webSearchTool };
64
64
  //# sourceMappingURL=WebSearchTool.d.mts.map
@@ -50,6 +50,7 @@ const webSearchTool = (options) => {
50
50
  name,
51
51
  description: "Search the web for current information. Returns ranked results with titles, URLs, and snippets.",
52
52
  inputSchema: fromEffectSchema(WebSearchToolArgs),
53
+ outputSchema: Schema.String,
53
54
  run: (args) => search({
54
55
  query: args.query,
55
56
  maxResults,
@@ -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,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"}
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, string, never, 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 outputSchema: Schema.String,\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;EACpD,cAAc,OAAO;EAKrB,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.17.0",
3
+ "version": "0.19.0-dev-20261109183959",
4
4
  "description": "Low-level primitives (loop, conversation, items, tools, streaming codecs) for building AI agents with Effect.",
5
5
  "keywords": [
6
6
  "agents",
@@ -74,6 +74,10 @@
74
74
  "types": "./dist/browser/BrowserTool.d.mts",
75
75
  "import": "./dist/browser/BrowserTool.mjs"
76
76
  },
77
+ "./File": {
78
+ "types": "./dist/domain/File.d.mts",
79
+ "import": "./dist/domain/File.mjs"
80
+ },
77
81
  "./Image": {
78
82
  "types": "./dist/domain/Image.d.mts",
79
83
  "import": "./dist/domain/Image.mjs"
@@ -222,6 +226,10 @@
222
226
  "types": "./dist/tokenizer/Tokenizer.d.mts",
223
227
  "import": "./dist/tokenizer/Tokenizer.mjs"
224
228
  },
229
+ "./Content": {
230
+ "types": "./dist/tool/Content.d.mts",
231
+ "import": "./dist/tool/Content.mjs"
232
+ },
225
233
  "./Tool": {
226
234
  "types": "./dist/tool/Tool.d.mts",
227
235
  "import": "./dist/tool/Tool.mjs"
@@ -230,17 +238,17 @@
230
238
  "types": "./dist/tool/Toolkit.d.mts",
231
239
  "import": "./dist/tool/Toolkit.mjs"
232
240
  },
233
- "./ToolResult": {
234
- "types": "./dist/tool/ToolResult.d.mts",
235
- "import": "./dist/tool/ToolResult.mjs"
236
- },
237
241
  "./ToolEvent": {
238
242
  "types": "./dist/tool/ToolEvent.d.mts",
239
243
  "import": "./dist/tool/ToolEvent.mjs"
240
244
  },
241
- "./Approval": {
242
- "types": "./dist/tool/Approval.d.mts",
243
- "import": "./dist/tool/Approval.mjs"
245
+ "./ToolOutput": {
246
+ "types": "./dist/tool/ToolOutput.d.mts",
247
+ "import": "./dist/tool/ToolOutput.mjs"
248
+ },
249
+ "./ToolDecision": {
250
+ "types": "./dist/tool/ToolDecision.d.mts",
251
+ "import": "./dist/tool/ToolDecision.mjs"
244
252
  },
245
253
  "./HistoryCheck": {
246
254
  "types": "./dist/tool/HistoryCheck.d.mts",
@@ -314,11 +322,11 @@
314
322
  "@standard-schema/spec": "^1.1.0"
315
323
  },
316
324
  "devDependencies": {
317
- "effect": "4.0.0-rc.111",
325
+ "effect": "4.1.2",
318
326
  "typescript": "^7.0.2"
319
327
  },
320
328
  "peerDependencies": {
321
- "effect": ">=4.0.0-rc.111 <5.0.0"
329
+ "effect": ">=4.0.1 <5.0.0"
322
330
  },
323
331
  "scripts": {
324
332
  "build": "tsdown",
@@ -71,6 +71,7 @@ export const gotoTool = (session: BrowserSession) =>
71
71
  name: "browser_goto",
72
72
  description: "Navigate the browser to an absolute URL.",
73
73
  inputSchema: Tool.fromEffectSchema(GotoArgs),
74
+ outputSchema: Schema.String,
74
75
  run: (args) =>
75
76
  Effect.andThen(session.goto(args.url), okAt(session)).pipe(
76
77
  Effect.withSpan("browser_goto", {
@@ -85,6 +86,7 @@ export const clickTool = (session: BrowserSession) =>
85
86
  name: "browser_click",
86
87
  description: "Click the element named by ref. A click may navigate to a new page.",
87
88
  inputSchema: Tool.fromEffectSchema(ClickArgs),
89
+ outputSchema: Schema.String,
88
90
  run: (args) =>
89
91
  Effect.andThen(session.click(args.ref), okAt(session)).pipe(
90
92
  Effect.withSpan("browser_click", {
@@ -100,6 +102,7 @@ export const fillTool = (session: BrowserSession) =>
100
102
  description:
101
103
  "Put text into the input named by ref. Filling alone does not submit; press Enter to submit the input.",
102
104
  inputSchema: Tool.fromEffectSchema(FillArgs),
105
+ outputSchema: Schema.String,
103
106
  run: (args) =>
104
107
  Effect.andThen(session.fill(args.ref, args.text), okAt(session)).pipe(
105
108
  Effect.withSpan("browser_fill", {
@@ -114,6 +117,7 @@ export const pressTool = (session: BrowserSession) =>
114
117
  name: "browser_press",
115
118
  description: "Press a keyboard key against the focused element.",
116
119
  inputSchema: Tool.fromEffectSchema(PressArgs),
120
+ outputSchema: Schema.String,
117
121
  run: (args) =>
118
122
  Effect.andThen(session.press(args.key), okAt(session)).pipe(
119
123
  Effect.withSpan("browser_press", {
@@ -129,6 +133,7 @@ export const scrollTool = (session: BrowserSession) =>
129
133
  description:
130
134
  "Scroll the viewport. Only useful to bring an element into view - a page-reading tool's text is already scroll-independent.",
131
135
  inputSchema: Tool.fromEffectSchema(ScrollArgs),
136
+ outputSchema: Schema.String,
132
137
  run: (args) =>
133
138
  Effect.andThen(session.scroll({ direction: args.direction }), okAt(session)).pipe(
134
139
  Effect.withSpan("browser_scroll", {
@@ -0,0 +1,79 @@
1
+ import { Schema } from "effect"
2
+ import type { MediaBase64, MediaBytes, MediaSource, MediaUrl } from "./Media.js"
3
+
4
+ /**
5
+ * MIME types of files a user hands to a model: documents, audio, video. The
6
+ * listed ones are common; the `(string & {})` tail accepts any other, so a
7
+ * newly supported format works without an SDK update. Which types a model
8
+ * reads is the provider's call: an unsupported one is rejected by the
9
+ * provider, not converted here.
10
+ */
11
+ export type FileMimeType =
12
+ | "application/pdf"
13
+ | "text/plain"
14
+ | "text/markdown"
15
+ | "text/csv"
16
+ | "text/html"
17
+ | "application/json"
18
+ | "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
19
+ | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
20
+ | "audio/mpeg"
21
+ | "audio/wav"
22
+ | "video/mp4"
23
+ // eslint-disable-next-line @typescript-eslint/ban-types
24
+ | (string & {})
25
+
26
+ const FileMimeTypeSchema: Schema.Codec<FileMimeType> = Schema.String
27
+
28
+ export type FileUrlSource = MediaUrl<FileMimeType>
29
+ export type FileBase64Source = MediaBase64<FileMimeType>
30
+ export type FileBytesSource = MediaBytes<FileMimeType>
31
+
32
+ /** Where a file lives: a URL the model fetches, inline base64, or raw bytes. */
33
+ export type FileSource = MediaSource<FileMimeType>
34
+
35
+ export const FileUrlSource = Schema.TaggedStruct("url", {
36
+ url: Schema.String,
37
+ mimeType: Schema.optionalKey(FileMimeTypeSchema),
38
+ })
39
+
40
+ export const FileBase64Source = Schema.TaggedStruct("base64", {
41
+ base64: Schema.String,
42
+ mimeType: FileMimeTypeSchema,
43
+ })
44
+
45
+ export const FileBytesSource = Schema.TaggedStruct("bytes", {
46
+ bytes: Schema.Uint8Array,
47
+ mimeType: FileMimeTypeSchema,
48
+ })
49
+
50
+ export const FileSource: Schema.Codec<FileSource> = Schema.Union([
51
+ FileUrlSource,
52
+ FileBase64Source,
53
+ FileBytesSource,
54
+ ])
55
+
56
+ /** `FileSource` as JSON: bytes encode as base64 (e.g. tool output on a UI wire). */
57
+ export const FileSourceJson = Schema.Union([
58
+ FileUrlSource,
59
+ FileBase64Source,
60
+ Schema.TaggedStruct("bytes", {
61
+ bytes: Schema.Uint8ArrayFromBase64,
62
+ mimeType: FileMimeTypeSchema,
63
+ }),
64
+ ])
65
+
66
+ export const fileUrl = (url: string, mimeType?: FileMimeType): FileUrlSource =>
67
+ mimeType !== undefined ? { _tag: "url", url, mimeType } : { _tag: "url", url }
68
+
69
+ export const fileBase64 = (base64: string, mimeType: FileMimeType): FileBase64Source => ({
70
+ _tag: "base64",
71
+ base64,
72
+ mimeType,
73
+ })
74
+
75
+ export const fileBytes = (bytes: Uint8Array, mimeType: FileMimeType): FileBytesSource => ({
76
+ _tag: "bytes",
77
+ bytes,
78
+ mimeType,
79
+ })
@@ -28,7 +28,7 @@ export type ImageMimeType =
28
28
  // eslint-disable-next-line @typescript-eslint/ban-types
29
29
  | (string & {})
30
30
 
31
- const ImageMimeTypeSchema = Schema.String as unknown as Schema.Schema<ImageMimeType>
31
+ const ImageMimeTypeSchema: Schema.Codec<ImageMimeType> = Schema.String
32
32
 
33
33
  export type ImageUrlSource = MediaUrl<ImageMimeType>
34
34
  export type ImageBase64Source = MediaBase64<ImageMimeType>
@@ -45,7 +45,7 @@ export type ImageSource = MediaSource<ImageMimeType>
45
45
 
46
46
  export const ImageUrlSource = Schema.TaggedStruct("url", {
47
47
  url: Schema.String,
48
- mimeType: Schema.optional(ImageMimeTypeSchema),
48
+ mimeType: Schema.optionalKey(ImageMimeTypeSchema),
49
49
  })
50
50
 
51
51
  export const ImageBase64Source = Schema.TaggedStruct("base64", {
@@ -58,11 +58,21 @@ export const ImageBytesSource = Schema.TaggedStruct("bytes", {
58
58
  mimeType: ImageMimeTypeSchema,
59
59
  })
60
60
 
61
- export const ImageSource: Schema.Schema<ImageSource> = Schema.Union([
61
+ export const ImageSource: Schema.Codec<ImageSource> = Schema.Union([
62
62
  ImageUrlSource,
63
63
  ImageBase64Source,
64
64
  ImageBytesSource,
65
- ]) as unknown as Schema.Schema<ImageSource>
65
+ ])
66
+
67
+ /** `ImageSource` as JSON: bytes encode as base64 (e.g. tool output on a UI wire). */
68
+ export const ImageSourceJson = Schema.Union([
69
+ ImageUrlSource,
70
+ ImageBase64Source,
71
+ Schema.TaggedStruct("bytes", {
72
+ bytes: Schema.Uint8ArrayFromBase64,
73
+ mimeType: ImageMimeTypeSchema,
74
+ }),
75
+ ])
66
76
 
67
77
  export const imageUrl = (url: string, mimeType?: ImageMimeType): ImageUrlSource =>
68
78
  mimeType !== undefined ? { _tag: "url", url, mimeType } : { _tag: "url", url }
@@ -1,4 +1,5 @@
1
1
  import { Schema } from "effect"
2
+ import { FileSource } from "./File.js"
2
3
  import { ImageSource } from "./Image.js"
3
4
 
4
5
  // ---------------------------------------------------------------------------
@@ -25,6 +26,20 @@ export const InputImage = Schema.Struct({
25
26
  })
26
27
  export type InputImage = typeof InputImage.Type
27
28
 
29
+ /**
30
+ * User-provided file: a document (PDF, text, docx), audio or video. The
31
+ * `source` MIME type says which; provider codecs map it to their own file
32
+ * part, and a provider that cannot read a type rejects the request.
33
+ *
34
+ * Not in `ContentBlock` yet: it joins once every provider codec encodes it.
35
+ */
36
+ export const InputFile = Schema.Struct({
37
+ type: Schema.Literal("input_file"),
38
+ source: FileSource,
39
+ filename: Schema.optionalKey(Schema.String),
40
+ })
41
+ export type InputFile = typeof InputFile.Type
42
+
28
43
  // ---------------------------------------------------------------------------
29
44
  // Annotations - source / citation pointers attached to `output_text` blocks.
30
45
  // Provider-agnostic: each provider populates the fields it has (character
@@ -159,10 +174,22 @@ export const ToolCall = Schema.Struct({
159
174
  })
160
175
  export type ToolCall = typeof ToolCall.Type
161
176
 
177
+ /** A JSON value in a tool output. Kept as a value; provider codecs serialize it. */
178
+ export const InputJson = Schema.Struct({
179
+ type: Schema.Literal("input_json"),
180
+ value: Schema.Json,
181
+ })
182
+ export type InputJson = typeof InputJson.Type
183
+
184
+ export const ToolOutputContent = Schema.Union([InputText, InputJson, InputImage, InputFile])
185
+ export type ToolOutputContent = typeof ToolOutputContent.Type
186
+
162
187
  export const ToolCallOutput = Schema.Struct({
163
188
  type: Schema.Literal("function_call_output"),
164
189
  call_id: Schema.String,
165
- output: Schema.String,
190
+ output: Schema.Array(ToolOutputContent),
191
+ /** The call failed. Native on some providers; others only see the content. */
192
+ isError: Schema.optionalKey(Schema.Boolean),
166
193
  providerData: ProviderData,
167
194
  })
168
195
  export type ToolCallOutput = typeof ToolCallOutput.Type
@@ -191,6 +218,8 @@ export type HistoryItem = typeof HistoryItem.Type
191
218
 
192
219
  export const isInputText = Schema.is(InputText)
193
220
  export const isInputImage = Schema.is(InputImage)
221
+ export const isInputFile = Schema.is(InputFile)
222
+ export const isInputJson = Schema.is(InputJson)
194
223
  export const isOutputText = Schema.is(OutputText)
195
224
  export const isOutputImage = Schema.is(OutputImage)
196
225
  export const isRefusal = Schema.is(Refusal)
@@ -269,8 +298,15 @@ export const assistantText = (text: string): Message => ({
269
298
  content: [{ type: "output_text", text }],
270
299
  })
271
300
 
272
- export const toolCallOutput = (call_id: string, output: string): ToolCallOutput => ({
301
+ /** A tool output with one text part. */
302
+ export const toolCallOutput = (call_id: string, text: string): ToolCallOutput => ({
273
303
  type: "function_call_output",
274
304
  call_id,
275
- output,
305
+ output: [{ type: "input_text", text }],
276
306
  })
307
+
308
+ export const text = (text: string): InputText => ({ type: "input_text", text })
309
+ export const json = (value: Schema.Json): InputJson => ({ type: "input_json", value })
310
+ export const image = (source: ImageSource): InputImage => ({ type: "input_image", source })
311
+ export const file = (source: FileSource, filename?: string): InputFile =>
312
+ filename === undefined ? { type: "input_file", source } : { type: "input_file", source, filename }