@effect-uai/core 0.18.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 (162) hide show
  1. package/README.md +4 -4
  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 +1 -1
  26. package/dist/{dist-C8RmtoR8.mjs → dist-B5K-y4Be.mjs} +51 -32
  27. package/dist/dist-B5K-y4Be.mjs.map +1 -0
  28. package/dist/domain/File.d.mts +2 -0
  29. package/dist/domain/File.mjs +51 -0
  30. package/dist/domain/File.mjs.map +1 -0
  31. package/dist/domain/Image.d.mts +2 -2
  32. package/dist/domain/Image.mjs +12 -2
  33. package/dist/domain/Image.mjs.map +1 -1
  34. package/dist/domain/Items.d.mts +2 -2
  35. package/dist/domain/Items.mjs +65 -4
  36. package/dist/domain/Items.mjs.map +1 -1
  37. package/dist/domain/Realtime.d.mts +72 -490
  38. package/dist/domain/Realtime.d.mts.map +1 -1
  39. package/dist/domain/Research.d.mts +1 -1
  40. package/dist/domain/Transcript.test.mjs +1 -1
  41. package/dist/domain/Turn.d.mts +57 -262
  42. package/dist/domain/Turn.d.mts.map +1 -1
  43. package/dist/domain/Turn.mjs +1 -1
  44. package/dist/embedding-model/Embedding.d.mts +1 -1
  45. package/dist/image-generator/ImageGenerator.d.mts +10 -66
  46. package/dist/image-generator/ImageGenerator.d.mts.map +1 -1
  47. package/dist/index.d.mts +10 -9
  48. package/dist/index.mjs +7 -6
  49. package/dist/language-model/LanguageModel.d.mts +2 -2
  50. package/dist/loop/Loop.d.mts +1 -1
  51. package/dist/loop/Loop.mjs.map +1 -1
  52. package/dist/messenger/Messenger.d.mts +43 -289
  53. package/dist/messenger/Messenger.d.mts.map +1 -1
  54. package/dist/messenger/MessengerAdapter.test.mjs +1 -1
  55. package/dist/observability/Metrics.d.mts +1 -1
  56. package/dist/observability/Metrics.test.mjs +1 -1
  57. package/dist/observability/Telemetry.test.mjs +1 -1
  58. package/dist/realtime/RealtimeSession.d.mts +1 -1
  59. package/dist/realtime/RealtimeSession.test.mjs +1 -1
  60. package/dist/sandbox/Sandbox.d.mts +32 -237
  61. package/dist/sandbox/Sandbox.d.mts.map +1 -1
  62. package/dist/streaming/Multipart.mjs +2 -1
  63. package/dist/streaming/Multipart.mjs.map +1 -1
  64. package/dist/streaming/Multipart.test.mjs +28 -0
  65. package/dist/streaming/Multipart.test.mjs.map +1 -0
  66. package/dist/streaming/Settle.test.mjs +1 -1
  67. package/dist/streaming/WebSocketSession.test.mjs +1 -1
  68. package/dist/testing/MockMessenger.d.mts +19 -134
  69. package/dist/testing/MockMessenger.d.mts.map +1 -1
  70. package/dist/testing/MockProvider.d.mts +1 -1
  71. package/dist/testing/MockSandbox.d.mts +65 -446
  72. package/dist/testing/MockSandbox.d.mts.map +1 -1
  73. package/dist/tool/Content.d.mts +2 -0
  74. package/dist/tool/Content.mjs +46 -0
  75. package/dist/tool/Content.mjs.map +1 -0
  76. package/dist/tool/Content.test.d.mts +1 -0
  77. package/dist/tool/Content.test.mjs +48 -0
  78. package/dist/tool/Content.test.mjs.map +1 -0
  79. package/dist/tool/HistoryCheck.d.mts +6 -15
  80. package/dist/tool/HistoryCheck.d.mts.map +1 -1
  81. package/dist/tool/HistoryCheck.mjs +10 -24
  82. package/dist/tool/HistoryCheck.mjs.map +1 -1
  83. package/dist/tool/Tool.d.mts +2 -2
  84. package/dist/tool/Tool.mjs +55 -130
  85. package/dist/tool/Tool.mjs.map +1 -1
  86. package/dist/tool/Tool.test.mjs +220 -176
  87. package/dist/tool/Tool.test.mjs.map +1 -1
  88. package/dist/tool/ToolDecision.d.mts +164 -0
  89. package/dist/tool/ToolDecision.d.mts.map +1 -0
  90. package/dist/tool/ToolDecision.mjs +146 -0
  91. package/dist/tool/ToolDecision.mjs.map +1 -0
  92. package/dist/tool/ToolDecision.test.d.mts +1 -0
  93. package/dist/tool/ToolDecision.test.mjs +330 -0
  94. package/dist/tool/ToolDecision.test.mjs.map +1 -0
  95. package/dist/tool/ToolEvent.d.mts +2 -2
  96. package/dist/tool/ToolEvent.mjs +2 -34
  97. package/dist/tool/ToolEvent.mjs.map +1 -1
  98. package/dist/tool/ToolOutput.d.mts +2 -0
  99. package/dist/tool/ToolOutput.mjs +128 -0
  100. package/dist/tool/ToolOutput.mjs.map +1 -0
  101. package/dist/tool/ToolOutput.test.d.mts +1 -0
  102. package/dist/tool/ToolOutput.test.mjs +153 -0
  103. package/dist/tool/ToolOutput.test.mjs.map +1 -0
  104. package/dist/tool/Toolkit.d.mts +2 -2
  105. package/dist/tool/Toolkit.mjs +230 -165
  106. package/dist/tool/Toolkit.mjs.map +1 -1
  107. package/dist/tool/Toolkit.test.mjs +431 -389
  108. package/dist/tool/Toolkit.test.mjs.map +1 -1
  109. package/dist/web-read/WebReadTool.d.mts +2 -2
  110. package/dist/web-read/WebReadTool.mjs +1 -0
  111. package/dist/web-read/WebReadTool.mjs.map +1 -1
  112. package/dist/web-search/WebSearchTool.d.mts +2 -2
  113. package/dist/web-search/WebSearchTool.mjs +1 -0
  114. package/dist/web-search/WebSearchTool.mjs.map +1 -1
  115. package/package.json +17 -9
  116. package/src/browser/BrowserTool.ts +5 -0
  117. package/src/domain/File.ts +79 -0
  118. package/src/domain/Image.ts +14 -4
  119. package/src/domain/Items.ts +39 -3
  120. package/src/index.ts +3 -2
  121. package/src/loop/Loop.ts +24 -13
  122. package/src/streaming/Multipart.test.ts +26 -0
  123. package/src/streaming/Multipart.ts +5 -4
  124. package/src/tool/Content.test.ts +40 -0
  125. package/src/tool/Content.ts +38 -0
  126. package/src/tool/HistoryCheck.ts +21 -26
  127. package/src/tool/Tool.test.ts +240 -241
  128. package/src/tool/Tool.ts +203 -308
  129. package/src/tool/ToolDecision.test.ts +301 -0
  130. package/src/tool/ToolDecision.ts +360 -0
  131. package/src/tool/ToolEvent.ts +21 -41
  132. package/src/tool/ToolOutput.test.ts +132 -0
  133. package/src/tool/ToolOutput.ts +198 -0
  134. package/src/tool/Toolkit.test.ts +594 -454
  135. package/src/tool/Toolkit.ts +631 -356
  136. package/src/web-read/WebReadTool.ts +2 -1
  137. package/src/web-search/WebSearchTool.ts +2 -1
  138. package/dist/Image-Cv6iBLTy.d.mts.map +0 -1
  139. package/dist/Items-C7MyrYPX.d.mts.map +0 -1
  140. package/dist/Loop-ChpaO-ya.d.mts.map +0 -1
  141. package/dist/Tool-BF78QWtn.d.mts +0 -314
  142. package/dist/Tool-BF78QWtn.d.mts.map +0 -1
  143. package/dist/ToolEvent-Di4a723B.d.mts +0 -144
  144. package/dist/ToolEvent-Di4a723B.d.mts.map +0 -1
  145. package/dist/ToolResult-BsYQRjmW.d.mts +0 -152
  146. package/dist/ToolResult-BsYQRjmW.d.mts.map +0 -1
  147. package/dist/Toolkit-tlL0F2YR.d.mts +0 -193
  148. package/dist/Toolkit-tlL0F2YR.d.mts.map +0 -1
  149. package/dist/dist-C8RmtoR8.mjs.map +0 -1
  150. package/dist/tool/Approval.d.mts +0 -113
  151. package/dist/tool/Approval.d.mts.map +0 -1
  152. package/dist/tool/Approval.mjs +0 -80
  153. package/dist/tool/Approval.mjs.map +0 -1
  154. package/dist/tool/Approval.test.mjs +0 -371
  155. package/dist/tool/Approval.test.mjs.map +0 -1
  156. package/dist/tool/ToolResult.d.mts +0 -2
  157. package/dist/tool/ToolResult.mjs +0 -85
  158. package/dist/tool/ToolResult.mjs.map +0 -1
  159. package/src/tool/Approval.test.ts +0 -400
  160. package/src/tool/Approval.ts +0 -181
  161. package/src/tool/ToolResult.ts +0 -114
  162. /package/dist/{tool/Approval.test.d.mts → streaming/Multipart.test.d.mts} +0 -0
@@ -1,25 +1,16 @@
1
- import { o as HistoryItem, y as ToolCall } from "../Items-C7MyrYPX.mjs";
2
- import { t as ToolResult } from "../ToolResult-BsYQRjmW.mjs";
1
+ import { S as ToolCallOutput, o as HistoryItem, x as ToolCall } from "../Items-Bvx8s9QH.mjs";
2
+ import { Effect, Schema } from "effect";
3
3
  declare namespace HistoryCheck_d_exports {
4
4
  export { cancelAllPending, findUnansweredCalls, isReconciled };
5
5
  }
6
- /**
7
- * Return every `function_call` in `history` that does not have a matching
8
- * `function_call_output` later in `history` (correlated by `call_id`).
9
- * Empty result = history is provider-submittable from this invariant.
10
- */
6
+ /** Every `function_call` in `history` without a `function_call_output` (by `call_id`). */
11
7
  declare const findUnansweredCalls: (history: ReadonlyArray<HistoryItem>) => ReadonlyArray<ToolCall>;
12
- /** Cheap predicate: is this history submittable to a provider? */
13
8
  declare const isReconciled: (history: ReadonlyArray<HistoryItem>) => boolean;
14
9
  /**
15
- * Synthesize cancellation results for every unanswered call. Caller maps
16
- * via `toToolCallOutput` and appends to history before submitting.
17
- *
18
- * Use when: a new user message arrives mid-approval; an approval timer
19
- * fires; a persisted checkpoint contains orphans (crash recovery); a
20
- * stateless HTTP server reconstructed history from a stale checkpoint.
10
+ * A `Cancelled` output for every unanswered call, to append before the next
11
+ * model call. For your own error, use `findUnansweredCalls` + `ToolOutput.failure`.
21
12
  */
22
- declare const cancelAllPending: (history: ReadonlyArray<HistoryItem>, reason?: string) => ReadonlyArray<ToolResult>;
13
+ declare const cancelAllPending: (history: ReadonlyArray<HistoryItem>, reason?: string) => Effect.Effect<ReadonlyArray<ToolCallOutput>, Schema.SchemaError>;
23
14
  //#endregion
24
15
  export { cancelAllPending, findUnansweredCalls, isReconciled, HistoryCheck_d_exports as t };
25
16
  //# sourceMappingURL=HistoryCheck.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"HistoryCheck.d.mts","names":[],"sources":["../../src/tool/HistoryCheck.ts"],"mappings":";;;;;;;;;;cAoBa,sBAAmB,SACrB,cAAc,iBACtB,cAAc;;cAMJ,eAAY,SAAa,cAAc;;;;;;;;;cAWvC,mBAAgB,SAClB,cAAc,cAAY,oBAElC,cAAc"}
1
+ {"version":3,"file":"HistoryCheck.d.mts","names":[],"sources":["../../src/tool/HistoryCheck.ts"],"mappings":";;;;;;cAiBa,sBAAmB,SACrB,cAAc,iBACtB,cAAc;cAKJ,eAAY,SAAa,cAAc;;;;;cAOvC,mBAAgB,SAClB,cAAc,cAAY,oBAElC,OAAO,OAAO,cAAc,iBAAiB,OAAO"}
@@ -1,44 +1,30 @@
1
1
  import { n as __exportAll } from "../rolldown-runtime-EAsCxrDo.mjs";
2
2
  import { isToolCall, isToolCallOutput } from "../domain/Items.mjs";
3
- import { cancelled } from "./ToolResult.mjs";
3
+ import { Cancelled, failure } from "./ToolOutput.mjs";
4
+ import { Effect } from "effect";
4
5
  //#region src/tool/HistoryCheck.ts
5
6
  /**
6
- * History-consistency primitives. Useful even WITHOUT HITL.
7
- *
8
- * Every provider rejects a new request if any prior `function_call` lacks
9
- * a matching `function_call_output`. Multi-turn flows that can be
10
- * interrupted, restarted, or branched (HITL, mid-stream abort, persisted
11
- * checkpoints, stateless HTTP servers) need to detect orphans and
12
- * synthesize closing outputs before submitting.
13
- *
14
- * Recipe author calls these at known transition points (right before the
15
- * next provider request). Not invoked from inside the loop.
7
+ * History consistency. Providers reject a request when a `function_call` has no
8
+ * matching `function_call_output`; flows that can be interrupted, restarted or
9
+ * branched (approvals, aborts, persisted checkpoints) close orphans with these
10
+ * before the next model call.
16
11
  */
17
12
  var HistoryCheck_exports = /* @__PURE__ */ __exportAll({
18
13
  cancelAllPending: () => cancelAllPending,
19
14
  findUnansweredCalls: () => findUnansweredCalls,
20
15
  isReconciled: () => isReconciled
21
16
  });
22
- /**
23
- * Return every `function_call` in `history` that does not have a matching
24
- * `function_call_output` later in `history` (correlated by `call_id`).
25
- * Empty result = history is provider-submittable from this invariant.
26
- */
17
+ /** Every `function_call` in `history` without a `function_call_output` (by `call_id`). */
27
18
  const findUnansweredCalls = (history) => {
28
19
  const answered = new Set(history.filter(isToolCallOutput).map((o) => o.call_id));
29
20
  return history.filter(isToolCall).filter((c) => !answered.has(c.call_id));
30
21
  };
31
- /** Cheap predicate: is this history submittable to a provider? */
32
22
  const isReconciled = (history) => findUnansweredCalls(history).length === 0;
33
23
  /**
34
- * Synthesize cancellation results for every unanswered call. Caller maps
35
- * via `toToolCallOutput` and appends to history before submitting.
36
- *
37
- * Use when: a new user message arrives mid-approval; an approval timer
38
- * fires; a persisted checkpoint contains orphans (crash recovery); a
39
- * stateless HTTP server reconstructed history from a stale checkpoint.
24
+ * A `Cancelled` output for every unanswered call, to append before the next
25
+ * model call. For your own error, use `findUnansweredCalls` + `ToolOutput.failure`.
40
26
  */
41
- const cancelAllPending = (history, reason) => findUnansweredCalls(history).map((call) => cancelled(call, reason));
27
+ const cancelAllPending = (history, reason = "The call was cancelled before it ran.") => Effect.forEach(findUnansweredCalls(history), (call) => failure(call, Cancelled, new Cancelled({ message: reason })));
42
28
  //#endregion
43
29
  export { cancelAllPending, findUnansweredCalls, isReconciled, HistoryCheck_exports as t };
44
30
 
@@ -1 +1 @@
1
- {"version":3,"file":"HistoryCheck.mjs","names":[],"sources":["../../src/tool/HistoryCheck.ts"],"sourcesContent":["/**\n * History-consistency primitives. Useful even WITHOUT HITL.\n *\n * Every provider rejects a new request if any prior `function_call` lacks\n * a matching `function_call_output`. Multi-turn flows that can be\n * interrupted, restarted, or branched (HITL, mid-stream abort, persisted\n * checkpoints, stateless HTTP servers) need to detect orphans and\n * synthesize closing outputs before submitting.\n *\n * Recipe author calls these at known transition points (right before the\n * next provider request). Not invoked from inside the loop.\n */\nimport { type ToolCall, type HistoryItem, isToolCall, isToolCallOutput } from \"../domain/Items.js\"\nimport { type ToolResult, cancelled } from \"./ToolResult.js\"\n\n/**\n * Return every `function_call` in `history` that does not have a matching\n * `function_call_output` later in `history` (correlated by `call_id`).\n * Empty result = history is provider-submittable from this invariant.\n */\nexport const findUnansweredCalls = (\n history: ReadonlyArray<HistoryItem>,\n): ReadonlyArray<ToolCall> => {\n const answered = new Set(history.filter(isToolCallOutput).map((o) => o.call_id))\n return history.filter(isToolCall).filter((c) => !answered.has(c.call_id))\n}\n\n/** Cheap predicate: is this history submittable to a provider? */\nexport const isReconciled = (history: ReadonlyArray<HistoryItem>): boolean =>\n findUnansweredCalls(history).length === 0\n\n/**\n * Synthesize cancellation results for every unanswered call. Caller maps\n * via `toToolCallOutput` and appends to history before submitting.\n *\n * Use when: a new user message arrives mid-approval; an approval timer\n * fires; a persisted checkpoint contains orphans (crash recovery); a\n * stateless HTTP server reconstructed history from a stale checkpoint.\n */\nexport const cancelAllPending = (\n history: ReadonlyArray<HistoryItem>,\n reason?: string,\n): ReadonlyArray<ToolResult> => findUnansweredCalls(history).map((call) => cancelled(call, reason))\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAoBA,MAAa,uBACX,YAC4B;CAC5B,MAAM,WAAW,IAAI,IAAI,QAAQ,OAAO,gBAAgB,CAAC,CAAC,KAAK,MAAM,EAAE,OAAO,CAAC;CAC/E,OAAO,QAAQ,OAAO,UAAU,CAAC,CAAC,QAAQ,MAAM,CAAC,SAAS,IAAI,EAAE,OAAO,CAAC;AAC1E;;AAGA,MAAa,gBAAgB,YAC3B,oBAAoB,OAAO,CAAC,CAAC,WAAW;;;;;;;;;AAU1C,MAAa,oBACX,SACA,WAC8B,oBAAoB,OAAO,CAAC,CAAC,KAAK,SAAS,UAAU,MAAM,MAAM,CAAC"}
1
+ {"version":3,"file":"HistoryCheck.mjs","names":["ToolOutput.failure","ToolOutput.Cancelled"],"sources":["../../src/tool/HistoryCheck.ts"],"sourcesContent":["/**\n * History consistency. Providers reject a request when a `function_call` has no\n * matching `function_call_output`; flows that can be interrupted, restarted or\n * branched (approvals, aborts, persisted checkpoints) close orphans with these\n * before the next model call.\n */\nimport { Effect, type Schema } from \"effect\"\nimport {\n type HistoryItem,\n isToolCall,\n isToolCallOutput,\n type ToolCall,\n type ToolCallOutput,\n} from \"../domain/Items.js\"\nimport * as ToolOutput from \"./ToolOutput.js\"\n\n/** Every `function_call` in `history` without a `function_call_output` (by `call_id`). */\nexport const findUnansweredCalls = (\n history: ReadonlyArray<HistoryItem>,\n): ReadonlyArray<ToolCall> => {\n const answered = new Set(history.filter(isToolCallOutput).map((o) => o.call_id))\n return history.filter(isToolCall).filter((c) => !answered.has(c.call_id))\n}\n\nexport const isReconciled = (history: ReadonlyArray<HistoryItem>): boolean =>\n findUnansweredCalls(history).length === 0\n\n/**\n * A `Cancelled` output for every unanswered call, to append before the next\n * model call. For your own error, use `findUnansweredCalls` + `ToolOutput.failure`.\n */\nexport const cancelAllPending = (\n history: ReadonlyArray<HistoryItem>,\n reason = \"The call was cancelled before it ran.\",\n): Effect.Effect<ReadonlyArray<ToolCallOutput>, Schema.SchemaError> =>\n Effect.forEach(findUnansweredCalls(history), (call) =>\n ToolOutput.failure(call, ToolOutput.Cancelled, new ToolOutput.Cancelled({ message: reason })),\n )\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,MAAa,uBACX,YAC4B;CAC5B,MAAM,WAAW,IAAI,IAAI,QAAQ,OAAO,gBAAgB,CAAC,CAAC,KAAK,MAAM,EAAE,OAAO,CAAC;CAC/E,OAAO,QAAQ,OAAO,UAAU,CAAC,CAAC,QAAQ,MAAM,CAAC,SAAS,IAAI,EAAE,OAAO,CAAC;AAC1E;AAEA,MAAa,gBAAgB,YAC3B,oBAAoB,OAAO,CAAC,CAAC,WAAW;;;;;AAM1C,MAAa,oBACX,SACA,SAAS,4CAET,OAAO,QAAQ,oBAAoB,OAAO,IAAI,SAC5CA,QAAmB,MAAMC,WAAsB,IAAIA,UAAqB,EAAE,SAAS,OAAO,CAAC,CAAC,CAC9F"}
@@ -1,2 +1,2 @@
1
- import { A as providerToolsOf, C as fromEffectSchema, D as make, E as isProviderTool, M as toDescriptors, N as withName, O as noInput, P as withRun, S as fail, T as interaction, a as Emit, b as descriptorsOf, c as SignalTool, d as ToolE, f as ToolError, g as ToolValidationError, h as ToolR, i as DecodeResult, j as signal, k as provider, l as Tool, m as ToolInputSchema, n as AnyTool, o as InteractionTool, p as ToolFailed, r as DecodableTool, s as ProviderTool, t as AnyLocalTool, u as ToolDescriptor, v as decodeArgs, w as fromStandardSchema, x as execute, y as decodeCallInput } from "../Tool-BF78QWtn.mjs";
2
- export { AnyLocalTool, AnyTool, DecodableTool, DecodeResult, Emit, InteractionTool, ProviderTool, SignalTool, Tool, ToolDescriptor, ToolE, ToolError, ToolFailed, ToolInputSchema, ToolR, ToolValidationError, decodeArgs, decodeCallInput, descriptorsOf, execute, fail, fromEffectSchema, fromStandardSchema, interaction, isProviderTool, make, noInput, provider, providerToolsOf, signal, toDescriptors, withName, withRun };
1
+ import { A as fromStandardSchema, B as withName, C as WithFailures, D as descriptorsOf, E as decodeCallInput, F as provider, I as providerToolsOf, L as toDescriptors, M as isStreamed, N as make, O as fail, P as noInput, R as toStream, T as decodeArgs, V as withRun, _ as ToolInputSchema, a as Declared, b as ToolUnhandled, c as InputSchema, d as Tool, f as ToolDescriptor, g as ToolFailure, h as ToolFailed, i as AnyTool, j as isProviderTool, k as fromEffectSchema, l as ProviderTool, m as ToolError, n as AnyDescribed, o as DecodableTool, p as ToolE, r as AnyLocalTool, s as DecodeResult, t as AnyDeclared, u as Run, v as ToolOutput, w as declare, x as ToolValidationError, y as ToolR, z as withFailures } from "../Tool-Bkryw6-h.mjs";
2
+ export { AnyDeclared, AnyDescribed, AnyLocalTool, AnyTool, Declared, DecodableTool, DecodeResult, InputSchema, ProviderTool, Run, Tool, ToolDescriptor, ToolE, ToolError, ToolFailed, ToolFailure, ToolInputSchema, ToolOutput, ToolR, ToolUnhandled, ToolValidationError, WithFailures, declare, decodeArgs, decodeCallInput, descriptorsOf, fail, fromEffectSchema, fromStandardSchema, isProviderTool, isStreamed, make, noInput, provider, providerToolsOf, toDescriptors, toStream, withFailures, withName, withRun };
@@ -1,27 +1,26 @@
1
1
  import { n as __exportAll } from "../rolldown-runtime-EAsCxrDo.mjs";
2
- import { toolCallOutput } from "../domain/Items.mjs";
3
- import { serializeValue } from "./ToolResult.mjs";
4
- import { Effect, Match, Schema } from "effect";
2
+ import { Effect, Function, Match, Schema, Stream } from "effect";
5
3
  //#region src/tool/Tool.ts
6
4
  var Tool_exports = /* @__PURE__ */ __exportAll({
7
5
  ToolError: () => ToolError,
8
6
  ToolFailed: () => ToolFailed,
9
7
  ToolValidationError: () => ToolValidationError,
8
+ declare: () => declare,
10
9
  decodeArgs: () => decodeArgs,
11
10
  decodeCallInput: () => decodeCallInput,
12
11
  descriptorsOf: () => descriptorsOf,
13
- execute: () => execute,
14
12
  fail: () => fail,
15
13
  fromEffectSchema: () => fromEffectSchema,
16
14
  fromStandardSchema: () => fromStandardSchema,
17
- interaction: () => interaction,
18
15
  isProviderTool: () => isProviderTool,
16
+ isStreamed: () => isStreamed,
19
17
  make: () => make,
20
18
  noInput: () => noInput,
21
19
  provider: () => provider,
22
20
  providerToolsOf: () => providerToolsOf,
23
- signal: () => signal,
24
21
  toDescriptors: () => toDescriptors,
22
+ toStream: () => toStream,
23
+ withFailures: () => withFailures,
25
24
  withName: () => withName,
26
25
  withRun: () => withRun
27
26
  });
@@ -33,74 +32,36 @@ var ToolError = class extends Schema.TaggedError("@betalyra/effect-uai/ToolError
33
32
  }) {};
34
33
  /**
35
34
  * One Standard Schema validation issue, carried on `ToolValidationError`.
36
- * Mirrors `StandardSchemaV1.Issue`; `path` is left as `unknown` elements
37
- * because Standard Schema path segments may be symbols or `{ key }` objects.
35
+ * `path` elements stay `unknown`: Standard Schema segments may be symbols or `{ key }`.
38
36
  */
39
37
  const ToolValidationIssue = Schema.Struct({
40
38
  message: Schema.String,
41
39
  path: Schema.optional(Schema.Array(Schema.Unknown))
42
40
  });
43
- /**
44
- * The model's `arguments` for a call failed the tool's `inputSchema`. Distinct
45
- * from `ToolError` (malformed JSON, runtime crash) so callers can tell a
46
- * contract violation apart from a parse or execution failure, and so the
47
- * structured `issues` survive instead of being flattened into a message string.
48
- */
41
+ /** A call's `arguments` failed the tool's `inputSchema` (from `decodeArgs`). */
49
42
  var ToolValidationError = class extends Schema.TaggedError("@betalyra/effect-uai/ToolValidationError")("ToolValidationError", {
50
43
  call_id: Schema.String,
51
44
  tool: Schema.String,
52
45
  issues: Schema.Array(ToolValidationIssue)
53
46
  }) {};
54
47
  /**
55
- * The deliberate "speak to the model" failure sentinel. A tool's `run` that
56
- * fails with a `ToolFailed` (or a bare `string`, its sugar) is absorbed by
57
- * `Toolkit.run` into a `ToolResult.Failure` the model reads and adapts to,
58
- * instead of ending the run. Every other error type propagates typed on the
59
- * executor's stream. `kind` overrides the synthesized `Failure.kind`
60
- * (default `"tool_failed"`) so a tool can hand the model a distinguishable
61
- * category (`"not_found"`, `"rate_limited"`) without a new result variant.
62
- */
63
- var ToolFailed = class extends Schema.TaggedError("@betalyra/effect-uai/ToolFailed")("ToolFailed", {
64
- message: Schema.String,
65
- kind: Schema.optional(Schema.String)
66
- }) {};
67
- /**
68
- * Fail a tool's `run` with a model-visible message (optionally a `kind`).
69
- * `yield* Tool.fail("page not found", { kind: "not_found" })` inside a
70
- * `run`'s `Effect.gen`; the executor absorbs it as `ToolResult.Failure`.
71
- */
72
- const fail = (message, options) => Effect.fail(new ToolFailed({
73
- message,
74
- ...options?.kind !== void 0 ? { kind: options.kind } : {}
75
- }));
76
- /**
77
- * Convenience wrapper for Effect Schema users - adds both the
78
- * `validate` and `jsonSchema` extensions to a plain Effect Schema so it
79
- * can be used as a `Tool.inputSchema`.
48
+ * A ready-made model-visible error for one-off messages. It reaches the model
49
+ * only when listed in the tool's `failureSchema` (or via `Toolkit.describeFailures`).
80
50
  */
51
+ var ToolFailed = class extends Schema.TaggedError("@betalyra/effect-uai/ToolFailed")("ToolFailed", { message: Schema.String }) {};
52
+ /** `yield* Tool.fail("page not found")` inside a `run`. */
53
+ const fail = (message) => Effect.fail(new ToolFailed({ message }));
54
+ /** Adds the Standard Schema and Standard JSON Schema interfaces to an Effect Schema. */
81
55
  const fromEffectSchema = (schema) => Schema.toStandardJSONSchemaV1(Schema.toStandardSchemaV1(schema));
82
56
  /**
83
- * Use any schema library that implements both Standard Schema (validation)
84
- * and Standard JSON Schema (JSON Schema generation) as a `Tool.inputSchema`.
85
- * Covers Zod 4.2+, Valibot 1.2+, and ArkType 2.1.28+ in one helper.
86
- *
87
- * Effect Schema doesn't implement Standard JSON Schema natively — use
88
- * `fromEffectSchema` for those.
89
- *
90
- * The intersection constraint catches missing interfaces at compile time:
91
- * a Zod v3 schema (no Standard JSON Schema) produces a precise type error
92
- * pointing at the missing interface rather than a runtime surprise. The
93
- * helper itself is a thin type-narrowing identity — schemas that satisfy
94
- * both standards already structurally satisfy `ToolInputSchema`; the
95
- * helper makes the input type inference explicit at the call site.
57
+ * Types a schema that implements both Standard Schema and Standard JSON Schema
58
+ * (Zod 4.2+, Valibot 1.2+, ArkType 2.1.28+). A schema missing either half is a
59
+ * compile error here rather than a runtime surprise.
96
60
  */
97
61
  const fromStandardSchema = (schema) => schema;
98
62
  /**
99
- * Input schema for a tool that takes no arguments. Renders a clean
100
- * `{ type: "object", properties: {} }`; validation accepts anything and
101
- * yields `{}`. Use it instead of `fromEffectSchema(Schema.Struct({}))`,
102
- * which renders a degenerate `anyOf` (object-or-array) that strict
103
- * providers like Gemini reject.
63
+ * Input for a tool without arguments: renders `{ type: "object", properties: {} }`
64
+ * (an empty `Schema.Struct` renders an `anyOf` that strict providers reject).
104
65
  */
105
66
  const noInput = { "~standard": {
106
67
  version: 1,
@@ -118,80 +79,63 @@ const noInput = { "~standard": {
118
79
  }
119
80
  } };
120
81
  const resolveInputSchema = (schema) => Schema.isSchema(schema) ? fromEffectSchema(schema) : schema;
121
- /** A model-visible tool with a local `Effect` executor. */
122
- const make = (spec) => ({
123
- _tag: "LocalTool",
124
- ...spec,
125
- inputSchema: resolveInputSchema(spec.inputSchema)
126
- });
82
+ /** Whether `run` returned a `Stream` (values as partials) rather than an `Effect` (one value). */
83
+ const isStreamed = (out) => Stream.isStream(out);
84
+ /** An `Effect` is a one-element stream. */
85
+ const toStream = (out) => Effect.isEffect(out) ? Stream.fromEffect(out) : out;
127
86
  /**
128
- * A provider-hosted tool (native web search, code execution, RAG grounding).
129
- * No local executor — `provider`/`config` drive the provider adapter's
130
- * rendering. The model sees it; `Toolkit.run` reports it as `non_local_tool`.
87
+ * A tool `Toolkit.run` executes. `outputSchema` says what `run` returns and its
88
+ * encoded side must be JSON. `Content.Value` is the explicit "anything": text,
89
+ * JSON or media.
131
90
  */
132
- const provider = (spec) => ({
133
- _tag: "ProviderTool",
91
+ const make = (spec) => ({
134
92
  ...spec,
93
+ _tag: "LocalTool",
135
94
  inputSchema: resolveInputSchema(spec.inputSchema)
136
95
  });
137
96
  /**
138
- * A typed control-flow signal to the agent loop (escalate, pause, schedule,
139
- * hand off). Decode-only: the loop interprets the call rather than executing a
140
- * handler, so there is no `run`.
97
+ * A tool without `run`: the app handles its calls. A signal to the loop (no
98
+ * `outputSchema`), or a call answered elsewhere (typed by `outputSchema`).
141
99
  */
142
- const signal = (spec) => ({
143
- _tag: "SignalTool",
100
+ const declare = (spec) => ({
144
101
  ...spec,
102
+ _tag: "DeclaredTool",
145
103
  inputSchema: resolveInputSchema(spec.inputSchema)
146
104
  });
147
- /**
148
- * A typed request for an external actor to respond before the loop resumes
149
- * (frontend, Telegram, CLI prompt). Decode-only; the loop stops/pauses and
150
- * resumes by appending the actor's `function_call_output`.
151
- */
152
- const interaction = (spec) => ({
153
- _tag: "InteractionTool",
105
+ /** A provider-hosted tool. */
106
+ const provider = (spec) => ({
107
+ _tag: "ProviderTool",
154
108
  ...spec,
155
109
  inputSchema: resolveInputSchema(spec.inputSchema)
156
110
  });
157
- /**
158
- * Return a copy of a tool under a new `name`. Useful for resolving a name
159
- * clash before combining tools into one `Toolkit`. Literal-preserving, so the
160
- * renamed tool keys the toolkit record under the new name statically.
161
- */
111
+ /** A copy of a tool under a new `name`, e.g. to resolve a clash before `Toolkit.compose`. */
162
112
  const withName = (tool, name) => ({
163
113
  ...tool,
164
114
  name
165
115
  });
166
116
  /**
167
- * Replace a local tool's `run`, keeping its model-facing definition (name,
168
- * description, schema, `_tag`) identical. The new `run`'s `input` is typed from
169
- * the original tool, so override/mock need no annotation:
170
- *
171
- * const safe = { ...toolkit, send_email: Tool.withRun(toolkit.send_email,
172
- * ({ to }) => Effect.succeed({ status: "dry-run", to })) }
173
- *
174
- * Descriptors stay identical to production, so a mocked toolkit can't drift
175
- * from the contract the model sees.
117
+ * Give a tool a `run`, keeping everything else (name, description, schemas):
118
+ * implement a declared tool (a spec shared with the browser), or mock a tool.
119
+ * The new `run` returns the same output type.
176
120
  */
177
121
  const withRun = (tool, run) => ({
178
122
  ...tool,
123
+ _tag: "LocalTool",
179
124
  run
180
125
  });
181
- /** True for provider-hosted tools — the kind a provider renders natively. */
182
- const isProviderTool = (tool) => tool._tag === "ProviderTool";
183
126
  /**
184
- * The `ProviderTool`s in a toolkit, for a provider adapter to render as its
185
- * native hosted-tool entries (web search, code execution, grounding). The other
186
- * kinds render as function declarations via `descriptorsOf`.
127
+ * Add errors a call of this tool may end with, e.g. the app's `ToolDecision.Denied`
128
+ * for a tool that needs approval. Its `run` need not raise them; the app closes
129
+ * calls with them (`Toolkit.close`).
187
130
  */
131
+ const withFailures = Function.dual(2, (tool, failures) => ({
132
+ ...tool,
133
+ failureSchema: tool.failureSchema === void 0 ? failures : Schema.Union([tool.failureSchema, failures])
134
+ }));
135
+ const isProviderTool = (tool) => tool._tag === "ProviderTool";
136
+ /** The provider-hosted tools in a toolkit, for an adapter to render natively. */
188
137
  const providerToolsOf = (toolkit) => toolkit === void 0 ? [] : Object.values(toolkit).filter(isProviderTool);
189
- /**
190
- * Render tools to provider-agnostic descriptors. `ProviderTool`s are excluded:
191
- * they are provider-hosted and must never leak into the function-declaration
192
- * list — each adapter renders them natively via `providerToolsOf`. Every other
193
- * kind is model-visible as a declaration.
194
- */
138
+ /** Function descriptors for every tool except provider-hosted ones. */
195
139
  const toDescriptors = (tools) => tools.filter((tool) => !isProviderTool(tool)).map((tool) => {
196
140
  const inputSchema = tool.inputSchema["~standard"].jsonSchema.input({ target: "draft-2020-12" });
197
141
  const strict = "strict" in tool ? tool.strict : void 0;
@@ -206,19 +150,12 @@ const toDescriptors = (tools) => tools.filter((tool) => !isProviderTool(tool)).m
206
150
  inputSchema
207
151
  };
208
152
  });
209
- /**
210
- * Render a `Toolkit` (a name-indexed record of tools) to descriptors, treating
211
- * an absent toolkit as no tools. The normalization point the `LanguageModel`
212
- * boundary uses so a request can carry the toolkit itself instead of a
213
- * pre-rendered descriptor array. Lives here (not on `Toolkit`) to keep providers
214
- * free of a dependency on the toolkit module — it only needs the tool values.
215
- */
153
+ /** `toDescriptors` over a toolkit record; an absent toolkit has none. */
216
154
  const descriptorsOf = (toolkit) => toolkit === void 0 ? [] : toDescriptors(Object.values(toolkit));
217
155
  const VALIDATION_THREW = [{ message: "input schema validation threw" }];
218
156
  /**
219
- * Parse and validate a call's `arguments`. Empty arguments normalize to
220
- * `{}` (some models emit `""` for zero-arg tools); a throwing validator is
221
- * captured, not propagated. Never fails.
157
+ * Parse and validate a call's `arguments`, as data. Empty arguments read as `{}`
158
+ * (some models send `""` for tools without arguments). Never fails.
222
159
  */
223
160
  const decodeCallInput = (tool, call) => {
224
161
  const raw = call.arguments.trim() === "" ? "{}" : call.arguments;
@@ -240,13 +177,8 @@ const decodeCallInput = (tool, call) => {
240
177
  }))), Effect.catch((captured) => Effect.succeed(captured)));
241
178
  };
242
179
  /**
243
- * Decode and validate a function_call's JSON `arguments` against the tool's
244
- * own `inputSchema`, yielding the typed input. The decode-only half of
245
- * `execute` - reach for it when you intercept a call to translate it into a
246
- * control-flow decision rather than running the tool's `run`.
247
- *
248
- * Malformed JSON fails with `ToolError`; a parsed body that violates
249
- * `inputSchema` fails with `ToolValidationError` carrying the issues.
180
+ * A call's typed input, e.g. for a tool without `run` the loop handles itself.
181
+ * Bad JSON fails with `ToolError`, a schema violation with `ToolValidationError`.
250
182
  */
251
183
  const decodeArgs = (tool, call) => decodeCallInput(tool, call).pipe(Effect.flatMap(Match.type().pipe(Match.tag("ok", ({ input }) => Effect.succeed(input)), Match.tag("parseError", () => Effect.fail(new ToolError({
252
184
  call_id: call.call_id,
@@ -257,14 +189,7 @@ const decodeArgs = (tool, call) => decodeCallInput(tool, call).pipe(Effect.flatM
257
189
  tool: tool.name,
258
190
  issues
259
191
  }))), Match.exhaustive)));
260
- /**
261
- * Decode and validate the JSON arguments of a function_call against the
262
- * tool's input schema, run the tool, and serialize the output into a
263
- * function_call_output item. Single-shot: intermediate events emitted by
264
- * `run` are discarded (use `Toolkit.run` to stream them).
265
- */
266
- const execute = (tool, call) => decodeArgs(tool, call).pipe(Effect.flatMap((input) => tool.run(input, () => Effect.void)), Effect.map((output) => toolCallOutput(call.call_id, serializeValue(output))));
267
192
  //#endregion
268
- export { ToolError, ToolFailed, ToolValidationError, decodeArgs, decodeCallInput, descriptorsOf, execute, fail, fromEffectSchema, fromStandardSchema, interaction, isProviderTool, make, noInput, provider, providerToolsOf, signal, Tool_exports as t, toDescriptors, withName, withRun };
193
+ export { ToolError, ToolFailed, ToolValidationError, declare, decodeArgs, decodeCallInput, descriptorsOf, fail, fromEffectSchema, fromStandardSchema, isProviderTool, isStreamed, make, noInput, provider, providerToolsOf, Tool_exports as t, toDescriptors, toStream, withFailures, withName, withRun };
269
194
 
270
195
  //# sourceMappingURL=Tool.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Tool.mjs","names":[],"sources":["../../src/tool/Tool.ts"],"sourcesContent":["import type { StandardJSONSchemaV1, StandardSchemaV1 } from \"@standard-schema/spec\"\nimport { Effect, Match, Schema } from \"effect\"\nimport type { ToolCall, ToolCallOutput } from \"../domain/Items.js\"\nimport { toolCallOutput } from \"../domain/Items.js\"\nimport { serializeValue } from \"./ToolResult.js\"\n\nexport class ToolError extends Schema.TaggedError<ToolError>(\"@betalyra/effect-uai/ToolError\")(\n \"ToolError\",\n {\n call_id: Schema.String,\n tool: Schema.String,\n message: Schema.String,\n cause: Schema.optional(Schema.Unknown),\n },\n) {}\n\n/**\n * One Standard Schema validation issue, carried on `ToolValidationError`.\n * Mirrors `StandardSchemaV1.Issue`; `path` is left as `unknown` elements\n * because Standard Schema path segments may be symbols or `{ key }` objects.\n */\nconst ToolValidationIssue = Schema.Struct({\n message: Schema.String,\n path: Schema.optional(Schema.Array(Schema.Unknown)),\n})\n\n/**\n * The model's `arguments` for a call failed the tool's `inputSchema`. Distinct\n * from `ToolError` (malformed JSON, runtime crash) so callers can tell a\n * contract violation apart from a parse or execution failure, and so the\n * structured `issues` survive instead of being flattened into a message string.\n */\nexport class ToolValidationError extends Schema.TaggedError<ToolValidationError>(\n \"@betalyra/effect-uai/ToolValidationError\",\n)(\"ToolValidationError\", {\n call_id: Schema.String,\n tool: Schema.String,\n issues: Schema.Array(ToolValidationIssue),\n}) {}\n\n/**\n * The deliberate \"speak to the model\" failure sentinel. A tool's `run` that\n * fails with a `ToolFailed` (or a bare `string`, its sugar) is absorbed by\n * `Toolkit.run` into a `ToolResult.Failure` the model reads and adapts to,\n * instead of ending the run. Every other error type propagates typed on the\n * executor's stream. `kind` overrides the synthesized `Failure.kind`\n * (default `\"tool_failed\"`) so a tool can hand the model a distinguishable\n * category (`\"not_found\"`, `\"rate_limited\"`) without a new result variant.\n */\nexport class ToolFailed extends Schema.TaggedError<ToolFailed>(\"@betalyra/effect-uai/ToolFailed\")(\n \"ToolFailed\",\n {\n message: Schema.String,\n kind: Schema.optional(Schema.String),\n },\n) {}\n\n/**\n * Fail a tool's `run` with a model-visible message (optionally a `kind`).\n * `yield* Tool.fail(\"page not found\", { kind: \"not_found\" })` inside a\n * `run`'s `Effect.gen`; the executor absorbs it as `ToolResult.Failure`.\n */\nexport const fail = (\n message: string,\n options?: { readonly kind?: string },\n): Effect.Effect<never, ToolFailed> =>\n Effect.fail(\n new ToolFailed({ message, ...(options?.kind !== undefined ? { kind: options.kind } : {}) }),\n )\n\n/**\n * Schemas accepted on `Tool.inputSchema`. Must implement both Standard\n * Schema validation and JSON Schema conversion (for rendering tool\n * descriptors to provider request bodies).\n *\n * Any Standard-Schema-compliant library that exposes both interfaces\n * works directly: Zod 4+, Valibot, ArkType, Effect Schema (after\n * `fromEffectSchema`), etc.\n */\nexport type ToolInputSchema<Input = unknown> = StandardSchemaV1<unknown, Input> &\n StandardJSONSchemaV1<unknown, Input>\n\n/**\n * Convenience wrapper for Effect Schema users - adds both the\n * `validate` and `jsonSchema` extensions to a plain Effect Schema so it\n * can be used as a `Tool.inputSchema`.\n */\nexport const fromEffectSchema = <S extends Schema.Codec<any, any, never, any>>(\n schema: S,\n): S & ToolInputSchema<S[\"Type\"]> =>\n Schema.toStandardJSONSchemaV1(Schema.toStandardSchemaV1(schema))\n\n/**\n * Use any schema library that implements both Standard Schema (validation)\n * and Standard JSON Schema (JSON Schema generation) as a `Tool.inputSchema`.\n * Covers Zod 4.2+, Valibot 1.2+, and ArkType 2.1.28+ in one helper.\n *\n * Effect Schema doesn't implement Standard JSON Schema natively — use\n * `fromEffectSchema` for those.\n *\n * The intersection constraint catches missing interfaces at compile time:\n * a Zod v3 schema (no Standard JSON Schema) produces a precise type error\n * pointing at the missing interface rather than a runtime surprise. The\n * helper itself is a thin type-narrowing identity — schemas that satisfy\n * both standards already structurally satisfy `ToolInputSchema`; the\n * helper makes the input type inference explicit at the call site.\n */\nexport const fromStandardSchema = <S extends StandardSchemaV1 & StandardJSONSchemaV1>(\n schema: S,\n): S & ToolInputSchema<StandardSchemaV1.InferOutput<S>> =>\n schema as S & ToolInputSchema<StandardSchemaV1.InferOutput<S>>\n\n/**\n * Input schema for a tool that takes no arguments. Renders a clean\n * `{ type: \"object\", properties: {} }`; validation accepts anything and\n * yields `{}`. Use it instead of `fromEffectSchema(Schema.Struct({}))`,\n * which renders a degenerate `anyOf` (object-or-array) that strict\n * providers like Gemini reject.\n */\nexport const noInput: ToolInputSchema<Record<string, never>> = {\n \"~standard\": {\n version: 1,\n vendor: \"effect-uai\",\n validate: () => ({ value: {} }),\n jsonSchema: {\n input: () => ({ type: \"object\", properties: {} }),\n output: () => ({ type: \"object\", properties: {} }),\n },\n },\n}\n\n/**\n * Emit one intermediate `Event` from inside a tool's `run`. Backed by the\n * executor's per-call queue, so it returns an `Effect` (backpressure) and\n * composes with `Stream.runForEach(emit)`.\n */\nexport type Emit<Event> = (event: Event) => Effect.Effect<void>\n\n/**\n * A model-visible tool with a local `Effect` executor. `run` computes the\n * model-facing `Output`; emitting progress is a side channel via `emit`. A\n * plain tool never calls `emit` (its `Event` is irrelevant); a streaming tool\n * emits intermediate `Event`s that flow to the consumer as\n * `ToolEvent.Progress` in real time.\n *\n * This is one of four tool *kinds*, discriminated by `_tag`. The other three\n * (`ProviderTool`, `SignalTool`, `InteractionTool`) are model-visible but have\n * no local executor — see their constructors below. `Tool` keeps its name (and\n * the `Tool.make` constructor) because the local kind is by far the common one.\n */\nexport type Tool<Name extends string, Input, Event, Output, E = unknown, R = never> = {\n readonly _tag: \"LocalTool\"\n readonly name: Name\n readonly description: string\n readonly inputSchema: ToolInputSchema<Input>\n readonly run: (input: Input, emit: Emit<Event>) => Effect.Effect<Output, E, R>\n /**\n * Bound on this tool's emit queue. Unbounded when omitted. Per-tool because\n * backpressure depends on how a given tool emits, unlike `concurrency`\n * (cross-tool, on `Toolkit.run`'s options).\n */\n readonly emitBufferSize?: number\n /**\n * Whether the provider should render this tool with its strict-mode\n * flag (OpenAI's `strict: true`, etc). Default: true. The framework\n * never rewrites the schema; if the rendered JSON Schema isn't\n * compatible, the provider returns an error.\n */\n readonly strict?: boolean\n}\n\n/**\n * A provider-hosted tool: visible to the model and executed by the *provider*\n * (native web search, code execution, RAG grounding), never by this process.\n * It has no local `run`; `provider`/`config` tell the provider adapter how to\n * render it. Passing it to `Toolkit.run` yields a `non_local_tool` result.\n */\nexport type ProviderTool<Name extends string, Input, Provider extends string, Config> = {\n readonly _tag: \"ProviderTool\"\n readonly name: Name\n readonly description: string\n readonly inputSchema: ToolInputSchema<Input>\n readonly provider: Provider\n readonly config: Config\n readonly strict?: boolean\n}\n\n/**\n * A typed request for the agent loop to change control flow (escalate, pause,\n * schedule, hand off). Model-visible and decodable (`decodeArgs`) but never\n * locally executed — the loop intercepts the call in `onTurnComplete` and acts\n * on it, so there is no fake `run`. `Toolkit.run` reports it as `non_local_tool`.\n */\nexport type SignalTool<Name extends string, Input> = {\n readonly _tag: \"SignalTool\"\n readonly name: Name\n readonly description: string\n readonly inputSchema: ToolInputSchema<Input>\n}\n\n/**\n * A typed request for an external actor (user, channel, frontend) to respond\n * before the loop resumes. Like `SignalTool` it is decode-only, but its\n * lifecycle differs: the loop usually stops/pauses and resumes later by\n * appending a `function_call_output` once the actor replies.\n */\nexport type InteractionTool<Name extends string, Input> = {\n readonly _tag: \"InteractionTool\"\n readonly name: Name\n readonly description: string\n readonly inputSchema: ToolInputSchema<Input>\n}\n\n/** A local (executable) tool of any shape. Readability alias. */\nexport type AnyLocalTool<E = any, R = any> = Tool<string, any, any, any, E, R>\n\n/** Any of the four model-visible tool kinds. */\nexport type AnyTool<E = any, R = any> =\n | Tool<string, any, any, any, E, R>\n | ProviderTool<string, any, string, any>\n | SignalTool<string, any>\n | InteractionTool<string, any>\n\n/** A model-visible tool that carries a decodable input schema (every kind). */\nexport type DecodableTool<Input> = {\n readonly name: string\n readonly inputSchema: ToolInputSchema<Input>\n}\n\n/** Extract the `R` of a local tool; non-local kinds contribute `never`. */\nexport type ToolR<T> = T extends Tool<string, any, any, any, any, infer R> ? R : never\n\n/** Extract the `E` of a local tool; non-local kinds contribute `never`. */\nexport type ToolE<T> = T extends Tool<string, any, any, any, infer E, any> ? E : never\n\n/**\n * Provider-agnostic tool descriptor. Each provider maps `inputSchema`\n * to its own wire field (OpenAI → `parameters`, Anthropic →\n * `input_schema`). Built from a `Tool` by `Tool.toDescriptors`.\n */\nexport type ToolDescriptor = {\n readonly name: string\n readonly description: string\n readonly inputSchema: Record<string, unknown>\n readonly strict?: boolean\n}\n\nconst resolveInputSchema = (\n schema: ToolInputSchema<any> | Schema.Codec<any, any, never, any>,\n): ToolInputSchema<any> =>\n Schema.isSchema(schema)\n ? fromEffectSchema(schema as Schema.Codec<any, any, never, any>)\n : (schema as ToolInputSchema<any>)\n\n/** A model-visible tool with a local `Effect` executor. */\nexport const make: {\n <\n Name extends string,\n S extends Schema.Codec<any, any, never, any>,\n Event,\n Output,\n E = never,\n R = never,\n >(\n spec: Omit<Tool<Name, S[\"Type\"], Event, Output, E, R>, \"_tag\" | \"inputSchema\"> & {\n readonly inputSchema: S\n },\n ): Tool<Name, S[\"Type\"], Event, Output, E, R>\n <Name extends string, Input, Event, Output, E = never, R = never>(\n spec: Omit<Tool<Name, Input, Event, Output, E, R>, \"_tag\">,\n ): Tool<Name, Input, Event, Output, E, R>\n} = (\n spec: Omit<AnyLocalTool, \"_tag\" | \"inputSchema\"> & {\n readonly inputSchema: ToolInputSchema<any> | Schema.Codec<any, any, never, any>\n },\n): AnyLocalTool => ({\n _tag: \"LocalTool\",\n ...spec,\n inputSchema: resolveInputSchema(spec.inputSchema),\n})\n\n/**\n * A provider-hosted tool (native web search, code execution, RAG grounding).\n * No local executor — `provider`/`config` drive the provider adapter's\n * rendering. The model sees it; `Toolkit.run` reports it as `non_local_tool`.\n */\nexport const provider: {\n <\n Name extends string,\n S extends Schema.Codec<any, any, never, any>,\n Provider extends string,\n Config,\n >(\n spec: Omit<ProviderTool<Name, S[\"Type\"], Provider, Config>, \"_tag\" | \"inputSchema\"> & {\n readonly inputSchema: S\n },\n ): ProviderTool<Name, S[\"Type\"], Provider, Config>\n <Name extends string, Input, Provider extends string, Config>(\n spec: Omit<ProviderTool<Name, Input, Provider, Config>, \"_tag\">,\n ): ProviderTool<Name, Input, Provider, Config>\n} = (\n spec: Omit<ProviderTool<string, any, string, any>, \"_tag\" | \"inputSchema\"> & {\n readonly inputSchema: ToolInputSchema<any> | Schema.Codec<any, any, never, any>\n },\n): ProviderTool<string, any, string, any> => ({\n _tag: \"ProviderTool\",\n ...spec,\n inputSchema: resolveInputSchema(spec.inputSchema),\n})\n\n/**\n * A typed control-flow signal to the agent loop (escalate, pause, schedule,\n * hand off). Decode-only: the loop interprets the call rather than executing a\n * handler, so there is no `run`.\n */\nexport const signal: {\n <Name extends string, S extends Schema.Codec<any, any, never, any>>(\n spec: Omit<SignalTool<Name, S[\"Type\"]>, \"_tag\" | \"inputSchema\"> & {\n readonly inputSchema: S\n },\n ): SignalTool<Name, S[\"Type\"]>\n <Name extends string, Input>(spec: Omit<SignalTool<Name, Input>, \"_tag\">): SignalTool<Name, Input>\n} = (\n spec: Omit<SignalTool<string, any>, \"_tag\" | \"inputSchema\"> & {\n readonly inputSchema: ToolInputSchema<any> | Schema.Codec<any, any, never, any>\n },\n): SignalTool<string, any> => ({\n _tag: \"SignalTool\",\n ...spec,\n inputSchema: resolveInputSchema(spec.inputSchema),\n})\n\n/**\n * A typed request for an external actor to respond before the loop resumes\n * (frontend, Telegram, CLI prompt). Decode-only; the loop stops/pauses and\n * resumes by appending the actor's `function_call_output`.\n */\nexport const interaction: {\n <Name extends string, S extends Schema.Codec<any, any, never, any>>(\n spec: Omit<InteractionTool<Name, S[\"Type\"]>, \"_tag\" | \"inputSchema\"> & {\n readonly inputSchema: S\n },\n ): InteractionTool<Name, S[\"Type\"]>\n <Name extends string, Input>(\n spec: Omit<InteractionTool<Name, Input>, \"_tag\">,\n ): InteractionTool<Name, Input>\n} = (\n spec: Omit<InteractionTool<string, any>, \"_tag\" | \"inputSchema\"> & {\n readonly inputSchema: ToolInputSchema<any> | Schema.Codec<any, any, never, any>\n },\n): InteractionTool<string, any> => ({\n _tag: \"InteractionTool\",\n ...spec,\n inputSchema: resolveInputSchema(spec.inputSchema),\n})\n\n/**\n * Return a copy of a tool under a new `name`. Useful for resolving a name\n * clash before combining tools into one `Toolkit`. Literal-preserving, so the\n * renamed tool keys the toolkit record under the new name statically.\n */\nexport const withName = <N extends string, T extends AnyTool>(\n tool: T,\n name: N,\n): Omit<T, \"name\"> & { readonly name: N } => ({ ...tool, name })\n\n/**\n * Replace a local tool's `run`, keeping its model-facing definition (name,\n * description, schema, `_tag`) identical. The new `run`'s `input` is typed from\n * the original tool, so override/mock need no annotation:\n *\n * const safe = { ...toolkit, send_email: Tool.withRun(toolkit.send_email,\n * ({ to }) => Effect.succeed({ status: \"dry-run\", to })) }\n *\n * Descriptors stay identical to production, so a mocked toolkit can't drift\n * from the contract the model sees.\n */\nexport const withRun = <\n Name extends string,\n Input,\n Event,\n Output,\n E,\n R,\n Output2,\n E2 = never,\n R2 = never,\n>(\n tool: Tool<Name, Input, Event, Output, E, R>,\n run: (input: Input, emit: Emit<Event>) => Effect.Effect<Output2, E2, R2>,\n): Tool<Name, Input, Event, Output2, E2, R2> => ({ ...tool, run })\n\n/** True for provider-hosted tools — the kind a provider renders natively. */\nexport const isProviderTool = (tool: AnyTool): tool is ProviderTool<string, any, string, any> =>\n tool._tag === \"ProviderTool\"\n\n/**\n * The `ProviderTool`s in a toolkit, for a provider adapter to render as its\n * native hosted-tool entries (web search, code execution, grounding). The other\n * kinds render as function declarations via `descriptorsOf`.\n */\nexport const providerToolsOf = (\n toolkit?: Readonly<Record<string, AnyTool>>,\n): ReadonlyArray<ProviderTool<string, any, string, any>> =>\n toolkit === undefined ? [] : Object.values(toolkit).filter(isProviderTool)\n\n/**\n * Render tools to provider-agnostic descriptors. `ProviderTool`s are excluded:\n * they are provider-hosted and must never leak into the function-declaration\n * list — each adapter renders them natively via `providerToolsOf`. Every other\n * kind is model-visible as a declaration.\n */\nexport const toDescriptors = (tools: ReadonlyArray<AnyTool>): ReadonlyArray<ToolDescriptor> =>\n tools\n .filter((tool) => !isProviderTool(tool))\n .map((tool) => {\n const inputSchema = tool.inputSchema[\"~standard\"].jsonSchema.input({\n target: \"draft-2020-12\",\n })\n // `strict` only exists on local/provider kinds; signals/interactions omit it.\n const strict = \"strict\" in tool ? tool.strict : undefined\n return strict !== undefined\n ? { name: tool.name, description: tool.description, inputSchema, strict }\n : { name: tool.name, description: tool.description, inputSchema }\n })\n\n/**\n * Render a `Toolkit` (a name-indexed record of tools) to descriptors, treating\n * an absent toolkit as no tools. The normalization point the `LanguageModel`\n * boundary uses so a request can carry the toolkit itself instead of a\n * pre-rendered descriptor array. Lives here (not on `Toolkit`) to keep providers\n * free of a dependency on the toolkit module — it only needs the tool values.\n */\nexport const descriptorsOf = (\n toolkit?: Readonly<Record<string, AnyTool>>,\n): ReadonlyArray<ToolDescriptor> =>\n toolkit === undefined ? [] : toDescriptors(Object.values(toolkit))\n\n/**\n * Outcome of decoding a call's `arguments` against a tool's `inputSchema`,\n * as data so both the typed (`decodeArgs`) and result-synthesizing\n * (`Toolkit.run`) callers can translate it their own way.\n */\nexport type DecodeResult<Input> =\n | { readonly _tag: \"ok\"; readonly input: Input }\n | { readonly _tag: \"parseError\" }\n | { readonly _tag: \"invalid\"; readonly issues: ReadonlyArray<StandardSchemaV1.Issue> }\n\nconst VALIDATION_THREW: ReadonlyArray<StandardSchemaV1.Issue> = [\n { message: \"input schema validation threw\" },\n]\n\n/**\n * Parse and validate a call's `arguments`. Empty arguments normalize to\n * `{}` (some models emit `\"\"` for zero-arg tools); a throwing validator is\n * captured, not propagated. Never fails.\n */\nexport const decodeCallInput = <Input>(\n tool: DecodableTool<Input>,\n call: ToolCall,\n): Effect.Effect<DecodeResult<Input>> => {\n const raw = call.arguments.trim() === \"\" ? \"{}\" : call.arguments\n return Effect.try({\n // @effect-diagnostics-next-linepreferSchemaOverJson:off\n try: () => JSON.parse(raw) as unknown,\n catch: (): DecodeResult<Input> => ({ _tag: \"parseError\" }),\n }).pipe(\n Effect.flatMap((parsed) =>\n Effect.tryPromise({\n try: () => Promise.resolve(tool.inputSchema[\"~standard\"].validate(parsed)),\n catch: (): DecodeResult<Input> => ({ _tag: \"invalid\", issues: VALIDATION_THREW }),\n }).pipe(\n Effect.map((result): DecodeResult<Input> =>\n result.issues !== undefined\n ? { _tag: \"invalid\", issues: result.issues }\n : { _tag: \"ok\", input: result.value },\n ),\n ),\n ),\n Effect.catch((captured: DecodeResult<Input>) => Effect.succeed(captured)),\n )\n}\n\n/**\n * Decode and validate a function_call's JSON `arguments` against the tool's\n * own `inputSchema`, yielding the typed input. The decode-only half of\n * `execute` - reach for it when you intercept a call to translate it into a\n * control-flow decision rather than running the tool's `run`.\n *\n * Malformed JSON fails with `ToolError`; a parsed body that violates\n * `inputSchema` fails with `ToolValidationError` carrying the issues.\n */\nexport const decodeArgs = <Input>(\n tool: DecodableTool<Input>,\n call: ToolCall,\n): Effect.Effect<Input, ToolError | ToolValidationError> =>\n decodeCallInput(tool, call).pipe(\n Effect.flatMap(\n Match.type<DecodeResult<Input>>().pipe(\n Match.tag(\"ok\", ({ input }) => Effect.succeed(input)),\n Match.tag(\"parseError\", () =>\n Effect.fail(\n new ToolError({\n call_id: call.call_id,\n tool: tool.name,\n message: \"Failed to parse JSON arguments\",\n }),\n ),\n ),\n Match.tag(\"invalid\", ({ issues }) =>\n Effect.fail(new ToolValidationError({ call_id: call.call_id, tool: tool.name, issues })),\n ),\n Match.exhaustive,\n ),\n ),\n )\n\n/**\n * Decode and validate the JSON arguments of a function_call against the\n * tool's input schema, run the tool, and serialize the output into a\n * function_call_output item. Single-shot: intermediate events emitted by\n * `run` are discarded (use `Toolkit.run` to stream them).\n */\nexport const execute = <Name extends string, Input, Event, Output, E, R>(\n tool: Tool<Name, Input, Event, Output, E, R>,\n call: ToolCall,\n): Effect.Effect<ToolCallOutput, E | ToolError | ToolValidationError, R> =>\n decodeArgs(tool, call).pipe(\n Effect.flatMap((input) => tool.run(input, () => Effect.void)),\n Effect.map((output) => toolCallOutput(call.call_id, serializeValue(output))),\n )\n"],"mappings":"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"}
1
+ {"version":3,"file":"Tool.mjs","names":[],"sources":["../../src/tool/Tool.ts"],"sourcesContent":["import type { StandardJSONSchemaV1, StandardSchemaV1 } from \"@standard-schema/spec\"\nimport { Effect, Function, Match, Schema, Stream } from \"effect\"\nimport type { ToolCall } from \"../domain/Items.js\"\n\nexport class ToolError extends Schema.TaggedError<ToolError>(\"@betalyra/effect-uai/ToolError\")(\n \"ToolError\",\n {\n call_id: Schema.String,\n tool: Schema.String,\n message: Schema.String,\n cause: Schema.optional(Schema.Unknown),\n },\n) {}\n\n/**\n * One Standard Schema validation issue, carried on `ToolValidationError`.\n * `path` elements stay `unknown`: Standard Schema segments may be symbols or `{ key }`.\n */\nconst ToolValidationIssue = Schema.Struct({\n message: Schema.String,\n path: Schema.optional(Schema.Array(Schema.Unknown)),\n})\n\n/** A call's `arguments` failed the tool's `inputSchema` (from `decodeArgs`). */\nexport class ToolValidationError extends Schema.TaggedError<ToolValidationError>(\n \"@betalyra/effect-uai/ToolValidationError\",\n)(\"ToolValidationError\", {\n call_id: Schema.String,\n tool: Schema.String,\n issues: Schema.Array(ToolValidationIssue),\n}) {}\n\n/**\n * A ready-made model-visible error for one-off messages. It reaches the model\n * only when listed in the tool's `failureSchema` (or via `Toolkit.describeFailures`).\n */\nexport class ToolFailed extends Schema.TaggedError<ToolFailed>(\"@betalyra/effect-uai/ToolFailed\")(\n \"ToolFailed\",\n { message: Schema.String },\n) {}\n\n/** `yield* Tool.fail(\"page not found\")` inside a `run`. */\nexport const fail = (message: string): Effect.Effect<never, ToolFailed> =>\n Effect.fail(new ToolFailed({ message }))\n\n// ---------------------------------------------------------------------------\n// Input schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Standard Schema with JSON Schema conversion (Zod 4+, Valibot, ArkType, or an\n * Effect Schema via `fromEffectSchema`). Validates the model's arguments and\n * renders the provider descriptor.\n */\nexport type ToolInputSchema<Input = unknown> = StandardSchemaV1<unknown, Input> &\n StandardJSONSchemaV1<unknown, Input>\n\n/** What `inputSchema` accepts: an Effect Schema directly, or a `ToolInputSchema`. */\nexport type InputSchema<Input> = Schema.Codec<Input, any, never, any> | ToolInputSchema<Input>\n\n/** Adds the Standard Schema and Standard JSON Schema interfaces to an Effect Schema. */\nexport const fromEffectSchema = <S extends Schema.Codec<any, any, never, any>>(\n schema: S,\n): S & ToolInputSchema<S[\"Type\"]> =>\n Schema.toStandardJSONSchemaV1(Schema.toStandardSchemaV1(schema))\n\n/**\n * Types a schema that implements both Standard Schema and Standard JSON Schema\n * (Zod 4.2+, Valibot 1.2+, ArkType 2.1.28+). A schema missing either half is a\n * compile error here rather than a runtime surprise.\n */\nexport const fromStandardSchema = <S extends StandardSchemaV1 & StandardJSONSchemaV1>(\n schema: S,\n): S & ToolInputSchema<StandardSchemaV1.InferOutput<S>> =>\n schema as S & ToolInputSchema<StandardSchemaV1.InferOutput<S>>\n\n/**\n * Input for a tool without arguments: renders `{ type: \"object\", properties: {} }`\n * (an empty `Schema.Struct` renders an `anyOf` that strict providers reject).\n */\nexport const noInput: ToolInputSchema<Record<string, never>> = {\n \"~standard\": {\n version: 1,\n vendor: \"effect-uai\",\n validate: () => ({ value: {} }),\n jsonSchema: {\n input: () => ({ type: \"object\", properties: {} }),\n output: () => ({ type: \"object\", properties: {} }),\n },\n },\n}\n\nconst resolveInputSchema = <Input>(schema: InputSchema<Input>): ToolInputSchema<Input> =>\n Schema.isSchema(schema) ? fromEffectSchema(schema) : schema\n\n// ---------------------------------------------------------------------------\n// Tool kinds\n// ---------------------------------------------------------------------------\n\n/** One result (`Effect`) or partial results whose last element is the result (`Stream`). */\nexport type Run<Input, Output, E, R> = (\n input: Input,\n) => Effect.Effect<Output, E, R> | Stream.Stream<Output, E, R>\n\n/** Whether `run` returned a `Stream` (values as partials) rather than an `Effect` (one value). */\nexport const isStreamed = <A, E, R>(\n out: Effect.Effect<A, E, R> | Stream.Stream<A, E, R>,\n): out is Stream.Stream<A, E, R> => Stream.isStream(out)\n\n/** An `Effect` is a one-element stream. */\nexport const toStream = <A, E, R>(\n out: Effect.Effect<A, E, R> | Stream.Stream<A, E, R>,\n): Stream.Stream<A, E, R> => (Effect.isEffect(out) ? Stream.fromEffect(out) : out)\n\ntype Described<Name extends string, Input, Output, Failure> = {\n readonly name: Name\n readonly description: string\n readonly inputSchema: ToolInputSchema<Input>\n /** Checks every value and encodes it for history and the UI. A rejected value is `OutputInvalid`. */\n readonly outputSchema?: Schema.Codec<Output, any>\n /**\n * Every error a call may end with that the model sees: errors `run` raises and\n * errors the app closes calls with (`ToolDecision.Denied`, see `Toolkit.close`).\n */\n readonly failureSchema?: Schema.Codec<Failure, any>\n /** Render with the provider's strict-mode flag. Default: true. */\n readonly strict?: boolean\n}\n\n/**\n * A model-visible tool that `Toolkit.run` executes: errors matching\n * `failureSchema` reach the model, any other error fails the stream.\n */\nexport type Tool<\n Name extends string,\n Input,\n Output,\n Failure = never,\n E = never,\n R = never,\n> = Described<Name, Input, Output, Failure> & {\n readonly _tag: \"LocalTool\"\n readonly run: Run<Input, Output, E, R>\n}\n\n/**\n * A model-visible tool without `run`: the app handles its calls. A signal to\n * the loop (`escalate`), or a call answered elsewhere (`ask_user`, typed by\n * `outputSchema`). `Tool.withRun` turns it into a `Tool`.\n */\nexport type Declared<Name extends string, Input, Output = never, Failure = never> = Described<\n Name,\n Input,\n Output,\n Failure\n> & {\n readonly _tag: \"DeclaredTool\"\n}\n\n/**\n * A provider-hosted tool (native web search, code execution, grounding), executed\n * by the provider. `provider` / `config` drive the adapter's rendering.\n */\nexport type ProviderTool<Name extends string, Input, Provider extends string, Config> = {\n readonly _tag: \"ProviderTool\"\n readonly name: Name\n readonly description: string\n readonly inputSchema: ToolInputSchema<Input>\n readonly provider: Provider\n readonly config: Config\n readonly strict?: boolean\n}\n\nexport type AnyLocalTool<E = any, R = any> = Tool<string, any, any, any, E, R>\n\nexport type AnyDeclared = Declared<string, any, any, any>\n\n/** A tool with schemas the app sees: `Tool` or `Declared`. */\nexport type AnyDescribed = AnyLocalTool | AnyDeclared\n\nexport type AnyTool<E = any, R = any> =\n | AnyLocalTool<E, R>\n | AnyDeclared\n | ProviderTool<string, any, string, any>\n\n/** Any tool kind with a decodable input schema. */\nexport type DecodableTool<Input> = {\n readonly name: string\n readonly inputSchema: ToolInputSchema<Input>\n}\n\ntype DescribedTag = { readonly _tag: \"LocalTool\" | \"DeclaredTool\" }\n\nexport type ToolOutput<T> = T extends DescribedTag & Described<string, any, infer O, any>\n ? O\n : never\nexport type ToolFailure<T> = T extends DescribedTag & Described<string, any, any, infer F>\n ? F\n : never\nexport type ToolE<T> = T extends Tool<string, any, any, any, infer E, any> ? E : never\nexport type ToolR<T> = T extends Tool<string, any, any, any, any, infer R> ? R : never\n\n/** The errors a tool did not declare: these fail `Toolkit.run`'s stream. */\nexport type ToolUnhandled<T> =\n T extends Tool<string, any, any, infer F, infer E, any> ? Exclude<E, F> : never\n\ntype Spec<Name extends string, Input, Failure, FailureEncoded> = {\n readonly name: Name\n readonly description: string\n readonly inputSchema: InputSchema<Input>\n readonly failureSchema?: Schema.Codec<Failure, FailureEncoded>\n readonly strict?: boolean\n}\n\n/**\n * A tool `Toolkit.run` executes. `outputSchema` says what `run` returns and its\n * encoded side must be JSON. `Content.Value` is the explicit \"anything\": text,\n * JSON or media.\n */\nexport const make = <\n const Name extends string,\n Input,\n Output,\n Encoded extends Schema.Json,\n Failure = never,\n FailureEncoded extends Schema.Json = never,\n E = never,\n R = never,\n>(\n spec: Spec<Name, Input, Failure, FailureEncoded> & {\n readonly outputSchema: Schema.Codec<Output, Encoded>\n readonly run: Run<Input, Output, E, R>\n },\n): Tool<Name, Input, Output, Failure, E, R> => ({\n ...spec,\n _tag: \"LocalTool\",\n inputSchema: resolveInputSchema(spec.inputSchema),\n})\n\n/**\n * A tool without `run`: the app handles its calls. A signal to the loop (no\n * `outputSchema`), or a call answered elsewhere (typed by `outputSchema`).\n */\nexport const declare = <\n const Name extends string,\n Input,\n Output = never,\n Encoded extends Schema.Json = never,\n Failure = never,\n FailureEncoded extends Schema.Json = never,\n>(\n spec: Spec<Name, Input, Failure, FailureEncoded> & {\n readonly outputSchema?: Schema.Codec<Output, Encoded>\n },\n): Declared<Name, Input, Output, Failure> => ({\n ...spec,\n _tag: \"DeclaredTool\",\n inputSchema: resolveInputSchema(spec.inputSchema),\n})\n\n/** A provider-hosted tool. */\nexport const provider = <const Name extends string, Input, Provider extends string, Config>(\n spec: Omit<ProviderTool<Name, Input, Provider, Config>, \"_tag\" | \"inputSchema\"> & {\n readonly inputSchema: InputSchema<Input>\n },\n): ProviderTool<Name, Input, Provider, Config> => ({\n _tag: \"ProviderTool\",\n ...spec,\n inputSchema: resolveInputSchema(spec.inputSchema),\n})\n\n/** A copy of a tool under a new `name`, e.g. to resolve a clash before `Toolkit.compose`. */\nexport const withName = <N extends string, T extends AnyTool>(\n tool: T,\n name: N,\n): Omit<T, \"name\"> & { readonly name: N } => ({ ...tool, name })\n\n/**\n * Give a tool a `run`, keeping everything else (name, description, schemas):\n * implement a declared tool (a spec shared with the browser), or mock a tool.\n * The new `run` returns the same output type.\n */\nexport const withRun = <Name extends string, Input, Output, Failure, E2 = never, R2 = never>(\n tool: Tool<Name, Input, Output, Failure, any, any> | Declared<Name, Input, Output, Failure>,\n run: Run<Input, Output, E2, R2>,\n): Tool<Name, Input, Output, Failure, E2, R2> => ({ ...tool, _tag: \"LocalTool\", run })\n\n/** The same kind of tool, with more failures. */\nexport type WithFailures<T, F2> =\n T extends Tool<infer N, infer I, infer O, infer F, infer E, infer R>\n ? Tool<N, I, O, F | F2, E, R>\n : T extends Declared<infer N, infer I, infer O, infer F>\n ? Declared<N, I, O, F | F2>\n : never\n\n/**\n * Add errors a call of this tool may end with, e.g. the app's `ToolDecision.Denied`\n * for a tool that needs approval. Its `run` need not raise them; the app closes\n * calls with them (`Toolkit.close`).\n */\nexport const withFailures: {\n <F2, F2Encoded extends Schema.Json>(\n failures: Schema.Codec<F2, F2Encoded>,\n ): <T extends AnyDescribed>(tool: T) => WithFailures<T, F2>\n <T extends AnyDescribed, F2, F2Encoded extends Schema.Json>(\n tool: T,\n failures: Schema.Codec<F2, F2Encoded>,\n ): WithFailures<T, F2>\n} = Function.dual(2, (tool: AnyDescribed, failures: Schema.Codec<unknown, any>): AnyDescribed => ({\n ...tool,\n failureSchema:\n tool.failureSchema === undefined ? failures : Schema.Union([tool.failureSchema, failures]),\n}))\n\n// ---------------------------------------------------------------------------\n// Descriptors\n// ---------------------------------------------------------------------------\n\n/** Provider-agnostic descriptor; each provider maps `inputSchema` to its own field. */\nexport type ToolDescriptor = {\n readonly name: string\n readonly description: string\n readonly inputSchema: Record<string, unknown>\n readonly strict?: boolean\n}\n\nexport const isProviderTool = (tool: AnyTool): tool is ProviderTool<string, any, string, any> =>\n tool._tag === \"ProviderTool\"\n\n/** The provider-hosted tools in a toolkit, for an adapter to render natively. */\nexport const providerToolsOf = (\n toolkit?: Readonly<Record<string, AnyTool>>,\n): ReadonlyArray<ProviderTool<string, any, string, any>> =>\n toolkit === undefined ? [] : Object.values(toolkit).filter(isProviderTool)\n\n/** Function descriptors for every tool except provider-hosted ones. */\nexport const toDescriptors = (tools: ReadonlyArray<AnyTool>): ReadonlyArray<ToolDescriptor> =>\n tools\n .filter((tool) => !isProviderTool(tool))\n .map((tool) => {\n const inputSchema = tool.inputSchema[\"~standard\"].jsonSchema.input({\n target: \"draft-2020-12\",\n })\n const strict = \"strict\" in tool ? tool.strict : undefined\n return strict !== undefined\n ? { name: tool.name, description: tool.description, inputSchema, strict }\n : { name: tool.name, description: tool.description, inputSchema }\n })\n\n/** `toDescriptors` over a toolkit record; an absent toolkit has none. */\nexport const descriptorsOf = (\n toolkit?: Readonly<Record<string, AnyTool>>,\n): ReadonlyArray<ToolDescriptor> =>\n toolkit === undefined ? [] : toDescriptors(Object.values(toolkit))\n\n// ---------------------------------------------------------------------------\n// Decoding arguments\n// ---------------------------------------------------------------------------\n\nexport type DecodeResult<Input> =\n | { readonly _tag: \"ok\"; readonly input: Input }\n | { readonly _tag: \"parseError\" }\n | { readonly _tag: \"invalid\"; readonly issues: ReadonlyArray<StandardSchemaV1.Issue> }\n\nconst VALIDATION_THREW: ReadonlyArray<StandardSchemaV1.Issue> = [\n { message: \"input schema validation threw\" },\n]\n\n/**\n * Parse and validate a call's `arguments`, as data. Empty arguments read as `{}`\n * (some models send `\"\"` for tools without arguments). Never fails.\n */\nexport const decodeCallInput = <Input>(\n tool: DecodableTool<Input>,\n call: ToolCall,\n): Effect.Effect<DecodeResult<Input>> => {\n const raw = call.arguments.trim() === \"\" ? \"{}\" : call.arguments\n return Effect.try({\n // @effect-diagnostics-next-linepreferSchemaOverJson:off\n try: () => JSON.parse(raw) as unknown,\n catch: (): DecodeResult<Input> => ({ _tag: \"parseError\" }),\n }).pipe(\n Effect.flatMap((parsed) =>\n Effect.tryPromise({\n try: () => Promise.resolve(tool.inputSchema[\"~standard\"].validate(parsed)),\n catch: (): DecodeResult<Input> => ({ _tag: \"invalid\", issues: VALIDATION_THREW }),\n }).pipe(\n Effect.map((result): DecodeResult<Input> =>\n result.issues !== undefined\n ? { _tag: \"invalid\", issues: result.issues }\n : { _tag: \"ok\", input: result.value },\n ),\n ),\n ),\n Effect.catch((captured: DecodeResult<Input>) => Effect.succeed(captured)),\n )\n}\n\n/**\n * A call's typed input, e.g. for a tool without `run` the loop handles itself.\n * Bad JSON fails with `ToolError`, a schema violation with `ToolValidationError`.\n */\nexport const decodeArgs = <Input>(\n tool: DecodableTool<Input>,\n call: ToolCall,\n): Effect.Effect<Input, ToolError | ToolValidationError> =>\n decodeCallInput(tool, call).pipe(\n Effect.flatMap(\n Match.type<DecodeResult<Input>>().pipe(\n Match.tag(\"ok\", ({ input }) => Effect.succeed(input)),\n Match.tag(\"parseError\", () =>\n Effect.fail(\n new ToolError({\n call_id: call.call_id,\n tool: tool.name,\n message: \"Failed to parse JSON arguments\",\n }),\n ),\n ),\n Match.tag(\"invalid\", ({ issues }) =>\n Effect.fail(new ToolValidationError({ call_id: call.call_id, tool: tool.name, issues })),\n ),\n Match.exhaustive,\n ),\n ),\n )\n"],"mappings":"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"}