@effect/ai 0.29.1 → 0.30.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.
package/src/Toolkit.ts CHANGED
@@ -40,11 +40,13 @@
40
40
  import * as Context from "effect/Context"
41
41
  import * as Effect from "effect/Effect"
42
42
  import { CommitPrototype } from "effect/Effectable"
43
+ import * as Either from "effect/Either"
43
44
  import { identity } from "effect/Function"
44
45
  import type { Inspectable } from "effect/Inspectable"
45
46
  import { BaseProto as InspectableProto } from "effect/Inspectable"
46
47
  import * as Layer from "effect/Layer"
47
48
  import type { ParseError } from "effect/ParseResult"
49
+ import * as ParseResult from "effect/ParseResult"
48
50
  import { type Pipeable, pipeArguments } from "effect/Pipeable"
49
51
  import * as Predicate from "effect/Predicate"
50
52
  import * as Schema from "effect/Schema"
@@ -226,10 +228,7 @@ export interface WithHandler<in out Tools extends Record<string, Tool.Any>> {
226
228
  */
227
229
  params: Tool.Parameters<Tools[Name]>
228
230
  ) => Effect.Effect<
229
- {
230
- readonly result: Tool.Success<Tools[Name]>
231
- readonly encodedResult: unknown
232
- },
231
+ Tool.HandlerResult<Tools[Name]>,
233
232
  Tool.Failure<Tools[Name]>,
234
233
  Tool.Requirements<Tools[Name]>
235
234
  >
@@ -267,26 +266,23 @@ const Proto = {
267
266
  const schemasCache = new WeakMap<any, {
268
267
  readonly context: Context.Context<never>
269
268
  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
269
  readonly decodeParameters: (u: unknown) => Effect.Effect<Tool.Parameters<any>, ParseError>
270
+ readonly validateResult: (u: unknown) => Effect.Effect<Either.Either<unknown, unknown>, ParseError>
271
+ readonly encodeResult: (u: unknown) => Effect.Effect<Schema.EitherEncoded<unknown, unknown>, ParseError>
274
272
  }>()
275
273
  const getSchemas = (tool: Tool.Any) => {
276
274
  let schemas = schemasCache.get(tool)
277
275
  if (Predicate.isUndefined(schemas)) {
278
276
  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
277
  const decodeParameters = Schema.decodeUnknown(tool.parametersSchema) as any
278
+ const validateResult = Schema.validate(tool.resultSchema) as any
279
+ const encodeResult = Schema.encodeUnknown(tool.resultSchema) as any
283
280
  schemas = {
284
281
  context: handler.context,
285
282
  handler: handler.handler,
286
- encodeSuccess,
287
- encodeFailure,
288
- decodeFailure,
289
- decodeParameters
283
+ decodeParameters,
284
+ validateResult,
285
+ encodeResult
290
286
  }
291
287
  schemasCache.set(tool, schemas)
292
288
  }
@@ -318,23 +314,28 @@ const Proto = {
318
314
  })
319
315
  )
320
316
  const result = yield* schemas.handler(decodedParams).pipe(
317
+ Effect.matchEffect({
318
+ onFailure: (error) =>
319
+ tool.failureMode === "error"
320
+ ? Effect.fail(error)
321
+ : Effect.succeed(Either.left(error)),
322
+ onSuccess: (value) => Effect.succeed(Either.right(value))
323
+ }),
324
+ Effect.flatMap((either) => schemas.validateResult(either)),
321
325
  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
- )
326
+ Effect.mapError((cause) =>
327
+ ParseResult.isParseError(cause)
328
+ ? new AiError.MalformedInput({
329
+ module: "Toolkit",
330
+ method: `${name}.handle`,
331
+ description: `Failed to validate tool call result for tool '${name}'`,
332
+ cause
333
+ })
334
+ : cause
334
335
  )
335
336
  )
336
337
  const encodedResult = yield* Effect.mapError(
337
- schemas.encodeSuccess(result),
338
+ schemas.encodeResult(result),
338
339
  (cause) =>
339
340
  new AiError.MalformedInput({
340
341
  module: "Toolkit",
@@ -351,7 +352,7 @@ const Proto = {
351
352
  )
352
353
  return {
353
354
  tools,
354
- handle
355
+ handle: handle as any
355
356
  } satisfies WithHandler<Record<string, any>>
356
357
  })
357
358
  },