@effect/ai 0.14.1 → 0.16.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 (134) hide show
  1. package/AiEmbeddingModel/package.json +6 -0
  2. package/AiLanguageModel/package.json +6 -0
  3. package/AiTool/package.json +6 -0
  4. package/dist/cjs/AiChat.js +65 -86
  5. package/dist/cjs/AiChat.js.map +1 -1
  6. package/dist/cjs/{Embeddings.js → AiEmbeddingModel.js} +12 -12
  7. package/dist/cjs/AiEmbeddingModel.js.map +1 -0
  8. package/dist/cjs/AiError.js +8 -1
  9. package/dist/cjs/AiError.js.map +1 -1
  10. package/dist/cjs/AiInput.js +335 -248
  11. package/dist/cjs/AiInput.js.map +1 -1
  12. package/dist/cjs/AiLanguageModel.js +311 -0
  13. package/dist/cjs/AiLanguageModel.js.map +1 -0
  14. package/dist/cjs/AiModel.js +11 -5
  15. package/dist/cjs/AiModel.js.map +1 -1
  16. package/dist/cjs/AiPlan.js +10 -3
  17. package/dist/cjs/AiPlan.js.map +1 -1
  18. package/dist/cjs/AiResponse.js +481 -165
  19. package/dist/cjs/AiResponse.js.map +1 -1
  20. package/dist/cjs/AiTelemetry.js +10 -3
  21. package/dist/cjs/AiTelemetry.js.map +1 -1
  22. package/dist/cjs/AiTool.js +93 -0
  23. package/dist/cjs/AiTool.js.map +1 -0
  24. package/dist/cjs/AiToolkit.js +121 -98
  25. package/dist/cjs/AiToolkit.js.map +1 -1
  26. package/dist/cjs/Tokenizer.js +14 -16
  27. package/dist/cjs/Tokenizer.js.map +1 -1
  28. package/dist/cjs/index.js +7 -9
  29. package/dist/cjs/internal/aiPlan.js +6 -9
  30. package/dist/cjs/internal/aiPlan.js.map +1 -1
  31. package/dist/cjs/internal/common.js +22 -0
  32. package/dist/cjs/internal/common.js.map +1 -0
  33. package/dist/dts/AiChat.d.ts +58 -44
  34. package/dist/dts/AiChat.d.ts.map +1 -1
  35. package/dist/dts/{Embeddings.d.ts → AiEmbeddingModel.d.ts} +13 -14
  36. package/dist/dts/AiEmbeddingModel.d.ts.map +1 -0
  37. package/dist/dts/AiError.d.ts +4 -3
  38. package/dist/dts/AiError.d.ts.map +1 -1
  39. package/dist/dts/AiInput.d.ts +441 -146
  40. package/dist/dts/AiInput.d.ts.map +1 -1
  41. package/dist/dts/AiLanguageModel.d.ts +263 -0
  42. package/dist/dts/AiLanguageModel.d.ts.map +1 -0
  43. package/dist/dts/AiModel.d.ts +21 -20
  44. package/dist/dts/AiModel.d.ts.map +1 -1
  45. package/dist/dts/AiPlan.d.ts +90 -26
  46. package/dist/dts/AiPlan.d.ts.map +1 -1
  47. package/dist/dts/AiResponse.d.ts +711 -100
  48. package/dist/dts/AiResponse.d.ts.map +1 -1
  49. package/dist/dts/AiTelemetry.d.ts +175 -157
  50. package/dist/dts/AiTelemetry.d.ts.map +1 -1
  51. package/dist/dts/AiTool.d.ts +288 -0
  52. package/dist/dts/AiTool.d.ts.map +1 -0
  53. package/dist/dts/AiToolkit.d.ts +50 -111
  54. package/dist/dts/AiToolkit.d.ts.map +1 -1
  55. package/dist/dts/Tokenizer.d.ts +8 -6
  56. package/dist/dts/Tokenizer.d.ts.map +1 -1
  57. package/dist/dts/index.d.ts +8 -12
  58. package/dist/dts/index.d.ts.map +1 -1
  59. package/dist/dts/internal/common.d.ts +2 -0
  60. package/dist/dts/internal/common.d.ts.map +1 -0
  61. package/dist/esm/AiChat.js +62 -83
  62. package/dist/esm/AiChat.js.map +1 -1
  63. package/dist/esm/{Embeddings.js → AiEmbeddingModel.js} +10 -10
  64. package/dist/esm/AiEmbeddingModel.js.map +1 -0
  65. package/dist/esm/AiError.js +8 -1
  66. package/dist/esm/AiError.js.map +1 -1
  67. package/dist/esm/AiInput.js +316 -238
  68. package/dist/esm/AiInput.js.map +1 -1
  69. package/dist/esm/AiLanguageModel.js +300 -0
  70. package/dist/esm/AiLanguageModel.js.map +1 -0
  71. package/dist/esm/AiModel.js +11 -5
  72. package/dist/esm/AiModel.js.map +1 -1
  73. package/dist/esm/AiPlan.js +8 -2
  74. package/dist/esm/AiPlan.js.map +1 -1
  75. package/dist/esm/AiResponse.js +467 -162
  76. package/dist/esm/AiResponse.js.map +1 -1
  77. package/dist/esm/AiTelemetry.js +8 -2
  78. package/dist/esm/AiTelemetry.js.map +1 -1
  79. package/dist/esm/AiTool.js +82 -0
  80. package/dist/esm/AiTool.js.map +1 -0
  81. package/dist/esm/AiToolkit.js +118 -96
  82. package/dist/esm/AiToolkit.js.map +1 -1
  83. package/dist/esm/Tokenizer.js +14 -16
  84. package/dist/esm/Tokenizer.js.map +1 -1
  85. package/dist/esm/index.js +8 -12
  86. package/dist/esm/index.js.map +1 -1
  87. package/dist/esm/internal/aiPlan.js +4 -7
  88. package/dist/esm/internal/aiPlan.js.map +1 -1
  89. package/dist/esm/internal/common.js +14 -0
  90. package/dist/esm/internal/common.js.map +1 -0
  91. package/package.json +28 -36
  92. package/src/AiChat.ts +182 -207
  93. package/src/{Embeddings.ts → AiEmbeddingModel.ts} +19 -18
  94. package/src/AiError.ts +8 -1
  95. package/src/AiInput.ts +434 -313
  96. package/src/AiLanguageModel.ts +569 -0
  97. package/src/AiModel.ts +47 -29
  98. package/src/AiPlan.ts +102 -30
  99. package/src/AiResponse.ts +743 -187
  100. package/src/AiTelemetry.ts +214 -197
  101. package/src/AiTool.ts +496 -0
  102. package/src/AiToolkit.ts +200 -240
  103. package/src/Tokenizer.ts +18 -22
  104. package/src/index.ts +9 -14
  105. package/src/internal/aiPlan.ts +12 -14
  106. package/src/internal/common.ts +12 -0
  107. package/AiModels/package.json +0 -6
  108. package/AiRole/package.json +0 -6
  109. package/Completions/package.json +0 -6
  110. package/Embeddings/package.json +0 -6
  111. package/dist/cjs/AiModels.js +0 -54
  112. package/dist/cjs/AiModels.js.map +0 -1
  113. package/dist/cjs/AiRole.js +0 -106
  114. package/dist/cjs/AiRole.js.map +0 -1
  115. package/dist/cjs/Completions.js +0 -256
  116. package/dist/cjs/Completions.js.map +0 -1
  117. package/dist/cjs/Embeddings.js.map +0 -1
  118. package/dist/dts/AiModels.d.ts +0 -34
  119. package/dist/dts/AiModels.d.ts.map +0 -1
  120. package/dist/dts/AiRole.d.ts +0 -111
  121. package/dist/dts/AiRole.d.ts.map +0 -1
  122. package/dist/dts/Completions.d.ts +0 -128
  123. package/dist/dts/Completions.d.ts.map +0 -1
  124. package/dist/dts/Embeddings.d.ts.map +0 -1
  125. package/dist/esm/AiModels.js +0 -44
  126. package/dist/esm/AiModels.js.map +0 -1
  127. package/dist/esm/AiRole.js +0 -93
  128. package/dist/esm/AiRole.js.map +0 -1
  129. package/dist/esm/Completions.js +0 -245
  130. package/dist/esm/Completions.js.map +0 -1
  131. package/dist/esm/Embeddings.js.map +0 -1
  132. package/src/AiModels.ts +0 -77
  133. package/src/AiRole.ts +0 -122
  134. package/src/Completions.ts +0 -434
package/src/AiToolkit.ts CHANGED
@@ -3,299 +3,259 @@
3
3
  */
4
4
  import * as Context from "effect/Context"
5
5
  import * as Effect from "effect/Effect"
6
- import * as Effectable from "effect/Effectable"
7
- import { identity } from "effect/Function"
8
- import * as HashMap from "effect/HashMap"
9
- import * as Inspectable from "effect/Inspectable"
6
+ import { CommitPrototype } from "effect/Effectable"
7
+ import type { Inspectable } from "effect/Inspectable"
8
+ import { BaseProto as InspectableProto } from "effect/Inspectable"
10
9
  import * as Layer from "effect/Layer"
10
+ import type { ParseError } from "effect/ParseResult"
11
+ import type { Pipeable } from "effect/Pipeable"
11
12
  import { pipeArguments } from "effect/Pipeable"
12
- import type * as Schema from "effect/Schema"
13
- import type { Scope } from "effect/Scope"
14
- import type * as Types from "effect/Types"
13
+ import * as Predicate from "effect/Predicate"
14
+ import * as Schema from "effect/Schema"
15
+ import type * as Scope from "effect/Scope"
16
+ import { AiError } from "./AiError.js"
17
+ import * as AiTool from "./AiTool.js"
15
18
 
16
19
  /**
17
20
  * @since 1.0.0
18
- * @category type ids
21
+ * @category Type Ids
19
22
  */
20
23
  export const TypeId: unique symbol = Symbol.for("@effect/ai/AiToolkit")
21
24
 
22
25
  /**
23
26
  * @since 1.0.0
24
- * @category type ids
27
+ * @category Type Ids
25
28
  */
26
29
  export type TypeId = typeof TypeId
27
30
 
28
31
  /**
32
+ * An `AiToolkit` represents a set of tools that a large language model can
33
+ * use to augment its response.
34
+ *
29
35
  * @since 1.0.0
30
- * @category models
36
+ * @category Models
31
37
  */
32
- export interface AiToolkit<in out Tools extends Tool.AnySchema>
33
- extends Effect.Effect<Handlers<Tools>, never, Tool.Services<Tools> | Registry>, Inspectable.Inspectable
38
+ export interface AiToolkit<in out Tools extends AiTool.Any>
39
+ extends Effect.Effect<ToHandler<Tools>, never, AiTool.ToHandler<Tools>>, Inspectable, Pipeable
34
40
  {
35
- readonly [TypeId]: TypeId
36
- readonly tools: HashMap.HashMap<string, Tools>
37
- readonly add: <S extends Tool.AnySchema>(tool: S) => AiToolkit<Tools | S>
38
- readonly addAll: <ToAdd extends ReadonlyArray<Tool.AnySchema>>(
39
- ...tools: ToAdd
40
- ) => AiToolkit<Tools | ToAdd[number]>
41
- readonly concat: <T extends Tool.AnySchema>(that: AiToolkit<T>) => AiToolkit<Tools | T>
42
- readonly implement: <R, EX = never, RX = never>(
43
- f: (
44
- handlers: Handlers<Tools>
45
- ) => Handlers<never, R> | Effect.Effect<Handlers<never, R>, EX, RX>
46
- ) => Layer.Layer<Tool.ServiceFromTag<Tools["_tag"]> | Registry, EX, Exclude<R | RX, Scope>>
47
- }
48
-
49
- /**
50
- * @since 1.0.0
51
- * @category models
52
- */
53
- export declare namespace AiToolkit {
54
- /**
55
- * @since 1.0.0
56
- * @category models
57
- */
58
- export type Tools<A> = A extends AiToolkit<infer Tools> ? Tools : never
59
-
60
- /**
61
- * @since 1.0.0
62
- * @category models
63
- */
64
- export type SuccessSchema<A> = A extends AiToolkit<infer Tools> ? Tools["success"] : never
65
- }
66
-
67
- /**
68
- * @since 1.0.0
69
- * @category tool
70
- */
71
- export declare namespace Tool {
72
- /**
73
- * @since 1.0.0
74
- * @category tool
75
- */
76
- export interface AnySchema {
77
- readonly [Schema.TypeId]: any
78
- readonly _tag: string
79
- readonly Type: Schema.SerializableWithResult.All
80
- readonly success: Schema.Schema.Any
81
- }
82
-
83
- /**
84
- * @since 1.0.0
85
- * @category tool
86
- */
87
- export type Success<Tool extends AnySchema> = Schema.WithResult.Success<Tool["Type"]>
88
-
89
- /**
90
- * @since 1.0.0
91
- * @category tool
92
- */
93
- export type Failure<Tool extends AnySchema> = Schema.WithResult.Failure<Tool["Type"]>
94
-
95
- /**
96
- * @since 1.0.0
97
- * @category tool
98
- */
99
- export type Context<Tool extends AnySchema> = Schema.WithResult.Context<Tool["Type"]>
100
-
101
- /**
102
- * @since 1.0.0
103
- * @category tool
104
- */
105
- export type Handler<Tool extends AnySchema, R> = (
106
- params: Tool["Type"]
107
- ) => Effect.Effect<Success<Tool>, Failure<Tool>, R>
41
+ new(_: never): {}
108
42
 
109
- /**
110
- * @since 1.0.0
111
- * @category tool
112
- */
113
- export type HandlerAny = (params: any) => Effect.Effect<any, any, any>
43
+ readonly [TypeId]: TypeId
114
44
 
115
45
  /**
116
- * @since 1.0.0
117
- * @category tool
46
+ * A map containing the tools that are part of this toolkit.
118
47
  */
119
- export interface Service<Tag extends string> {
120
- readonly _: unique symbol
121
- readonly name: Types.Invariant<Tag>
122
- }
48
+ readonly tools: AiTool.ByName<Tools>
123
49
 
124
50
  /**
125
- * @since 1.0.0
126
- * @category tool
51
+ * Converts this toolkit into a `Context` object containing the handlers for
52
+ * all tools in the toolkit.
127
53
  */
128
- export type ServiceFromTag<Tag extends string> = Tag extends infer T ? T extends string ? Service<T> : never : never
54
+ toContext<Handlers extends HandlersFrom<Tools>, EX = never, RX = never>(
55
+ build: Handlers | Effect.Effect<Handlers, EX, RX>
56
+ ): Effect.Effect<Context.Context<AiTool.ToHandler<Tools>>, EX, RX>
129
57
 
130
58
  /**
131
- * @since 1.0.0
132
- * @category tool
59
+ * Converts this toolkit into a `Layer` containing the handlers for all tools
60
+ * in the toolkit.
133
61
  */
134
- export type Services<Tools extends AnySchema> = ServiceFromTag<Tools["_tag"]>
62
+ toLayer<Handlers extends HandlersFrom<Tools>, EX = never, RX = never>(
63
+ build: Handlers | Effect.Effect<Handlers, EX, RX>
64
+ ): Layer.Layer<AiTool.ToHandler<Tools>, EX, Exclude<RX, Scope.Scope>>
135
65
  }
136
66
 
137
67
  /**
138
68
  * @since 1.0.0
139
- * @category registry
69
+ * @category Models
140
70
  */
141
- export class Registry extends Context.Tag("@effect/ai/AiToolkit/Registry")<
142
- Registry,
143
- Map<Tool.AnySchema, Tool.HandlerAny>
144
- >() {
145
- static readonly Live: Layer.Layer<Registry> = Layer.sync(Registry, () => new Map())
146
- }
147
-
148
- class AiToolkitImpl<Tools extends Tool.AnySchema>
149
- extends Effectable.Class<Handlers<Tools>, never, Tool.Services<Tools> | Registry>
150
- implements AiToolkit<Tools>
151
- {
71
+ export interface Any {
152
72
  readonly [TypeId]: TypeId
153
- constructor(readonly tools: HashMap.HashMap<string, Tools>) {
154
- super()
155
- this[TypeId] = TypeId
156
- }
157
- toJSON(): unknown {
158
- return {
159
- _id: "@effect/ai/AiToolkit",
160
- tools: [...HashMap.values(this.tools)].map((tool) => tool._tag)
161
- }
162
- }
163
- toString(): string {
164
- return Inspectable.format(this)
165
- }
166
- [Inspectable.NodeInspectSymbol](): string {
167
- return Inspectable.format(this)
168
- }
169
- pipe() {
170
- return pipeArguments(this, arguments)
171
- }
172
- add<S extends Tool.AnySchema>(tool: S): AiToolkit<Tools | S> {
173
- return new AiToolkitImpl(HashMap.set(this.tools, tool._tag, tool as any)) as any
174
- }
175
- addAll<ToAdd extends ReadonlyArray<Tool.AnySchema>>(...tools: ToAdd): AiToolkit<Tools | ToAdd[number]> {
176
- let map = this.tools
177
- for (const tool of tools) {
178
- map = HashMap.set(map, tool._tag, tool as any)
179
- }
180
- return new AiToolkitImpl(map as any)
181
- }
182
- concat<T extends Tool.AnySchema>(that: AiToolkit<T>): AiToolkit<Tools | T> {
183
- return new AiToolkitImpl(HashMap.union(this.tools, that.tools))
184
- }
185
- implement<R, EX = never, RX = never>(
186
- f: (
187
- handlers: Handlers<Tools>
188
- ) => Handlers<never, R> | Effect.Effect<Handlers<never, R>, EX, RX>
189
- ): Layer.Layer<Tool.ServiceFromTag<Tools["_tag"]> | Registry, EX, Exclude<R | RX, Scope>> {
190
- return registerHandlers(this as any, f as any).pipe(Layer.scopedDiscard, Layer.provideMerge(Registry.Live))
191
- }
192
- commit(): Effect.Effect<Handlers<Tools>, never, Tool.ServiceFromTag<Tools["_tag"]> | Registry> {
193
- return Effect.map(Registry, (map) => {
194
- let handlers = HashMap.empty<string, Tool.HandlerAny>()
195
- for (const [tag, tool] of this.tools) {
196
- handlers = HashMap.set(handlers, tag, map.get(tool)!)
197
- }
198
- return new HandlersImpl(this as any, handlers)
199
- }) as any
200
- }
73
+ readonly tools: ReadonlyMap<string, AiTool.Any>
201
74
  }
202
75
 
203
- const registerHandlers = (
204
- toolkit: AiToolkit<any>,
205
- f: (handlers: Handlers<any, any>) => Handlers<any, any> | Effect.Effect<Handlers<any, any>>
206
- ) =>
207
- Effect.context<any>().pipe(
208
- Effect.bindTo("context"),
209
- Effect.bind("handlers", () => {
210
- const handlers = f(HandlersImpl.fromToolkit(toolkit))
211
- return Effect.isEffect(handlers) ? handlers : Effect.succeed(handlers)
212
- }),
213
- Effect.tap(({ context, handlers }) => {
214
- const registry = Context.unsafeGet(context, Registry)
215
- for (const [tag, handler] of handlers.handlers) {
216
- const tool = HashMap.unsafeGet(handlers.toolkit.tools, tag)
217
- registry.set(tool, function(params: any) {
218
- return Effect.withSpan(
219
- Effect.mapInputContext(handler(params), (input) => Context.merge(input, context)),
220
- "AiToolkit.handler",
221
- {
222
- captureStackTrace: false,
223
- attributes: {
224
- tool: tag,
225
- parameters: params
226
- }
227
- }
228
- )
229
- })
230
- }
231
- })
232
- )
233
-
234
76
  /**
77
+ * Represents an `AiToolkit` which has been augmented with a handler function
78
+ * for resolving tool call requests.
79
+ *
235
80
  * @since 1.0.0
236
- * @category constructors
81
+ * @category Models
237
82
  */
238
- export const empty: AiToolkit<never> = new AiToolkitImpl(HashMap.empty())
83
+ export interface ToHandler<in out Tool extends AiTool.Any> {
84
+ readonly tools: ReadonlyArray<Tool>
85
+ readonly handle: (toolName: AiTool.Name<Tool>, toolParams: AiTool.Parameters<Tool>) => AiTool.HandlerEffect<Tool>
86
+ }
239
87
 
240
88
  /**
89
+ * A utility mapped type which associates tool names with their handlers.
90
+ *
241
91
  * @since 1.0.0
242
- * @category handlers
92
+ * @category Utility Types
243
93
  */
244
- export const HandlersTypeId: unique symbol = Symbol.for("@effect/ai/AiToolkit/Handlers")
94
+ export type HandlersFrom<Tool extends AiTool.Any> = {
95
+ [Name in Tool as Tool["name"]]: (params: AiTool.Parameters<Tool>) => AiTool.HandlerEffect<Tool>
96
+ }
245
97
 
246
98
  /**
99
+ * A utility type which returns the tools in an `AiToolkit`.
100
+ *
247
101
  * @since 1.0.0
248
- * @category handlers
102
+ * @category Utility Types
249
103
  */
250
- export type HandlersTypeId = typeof HandlersTypeId
104
+ export type Tools<Toolkit> = Toolkit extends AiToolkit<infer Tool> ? string extends Tool["name"] ? never : Tool : never
105
+
106
+ const Proto = {
107
+ ...CommitPrototype,
108
+ ...InspectableProto,
109
+ [TypeId]: TypeId,
110
+ toContext(this: AiToolkit<any>, build: Effect.Effect<Record<string, (params: any) => any>>) {
111
+ return Effect.gen(this, function*() {
112
+ const context = yield* Effect.context<never>()
113
+ const handlers = Effect.isEffect(build) ? yield* build : build
114
+ const contextMap = new Map<string, unknown>()
115
+ for (const [name, handler] of Object.entries(handlers)) {
116
+ const tool = this.tools[name]!
117
+ contextMap.set(tool.key, { handler, context })
118
+ }
119
+ return Context.unsafeMake(contextMap)
120
+ })
121
+ },
122
+ toLayer(this: AiToolkit<any>, build: Effect.Effect<Record<string, (params: any) => any>>) {
123
+ return Layer.scopedContext(this.toContext(build))
124
+ },
125
+ commit(this: AiToolkit<AiTool.AnyWithProtocol>) {
126
+ return Effect.gen(this, function*() {
127
+ const context = yield* Effect.context<never>()
128
+ const tools = this.tools
129
+ const schemasCache = new WeakMap<any, {
130
+ readonly context: Context.Context<never>
131
+ readonly handler: (params: any) => Effect.Effect<any, any>
132
+ readonly encodeSuccess: (u: unknown) => Effect.Effect<unknown, ParseError>
133
+ readonly decodeFailure: (u: unknown) => Effect.Effect<AiTool.Failure<any>, ParseError>
134
+ readonly decodeParameters: (u: unknown) => Effect.Effect<AiTool.Parameters<any>, ParseError>
135
+ }>()
136
+ const getSchemas = (tool: AiTool.AnyWithProtocol) => {
137
+ let schemas = schemasCache.get(tool)
138
+ if (Predicate.isUndefined(schemas)) {
139
+ const handler = context.unsafeMap.get(tool.key)! as AiTool.Handler<any>
140
+ const encodeSuccess = Schema.encodeUnknown(tool.successSchema) as any
141
+ const decodeFailure = Schema.decodeUnknown(tool.failureSchema as any) as any
142
+ const decodeParameters = Schema.decodeUnknown(tool.parametersSchema) as any
143
+ schemas = {
144
+ context: handler.context,
145
+ handler: handler.handler,
146
+ encodeSuccess,
147
+ decodeFailure,
148
+ decodeParameters
149
+ }
150
+ schemasCache.set(tool, schemas)
151
+ }
152
+ return schemas
153
+ }
154
+ const handle = Effect.fn("AiToolkit.handler", { captureStackTrace: false })(
155
+ function*(toolName: string, toolParams: unknown) {
156
+ yield* Effect.annotateCurrentSpan({
157
+ tool: toolName,
158
+ parameters: toolParams
159
+ })
160
+ const tool = tools[toolName]!
161
+ const schemas = getSchemas(tool)
162
+ const decodedParams = yield* Effect.mapError(
163
+ schemas.decodeParameters(toolParams),
164
+ (cause) =>
165
+ new AiError({
166
+ module: "AiToolkit",
167
+ method: `${toolName}.handle`,
168
+ description: `Failed to decode tool call parameters for tool '${toolName}' from '${toolParams}'`,
169
+ cause
170
+ })
171
+ )
172
+ const result = yield* schemas.handler(decodedParams).pipe(
173
+ Effect.mapInputContext((input) => Context.merge(schemas.context, input)),
174
+ Effect.catchAll((error) =>
175
+ schemas.decodeFailure(error).pipe(
176
+ Effect.mapError((cause) =>
177
+ new AiError({
178
+ module: "AiToolkit",
179
+ method: `${toolName}.handle`,
180
+ description: `Failed to decode tool call failure for tool '${toolName}'`,
181
+ cause
182
+ })
183
+ ),
184
+ Effect.flatMap(Effect.fail)
185
+ )
186
+ )
187
+ )
188
+ const encodedResult = yield* Effect.mapError(
189
+ schemas.encodeSuccess(result),
190
+ (cause) =>
191
+ new AiError({
192
+ module: "AiToolkit",
193
+ method: `${toolName}.handle`,
194
+ description: `Failed to encode tool call result for tool '${toolName}'`,
195
+ cause
196
+ })
197
+ )
198
+ return {
199
+ result,
200
+ encodedResult
201
+ } satisfies AiTool.HandlerResult<any>
202
+ }
203
+ )
204
+ return {
205
+ tools: Array.from(Object.values(tools)),
206
+ handle
207
+ }
208
+ })
209
+ },
210
+ toJSON(this: AiToolkit<any>): unknown {
211
+ return {
212
+ _id: "@effect/ai/AiToolkit",
213
+ tools: Array.from(Object.values(this.tools)).map((tool) => tool.name)
214
+ }
215
+ },
216
+ pipe() {
217
+ return pipeArguments(this, arguments)
218
+ }
219
+ }
220
+
221
+ const makeProto = <Tools extends AiTool.Any>(tools: Record<string, Tools>): AiToolkit<Tools> =>
222
+ Object.assign(function() {}, Proto, { tools }) as any
223
+
224
+ const resolveInput = <Tools extends ReadonlyArray<AiTool.Any>>(
225
+ ...tools: Tools
226
+ ): Record<string, Tools[number]> => {
227
+ const output = {} as Record<string, Tools[number]>
228
+ for (const tool of tools) {
229
+ const value = (Schema.isSchema(tool) ? AiTool.fromTaggedRequest(tool as any) : tool) as any
230
+ output[tool.name] = value
231
+ }
232
+ return output
233
+ }
251
234
 
252
235
  /**
236
+ * Constructs a new `AiToolkit` from the specified tools.
237
+ *
253
238
  * @since 1.0.0
254
- * @category handlers
239
+ * @category Constructors
255
240
  */
256
- export interface Handlers<in out Tools extends Tool.AnySchema, R = never> {
257
- readonly [HandlersTypeId]: Handlers.Variance<Tools>
258
- readonly toolkit: AiToolkit<Tools>
259
- readonly handlers: HashMap.HashMap<string, Tool.Handler<any, R>>
260
- readonly handle: <Tag extends Types.Tags<Tools>, RH>(
261
- tag: Tag,
262
- f: Tool.Handler<Types.ExtractTag<Tools, Tag>, RH>
263
- ) => Handlers<Types.ExcludeTag<Tools, Tag>, R | RH | Tool.Context<Types.ExtractTag<Tools, Tag>>>
264
- }
241
+ export const make = <const Tools extends ReadonlyArray<AiTool.Any>>(
242
+ ...tools: Tools
243
+ ): AiToolkit<Tools[number]> => makeProto(resolveInput(...tools))
265
244
 
266
245
  /**
246
+ * Merges this toolkit with one or more other toolkits.
247
+ *
267
248
  * @since 1.0.0
268
- * @category handlers
249
+ * @category Merging
269
250
  */
270
- export declare namespace Handlers {
271
- /**
272
- * @since 1.0.0
273
- * @category handlers
274
- */
275
- export interface Variance<Tools extends Tool.AnySchema> {
276
- readonly _Tools: Types.Invariant<Tools>
277
- }
278
- }
279
-
280
- const handlersVariance = {
281
- _Tools: identity
282
- }
283
-
284
- class HandlersImpl<Tools extends Tool.AnySchema, R = never> implements Handlers<Tools, R> {
285
- readonly [HandlersTypeId]: Handlers.Variance<Tools>
286
- constructor(
287
- readonly toolkit: AiToolkit<Tools>,
288
- readonly handlers: HashMap.HashMap<string, Tool.Handler<any, R>>
289
- ) {
290
- this[HandlersTypeId] = handlersVariance
291
- }
292
- static fromToolkit<Tools extends Tool.AnySchema>(toolkit: AiToolkit<Tools>): Handlers<Tools> {
293
- return new HandlersImpl(toolkit, HashMap.empty())
294
- }
295
- handle<Tag extends Types.Tags<Tools>, RH>(
296
- tag: Tag,
297
- f: Tool.Handler<Types.ExtractTag<Tools, Tag>, RH>
298
- ): Handlers<Types.ExcludeTag<Tools, Tag>, R | RH | Tool.Context<Types.ExtractTag<Tools, Tag>>> {
299
- return new HandlersImpl(this.toolkit as any, HashMap.set(this.handlers, tag, f as any))
251
+ export const merge = <const Toolkits extends ReadonlyArray<Any>>(
252
+ ...toolkits: Toolkits
253
+ ): AiToolkit<Tools<Toolkits[number]>> => {
254
+ const tools = {} as Record<string, any>
255
+ for (const toolkit of toolkits) {
256
+ for (const [name, tool] of toolkit.tools) {
257
+ tools[name] = tool
258
+ }
300
259
  }
260
+ return makeProto(tools) as any
301
261
  }
package/src/Tokenizer.ts CHANGED
@@ -1,17 +1,15 @@
1
1
  /**
2
2
  * @since 1.0.0
3
3
  */
4
- import * as Chunk from "effect/Chunk"
5
4
  import * as Context from "effect/Context"
6
5
  import * as Effect from "effect/Effect"
7
- import * as Option from "effect/Option"
6
+ import * as Predicate from "effect/Predicate"
8
7
  import type { AiError } from "./AiError.js"
9
- import type { Message } from "./AiInput.js"
10
8
  import * as AiInput from "./AiInput.js"
11
9
 
12
10
  /**
13
11
  * @since 1.0.0
14
- * @category tags
12
+ * @category Tags
15
13
  */
16
14
  export class Tokenizer extends Context.Tag("@effect/ai/Tokenizer")<
17
15
  Tokenizer,
@@ -20,22 +18,21 @@ export class Tokenizer extends Context.Tag("@effect/ai/Tokenizer")<
20
18
 
21
19
  /**
22
20
  * @since 1.0.0
23
- * @category models
24
21
  */
25
22
  export declare namespace Tokenizer {
26
23
  /**
27
24
  * @since 1.0.0
28
- * @models
25
+ * @category Models
29
26
  */
30
27
  export interface Service {
31
- readonly tokenize: (content: AiInput.Input) => Effect.Effect<Array<number>, AiError>
32
- readonly truncate: (content: AiInput.Input, tokens: number) => Effect.Effect<AiInput.Input, AiError>
28
+ readonly tokenize: (input: AiInput.Raw) => Effect.Effect<Array<number>, AiError>
29
+ readonly truncate: (input: AiInput.Raw, tokens: number) => Effect.Effect<AiInput.AiInput, AiError>
33
30
  }
34
31
  }
35
32
 
36
33
  /**
37
34
  * @since 1.0.0
38
- * @category constructors
35
+ * @category Constructors
39
36
  */
40
37
  export const make = (options: {
41
38
  readonly tokenize: (content: AiInput.AiInput) => Effect.Effect<Array<number>, AiError>
@@ -44,33 +41,32 @@ export const make = (options: {
44
41
  tokenize(input) {
45
42
  return options.tokenize(AiInput.make(input))
46
43
  },
47
- truncate(content, tokens) {
48
- return truncate(AiInput.make(content), options.tokenize, tokens)
44
+ truncate(input, tokens) {
45
+ return truncate(AiInput.make(input), options.tokenize, tokens)
49
46
  }
50
47
  })
51
48
 
52
49
  const truncate = (
53
50
  self: AiInput.AiInput,
54
- tokenize: (content: AiInput.AiInput) => Effect.Effect<Array<number>, AiError>,
51
+ tokenize: (input: AiInput.AiInput) => Effect.Effect<Array<number>, AiError>,
55
52
  maxTokens: number
56
53
  ): Effect.Effect<AiInput.AiInput, AiError> =>
57
54
  Effect.suspend(() => {
58
55
  let count = 0
59
- let inParts = self
60
- let outParts: Chunk.Chunk<Message> = Chunk.empty()
56
+ let inputMessages = self.messages
57
+ let outputMessages: Array<AiInput.Message> = []
61
58
  const loop: Effect.Effect<AiInput.AiInput, AiError> = Effect.suspend(() => {
62
- const o = Chunk.last(inParts)
63
- if (Option.isNone(o)) {
64
- return Effect.succeed(AiInput.make(outParts))
59
+ const message = inputMessages[inputMessages.length - 1]
60
+ if (Predicate.isUndefined(message)) {
61
+ return Effect.succeed(AiInput.make(outputMessages))
65
62
  }
66
- const part = o.value
67
- inParts = Chunk.dropRight(inParts, 1)
68
- return Effect.flatMap(tokenize(Chunk.of(part)), (tokens) => {
63
+ inputMessages = inputMessages.slice(0, inputMessages.length - 1)
64
+ return Effect.flatMap(tokenize(AiInput.make(message)), (tokens) => {
69
65
  count += tokens.length
70
66
  if (count > maxTokens) {
71
- return Effect.succeed(AiInput.make(outParts))
67
+ return Effect.succeed(AiInput.make(outputMessages))
72
68
  }
73
- outParts = Chunk.prepend(outParts, part)
69
+ outputMessages = [message, ...outputMessages]
74
70
  return loop
75
71
  })
76
72
  })
package/src/index.ts CHANGED
@@ -6,37 +6,37 @@ export * as AiChat from "./AiChat.js"
6
6
  /**
7
7
  * @since 1.0.0
8
8
  */
9
- export * as AiError from "./AiError.js"
9
+ export * as AiEmbeddingModel from "./AiEmbeddingModel.js"
10
10
 
11
11
  /**
12
12
  * @since 1.0.0
13
13
  */
14
- export * as AiInput from "./AiInput.js"
14
+ export * as AiError from "./AiError.js"
15
15
 
16
16
  /**
17
17
  * @since 1.0.0
18
18
  */
19
- export * as AiModel from "./AiModel.js"
19
+ export * as AiInput from "./AiInput.js"
20
20
 
21
21
  /**
22
22
  * @since 1.0.0
23
23
  */
24
- export * as AiModels from "./AiModels.js"
24
+ export * as AiLanguageModel from "./AiLanguageModel.js"
25
25
 
26
26
  /**
27
27
  * @since 1.0.0
28
28
  */
29
- export * as AiPlan from "./AiPlan.js"
29
+ export * as AiModel from "./AiModel.js"
30
30
 
31
31
  /**
32
32
  * @since 1.0.0
33
33
  */
34
- export * as AiResponse from "./AiResponse.js"
34
+ export * as AiPlan from "./AiPlan.js"
35
35
 
36
36
  /**
37
37
  * @since 1.0.0
38
38
  */
39
- export * as AiRole from "./AiRole.js"
39
+ export * as AiResponse from "./AiResponse.js"
40
40
 
41
41
  /**
42
42
  * @since 1.0.0
@@ -46,17 +46,12 @@ export * as AiTelemetry from "./AiTelemetry.js"
46
46
  /**
47
47
  * @since 1.0.0
48
48
  */
49
- export * as AiToolkit from "./AiToolkit.js"
50
-
51
- /**
52
- * @since 1.0.0
53
- */
54
- export * as Completions from "./Completions.js"
49
+ export * as AiTool from "./AiTool.js"
55
50
 
56
51
  /**
57
52
  * @since 1.0.0
58
53
  */
59
- export * as Embeddings from "./Embeddings.js"
54
+ export * as AiToolkit from "./AiToolkit.js"
60
55
 
61
56
  /**
62
57
  * @since 1.0.0