@effect/ai 0.30.0 → 0.31.1

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/Tool.ts CHANGED
@@ -27,7 +27,7 @@
27
27
  * @since 1.0.0
28
28
  */
29
29
  import * as Context from "effect/Context"
30
- import * as Effect from "effect/Effect"
30
+ import type * as Effect from "effect/Effect"
31
31
  import { constFalse, constTrue, identity } from "effect/Function"
32
32
  import * as JsonSchema from "effect/JSONSchema"
33
33
  import * as Option from "effect/Option"
@@ -37,7 +37,7 @@ import * as Predicate from "effect/Predicate"
37
37
  import * as Schema from "effect/Schema"
38
38
  import * as AST from "effect/SchemaAST"
39
39
  import type { Covariant } from "effect/Types"
40
- import * as AiError from "./AiError.js"
40
+ import type * as AiError from "./AiError.js"
41
41
 
42
42
  // =============================================================================
43
43
  // Type Ids
@@ -164,12 +164,6 @@ export interface Tool<
164
164
  */
165
165
  readonly failureSchema: Config["failure"]
166
166
 
167
- /**
168
- * A `Schema` representing the result of a tool call, whether it succeeds or
169
- * fails.
170
- */
171
- readonly resultSchema: Schema.Either<Config["success"], Config["failure"]>
172
-
173
167
  /**
174
168
  * A `Context` object containing tool annotations which can store metadata
175
169
  * about the tool.
@@ -340,13 +334,6 @@ export interface ProviderDefined<
340
334
  * this tool into a `Layer`.
341
335
  */
342
336
  readonly requiresHandler: RequiresHandler
343
-
344
- /**
345
- * Decodes the result received after the provider-defined tool is called.
346
- */
347
- decodeResult(
348
- args: unknown
349
- ): Effect.Effect<Config["success"]["Type"], AiError.AiError>
350
337
  }
351
338
 
352
339
  /**
@@ -509,7 +496,6 @@ export interface Any extends Pipeable {
509
496
  readonly parametersSchema: AnyStructSchema
510
497
  readonly successSchema: Schema.Schema.Any
511
498
  readonly failureSchema: Schema.Schema.All
512
- readonly resultSchema: Schema.Either<any, any>
513
499
  readonly failureMode: FailureMode
514
500
  readonly annotations: Context.Context<never>
515
501
  }
@@ -705,8 +691,8 @@ export type Result<T> = T extends Tool<
705
691
  infer _Name,
706
692
  infer _Config,
707
693
  infer _Requirements
708
- > ? Schema.Either<_Config["success"], _Config["failure"]>["Type"] :
709
- never
694
+ > ? Success<T> | Failure<T>
695
+ : never
710
696
 
711
697
  /**
712
698
  * A utility type to extract the encoded type of the tool call result whether
@@ -719,8 +705,8 @@ export type ResultEncoded<T> = T extends Tool<
719
705
  infer _Name,
720
706
  infer _Config,
721
707
  infer _Requirements
722
- > ? Schema.Either<_Config["success"], _Config["failure"]>["Encoded"] :
723
- never
708
+ > ? SuccessEncoded<T> | FailureEncoded<T>
709
+ : never
724
710
 
725
711
  /**
726
712
  * A utility type to extract the requirements of an `Tool`.
@@ -759,6 +745,10 @@ export interface Handler<Name extends string> {
759
745
  * @category Models
760
746
  */
761
747
  export interface HandlerResult<Tool extends Any> {
748
+ /**
749
+ * Whether the result of executing the tool call handler was an error or not.
750
+ */
751
+ readonly isFailure: boolean
762
752
  /**
763
753
  * The result of executing the handler for a particular tool.
764
754
  */
@@ -768,7 +758,7 @@ export interface HandlerResult<Tool extends Any> {
768
758
  * tool as a JSON-serializable value. The encoded result can be incorporated
769
759
  * into subsequent requests to the large language model.
770
760
  */
771
- readonly encodedResult: Schema.EitherEncoded<unknown, unknown>
761
+ readonly encodedResult: unknown
772
762
  }
773
763
 
774
764
  /**
@@ -782,7 +772,7 @@ export type HandlerError<T> = T extends Tool<
782
772
  infer _Name,
783
773
  infer _Config,
784
774
  infer _Requirements
785
- > ? _Config["failureMode"] extends "error" ? Schema.Schema.Type<_Config["failure"]>
775
+ > ? _Config["failureMode"] extends "error" ? _Config["failure"]["Type"]
786
776
  : never
787
777
  : never
788
778
 
@@ -863,21 +853,7 @@ const Proto = {
863
853
 
864
854
  const ProviderDefinedProto = {
865
855
  ...Proto,
866
- [ProviderDefinedTypeId]: ProviderDefinedTypeId,
867
- decodeResult(this: AnyProviderDefined, result: unknown) {
868
- return Schema.decodeUnknown(this.successSchema)(result).pipe(
869
- Effect.orElse(() => Schema.decodeUnknown(this.failureSchema as any)(result)),
870
- Effect.mapError(
871
- (cause) =>
872
- new AiError.MalformedOutput({
873
- module: "Tool",
874
- method: "ProviderDefined.decodeResult",
875
- description: `Failed to decode the result of provider-defined tool '${this.name}'`,
876
- cause
877
- })
878
- )
879
- )
880
- }
856
+ [ProviderDefinedTypeId]: ProviderDefinedTypeId
881
857
  }
882
858
 
883
859
  const userDefinedProto = <
@@ -892,7 +868,6 @@ const userDefinedProto = <
892
868
  readonly parametersSchema: Parameters
893
869
  readonly successSchema: Success
894
870
  readonly failureSchema: Failure
895
- readonly resultSchema: Schema.Either<Success, Failure>
896
871
  readonly annotations: Context.Context<never>
897
872
  readonly failureMode: Mode
898
873
  }): Tool<
@@ -927,7 +902,6 @@ const providerDefinedProto = <
927
902
  readonly parametersSchema: Parameters
928
903
  readonly successSchema: Success
929
904
  readonly failureSchema: Failure
930
- readonly resultSchema: Schema.Either<Success, Failure>
931
905
  readonly failureMode: FailureMode
932
906
  }): ProviderDefined<
933
907
  Name,
@@ -1022,10 +996,6 @@ export const make = <
1022
996
  > => {
1023
997
  const successSchema = options?.success ?? Schema.Void
1024
998
  const failureSchema = options?.failure ?? Schema.Never
1025
- const resultSchema = Schema.Either({
1026
- left: failureSchema,
1027
- right: successSchema
1028
- })
1029
999
  return userDefinedProto({
1030
1000
  name,
1031
1001
  description: options?.description,
@@ -1034,7 +1004,6 @@ export const make = <
1034
1004
  : constEmptyStruct,
1035
1005
  successSchema,
1036
1006
  failureSchema,
1037
- resultSchema,
1038
1007
  failureMode: options?.failureMode ?? "error",
1039
1008
  annotations: Context.empty()
1040
1009
  }) as any
@@ -1146,10 +1115,6 @@ export const providerDefined = <
1146
1115
  const failureMode = "failureMode" in args ? args.failureMode : undefined
1147
1116
  const successSchema = options?.success ?? Schema.Void
1148
1117
  const failureSchema = options?.failure ?? Schema.Never
1149
- const resultSchema = Schema.Either({
1150
- right: successSchema,
1151
- left: failureSchema
1152
- })
1153
1118
  return providerDefinedProto({
1154
1119
  id: options.id,
1155
1120
  name: options.toolkitName,
@@ -1162,7 +1127,6 @@ export const providerDefined = <
1162
1127
  : constEmptyStruct,
1163
1128
  successSchema,
1164
1129
  failureSchema,
1165
- resultSchema,
1166
1130
  failureMode: failureMode ?? "error"
1167
1131
  }) as any
1168
1132
  }
@@ -1213,10 +1177,6 @@ export const fromTaggedRequest = <S extends AnyTaggedRequestSchema>(
1213
1177
  parametersSchema: schema,
1214
1178
  successSchema: schema.success,
1215
1179
  failureSchema: schema.failure,
1216
- resultSchema: Schema.Either({
1217
- left: schema.failure,
1218
- right: schema.success
1219
- }),
1220
1180
  failureMode: "error",
1221
1181
  annotations: Context.empty()
1222
1182
  }) as any
package/src/Toolkit.ts CHANGED
@@ -40,7 +40,6 @@
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"
44
43
  import { identity } from "effect/Function"
45
44
  import type { Inspectable } from "effect/Inspectable"
46
45
  import { BaseProto as InspectableProto } from "effect/Inspectable"
@@ -267,16 +266,17 @@ const Proto = {
267
266
  readonly context: Context.Context<never>
268
267
  readonly handler: (params: any) => Effect.Effect<any, any>
269
268
  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>
269
+ readonly validateResult: (u: unknown) => Effect.Effect<unknown, ParseError>
270
+ readonly encodeResult: (u: unknown) => Effect.Effect<unknown, ParseError>
272
271
  }>()
273
272
  const getSchemas = (tool: Tool.Any) => {
274
273
  let schemas = schemasCache.get(tool)
275
274
  if (Predicate.isUndefined(schemas)) {
276
275
  const handler = context.unsafeMap.get(tool.id)! as Tool.Handler<any>
277
276
  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
277
+ const resultSchema = Schema.Union(tool.successSchema, tool.failureSchema)
278
+ const validateResult = Schema.validate(resultSchema) as any
279
+ const encodeResult = Schema.encodeUnknown(resultSchema) as any
280
280
  schemas = {
281
281
  context: handler.context,
282
282
  handler: handler.handler,
@@ -313,15 +313,16 @@ const Proto = {
313
313
  cause
314
314
  })
315
315
  )
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)),
316
+ const { isFailure, result } = yield* schemas.handler(decodedParams).pipe(
317
+ Effect.map((result) => ({ result, isFailure: false })),
318
+ Effect.catchAll((error) =>
319
+ // If the tool handler failed, check the tool's failure mode to
320
+ // determine how the result should be returned to the end user
321
+ tool.failureMode === "error"
322
+ ? Effect.fail(error)
323
+ : Effect.succeed({ result: error, isFailure: true })
324
+ ),
325
+ Effect.tap(({ result }) => schemas.validateResult(result)),
325
326
  Effect.mapInputContext((input) => Context.merge(schemas.context, input)),
326
327
  Effect.mapError((cause) =>
327
328
  ParseResult.isParseError(cause)
@@ -345,6 +346,7 @@ const Proto = {
345
346
  })
346
347
  )
347
348
  return {
349
+ isFailure,
348
350
  result,
349
351
  encodedResult
350
352
  } satisfies Tool.HandlerResult<any>
@@ -352,7 +354,7 @@ const Proto = {
352
354
  )
353
355
  return {
354
356
  tools,
355
- handle: handle as any
357
+ handle
356
358
  } satisfies WithHandler<Record<string, any>>
357
359
  })
358
360
  },