@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.
- package/README.md +5 -5
- package/dist/Content-D_Qfn8Ja.d.mts +48 -0
- package/dist/Content-D_Qfn8Ja.d.mts.map +1 -0
- package/dist/File-B923KvZ9.d.mts +46 -0
- package/dist/File-B923KvZ9.d.mts.map +1 -0
- package/dist/{Image-Cv6iBLTy.d.mts → Image-Bzc1H_UK.d.mts} +19 -8
- package/dist/Image-Bzc1H_UK.d.mts.map +1 -0
- package/dist/{Items-C7MyrYPX.d.mts → Items-Bvx8s9QH.d.mts} +109 -16
- package/dist/Items-Bvx8s9QH.d.mts.map +1 -0
- package/dist/{Loop-ChpaO-ya.d.mts → Loop-CeA0AelN.d.mts} +7 -6
- package/dist/Loop-CeA0AelN.d.mts.map +1 -0
- package/dist/Tool-Bkryw6-h.d.mts +206 -0
- package/dist/Tool-Bkryw6-h.d.mts.map +1 -0
- package/dist/ToolEvent-9inLx5cI.d.mts +22 -0
- package/dist/ToolEvent-9inLx5cI.d.mts.map +1 -0
- package/dist/ToolOutput-BNTIQgGB.d.mts +151 -0
- package/dist/ToolOutput-BNTIQgGB.d.mts.map +1 -0
- package/dist/Toolkit-D2VGeD5R.d.mts +212 -0
- package/dist/Toolkit-D2VGeD5R.d.mts.map +1 -0
- package/dist/browser/BrowserTool.d.mts +84 -22
- package/dist/browser/BrowserTool.d.mts.map +1 -1
- package/dist/browser/BrowserTool.mjs +5 -0
- package/dist/browser/BrowserTool.mjs.map +1 -1
- package/dist/capabilities/Capabilities.d.mts +1 -1
- package/dist/decision-model/Decision.test.mjs +4 -4
- package/dist/dist-B5K-y4Be.mjs +191 -0
- package/dist/dist-B5K-y4Be.mjs.map +1 -0
- package/dist/dist-CorQTQL-.mjs +1533 -0
- package/dist/dist-CorQTQL-.mjs.map +1 -0
- package/dist/dist-DNeuh84d.mjs +7 -0
- package/dist/dist-DNeuh84d.mjs.map +1 -0
- package/dist/dist-DzeSyeYF.mjs +10253 -0
- package/dist/dist-DzeSyeYF.mjs.map +1 -0
- package/dist/domain/File.d.mts +2 -0
- package/dist/domain/File.mjs +51 -0
- package/dist/domain/File.mjs.map +1 -0
- package/dist/domain/Image.d.mts +2 -2
- package/dist/domain/Image.mjs +12 -2
- package/dist/domain/Image.mjs.map +1 -1
- package/dist/domain/Items.d.mts +2 -2
- package/dist/domain/Items.mjs +65 -4
- package/dist/domain/Items.mjs.map +1 -1
- package/dist/domain/Realtime.d.mts +72 -490
- package/dist/domain/Realtime.d.mts.map +1 -1
- package/dist/domain/Research.d.mts +1 -1
- package/dist/domain/Transcript.test.mjs +3 -3
- package/dist/domain/Turn.d.mts +57 -262
- package/dist/domain/Turn.d.mts.map +1 -1
- package/dist/domain/Turn.mjs +1 -1
- package/dist/domain/Turn.test.mjs +2 -2
- package/dist/embedding-model/Embedding.d.mts +1 -1
- package/dist/embedding-model/EmbeddingModel.test.mjs +2 -2
- package/dist/embedding-model/EmbeddingModel.test.mjs.map +1 -1
- package/dist/image-generator/ImageGenerator.d.mts +10 -66
- package/dist/image-generator/ImageGenerator.d.mts.map +1 -1
- package/dist/index.C4tKZ0yW-LuFnBtmu.mjs +7042 -0
- package/dist/index.C4tKZ0yW-LuFnBtmu.mjs.map +1 -0
- package/dist/index.d.mts +10 -9
- package/dist/index.mjs +7 -6
- package/dist/language-model/LanguageModel.d.mts +2 -2
- package/dist/language-model/LanguageModel.test.mjs +2 -2
- package/dist/loop/Loop.d.mts +1 -1
- package/dist/loop/Loop.mjs.map +1 -1
- package/dist/loop/Loop.test.mjs +3 -3
- package/dist/math/Probability.test.mjs +2 -2
- package/dist/messenger/Messenger.d.mts +43 -289
- package/dist/messenger/Messenger.d.mts.map +1 -1
- package/dist/messenger/MessengerAdapter.test.mjs +3 -3
- package/dist/music-generator/MusicGenerator.test.mjs +3 -3
- package/dist/observability/Metrics.d.mts +1 -1
- package/dist/observability/Metrics.test.mjs +3 -3
- package/dist/observability/Telemetry.d.mts +1 -1
- package/dist/observability/Telemetry.mjs +1 -1
- package/dist/observability/Telemetry.mjs.map +1 -1
- package/dist/observability/Telemetry.test.mjs +4 -4
- package/dist/observability/Telemetry.test.mjs.map +1 -1
- package/dist/realtime/RealtimeSession.d.mts +1 -1
- package/dist/realtime/RealtimeSession.test.mjs +4 -4
- package/dist/retry/Retry.test.mjs +2 -2
- package/dist/sandbox/Sandbox.d.mts +32 -237
- package/dist/sandbox/Sandbox.d.mts.map +1 -1
- package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs +3 -3
- package/dist/streaming/JSONL.test.mjs +2 -2
- package/dist/streaming/Multipart.d.mts +1 -1
- package/dist/streaming/Multipart.mjs +3 -2
- package/dist/streaming/Multipart.mjs.map +1 -1
- package/dist/streaming/Multipart.test.mjs +28 -0
- package/dist/streaming/Multipart.test.mjs.map +1 -0
- package/dist/streaming/SSE.d.mts +1 -1
- package/dist/streaming/SSE.mjs +2 -2
- package/dist/streaming/SSE.mjs.map +1 -1
- package/dist/streaming/SSE.test.mjs +2 -2
- package/dist/streaming/Settle.test.mjs +3 -3
- package/dist/streaming/WebSocketSession.d.mts +5 -3
- package/dist/streaming/WebSocketSession.d.mts.map +1 -1
- package/dist/streaming/WebSocketSession.mjs +22 -10
- package/dist/streaming/WebSocketSession.mjs.map +1 -1
- package/dist/streaming/WebSocketSession.test.mjs +41 -5
- package/dist/streaming/WebSocketSession.test.mjs.map +1 -1
- package/dist/structured-format/StructuredFormat.mjs.map +1 -1
- package/dist/structured-format/StructuredFormat.test.mjs +2 -2
- package/dist/testing/FakeWebSocket.d.mts +5 -1
- package/dist/testing/FakeWebSocket.d.mts.map +1 -1
- package/dist/testing/FakeWebSocket.mjs +12 -6
- package/dist/testing/FakeWebSocket.mjs.map +1 -1
- package/dist/testing/MockMessenger.d.mts +19 -134
- package/dist/testing/MockMessenger.d.mts.map +1 -1
- package/dist/testing/MockProvider.d.mts +1 -1
- package/dist/testing/MockSandbox.d.mts +65 -446
- package/dist/testing/MockSandbox.d.mts.map +1 -1
- package/dist/tool/Content.d.mts +2 -0
- package/dist/tool/Content.mjs +46 -0
- package/dist/tool/Content.mjs.map +1 -0
- package/dist/tool/Content.test.d.mts +1 -0
- package/dist/tool/Content.test.mjs +48 -0
- package/dist/tool/Content.test.mjs.map +1 -0
- package/dist/tool/HistoryCheck.d.mts +6 -15
- package/dist/tool/HistoryCheck.d.mts.map +1 -1
- package/dist/tool/HistoryCheck.mjs +10 -24
- package/dist/tool/HistoryCheck.mjs.map +1 -1
- package/dist/tool/Tool.d.mts +2 -2
- package/dist/tool/Tool.mjs +55 -130
- package/dist/tool/Tool.mjs.map +1 -1
- package/dist/tool/Tool.test.mjs +222 -178
- package/dist/tool/Tool.test.mjs.map +1 -1
- package/dist/tool/ToolDecision.d.mts +164 -0
- package/dist/tool/ToolDecision.d.mts.map +1 -0
- package/dist/tool/ToolDecision.mjs +146 -0
- package/dist/tool/ToolDecision.mjs.map +1 -0
- package/dist/tool/ToolDecision.test.d.mts +1 -0
- package/dist/tool/ToolDecision.test.mjs +330 -0
- package/dist/tool/ToolDecision.test.mjs.map +1 -0
- package/dist/tool/ToolEvent.d.mts +2 -2
- package/dist/tool/ToolEvent.mjs +2 -34
- package/dist/tool/ToolEvent.mjs.map +1 -1
- package/dist/tool/ToolOutput.d.mts +2 -0
- package/dist/tool/ToolOutput.mjs +128 -0
- package/dist/tool/ToolOutput.mjs.map +1 -0
- package/dist/tool/ToolOutput.test.d.mts +1 -0
- package/dist/tool/ToolOutput.test.mjs +153 -0
- package/dist/tool/ToolOutput.test.mjs.map +1 -0
- package/dist/tool/Toolkit.d.mts +2 -2
- package/dist/tool/Toolkit.mjs +230 -165
- package/dist/tool/Toolkit.mjs.map +1 -1
- package/dist/tool/Toolkit.test.mjs +433 -391
- package/dist/tool/Toolkit.test.mjs.map +1 -1
- package/dist/transcriber/Transcriber.test.mjs +3 -3
- package/dist/web-read/WebReadTool.d.mts +2 -2
- package/dist/web-read/WebReadTool.mjs +1 -0
- package/dist/web-read/WebReadTool.mjs.map +1 -1
- package/dist/web-search/WebSearchTool.d.mts +2 -2
- package/dist/web-search/WebSearchTool.mjs +1 -0
- package/dist/web-search/WebSearchTool.mjs.map +1 -1
- package/package.json +18 -10
- package/src/browser/BrowserTool.ts +5 -0
- package/src/domain/File.ts +79 -0
- package/src/domain/Image.ts +14 -4
- package/src/domain/Items.ts +39 -3
- package/src/embedding-model/EmbeddingModel.test.ts +2 -2
- package/src/index.ts +3 -2
- package/src/loop/Loop.ts +25 -14
- package/src/observability/Telemetry.test.ts +1 -1
- package/src/observability/Telemetry.ts +2 -2
- package/src/streaming/Multipart.test.ts +26 -0
- package/src/streaming/Multipart.ts +6 -5
- package/src/streaming/SSE.ts +2 -2
- package/src/streaming/WebSocketSession.test.ts +54 -2
- package/src/streaming/WebSocketSession.ts +27 -6
- package/src/structured-format/StructuredFormat.ts +1 -1
- package/src/testing/FakeWebSocket.ts +21 -6
- package/src/tool/Content.test.ts +40 -0
- package/src/tool/Content.ts +38 -0
- package/src/tool/HistoryCheck.ts +21 -26
- package/src/tool/Tool.test.ts +240 -241
- package/src/tool/Tool.ts +204 -309
- package/src/tool/ToolDecision.test.ts +301 -0
- package/src/tool/ToolDecision.ts +360 -0
- package/src/tool/ToolEvent.ts +21 -41
- package/src/tool/ToolOutput.test.ts +132 -0
- package/src/tool/ToolOutput.ts +198 -0
- package/src/tool/Toolkit.test.ts +594 -454
- package/src/tool/Toolkit.ts +631 -356
- package/src/web-read/WebReadTool.ts +2 -1
- package/src/web-search/WebSearchTool.ts +2 -1
- package/dist/Image-Cv6iBLTy.d.mts.map +0 -1
- package/dist/Items-C7MyrYPX.d.mts.map +0 -1
- package/dist/Loop-ChpaO-ya.d.mts.map +0 -1
- package/dist/Tool-BF78QWtn.d.mts +0 -314
- package/dist/Tool-BF78QWtn.d.mts.map +0 -1
- package/dist/ToolEvent-Di4a723B.d.mts +0 -144
- package/dist/ToolEvent-Di4a723B.d.mts.map +0 -1
- package/dist/ToolResult-BsYQRjmW.d.mts +0 -152
- package/dist/ToolResult-BsYQRjmW.d.mts.map +0 -1
- package/dist/Toolkit-tlL0F2YR.d.mts +0 -193
- package/dist/Toolkit-tlL0F2YR.d.mts.map +0 -1
- package/dist/dist-BaenoU1A.mjs +0 -145
- package/dist/dist-BaenoU1A.mjs.map +0 -1
- package/dist/dist-nohcnkD6.mjs +0 -182
- package/dist/dist-nohcnkD6.mjs.map +0 -1
- package/dist/magic-string.es-CB2hOw9v.mjs +0 -1014
- package/dist/magic-string.es-CB2hOw9v.mjs.map +0 -1
- package/dist/test.DNmyFkvJ-YPzDR0Co.mjs +0 -10254
- package/dist/test.DNmyFkvJ-YPzDR0Co.mjs.map +0 -1
- package/dist/tool/Approval.d.mts +0 -113
- package/dist/tool/Approval.d.mts.map +0 -1
- package/dist/tool/Approval.mjs +0 -80
- package/dist/tool/Approval.mjs.map +0 -1
- package/dist/tool/Approval.test.mjs +0 -371
- package/dist/tool/Approval.test.mjs.map +0 -1
- package/dist/tool/ToolResult.d.mts +0 -2
- package/dist/tool/ToolResult.mjs +0 -85
- package/dist/tool/ToolResult.mjs.map +0 -1
- package/dist/utils-CiH_DjFW.mjs +0 -3918
- package/dist/utils-CiH_DjFW.mjs.map +0 -1
- package/src/tool/Approval.test.ts +0 -400
- package/src/tool/Approval.ts +0 -181
- package/src/tool/ToolResult.ts +0 -114
- /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":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { streamTranscriptionFrom, transcribe } from "./Transcriber.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { n as globalExpect } from "../
|
|
4
|
-
import { t as import_dist } from "../dist-
|
|
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 {
|
|
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,
|
|
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,
|
|
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 {
|
|
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,
|
|
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,
|
|
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.
|
|
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
|
-
"./
|
|
242
|
-
"types": "./dist/tool/
|
|
243
|
-
"import": "./dist/tool/
|
|
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.
|
|
325
|
+
"effect": "4.1.2",
|
|
318
326
|
"typescript": "^7.0.2"
|
|
319
327
|
},
|
|
320
328
|
"peerDependencies": {
|
|
321
|
-
"effect": ">=4.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
|
+
})
|
package/src/domain/Image.ts
CHANGED
|
@@ -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
|
|
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.
|
|
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.
|
|
61
|
+
export const ImageSource: Schema.Codec<ImageSource> = Schema.Union([
|
|
62
62
|
ImageUrlSource,
|
|
63
63
|
ImageBase64Source,
|
|
64
64
|
ImageBytesSource,
|
|
65
|
-
])
|
|
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 }
|
package/src/domain/Items.ts
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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 }
|