@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
@@ -1 +0,0 @@
1
- {"version":3,"file":"Embeddings.js","names":["dataLoader","Context","Effect","identity","Option","Request","RequestResolver","Schema","AiError","Embeddings","Tag","EmbeddingRequest","TaggedRequest","failure","success","mutable","Array","Number","payload","input","String","makeBatchedResolver","embedMany","makeBatched","requests","map","request","pipe","flatMap","forEach","embeddings","index","succeed","discard","catchAll","error","fail","make","options","gen","cache","fromNullable","config","makeCache","optionFromOptional","resolver","maxBatchSize","batchN","embed","match","onNone","onSome","withRequestCaching","withRequestCache","withSpan","captureStackTrace","of","makeDataLoader","resolverDelayed","window"],"sources":["../../src/Embeddings.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
package/src/AiModels.ts DELETED
@@ -1,77 +0,0 @@
1
- /**
2
- * @since 1.0.0
3
- */
4
- import * as Context from "effect/Context"
5
- import * as Effect from "effect/Effect"
6
- import * as Equal from "effect/Equal"
7
- import * as Hash from "effect/Hash"
8
- import * as Layer from "effect/Layer"
9
- import * as RcMap from "effect/RcMap"
10
- import type * as Scope from "effect/Scope"
11
- import type { AiModel } from "./AiModel.js"
12
-
13
- /**
14
- * @since 1.0.0
15
- * @category tags
16
- */
17
- export class AiModels extends Context.Tag("@effect/ai/AiModels")<
18
- AiModels,
19
- AiModels.Service
20
- >() {}
21
-
22
- /**
23
- * @since 1.0.0
24
- */
25
- export declare namespace AiModels {
26
- /**
27
- * @since 1.0.0
28
- * @category models
29
- */
30
- export interface Service {
31
- readonly build: <Provides, Requires>(
32
- model: AiModel<Provides, Requires>,
33
- context: Context.Context<Requires>
34
- ) => Effect.Effect<Context.Context<Provides>, never, Scope.Scope>
35
- }
36
- }
37
-
38
- class AiModelsKey {
39
- constructor(
40
- readonly model: AiModel<any, any>,
41
- readonly service: unknown
42
- ) {}
43
-
44
- [Equal.symbol](that: AiModelsKey): boolean {
45
- return this.service === that.service && this.model.cacheKey === that.model.cacheKey
46
- }
47
- [Hash.symbol](): number {
48
- return Hash.combine(Hash.hash(this.service))(Hash.hash(this.model.cacheKey))
49
- }
50
- }
51
-
52
- const make = Effect.gen(function*() {
53
- const services = yield* RcMap.make({
54
- idleTimeToLive: "1 minute",
55
- lookup: (key: AiModelsKey) => Effect.provideService(key.model.provides, key.model.requires, key.service)
56
- })
57
-
58
- const build = <Provides, Requires>(
59
- model: AiModel<Provides, Requires>,
60
- context: Context.Context<Requires>
61
- ): Effect.Effect<Context.Context<Provides>, never, Scope.Scope> =>
62
- Effect.map(
63
- RcMap.get(
64
- services,
65
- new AiModelsKey(model, Context.get(context, model.requires as any))
66
- ),
67
- (context) => model.updateContext(context)
68
- )
69
-
70
- return { build } as const
71
- })
72
-
73
- /**
74
- * @since 1.0.0
75
- * @category layers
76
- */
77
- export const layer: Layer.Layer<AiModels> = Layer.scoped(AiModels, make)
package/src/AiRole.ts DELETED
@@ -1,122 +0,0 @@
1
- /**
2
- * @since 1.0.0
3
- */
4
- import * as Option from "effect/Option"
5
- import * as Schema from "effect/Schema"
6
-
7
- /**
8
- * @since 1.0.0
9
- * @category type ids
10
- */
11
- export const TypeId: unique symbol = Symbol.for("@effect/ai/AiRole")
12
-
13
- /**
14
- * @since 1.0.0
15
- * @category type ids
16
- */
17
- export type TypeId = typeof TypeId
18
-
19
- /**
20
- * @since 1.0.0
21
- * @category models
22
- */
23
- export type AiRole = User | UserWithName | Model
24
-
25
- /**
26
- * @since 1.0.0
27
- * @category models
28
- */
29
- export class User extends Schema.TaggedClass<User>("@effect/ai/AiRole/User")("User", {}) {
30
- /**
31
- * @since 1.0.0
32
- */
33
- readonly [TypeId]: TypeId = TypeId
34
-
35
- /**
36
- * @since 1.0.0
37
- */
38
- readonly kind = "user" as const
39
-
40
- /**
41
- * @since 1.0.0
42
- */
43
- readonly nameOption: Option.Option<string> = Option.none()
44
- }
45
-
46
- /**
47
- * @since 1.0.0
48
- * @category constructors
49
- */
50
- export const user: AiRole = new User()
51
-
52
- /**
53
- * @since 1.0.0
54
- * @category models
55
- */
56
- export class UserWithName extends Schema.TaggedClass<UserWithName>("@effect/ai/AiRole/UserWithName")("UserWithName", {
57
- name: Schema.String
58
- }) {
59
- /**
60
- * @since 1.0.0
61
- */
62
- readonly [TypeId]: TypeId = TypeId
63
-
64
- /**
65
- * @since 1.0.0
66
- */
67
- readonly kind = "user" as const
68
-
69
- /**
70
- * @since 1.0.0
71
- */
72
- get nameOption(): Option.Option<string> {
73
- return Option.some(this.name)
74
- }
75
- }
76
-
77
- /**
78
- * @since 1.0.0
79
- * @category constructors
80
- */
81
- export const userWithName = (name: string): AiRole => new UserWithName({ name }, { disableValidation: true })
82
-
83
- /**
84
- * @since 1.0.0
85
- * @category models
86
- */
87
- export class Model extends Schema.TaggedClass<Model>("@effect/ai/AiRole/Model")("Model", {}) {
88
- /**
89
- * @since 1.0.0
90
- */
91
- readonly [TypeId]: TypeId = TypeId
92
-
93
- /**
94
- * @since 1.0.0
95
- */
96
- readonly kind = "model" as const
97
-
98
- /**
99
- * @since 1.0.0
100
- */
101
- readonly nameOption: Option.Option<string> = Option.none()
102
- }
103
-
104
- /**
105
- * @since 1.0.0
106
- * @category constructors
107
- */
108
- export const model: AiRole = new Model()
109
-
110
- /**
111
- * @since 1.0.0
112
- * @category roles
113
- */
114
- export const AiRole: Schema.Union<[
115
- typeof User,
116
- typeof UserWithName,
117
- typeof Model
118
- ]> = Schema.Union(
119
- User,
120
- UserWithName,
121
- Model
122
- )
@@ -1,434 +0,0 @@
1
- /**
2
- * @since 1.0.0
3
- */
4
- import * as Chunk from "effect/Chunk"
5
- import * as Context from "effect/Context"
6
- import * as Effect from "effect/Effect"
7
- import * as HashMap from "effect/HashMap"
8
- import * as JsonSchema from "effect/JSONSchema"
9
- import * as Option from "effect/Option"
10
- import * as Predicate from "effect/Predicate"
11
- import * as Schema from "effect/Schema"
12
- import * as AST from "effect/SchemaAST"
13
- import * as Stream from "effect/Stream"
14
- import type { Span } from "effect/Tracer"
15
- import type { Concurrency } from "effect/Types"
16
- import { AiError } from "./AiError.js"
17
- import type { Message } from "./AiInput.js"
18
- import * as AiInput from "./AiInput.js"
19
- import type { AiResponse, ToolCallId, ToolCallPart } from "./AiResponse.js"
20
- import { WithResolved } from "./AiResponse.js"
21
- import type * as AiToolkit from "./AiToolkit.js"
22
-
23
- /**
24
- * @since 1.0.0
25
- * @category tags
26
- */
27
- export class Completions extends Context.Tag("@effect/ai/Completions")<
28
- Completions,
29
- Completions.Service
30
- >() {}
31
-
32
- /**
33
- * @since 1.0.0
34
- * @category models
35
- */
36
- export declare namespace Completions {
37
- /**
38
- * @since 1.0.0
39
- * @category models
40
- */
41
- export type StructuredSchema<A, I, R> = TaggedSchema<A, I, R> | IdentifiedSchema<A, I, R>
42
-
43
- /**
44
- * @since 1.0.0
45
- * @category models
46
- */
47
- export interface TaggedSchema<A, I, R> extends Schema.Schema<A, I, R> {
48
- readonly _tag: string
49
- }
50
-
51
- /**
52
- * @since 1.0.0
53
- * @category models
54
- */
55
- export interface IdentifiedSchema<A, I, R> extends Schema.Schema<A, I, R> {
56
- readonly identifier: string
57
- }
58
-
59
- /**
60
- * @since 1.0.0
61
- * @category models
62
- */
63
- export interface Service {
64
- readonly create: (input: AiInput.Input) => Effect.Effect<AiResponse, AiError>
65
- readonly stream: (input: AiInput.Input) => Stream.Stream<AiResponse, AiError>
66
- readonly structured: {
67
- <A, I, R>(options: {
68
- readonly input: AiInput.Input
69
- readonly schema: StructuredSchema<A, I, R>
70
- }): Effect.Effect<WithResolved<A>, AiError, R>
71
- <A, I, R>(options: {
72
- readonly input: AiInput.Input
73
- readonly schema: Schema.Schema<A, I, R>
74
- readonly toolCallId: string
75
- }): Effect.Effect<WithResolved<A>, AiError, R>
76
- }
77
- readonly toolkit: <Tools extends AiToolkit.Tool.AnySchema>(
78
- options: {
79
- readonly input: AiInput.Input
80
- readonly tools: AiToolkit.Handlers<Tools>
81
- readonly required?: Tools["_tag"] | boolean | undefined
82
- readonly concurrency?: Concurrency | undefined
83
- }
84
- ) => Effect.Effect<
85
- WithResolved<AiToolkit.Tool.Success<Tools>>,
86
- AiError | AiToolkit.Tool.Failure<Tools>,
87
- AiToolkit.Tool.Context<Tools>
88
- >
89
- readonly toolkitStream: <Tools extends AiToolkit.Tool.AnySchema>(
90
- options: {
91
- readonly input: AiInput.Input
92
- readonly tools: AiToolkit.Handlers<Tools>
93
- readonly required?: Tools["_tag"] | boolean | undefined
94
- readonly concurrency?: Concurrency | undefined
95
- }
96
- ) => Stream.Stream<
97
- WithResolved<AiToolkit.Tool.Success<Tools>>,
98
- AiError | AiToolkit.Tool.Failure<Tools>,
99
- AiToolkit.Tool.Context<Tools>
100
- >
101
- }
102
- }
103
-
104
- const constEmptyMap = new Map<never, never>()
105
-
106
- /**
107
- * @since 1.0.0
108
- * @category models
109
- */
110
- export interface CompletionOptions {
111
- readonly system: Option.Option<string>
112
- readonly input: Chunk.NonEmptyChunk<Message>
113
- readonly tools: Array<{
114
- readonly name: string
115
- readonly description: string
116
- readonly parameters: JsonSchema.JsonSchema7
117
- readonly structured: boolean
118
- }>
119
- readonly required: boolean | string
120
- }
121
-
122
- /**
123
- * @since 1.0.0
124
- * @category constructors
125
- */
126
- export const make = (options: {
127
- readonly create: (options: {
128
- readonly system: Option.Option<string>
129
- readonly input: Chunk.NonEmptyChunk<Message>
130
- readonly tools: Array<{
131
- readonly name: string
132
- readonly description: string
133
- readonly parameters: JsonSchema.JsonSchema7
134
- readonly structured: boolean
135
- }>
136
- readonly required: boolean | string
137
- readonly span: Span
138
- }) => Effect.Effect<AiResponse, AiError>
139
- readonly stream: (options: {
140
- readonly system: Option.Option<string>
141
- readonly input: Chunk.NonEmptyChunk<Message>
142
- readonly tools: Array<{
143
- readonly name: string
144
- readonly description: string
145
- readonly parameters: JsonSchema.JsonSchema7
146
- readonly structured: boolean
147
- }>
148
- readonly required: boolean | string
149
- readonly span: Span
150
- }) => Stream.Stream<AiResponse, AiError>
151
- }): Effect.Effect<Completions.Service> =>
152
- Effect.map(Effect.serviceOption(AiInput.SystemInstruction), (parentSystem) => {
153
- return Completions.of({
154
- create(input) {
155
- return Effect.useSpan(
156
- "Completions.create",
157
- { captureStackTrace: false },
158
- (span) =>
159
- Effect.serviceOption(AiInput.SystemInstruction).pipe(
160
- Effect.flatMap((system) =>
161
- options.create({
162
- input: AiInput.make(input) as Chunk.NonEmptyChunk<Message>,
163
- system: Option.orElse(system, () => parentSystem),
164
- tools: [],
165
- required: false,
166
- span
167
- })
168
- )
169
- )
170
- )
171
- },
172
- stream(input_) {
173
- const input = AiInput.make(input_)
174
- return Effect.makeSpanScoped("Completions.stream", { captureStackTrace: false }).pipe(
175
- Effect.zip(Effect.serviceOption(AiInput.SystemInstruction)),
176
- Effect.map(([span, system]) =>
177
- options.stream({
178
- input: input as Chunk.NonEmptyChunk<Message>,
179
- system: Option.orElse(system, () => parentSystem),
180
- tools: [],
181
- required: false,
182
- span
183
- })
184
- ),
185
- Stream.unwrapScoped
186
- )
187
- },
188
- structured(opts) {
189
- const input = AiInput.make(opts.input)
190
- const decode = Schema.decodeUnknown(opts.schema)
191
- const toolId = "toolCallId" in opts
192
- ? opts.toolCallId
193
- : "_tag" in opts.schema
194
- ? opts.schema._tag
195
- : opts.schema.identifier
196
- return Effect.useSpan(
197
- "Completions.structured",
198
- { attributes: { toolId }, captureStackTrace: false },
199
- (span) =>
200
- Effect.serviceOption(AiInput.SystemInstruction).pipe(
201
- Effect.flatMap((system) =>
202
- options.create({
203
- input: input as Chunk.NonEmptyChunk<Message>,
204
- system: Option.orElse(system, () => parentSystem),
205
- tools: [convertTool(toolId, opts.schema, true)],
206
- required: true,
207
- span
208
- })
209
- ),
210
- Effect.flatMap((response) =>
211
- Chunk.findFirst(
212
- response.parts,
213
- (part): part is ToolCallPart => part._tag === "ToolCall" && part.name === toolId
214
- ).pipe(
215
- Option.match({
216
- onNone: () =>
217
- Effect.fail(
218
- new AiError({
219
- module: "Completions",
220
- method: "structured",
221
- description: `Tool call '${toolId}' not found in response`
222
- })
223
- ),
224
- onSome: (toolCall) =>
225
- Effect.matchEffect(decode(toolCall.params), {
226
- onFailure: (cause) =>
227
- new AiError({
228
- module: "Completions",
229
- method: "structured",
230
- description: `Failed to decode tool call '${toolId}' parameters`,
231
- cause
232
- }),
233
- onSuccess: (resolved) =>
234
- Effect.succeed(
235
- new WithResolved({
236
- response,
237
- resolved: new Map([[toolCall.id, resolved]]),
238
- encoded: new Map([[toolCall.id, toolCall.params]])
239
- })
240
- )
241
- })
242
- })
243
- )
244
- )
245
- )
246
- )
247
- },
248
- toolkit({ concurrency, input: inputInput, required = false, tools }) {
249
- const input = AiInput.make(inputInput)
250
- const toolArr: Array<{
251
- name: string
252
- description: string
253
- parameters: JsonSchema.JsonSchema7
254
- structured: boolean
255
- }> = []
256
- for (const [, tool] of tools.toolkit.tools) {
257
- toolArr.push(convertTool(tool._tag, tool as any))
258
- }
259
- return Effect.useSpan(
260
- "Completions.toolkit",
261
- { attributes: { concurrency, required }, captureStackTrace: false },
262
- (span) =>
263
- Effect.serviceOption(AiInput.SystemInstruction).pipe(
264
- Effect.flatMap((system) =>
265
- options.create({
266
- input: input as Chunk.NonEmptyChunk<Message>,
267
- system: Option.orElse(system, () => parentSystem),
268
- tools: toolArr,
269
- required: required as any,
270
- span
271
- })
272
- ),
273
- Effect.flatMap((response) => resolveParts({ response, tools, concurrency, method: "toolkit" }))
274
- ) as any
275
- )
276
- },
277
- toolkitStream({ concurrency, input, required = false, tools }) {
278
- const toolArr: Array<{
279
- name: string
280
- description: string
281
- parameters: JsonSchema.JsonSchema7
282
- structured: boolean
283
- }> = []
284
- for (const [, tool] of tools.toolkit.tools) {
285
- toolArr.push(convertTool(tool._tag, tool as any))
286
- }
287
- return Effect.makeSpanScoped("Completions.stream", {
288
- captureStackTrace: false,
289
- attributes: { required, concurrency }
290
- }).pipe(
291
- Effect.zip(Effect.serviceOption(AiInput.SystemInstruction)),
292
- Effect.map(([span, system]) =>
293
- options.stream({
294
- input: AiInput.make(input) as Chunk.NonEmptyChunk<Message>,
295
- system: Option.orElse(system, () => parentSystem),
296
- tools: toolArr,
297
- required: required as any,
298
- span
299
- })
300
- ),
301
- Stream.unwrapScoped,
302
- Stream.mapEffect(
303
- (chunk) => resolveParts({ response: chunk, tools, concurrency, method: "toolkitStream" }),
304
- { concurrency: "unbounded" }
305
- )
306
- ) as any
307
- }
308
- })
309
- })
310
-
311
- const convertTool = <A, I, R>(
312
- name: string,
313
- schema: Schema.Schema<A, I, R>,
314
- structured = false
315
- ) => ({
316
- name,
317
- description: getDescription(schema.ast),
318
- parameters: makeJsonSchema(AST.omit(schema.ast, ["_tag"])),
319
- structured
320
- })
321
-
322
- const makeJsonSchema = (ast: AST.AST): JsonSchema.JsonSchema7 => {
323
- const $defs = {}
324
- const schema = JsonSchema.fromAST(ast, {
325
- definitions: $defs,
326
- topLevelReferenceStrategy: "skip"
327
- })
328
- if (Object.keys($defs).length === 0) return schema
329
- ;(schema as any).$defs = $defs
330
- return schema
331
- }
332
-
333
- const getDescription = (ast: AST.AST): string => {
334
- const annotations = ast._tag === "Transformation" ?
335
- {
336
- ...ast.to.annotations,
337
- ...ast.annotations
338
- } :
339
- ast.annotations
340
- return AST.DescriptionAnnotationId in annotations ? annotations[AST.DescriptionAnnotationId] as string : ""
341
- }
342
-
343
- const resolveParts = (
344
- options: {
345
- readonly response: AiResponse
346
- readonly tools: AiToolkit.Handlers<any>
347
- readonly concurrency: Concurrency | undefined
348
- readonly method: string
349
- }
350
- ) => {
351
- const toolNames: Array<string> = []
352
- const toolParts = Chunk.filter(
353
- options.response.parts,
354
- (part): part is ToolCallPart => {
355
- if (part._tag === "ToolCall") {
356
- toolNames.push(part.name)
357
- return true
358
- }
359
- return false
360
- }
361
- )
362
- if (Chunk.isEmpty(toolParts)) {
363
- return Effect.succeed(
364
- new WithResolved({
365
- response: options.response,
366
- resolved: constEmptyMap,
367
- encoded: constEmptyMap
368
- })
369
- )
370
- }
371
- const resolved = new Map<ToolCallId, AiToolkit.Tool.Success<any>>()
372
- const encoded = new Map<ToolCallId, unknown>()
373
- return Effect.annotateCurrentSpan("toolCalls", toolNames).pipe(
374
- Effect.zipRight(Effect.forEach(
375
- toolParts,
376
- (part) => {
377
- const tool = HashMap.unsafeGet(options.tools.toolkit.tools, part.name)
378
- const handler = HashMap.unsafeGet(options.tools.handlers, part.name)
379
- const decodeParams = Schema.decodeUnknown(tool as any)
380
- const encodeSuccess = Schema.encode(tool.success)
381
- return decodeParams(injectTag(part.params, part.name)).pipe(
382
- Effect.mapError((cause) =>
383
- new AiError({
384
- module: "Completions",
385
- method: options.method,
386
- description: `Failed to decode tool call '${part.name}' parameters`,
387
- cause
388
- })
389
- ),
390
- Effect.flatMap(handler),
391
- Effect.tap((value) => {
392
- return encodeSuccess(value).pipe(
393
- Effect.mapError((cause) =>
394
- new AiError({
395
- module: "Completions",
396
- method: options.method,
397
- description: `Failed to encode tool call '${part.name}' result`,
398
- cause
399
- })
400
- ),
401
- Effect.map((encodedValue) => {
402
- resolved.set(part.id, value)
403
- encoded.set(part.id, encodedValue)
404
- })
405
- )
406
- })
407
- )
408
- },
409
- { concurrency: options.concurrency, discard: true }
410
- )),
411
- Effect.as(new WithResolved({ response: options.response, resolved, encoded }))
412
- )
413
- }
414
-
415
- /**
416
- * Certain providers (i.e. Anthropic) do not do a great job returning the
417
- * `_tag` enum with the parameters for a tool call. This method ensures that
418
- * the `_tag` is injected into the tool call parameters to avoid issues when
419
- * decoding.
420
- */
421
- function injectTag(params: unknown, tag: string) {
422
- // If for some reason we do not receive an object back for the tool call
423
- // input parameters, just return them unchanged
424
- if (!Predicate.isObject(params)) {
425
- return params
426
- }
427
- // If the tool's `_tag` is already present in input parameters, return them
428
- // unchanged
429
- if (Predicate.hasProperty(params, "_tag")) {
430
- return params
431
- }
432
- // Otherwise inject the tool's `_tag` into the input parameters
433
- return { ...params, _tag: tag }
434
- }