@effect/ai 0.26.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/Chat/package.json +6 -0
  2. package/EmbeddingModel/package.json +6 -0
  3. package/IdGenerator/package.json +6 -0
  4. package/LanguageModel/package.json +6 -0
  5. package/Model/package.json +6 -0
  6. package/Prompt/package.json +6 -0
  7. package/Response/package.json +6 -0
  8. package/Telemetry/package.json +6 -0
  9. package/Tool/package.json +6 -0
  10. package/Toolkit/package.json +6 -0
  11. package/dist/cjs/AiError.js +575 -11
  12. package/dist/cjs/AiError.js.map +1 -1
  13. package/dist/cjs/Chat.js +302 -0
  14. package/dist/cjs/Chat.js.map +1 -0
  15. package/dist/cjs/EmbeddingModel.js +184 -0
  16. package/dist/cjs/EmbeddingModel.js.map +1 -0
  17. package/dist/cjs/IdGenerator.js +255 -0
  18. package/dist/cjs/IdGenerator.js.map +1 -0
  19. package/dist/cjs/LanguageModel.js +584 -0
  20. package/dist/cjs/LanguageModel.js.map +1 -0
  21. package/dist/cjs/McpServer.js +12 -4
  22. package/dist/cjs/McpServer.js.map +1 -1
  23. package/dist/cjs/Model.js +118 -0
  24. package/dist/cjs/Model.js.map +1 -0
  25. package/dist/cjs/Prompt.js +649 -0
  26. package/dist/cjs/Prompt.js.map +1 -0
  27. package/dist/cjs/Response.js +635 -0
  28. package/dist/cjs/Response.js.map +1 -0
  29. package/dist/cjs/Telemetry.js +176 -0
  30. package/dist/cjs/Telemetry.js.map +1 -0
  31. package/dist/cjs/Tokenizer.js +87 -8
  32. package/dist/cjs/Tokenizer.js.map +1 -1
  33. package/dist/cjs/Tool.js +556 -0
  34. package/dist/cjs/Tool.js.map +1 -0
  35. package/dist/cjs/Toolkit.js +279 -0
  36. package/dist/cjs/Toolkit.js.map +1 -0
  37. package/dist/cjs/index.js +21 -19
  38. package/dist/dts/AiError.d.ts +577 -9
  39. package/dist/dts/AiError.d.ts.map +1 -1
  40. package/dist/dts/Chat.d.ts +356 -0
  41. package/dist/dts/Chat.d.ts.map +1 -0
  42. package/dist/dts/EmbeddingModel.d.ts +153 -0
  43. package/dist/dts/EmbeddingModel.d.ts.map +1 -0
  44. package/dist/dts/IdGenerator.d.ts +272 -0
  45. package/dist/dts/IdGenerator.d.ts.map +1 -0
  46. package/dist/dts/LanguageModel.d.ts +458 -0
  47. package/dist/dts/LanguageModel.d.ts.map +1 -0
  48. package/dist/dts/McpSchema.d.ts +25 -25
  49. package/dist/dts/McpServer.d.ts +6 -4
  50. package/dist/dts/McpServer.d.ts.map +1 -1
  51. package/dist/dts/Model.d.ts +124 -0
  52. package/dist/dts/Model.d.ts.map +1 -0
  53. package/dist/dts/Prompt.d.ts +1119 -0
  54. package/dist/dts/Prompt.d.ts.map +1 -0
  55. package/dist/dts/Response.d.ts +1519 -0
  56. package/dist/dts/Response.d.ts.map +1 -0
  57. package/dist/dts/Telemetry.d.ts +520 -0
  58. package/dist/dts/Telemetry.d.ts.map +1 -0
  59. package/dist/dts/Tokenizer.d.ts +131 -13
  60. package/dist/dts/Tokenizer.d.ts.map +1 -1
  61. package/dist/dts/Tool.d.ts +876 -0
  62. package/dist/dts/Tool.d.ts.map +1 -0
  63. package/dist/dts/Toolkit.d.ts +310 -0
  64. package/dist/dts/Toolkit.d.ts.map +1 -0
  65. package/dist/dts/index.d.ts +498 -13
  66. package/dist/dts/index.d.ts.map +1 -1
  67. package/dist/esm/AiError.js +570 -10
  68. package/dist/esm/AiError.js.map +1 -1
  69. package/dist/esm/Chat.js +291 -0
  70. package/dist/esm/Chat.js.map +1 -0
  71. package/dist/esm/EmbeddingModel.js +173 -0
  72. package/dist/esm/EmbeddingModel.js.map +1 -0
  73. package/dist/esm/IdGenerator.js +245 -0
  74. package/dist/esm/IdGenerator.js.map +1 -0
  75. package/dist/esm/LanguageModel.js +572 -0
  76. package/dist/esm/LanguageModel.js.map +1 -0
  77. package/dist/esm/McpServer.js +12 -4
  78. package/dist/esm/McpServer.js.map +1 -1
  79. package/dist/esm/Model.js +108 -0
  80. package/dist/esm/Model.js.map +1 -0
  81. package/dist/esm/Prompt.js +633 -0
  82. package/dist/esm/Prompt.js.map +1 -0
  83. package/dist/esm/Response.js +619 -0
  84. package/dist/esm/Response.js.map +1 -0
  85. package/dist/esm/Telemetry.js +166 -0
  86. package/dist/esm/Telemetry.js.map +1 -0
  87. package/dist/esm/Tokenizer.js +87 -8
  88. package/dist/esm/Tokenizer.js.map +1 -1
  89. package/dist/esm/Tool.js +534 -0
  90. package/dist/esm/Tool.js.map +1 -0
  91. package/dist/esm/Toolkit.js +269 -0
  92. package/dist/esm/Toolkit.js.map +1 -0
  93. package/dist/esm/index.js +498 -13
  94. package/dist/esm/index.js.map +1 -1
  95. package/package.json +76 -68
  96. package/src/AiError.ts +739 -9
  97. package/src/Chat.ts +546 -0
  98. package/src/EmbeddingModel.ts +311 -0
  99. package/src/IdGenerator.ts +320 -0
  100. package/src/LanguageModel.ts +1074 -0
  101. package/src/McpServer.ts +337 -194
  102. package/src/Model.ts +155 -0
  103. package/src/Prompt.ts +1616 -0
  104. package/src/Response.ts +2131 -0
  105. package/src/Telemetry.ts +655 -0
  106. package/src/Tokenizer.ts +145 -24
  107. package/src/Tool.ts +1267 -0
  108. package/src/Toolkit.ts +516 -0
  109. package/src/index.ts +499 -13
  110. package/AiChat/package.json +0 -6
  111. package/AiEmbeddingModel/package.json +0 -6
  112. package/AiInput/package.json +0 -6
  113. package/AiLanguageModel/package.json +0 -6
  114. package/AiModel/package.json +0 -6
  115. package/AiResponse/package.json +0 -6
  116. package/AiTelemetry/package.json +0 -6
  117. package/AiTool/package.json +0 -6
  118. package/AiToolkit/package.json +0 -6
  119. package/dist/cjs/AiChat.js +0 -122
  120. package/dist/cjs/AiChat.js.map +0 -1
  121. package/dist/cjs/AiEmbeddingModel.js +0 -109
  122. package/dist/cjs/AiEmbeddingModel.js.map +0 -1
  123. package/dist/cjs/AiInput.js +0 -458
  124. package/dist/cjs/AiInput.js.map +0 -1
  125. package/dist/cjs/AiLanguageModel.js +0 -351
  126. package/dist/cjs/AiLanguageModel.js.map +0 -1
  127. package/dist/cjs/AiModel.js +0 -37
  128. package/dist/cjs/AiModel.js.map +0 -1
  129. package/dist/cjs/AiResponse.js +0 -681
  130. package/dist/cjs/AiResponse.js.map +0 -1
  131. package/dist/cjs/AiTelemetry.js +0 -58
  132. package/dist/cjs/AiTelemetry.js.map +0 -1
  133. package/dist/cjs/AiTool.js +0 -150
  134. package/dist/cjs/AiTool.js.map +0 -1
  135. package/dist/cjs/AiToolkit.js +0 -157
  136. package/dist/cjs/AiToolkit.js.map +0 -1
  137. package/dist/cjs/internal/common.js +0 -21
  138. package/dist/cjs/internal/common.js.map +0 -1
  139. package/dist/dts/AiChat.d.ts +0 -101
  140. package/dist/dts/AiChat.d.ts.map +0 -1
  141. package/dist/dts/AiEmbeddingModel.d.ts +0 -65
  142. package/dist/dts/AiEmbeddingModel.d.ts.map +0 -1
  143. package/dist/dts/AiInput.d.ts +0 -590
  144. package/dist/dts/AiInput.d.ts.map +0 -1
  145. package/dist/dts/AiLanguageModel.d.ts +0 -302
  146. package/dist/dts/AiLanguageModel.d.ts.map +0 -1
  147. package/dist/dts/AiModel.d.ts +0 -25
  148. package/dist/dts/AiModel.d.ts.map +0 -1
  149. package/dist/dts/AiResponse.d.ts +0 -863
  150. package/dist/dts/AiResponse.d.ts.map +0 -1
  151. package/dist/dts/AiTelemetry.d.ts +0 -242
  152. package/dist/dts/AiTelemetry.d.ts.map +0 -1
  153. package/dist/dts/AiTool.d.ts +0 -334
  154. package/dist/dts/AiTool.d.ts.map +0 -1
  155. package/dist/dts/AiToolkit.d.ts +0 -96
  156. package/dist/dts/AiToolkit.d.ts.map +0 -1
  157. package/dist/dts/internal/common.d.ts +0 -2
  158. package/dist/dts/internal/common.d.ts.map +0 -1
  159. package/dist/esm/AiChat.js +0 -111
  160. package/dist/esm/AiChat.js.map +0 -1
  161. package/dist/esm/AiEmbeddingModel.js +0 -98
  162. package/dist/esm/AiEmbeddingModel.js.map +0 -1
  163. package/dist/esm/AiInput.js +0 -433
  164. package/dist/esm/AiInput.js.map +0 -1
  165. package/dist/esm/AiLanguageModel.js +0 -340
  166. package/dist/esm/AiLanguageModel.js.map +0 -1
  167. package/dist/esm/AiModel.js +0 -29
  168. package/dist/esm/AiModel.js.map +0 -1
  169. package/dist/esm/AiResponse.js +0 -657
  170. package/dist/esm/AiResponse.js.map +0 -1
  171. package/dist/esm/AiTelemetry.js +0 -48
  172. package/dist/esm/AiTelemetry.js.map +0 -1
  173. package/dist/esm/AiTool.js +0 -134
  174. package/dist/esm/AiTool.js.map +0 -1
  175. package/dist/esm/AiToolkit.js +0 -147
  176. package/dist/esm/AiToolkit.js.map +0 -1
  177. package/dist/esm/internal/common.js +0 -14
  178. package/dist/esm/internal/common.js.map +0 -1
  179. package/src/AiChat.ts +0 -251
  180. package/src/AiEmbeddingModel.ts +0 -169
  181. package/src/AiInput.ts +0 -602
  182. package/src/AiLanguageModel.ts +0 -685
  183. package/src/AiModel.ts +0 -53
  184. package/src/AiResponse.ts +0 -986
  185. package/src/AiTelemetry.ts +0 -333
  186. package/src/AiTool.ts +0 -579
  187. package/src/AiToolkit.ts +0 -265
  188. package/src/internal/common.ts +0 -12
package/src/Toolkit.ts ADDED
@@ -0,0 +1,516 @@
1
+ /**
2
+ * The `Toolkit` module allows for creating and implementing a collection of
3
+ * `Tool`s which can be used to enhance the capabilities of a large language
4
+ * model beyond simple text generation.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { Toolkit, Tool } from "@effect/ai"
9
+ * import { Effect, Schema } from "effect"
10
+ *
11
+ * // Create individual tools
12
+ * const GetCurrentTime = Tool.make("GetCurrentTime", {
13
+ * description: "Get the current timestamp",
14
+ * success: Schema.Number
15
+ * })
16
+ *
17
+ * const GetWeather = Tool.make("GetWeather", {
18
+ * description: "Get weather for a location",
19
+ * parameters: { location: Schema.String },
20
+ * success: Schema.Struct({
21
+ * temperature: Schema.Number,
22
+ * condition: Schema.String
23
+ * })
24
+ * })
25
+ *
26
+ * // Create a toolkit with multiple tools
27
+ * const MyToolkit = Toolkit.make(GetCurrentTime, GetWeather)
28
+ *
29
+ * const MyToolkitLayer = MyToolkit.toLayer({
30
+ * GetCurrentTime: () => Effect.succeed(Date.now()),
31
+ * GetWeather: ({ location }) => Effect.succeed({
32
+ * temperature: 72,
33
+ * condition: "sunny"
34
+ * })
35
+ * })
36
+ * ```
37
+ *
38
+ * @since 1.0.0
39
+ */
40
+ import * as Context from "effect/Context"
41
+ import * as Effect from "effect/Effect"
42
+ import { CommitPrototype } from "effect/Effectable"
43
+ import { identity } from "effect/Function"
44
+ import type { Inspectable } from "effect/Inspectable"
45
+ import { BaseProto as InspectableProto } from "effect/Inspectable"
46
+ import * as Layer from "effect/Layer"
47
+ import type { ParseError } from "effect/ParseResult"
48
+ import { type Pipeable, pipeArguments } from "effect/Pipeable"
49
+ import * as Predicate from "effect/Predicate"
50
+ import * as Schema from "effect/Schema"
51
+ import type * as Scope from "effect/Scope"
52
+ import * as AiError from "./AiError.js"
53
+ import * as Tool from "./Tool.js"
54
+
55
+ /**
56
+ * Unique identifier for toolkit instances.
57
+ *
58
+ * @since 1.0.0
59
+ * @category Type Ids
60
+ */
61
+ export const TypeId = "~@effect/ai/Toolkit"
62
+
63
+ /**
64
+ * Type-level representation of the toolkit identifier.
65
+ *
66
+ * @since 1.0.0
67
+ * @category Type Ids
68
+ */
69
+ export type TypeId = typeof TypeId
70
+
71
+ /**
72
+ * Represents a collection of tools which can be used to enhance the
73
+ * capabilities of a large language model.
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * import { Toolkit, Tool } from "@effect/ai"
78
+ * import { Effect, Schema } from "effect"
79
+ *
80
+ * // Create individual tools
81
+ * const GetCurrentTime = Tool.make("GetCurrentTime", {
82
+ * description: "Get the current timestamp",
83
+ * success: Schema.Number
84
+ * })
85
+ *
86
+ * const GetWeather = Tool.make("GetWeather", {
87
+ * description: "Get weather for a location",
88
+ * parameters: { location: Schema.String },
89
+ * success: Schema.Struct({
90
+ * temperature: Schema.Number,
91
+ * condition: Schema.String
92
+ * })
93
+ * })
94
+ *
95
+ * // Create a toolkit with multiple tools
96
+ * const MyToolkit = Toolkit.make(GetCurrentTime, GetWeather)
97
+ *
98
+ * const MyToolkitLayer = MyToolkit.toLayer({
99
+ * GetCurrentTime: () => Effect.succeed(Date.now()),
100
+ * GetWeather: ({ location }) => Effect.succeed({
101
+ * temperature: 72,
102
+ * condition: "sunny"
103
+ * })
104
+ * })
105
+ * ```
106
+ *
107
+ * @since 1.0.0
108
+ * @category Models
109
+ */
110
+ export interface Toolkit<in out Tools extends Record<string, Tool.Any>> extends
111
+ Effect.Effect<
112
+ WithHandler<Tools>,
113
+ never,
114
+ Tool.HandlersFor<Tools>
115
+ >,
116
+ Inspectable,
117
+ Pipeable
118
+ {
119
+ readonly [TypeId]: TypeId
120
+
121
+ new(_: never): {}
122
+
123
+ /**
124
+ * A record containing all tools in this toolkit.
125
+ */
126
+ readonly tools: Tools
127
+
128
+ /**
129
+ * A helper method which can be used for type-safe handler declarations.
130
+ */
131
+ of<Handlers extends HandlersFrom<Tools>>(handlers: Handlers): Handlers
132
+
133
+ /**
134
+ * Converts a toolkit into an Effect Context containing handlers for each tool
135
+ * in the toolkit.
136
+ */
137
+ toContext<Handlers extends HandlersFrom<Tools>, EX = never, RX = never>(
138
+ build: Handlers | Effect.Effect<Handlers, EX, RX>
139
+ ): Effect.Effect<Context.Context<Tool.HandlersFor<Tools>>, EX, RX>
140
+
141
+ /**
142
+ * Converts a toolkit into a Layer containing handlers for each tool in the
143
+ * toolkit.
144
+ */
145
+ toLayer<Handlers extends HandlersFrom<Tools>, EX = never, RX = never>(
146
+ /**
147
+ * Handler functions or Effect that produces handlers.
148
+ */
149
+ build: Handlers | Effect.Effect<Handlers, EX, RX>
150
+ ): Layer.Layer<Tool.HandlersFor<Tools>, EX, Exclude<RX, Scope.Scope>>
151
+ }
152
+
153
+ /**
154
+ * A utility type which structurally represents any toolkit instance.
155
+ *
156
+ * @since 1.0.0
157
+ * @category Utility Types
158
+ */
159
+ export interface Any {
160
+ readonly [TypeId]: TypeId
161
+ readonly tools: Record<string, Tool.Any>
162
+ }
163
+
164
+ /**
165
+ * A utility type which can be used to extract the tool definitions from a
166
+ * toolkit.
167
+ *
168
+ * @since 1.0.0
169
+ * @category Utility Types
170
+ */
171
+ export type Tools<T> = T extends Toolkit<infer Tools> ? Tools : never
172
+
173
+ /**
174
+ * A utility type which can transforms either a record or an array of tools into
175
+ * a record where keys are tool names and values are the tool instances.
176
+ *
177
+ * @since 1.0.0
178
+ * @category Utility Types
179
+ */
180
+ export type ToolsByName<Tools> = Tools extends Record<string, Tool.Any> ?
181
+ { readonly [Name in keyof Tools]: Tools[Name] }
182
+ : Tools extends ReadonlyArray<Tool.Any> ? { readonly [Tool in Tools[number] as Tool["name"]]: Tool }
183
+ : never
184
+
185
+ /**
186
+ * A utility type that maps tool names to their required handler functions.
187
+ *
188
+ * @since 1.0.0
189
+ * @category Utility Types
190
+ */
191
+ export type HandlersFrom<Tools extends Record<string, Tool.Any>> = {
192
+ readonly [Name in keyof Tools as Tool.RequiresHandler<Tools[Name]> extends true ? Name : never]: (
193
+ params: Tool.Parameters<Tools[Name]>
194
+ ) => Effect.Effect<
195
+ Tool.Success<Tools[Name]>,
196
+ Tool.Failure<Tools[Name]>,
197
+ Tool.Requirements<Tools[Name]>
198
+ >
199
+ }
200
+
201
+ /**
202
+ * A toolkit instance with registered handlers ready for tool execution.
203
+ *
204
+ * @since 1.0.0
205
+ * @category Models
206
+ */
207
+ export interface WithHandler<in out Tools extends Record<string, Tool.Any>> {
208
+ /**
209
+ * The tools available in this toolkit instance.
210
+ */
211
+ readonly tools: Tools
212
+
213
+ /**
214
+ * Handler function for executing tool calls.
215
+ *
216
+ * Receives a tool name and parameters, validates the input, executes the
217
+ * corresponding handler, and returns both the typed result and encoded result.
218
+ */
219
+ readonly handle: <Name extends keyof Tools>(
220
+ /**
221
+ * The name of the tool to execute.
222
+ */
223
+ name: Name,
224
+ /**
225
+ * Parameters to pass to the tool handler.
226
+ */
227
+ params: Tool.Parameters<Tools[Name]>
228
+ ) => Effect.Effect<
229
+ {
230
+ readonly result: Tool.Success<Tools[Name]>
231
+ readonly encodedResult: unknown
232
+ },
233
+ Tool.Failure<Tools[Name]>,
234
+ Tool.Requirements<Tools[Name]>
235
+ >
236
+ }
237
+
238
+ const Proto = {
239
+ ...CommitPrototype,
240
+ ...InspectableProto,
241
+ of: identity,
242
+ toContext(
243
+ this: Toolkit<Record<string, Tool.Any>>,
244
+ build: Record<string, (params: any) => any> | Effect.Effect<Record<string, (params: any) => any>>
245
+ ) {
246
+ return Effect.gen(this, function*() {
247
+ const context = yield* Effect.context<never>()
248
+ const handlers = Effect.isEffect(build) ? yield* build : build
249
+ const contextMap = new Map<string, unknown>()
250
+ for (const [name, handler] of Object.entries(handlers)) {
251
+ const tool = this.tools[name]!
252
+ contextMap.set(tool.id, { handler, context })
253
+ }
254
+ return Context.unsafeMake(contextMap)
255
+ })
256
+ },
257
+ toLayer(
258
+ this: Toolkit<Record<string, Tool.Any>>,
259
+ build: Record<string, (params: any) => any> | Effect.Effect<Record<string, (params: any) => any>>
260
+ ) {
261
+ return Layer.scopedContext(this.toContext(build))
262
+ },
263
+ commit(this: Toolkit<Record<string, Tool.Any>>) {
264
+ return Effect.gen(this, function*() {
265
+ const tools = this.tools
266
+ const context = yield* Effect.context<never>()
267
+ const schemasCache = new WeakMap<any, {
268
+ readonly context: Context.Context<never>
269
+ readonly handler: (params: any) => Effect.Effect<any, any>
270
+ readonly encodeSuccess: (u: unknown) => Effect.Effect<unknown, ParseError>
271
+ readonly encodeFailure: (u: unknown) => Effect.Effect<unknown, ParseError>
272
+ readonly decodeFailure: (u: unknown) => Effect.Effect<Tool.Failure<any>, ParseError>
273
+ readonly decodeParameters: (u: unknown) => Effect.Effect<Tool.Parameters<any>, ParseError>
274
+ }>()
275
+ const getSchemas = (tool: Tool.Any) => {
276
+ let schemas = schemasCache.get(tool)
277
+ if (Predicate.isUndefined(schemas)) {
278
+ const handler = context.unsafeMap.get(tool.id)! as Tool.Handler<any>
279
+ const encodeSuccess = Schema.encodeUnknown(tool.successSchema) as any
280
+ const encodeFailure = Schema.encodeUnknown(tool.failureSchema as any) as any
281
+ const decodeFailure = Schema.decodeUnknown(tool.failureSchema as any) as any
282
+ const decodeParameters = Schema.decodeUnknown(tool.parametersSchema) as any
283
+ schemas = {
284
+ context: handler.context,
285
+ handler: handler.handler,
286
+ encodeSuccess,
287
+ encodeFailure,
288
+ decodeFailure,
289
+ decodeParameters
290
+ }
291
+ schemasCache.set(tool, schemas)
292
+ }
293
+ return schemas
294
+ }
295
+ const handle = Effect.fn("Toolkit.handle", { captureStackTrace: false })(
296
+ function*(name: string, params: unknown) {
297
+ yield* Effect.annotateCurrentSpan({ tool: name, parameters: params })
298
+ const tool = tools[name]
299
+ if (Predicate.isUndefined(tool)) {
300
+ const toolNames = Object.keys(tools).join(",")
301
+ return yield* new AiError.MalformedOutput({
302
+ module: "Toolkit",
303
+ method: `${name}.handle`,
304
+ description: `Failed to find tool with name '${name}' in toolkit - available tools: ${toolNames}`
305
+ })
306
+ }
307
+ const schemas = getSchemas(tool)
308
+ const decodedParams = yield* Effect.mapError(
309
+ schemas.decodeParameters(params),
310
+ (cause) =>
311
+ new AiError.MalformedOutput({
312
+ module: "Toolkit",
313
+ method: `${name}.handle`,
314
+ description: `Failed to decode tool call parameters for tool '${name}' from:\n'${
315
+ JSON.stringify(params, undefined, 2)
316
+ }'`,
317
+ cause
318
+ })
319
+ )
320
+ const result = yield* schemas.handler(decodedParams).pipe(
321
+ Effect.mapInputContext((input) => Context.merge(schemas.context, input)),
322
+ Effect.catchAll((error) =>
323
+ schemas.decodeFailure(error).pipe(
324
+ Effect.mapError((cause) =>
325
+ new AiError.MalformedInput({
326
+ module: "Toolkit",
327
+ method: `${name}.handle`,
328
+ description: `Failed to decode tool call failure for tool '${name}'`,
329
+ cause
330
+ })
331
+ ),
332
+ Effect.flatMap(Effect.fail)
333
+ )
334
+ )
335
+ )
336
+ const encodedResult = yield* Effect.mapError(
337
+ schemas.encodeSuccess(result),
338
+ (cause) =>
339
+ new AiError.MalformedInput({
340
+ module: "Toolkit",
341
+ method: `${name}.handle`,
342
+ description: `Failed to encode tool call result for tool '${name}'`,
343
+ cause
344
+ })
345
+ )
346
+ return {
347
+ result,
348
+ encodedResult
349
+ } satisfies Tool.HandlerResult<any>
350
+ }
351
+ )
352
+ return {
353
+ tools,
354
+ handle
355
+ } satisfies WithHandler<Record<string, any>>
356
+ })
357
+ },
358
+ toJSON(this: Toolkit<any>): unknown {
359
+ return {
360
+ _id: "@effect/ai/Toolkit",
361
+ tools: Array.from(Object.values(this.tools)).map((tool) => (tool as Tool.Any).name)
362
+ }
363
+ },
364
+ pipe() {
365
+ return pipeArguments(this, arguments)
366
+ }
367
+ }
368
+
369
+ const makeProto = <Tools extends Record<string, Tool.Any>>(tools: Tools): Toolkit<Tools> =>
370
+ Object.assign(function() {}, Proto, { tools }) as any
371
+
372
+ const resolveInput = <Tools extends ReadonlyArray<Tool.Any>>(
373
+ ...tools: Tools
374
+ ): Record<string, Tools[number]> => {
375
+ const output = {} as Record<string, Tools[number]>
376
+ for (const tool of tools) {
377
+ const value = (Schema.isSchema(tool) ? Tool.fromTaggedRequest(tool as any) : tool) as any
378
+ output[tool.name] = value
379
+ }
380
+ return output
381
+ }
382
+
383
+ /**
384
+ * An empty toolkit with no tools.
385
+ *
386
+ * Useful as a starting point for building toolkits or as a default value. Can
387
+ * be extended using the merge function to add tools.
388
+ *
389
+ * @since 1.0.0
390
+ * @category Constructors
391
+ */
392
+ export const empty: Toolkit<{}> = makeProto({})
393
+
394
+ /**
395
+ * Creates a new toolkit from the specified tools.
396
+ *
397
+ * This is the primary constructor for creating toolkits. It accepts multiple tools
398
+ * and organizes them into a toolkit that can be provided to AI language models.
399
+ * Tools can be either Tool instances or TaggedRequest schemas.
400
+ *
401
+ * @example
402
+ * ```ts
403
+ * import { Toolkit, Tool } from "@effect/ai"
404
+ * import { Schema } from "effect"
405
+ *
406
+ * const GetCurrentTime = Tool.make("GetCurrentTime", {
407
+ * description: "Get the current timestamp",
408
+ * success: Schema.Number
409
+ * })
410
+ *
411
+ * const GetWeather = Tool.make("get_weather", {
412
+ * description: "Get weather information",
413
+ * parameters: { location: Schema.String },
414
+ * success: Schema.Struct({
415
+ * temperature: Schema.Number,
416
+ * condition: Schema.String
417
+ * })
418
+ * })
419
+ *
420
+ * const toolkit = Toolkit.make(GetCurrentTime, GetWeather)
421
+ * ```
422
+ *
423
+ * @since 1.0.0
424
+ * @category Constructors
425
+ */
426
+ export const make = <Tools extends ReadonlyArray<Tool.Any>>(
427
+ ...tools: Tools
428
+ ): Toolkit<ToolsByName<Tools>> => makeProto(resolveInput(...tools)) as any
429
+
430
+ /**
431
+ * A utility type which simplifies a record type.
432
+ *
433
+ * @since 1.0.0
434
+ * @category Utility Types
435
+ */
436
+ export type SimplifyRecord<T> = { [K in keyof T]: T[K] } & {}
437
+
438
+ /**
439
+ * A utility type which merges two records of tools together.
440
+ *
441
+ * @since 1.0.0
442
+ * @category Utility Types
443
+ */
444
+ export type MergeRecords<U> = {
445
+ readonly [K in Extract<U extends unknown ? keyof U : never, string>]: Extract<
446
+ U extends Record<K, infer V> ? V : never,
447
+ Tool.Any
448
+ >
449
+ }
450
+
451
+ /**
452
+ * A utility type which merges the tool calls of two toolkits into a single
453
+ * toolkit.
454
+ *
455
+ * @since 1.0.0
456
+ * @category Utility Types
457
+ */
458
+ export type MergedTools<Toolkits extends ReadonlyArray<Any>> = SimplifyRecord<
459
+ MergeRecords<Tools<Toolkits[number]>>
460
+ >
461
+
462
+ /**
463
+ * Merges multiple toolkits into a single toolkit.
464
+ *
465
+ * Combines all tools from the provided toolkits into one unified toolkit.
466
+ * If there are naming conflicts, tools from later toolkits will override
467
+ * tools from earlier ones.
468
+ *
469
+ * @example
470
+ * ```ts
471
+ * import { Toolkit, Tool } from "@effect/ai"
472
+ *
473
+ * const mathToolkit = Toolkit.make(
474
+ * Tool.make("add"),
475
+ * Tool.make("subtract")
476
+ * )
477
+ *
478
+ * const utilityToolkit = Toolkit.make(
479
+ * Tool.make("get_time"),
480
+ * Tool.make("get_weather")
481
+ * )
482
+ *
483
+ * const combined = Toolkit.merge(mathToolkit, utilityToolkit)
484
+ * // combined now has: add, subtract, get_time, get_weather
485
+ * ```
486
+ *
487
+ * @example
488
+ * ```ts
489
+ * import { Toolkit, Tool } from "@effect/ai"
490
+ *
491
+ * // Incremental toolkit building
492
+ * const baseToolkit = Toolkit.make(Tool.make("base_tool"))
493
+ * const extendedToolkit = Toolkit.merge(
494
+ * baseToolkit,
495
+ * Toolkit.make(Tool.make("additional_tool")),
496
+ * Toolkit.make(Tool.make("another_tool"))
497
+ * )
498
+ * ```
499
+ *
500
+ * @since 1.0.0
501
+ * @category Constructors
502
+ */
503
+ export const merge = <const Toolkits extends ReadonlyArray<Any>>(
504
+ /**
505
+ * The toolkits to merge together.
506
+ */
507
+ ...toolkits: Toolkits
508
+ ): Toolkit<MergedTools<Toolkits>> => {
509
+ const tools = {} as Record<string, any>
510
+ for (const toolkit of toolkits) {
511
+ for (const [name, tool] of Object.entries(toolkit.tools)) {
512
+ tools[name] = tool
513
+ }
514
+ }
515
+ return makeProto(tools) as any
516
+ }