@effect/ai 0.1.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/AiChat/package.json +6 -0
- package/AiError/package.json +6 -0
- package/AiInput/package.json +6 -0
- package/AiResponse/package.json +6 -0
- package/AiRole/package.json +6 -0
- package/AiToolkit/package.json +6 -0
- package/Completions/package.json +6 -0
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/Tokenizer/package.json +6 -0
- package/dist/cjs/AiChat.js +151 -0
- package/dist/cjs/AiChat.js.map +1 -0
- package/dist/cjs/AiError.js +41 -0
- package/dist/cjs/AiError.js.map +1 -0
- package/dist/cjs/AiInput.js +349 -0
- package/dist/cjs/AiInput.js.map +1 -0
- package/dist/cjs/AiResponse.js +295 -0
- package/dist/cjs/AiResponse.js.map +1 -0
- package/dist/cjs/AiRole.js +106 -0
- package/dist/cjs/AiRole.js.map +1 -0
- package/dist/cjs/AiToolkit.js +132 -0
- package/dist/cjs/AiToolkit.js.map +1 -0
- package/dist/cjs/Completions.js +217 -0
- package/dist/cjs/Completions.js.map +1 -0
- package/dist/cjs/Tokenizer.js +59 -0
- package/dist/cjs/Tokenizer.js.map +1 -0
- package/dist/cjs/index.js +25 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/dts/AiChat.d.ts +73 -0
- package/dist/dts/AiChat.d.ts.map +1 -0
- package/dist/dts/AiError.d.ts +38 -0
- package/dist/dts/AiError.d.ts.map +1 -0
- package/dist/dts/AiInput.d.ts +283 -0
- package/dist/dts/AiInput.d.ts.map +1 -0
- package/dist/dts/AiResponse.d.ts +235 -0
- package/dist/dts/AiResponse.d.ts.map +1 -0
- package/dist/dts/AiRole.d.ts +111 -0
- package/dist/dts/AiRole.d.ts.map +1 -0
- package/dist/dts/AiToolkit.d.ts +158 -0
- package/dist/dts/AiToolkit.d.ts.map +1 -0
- package/dist/dts/Completions.d.ts +104 -0
- package/dist/dts/Completions.d.ts.map +1 -0
- package/dist/dts/Tokenizer.d.ts +34 -0
- package/dist/dts/Tokenizer.d.ts.map +1 -0
- package/dist/dts/index.d.ts +33 -0
- package/dist/dts/index.d.ts.map +1 -0
- package/dist/esm/AiChat.js +139 -0
- package/dist/esm/AiChat.js.map +1 -0
- package/dist/esm/AiError.js +31 -0
- package/dist/esm/AiError.js.map +1 -0
- package/dist/esm/AiInput.js +332 -0
- package/dist/esm/AiInput.js.map +1 -0
- package/dist/esm/AiResponse.js +281 -0
- package/dist/esm/AiResponse.js.map +1 -0
- package/dist/esm/AiRole.js +93 -0
- package/dist/esm/AiRole.js.map +1 -0
- package/dist/esm/AiToolkit.js +123 -0
- package/dist/esm/AiToolkit.js.map +1 -0
- package/dist/esm/Completions.js +206 -0
- package/dist/esm/Completions.js.map +1 -0
- package/dist/esm/Tokenizer.js +48 -0
- package/dist/esm/Tokenizer.js.map +1 -0
- package/dist/esm/index.js +33 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +4 -0
- package/package.json +100 -0
- package/src/AiChat.ts +274 -0
- package/src/AiError.ts +38 -0
- package/src/AiInput.ts +456 -0
- package/src/AiResponse.ts +343 -0
- package/src/AiRole.ts +122 -0
- package/src/AiToolkit.ts +314 -0
- package/src/Completions.ts +354 -0
- package/src/Tokenizer.ts +78 -0
- package/src/index.ts +39 -0
package/src/AiChat.ts
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 1.0.0
|
|
3
|
+
*/
|
|
4
|
+
import type { ParseError } from "@effect/schema/ParseResult"
|
|
5
|
+
import * as Schema from "@effect/schema/Schema"
|
|
6
|
+
import * as Channel from "effect/Channel"
|
|
7
|
+
import * as Chunk from "effect/Chunk"
|
|
8
|
+
import * as Effect from "effect/Effect"
|
|
9
|
+
import * as Ref from "effect/Ref"
|
|
10
|
+
import * as Stream from "effect/Stream"
|
|
11
|
+
import type { Concurrency } from "effect/Types"
|
|
12
|
+
import type { AiError } from "./AiError.js"
|
|
13
|
+
import * as AiInput from "./AiInput.js"
|
|
14
|
+
import { AiResponse, WithResolved } from "./AiResponse.js"
|
|
15
|
+
import type * as AiToolkit from "./AiToolkit.js"
|
|
16
|
+
import { Completions } from "./Completions.js"
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @since 1.0.0
|
|
20
|
+
* @category tags
|
|
21
|
+
*/
|
|
22
|
+
export class AiChat extends Effect.Tag("@effect/ai/AiChat")<
|
|
23
|
+
AiChat,
|
|
24
|
+
AiChat.Service
|
|
25
|
+
>() {}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @since 1.0.0
|
|
29
|
+
* @category models
|
|
30
|
+
*/
|
|
31
|
+
export declare namespace AiChat {
|
|
32
|
+
/**
|
|
33
|
+
* @since 1.0.0
|
|
34
|
+
* @category models
|
|
35
|
+
*/
|
|
36
|
+
export interface Service {
|
|
37
|
+
readonly history: Effect.Effect<AiInput.AiInput>
|
|
38
|
+
readonly export: Effect.Effect<unknown>
|
|
39
|
+
readonly exportJson: Effect.Effect<string>
|
|
40
|
+
readonly send: (input: AiInput.Input) => Effect.Effect<AiResponse, AiError>
|
|
41
|
+
readonly stream: (input: AiInput.Input) => Stream.Stream<AiResponse, AiError>
|
|
42
|
+
readonly structured: <A, I, R>(
|
|
43
|
+
tool: Completions.StructuredSchema<A, I, R>,
|
|
44
|
+
input: AiInput.Input
|
|
45
|
+
) => Effect.Effect<A, AiError, R>
|
|
46
|
+
readonly toolkit: <Tools extends AiToolkit.Tool.AnySchema>(
|
|
47
|
+
options: {
|
|
48
|
+
readonly input: AiInput.Input
|
|
49
|
+
readonly tools: AiToolkit.Handlers<Tools>
|
|
50
|
+
readonly required?: Tools["_tag"] | boolean | undefined
|
|
51
|
+
readonly concurrency?: Concurrency | undefined
|
|
52
|
+
}
|
|
53
|
+
) => Effect.Effect<
|
|
54
|
+
WithResolved<AiToolkit.Tool.Success<Tools>>,
|
|
55
|
+
AiError | AiToolkit.Tool.Failure<Tools>,
|
|
56
|
+
AiToolkit.Tool.Context<Tools>
|
|
57
|
+
>
|
|
58
|
+
readonly toolkitStream: <Tools extends AiToolkit.Tool.AnySchema>(
|
|
59
|
+
options: {
|
|
60
|
+
readonly input: AiInput.Input
|
|
61
|
+
readonly tools: AiToolkit.Handlers<Tools>
|
|
62
|
+
readonly required?: Tools["_tag"] | boolean | undefined
|
|
63
|
+
readonly concurrency?: Concurrency | undefined
|
|
64
|
+
}
|
|
65
|
+
) => Stream.Stream<
|
|
66
|
+
WithResolved<AiToolkit.Tool.Success<Tools>>,
|
|
67
|
+
AiError | AiToolkit.Tool.Failure<Tools>,
|
|
68
|
+
AiToolkit.Tool.Context<Tools>
|
|
69
|
+
>
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @since 1.0.0
|
|
75
|
+
* @category constructors
|
|
76
|
+
*/
|
|
77
|
+
export const fromInput = (input: AiInput.Input): Effect.Effect<AiChat.Service, never, Completions> =>
|
|
78
|
+
Ref.make(AiInput.make(input)).pipe(
|
|
79
|
+
Effect.bindTo("historyRef"),
|
|
80
|
+
Effect.bind("completions", () => Completions),
|
|
81
|
+
Effect.map(({ completions, historyRef }) => new AiChatImpl(historyRef, completions))
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
class AiChatImpl implements AiChat.Service {
|
|
85
|
+
readonly semaphore = Effect.unsafeMakeSemaphore(1)
|
|
86
|
+
|
|
87
|
+
constructor(
|
|
88
|
+
readonly historyRef: Ref.Ref<AiInput.AiInput>,
|
|
89
|
+
readonly completions: Completions.Service
|
|
90
|
+
) {}
|
|
91
|
+
|
|
92
|
+
get history() {
|
|
93
|
+
return Ref.get(this.historyRef)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get export() {
|
|
97
|
+
return Ref.get(this.historyRef).pipe(
|
|
98
|
+
Effect.flatMap(Schema.encode(AiInput.Schema)),
|
|
99
|
+
Effect.orDie
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get exportJson() {
|
|
104
|
+
return Ref.get(this.historyRef).pipe(
|
|
105
|
+
Effect.flatMap(Schema.encode(AiInput.SchemaJson)),
|
|
106
|
+
Effect.orDie
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
send(input: AiInput.Input) {
|
|
111
|
+
const newParts = AiInput.make(input)
|
|
112
|
+
return Ref.get(this.historyRef).pipe(
|
|
113
|
+
Effect.flatMap((parts) => {
|
|
114
|
+
const allParts = Chunk.appendAll(parts, newParts)
|
|
115
|
+
return this.completions.create(allParts).pipe(
|
|
116
|
+
Effect.tap((response) => {
|
|
117
|
+
const responseParts = AiInput.make(response)
|
|
118
|
+
return Ref.set(this.historyRef, Chunk.appendAll(allParts, responseParts))
|
|
119
|
+
})
|
|
120
|
+
)
|
|
121
|
+
}),
|
|
122
|
+
this.semaphore.withPermits(1),
|
|
123
|
+
Effect.withSpan("AiChat.send", { attributes: { input }, captureStackTrace: false })
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
stream(input: AiInput.Input) {
|
|
128
|
+
return Stream.suspend(() => {
|
|
129
|
+
let combined = AiResponse.empty
|
|
130
|
+
return Stream.fromChannel(Channel.acquireUseRelease(
|
|
131
|
+
this.semaphore.take(1).pipe(
|
|
132
|
+
Effect.zipRight(Ref.get(this.historyRef)),
|
|
133
|
+
Effect.map(Chunk.appendAll(AiInput.make(input)))
|
|
134
|
+
),
|
|
135
|
+
(parts) =>
|
|
136
|
+
this.completions.stream(parts).pipe(
|
|
137
|
+
Stream.map((chunk) => {
|
|
138
|
+
combined = combined.concat(chunk)
|
|
139
|
+
return chunk
|
|
140
|
+
}),
|
|
141
|
+
Stream.toChannel
|
|
142
|
+
),
|
|
143
|
+
(parts) =>
|
|
144
|
+
Effect.zipRight(
|
|
145
|
+
Ref.set(this.historyRef, Chunk.appendAll(parts, AiInput.make(combined))),
|
|
146
|
+
this.semaphore.release(1)
|
|
147
|
+
)
|
|
148
|
+
))
|
|
149
|
+
}).pipe(Stream.withSpan("AiChat.stream", { attributes: { input }, captureStackTrace: false }))
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
structured<A, I, R>(
|
|
153
|
+
schema: Completions.StructuredSchema<A, I, R>,
|
|
154
|
+
input: AiInput.Input
|
|
155
|
+
): Effect.Effect<A, AiError, R> {
|
|
156
|
+
const newParts = AiInput.make(input)
|
|
157
|
+
return Ref.get(this.historyRef).pipe(
|
|
158
|
+
Effect.flatMap((parts) => {
|
|
159
|
+
const allParts = Chunk.appendAll(parts, newParts)
|
|
160
|
+
return this.completions.structured({
|
|
161
|
+
input: allParts,
|
|
162
|
+
schema
|
|
163
|
+
}).pipe(
|
|
164
|
+
Effect.flatMap((response) => {
|
|
165
|
+
const responseParts = AiInput.make(response)
|
|
166
|
+
return Effect.as(
|
|
167
|
+
Ref.set(this.historyRef, Chunk.appendAll(allParts, responseParts)),
|
|
168
|
+
response.unsafeValue
|
|
169
|
+
)
|
|
170
|
+
})
|
|
171
|
+
)
|
|
172
|
+
}),
|
|
173
|
+
this.semaphore.withPermits(1),
|
|
174
|
+
Effect.withSpan("AiChat.structured", {
|
|
175
|
+
attributes: { input, schema: schema._tag ?? schema.identifier },
|
|
176
|
+
captureStackTrace: false
|
|
177
|
+
})
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
toolkit<Tools extends AiToolkit.Tool.AnySchema>(
|
|
182
|
+
options: {
|
|
183
|
+
readonly input: AiInput.Input
|
|
184
|
+
readonly tools: AiToolkit.Handlers<Tools>
|
|
185
|
+
readonly required?: Tools["_tag"] | boolean | undefined
|
|
186
|
+
readonly concurrency?: Concurrency | undefined
|
|
187
|
+
}
|
|
188
|
+
): Effect.Effect<
|
|
189
|
+
WithResolved<AiToolkit.Tool.Success<Tools>>,
|
|
190
|
+
AiError | AiToolkit.Tool.Failure<Tools>,
|
|
191
|
+
AiToolkit.Tool.Context<Tools>
|
|
192
|
+
> {
|
|
193
|
+
const newParts = AiInput.make(options.input)
|
|
194
|
+
return Ref.get(this.historyRef).pipe(
|
|
195
|
+
Effect.flatMap((parts) => {
|
|
196
|
+
const allParts = Chunk.appendAll(parts, newParts)
|
|
197
|
+
return this.completions.toolkit({
|
|
198
|
+
...options,
|
|
199
|
+
input: allParts
|
|
200
|
+
}).pipe(
|
|
201
|
+
Effect.tap((response) => {
|
|
202
|
+
const responseParts = AiInput.make(response)
|
|
203
|
+
return Ref.set(this.historyRef, Chunk.appendAll(allParts, responseParts))
|
|
204
|
+
})
|
|
205
|
+
)
|
|
206
|
+
}),
|
|
207
|
+
this.semaphore.withPermits(1),
|
|
208
|
+
Effect.withSpan("AiChat.toolkit", { attributes: { input: options.input }, captureStackTrace: false })
|
|
209
|
+
)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
toolkitStream<Tools extends AiToolkit.Tool.AnySchema>(
|
|
213
|
+
options: {
|
|
214
|
+
readonly input: AiInput.Input
|
|
215
|
+
readonly tools: AiToolkit.Handlers<Tools>
|
|
216
|
+
readonly required?: Tools["_tag"] | boolean | undefined
|
|
217
|
+
readonly concurrency?: Concurrency | undefined
|
|
218
|
+
}
|
|
219
|
+
): Stream.Stream<
|
|
220
|
+
WithResolved<AiToolkit.Tool.Success<Tools>>,
|
|
221
|
+
AiError | AiToolkit.Tool.Failure<Tools>,
|
|
222
|
+
AiToolkit.Tool.Context<Tools>
|
|
223
|
+
> {
|
|
224
|
+
return Stream.suspend(() => {
|
|
225
|
+
let combined = WithResolved.empty as WithResolved<AiToolkit.Tool.Success<Tools>>
|
|
226
|
+
return Stream.fromChannel(Channel.acquireUseRelease(
|
|
227
|
+
this.semaphore.take(1).pipe(
|
|
228
|
+
Effect.zipRight(Ref.get(this.historyRef)),
|
|
229
|
+
Effect.map(Chunk.appendAll(AiInput.make(options.input)))
|
|
230
|
+
),
|
|
231
|
+
(parts) =>
|
|
232
|
+
this.completions.toolkitStream({
|
|
233
|
+
...options,
|
|
234
|
+
input: parts
|
|
235
|
+
}).pipe(
|
|
236
|
+
Stream.map((chunk) => {
|
|
237
|
+
combined = combined.concat(chunk)
|
|
238
|
+
return chunk
|
|
239
|
+
}),
|
|
240
|
+
Stream.toChannel
|
|
241
|
+
),
|
|
242
|
+
(parts) =>
|
|
243
|
+
Effect.zipRight(
|
|
244
|
+
Ref.set(this.historyRef, Chunk.appendAll(parts, AiInput.make(combined))),
|
|
245
|
+
this.semaphore.release(1)
|
|
246
|
+
)
|
|
247
|
+
))
|
|
248
|
+
}).pipe(Stream.withSpan("AiChat.toolkitStream", { attributes: { input: options.input }, captureStackTrace: false }))
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* @since 1.0.0
|
|
254
|
+
* @category constructors
|
|
255
|
+
*/
|
|
256
|
+
export const empty: Effect.Effect<AiChat.Service, never, Completions> = fromInput(AiInput.empty)
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* @since 1.0.0
|
|
260
|
+
* @category constructors
|
|
261
|
+
*/
|
|
262
|
+
export const fromExport = (data: unknown): Effect.Effect<AiChat.Service, ParseError, Completions> =>
|
|
263
|
+
Schema.decodeUnknown(AiInput.Schema)(data).pipe(
|
|
264
|
+
Effect.flatMap(fromInput)
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* @since 1.0.0
|
|
269
|
+
* @category constructors
|
|
270
|
+
*/
|
|
271
|
+
export const fromJson = (data: string): Effect.Effect<AiChat.Service, ParseError, Completions> =>
|
|
272
|
+
Schema.decode(AiInput.SchemaJson)(data).pipe(
|
|
273
|
+
Effect.flatMap(fromInput)
|
|
274
|
+
)
|
package/src/AiError.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 1.0.0
|
|
3
|
+
*/
|
|
4
|
+
import * as Schema from "@effect/schema/Schema"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @since 1.0.0
|
|
8
|
+
* @category type ids
|
|
9
|
+
*/
|
|
10
|
+
export const TypeId: unique symbol = Symbol("@effect/ai/AiError")
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @since 1.0.0
|
|
14
|
+
* @category type ids
|
|
15
|
+
*/
|
|
16
|
+
export type TypeId = typeof TypeId
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @since 1.0.0
|
|
20
|
+
* @category errors
|
|
21
|
+
*/
|
|
22
|
+
export class AiError extends Schema.TaggedError<AiError>("@effect/ai/AiError")("AiError", {
|
|
23
|
+
module: Schema.String,
|
|
24
|
+
method: Schema.String,
|
|
25
|
+
description: Schema.String,
|
|
26
|
+
cause: Schema.optional(Schema.Defect)
|
|
27
|
+
}) {
|
|
28
|
+
/**
|
|
29
|
+
* @since 1.0.0
|
|
30
|
+
*/
|
|
31
|
+
readonly [TypeId]: TypeId = TypeId
|
|
32
|
+
/**
|
|
33
|
+
* @since 1.0.0
|
|
34
|
+
*/
|
|
35
|
+
get message(): string {
|
|
36
|
+
return `${this.module}.${this.method}: ${this.description}`
|
|
37
|
+
}
|
|
38
|
+
}
|