@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.
Files changed (75) hide show
  1. package/AiChat/package.json +6 -0
  2. package/AiError/package.json +6 -0
  3. package/AiInput/package.json +6 -0
  4. package/AiResponse/package.json +6 -0
  5. package/AiRole/package.json +6 -0
  6. package/AiToolkit/package.json +6 -0
  7. package/Completions/package.json +6 -0
  8. package/LICENSE +21 -0
  9. package/README.md +1 -0
  10. package/Tokenizer/package.json +6 -0
  11. package/dist/cjs/AiChat.js +151 -0
  12. package/dist/cjs/AiChat.js.map +1 -0
  13. package/dist/cjs/AiError.js +41 -0
  14. package/dist/cjs/AiError.js.map +1 -0
  15. package/dist/cjs/AiInput.js +349 -0
  16. package/dist/cjs/AiInput.js.map +1 -0
  17. package/dist/cjs/AiResponse.js +295 -0
  18. package/dist/cjs/AiResponse.js.map +1 -0
  19. package/dist/cjs/AiRole.js +106 -0
  20. package/dist/cjs/AiRole.js.map +1 -0
  21. package/dist/cjs/AiToolkit.js +132 -0
  22. package/dist/cjs/AiToolkit.js.map +1 -0
  23. package/dist/cjs/Completions.js +217 -0
  24. package/dist/cjs/Completions.js.map +1 -0
  25. package/dist/cjs/Tokenizer.js +59 -0
  26. package/dist/cjs/Tokenizer.js.map +1 -0
  27. package/dist/cjs/index.js +25 -0
  28. package/dist/cjs/index.js.map +1 -0
  29. package/dist/dts/AiChat.d.ts +73 -0
  30. package/dist/dts/AiChat.d.ts.map +1 -0
  31. package/dist/dts/AiError.d.ts +38 -0
  32. package/dist/dts/AiError.d.ts.map +1 -0
  33. package/dist/dts/AiInput.d.ts +283 -0
  34. package/dist/dts/AiInput.d.ts.map +1 -0
  35. package/dist/dts/AiResponse.d.ts +235 -0
  36. package/dist/dts/AiResponse.d.ts.map +1 -0
  37. package/dist/dts/AiRole.d.ts +111 -0
  38. package/dist/dts/AiRole.d.ts.map +1 -0
  39. package/dist/dts/AiToolkit.d.ts +158 -0
  40. package/dist/dts/AiToolkit.d.ts.map +1 -0
  41. package/dist/dts/Completions.d.ts +104 -0
  42. package/dist/dts/Completions.d.ts.map +1 -0
  43. package/dist/dts/Tokenizer.d.ts +34 -0
  44. package/dist/dts/Tokenizer.d.ts.map +1 -0
  45. package/dist/dts/index.d.ts +33 -0
  46. package/dist/dts/index.d.ts.map +1 -0
  47. package/dist/esm/AiChat.js +139 -0
  48. package/dist/esm/AiChat.js.map +1 -0
  49. package/dist/esm/AiError.js +31 -0
  50. package/dist/esm/AiError.js.map +1 -0
  51. package/dist/esm/AiInput.js +332 -0
  52. package/dist/esm/AiInput.js.map +1 -0
  53. package/dist/esm/AiResponse.js +281 -0
  54. package/dist/esm/AiResponse.js.map +1 -0
  55. package/dist/esm/AiRole.js +93 -0
  56. package/dist/esm/AiRole.js.map +1 -0
  57. package/dist/esm/AiToolkit.js +123 -0
  58. package/dist/esm/AiToolkit.js.map +1 -0
  59. package/dist/esm/Completions.js +206 -0
  60. package/dist/esm/Completions.js.map +1 -0
  61. package/dist/esm/Tokenizer.js +48 -0
  62. package/dist/esm/Tokenizer.js.map +1 -0
  63. package/dist/esm/index.js +33 -0
  64. package/dist/esm/index.js.map +1 -0
  65. package/dist/esm/package.json +4 -0
  66. package/package.json +100 -0
  67. package/src/AiChat.ts +274 -0
  68. package/src/AiError.ts +38 -0
  69. package/src/AiInput.ts +456 -0
  70. package/src/AiResponse.ts +343 -0
  71. package/src/AiRole.ts +122 -0
  72. package/src/AiToolkit.ts +314 -0
  73. package/src/Completions.ts +354 -0
  74. package/src/Tokenizer.ts +78 -0
  75. package/src/index.ts +39 -0
@@ -0,0 +1,343 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import * as Schema from "@effect/schema/Schema"
5
+ import * as Chunk from "effect/Chunk"
6
+ import * as Data from "effect/Data"
7
+ import * as Effect from "effect/Effect"
8
+ import * as Iterable from "effect/Iterable"
9
+ import * as Option from "effect/Option"
10
+ import * as Predicate from "effect/Predicate"
11
+ import { AiError } from "./AiError.js"
12
+ import * as AiRole from "./AiRole.js"
13
+
14
+ /**
15
+ * @since 1.0.0
16
+ * @category type ids
17
+ */
18
+ export const TypeId: unique symbol = Symbol("@effect/ai/AiResponse")
19
+
20
+ /**
21
+ * @since 1.0.0
22
+ * @category type ids
23
+ */
24
+ export type TypeId = typeof TypeId
25
+
26
+ /**
27
+ * @since 1.0.0
28
+ * @category parts
29
+ */
30
+ export const PartTypeId: unique symbol = Symbol("@effect/ai/AiResponse/Part")
31
+
32
+ /**
33
+ * @since 1.0.0
34
+ * @category parts
35
+ */
36
+ export type PartTypeId = typeof PartTypeId
37
+
38
+ const constDisableValidation = { disableValidation: true } as const
39
+
40
+ /**
41
+ * @since 1.0.0
42
+ * @category parts
43
+ */
44
+ export class TextPart extends Schema.TaggedClass<TextPart>("@effect/ai/AiResponse/TextPart")("Text", {
45
+ content: Schema.String
46
+ }) {
47
+ /**
48
+ * @since 1.0.0
49
+ */
50
+ readonly [PartTypeId]: PartTypeId = PartTypeId
51
+ /**
52
+ * @since 1.0.0
53
+ */
54
+ static fromContent(content: string): TextPart {
55
+ return new TextPart({ content }, constDisableValidation)
56
+ }
57
+ }
58
+
59
+ /**
60
+ * @since 1.0.0
61
+ * @category parts
62
+ */
63
+ export const ToolCallId = Schema.String.pipe(Schema.brand("ToolCallId"))
64
+
65
+ /**
66
+ * @since 1.0.0
67
+ * @category parts
68
+ */
69
+ export type ToolCallId = typeof ToolCallId.Type
70
+
71
+ /**
72
+ * @since 1.0.0
73
+ * @category parts
74
+ */
75
+ export class ToolCallPart extends Schema.TaggedClass<ToolCallPart>("@effect/ai/AiResponse/ToolCallPart")("ToolCall", {
76
+ id: ToolCallId,
77
+ name: Schema.String,
78
+ params: Schema.Unknown
79
+ }) {
80
+ /**
81
+ * @since 1.0.0
82
+ */
83
+ readonly [PartTypeId]: PartTypeId = PartTypeId
84
+ /**
85
+ * @since 1.0.0
86
+ */
87
+ static fromJson(
88
+ { id, name, params }: {
89
+ readonly id: string
90
+ readonly name: string
91
+ readonly params: string
92
+ }
93
+ ): Effect.Effect<ToolCallPart, AiError> {
94
+ return Effect.try({
95
+ try() {
96
+ return new ToolCallPart({ id: ToolCallId.make(id), name, params: JSON.parse(params) }, constDisableValidation)
97
+ },
98
+ catch: (cause) =>
99
+ new AiError({
100
+ module: "AiResponse",
101
+ method: "ToolCall.fromJson",
102
+ description: "Failed to parse parameters",
103
+ cause
104
+ })
105
+ })
106
+ }
107
+ /**
108
+ * @since 1.0.0
109
+ */
110
+ static fromUnknown(
111
+ { id, name, params }: {
112
+ readonly id: string
113
+ readonly name: string
114
+ readonly params: unknown
115
+ }
116
+ ): ToolCallPart {
117
+ return new ToolCallPart({ id: ToolCallId.make(id), name, params }, constDisableValidation)
118
+ }
119
+ }
120
+
121
+ /**
122
+ * @since 1.0.0
123
+ * @category parts
124
+ */
125
+ export class ImageUrlPart extends Schema.TaggedClass<ImageUrlPart>("@effect/ai/AiResponse/ImageUrlPart")("ImageUrl", {
126
+ url: Schema.String
127
+ }) {
128
+ /**
129
+ * @since 1.0.0
130
+ */
131
+ readonly [PartTypeId]: PartTypeId = PartTypeId
132
+ }
133
+
134
+ /**
135
+ * @since 1.0.0
136
+ * @category parts
137
+ */
138
+ export type Part = TextPart | ToolCallPart | ImageUrlPart
139
+
140
+ /**
141
+ * @since 1.0.0
142
+ * @category parts
143
+ */
144
+ export const Part: Schema.Union<[
145
+ typeof TextPart,
146
+ typeof ToolCallPart,
147
+ typeof ImageUrlPart
148
+ ]> = Schema.Union(TextPart, ToolCallPart, ImageUrlPart)
149
+
150
+ /**
151
+ * @since 1.0.0
152
+ * @category models
153
+ */
154
+ export class AiResponse extends Schema.Class<AiResponse>("@effect/ai/AiResponse")({
155
+ role: AiRole.AiRole,
156
+ parts: Schema.Chunk(Part)
157
+ }) {
158
+ /**
159
+ * @since 1.0.0
160
+ */
161
+ readonly [TypeId]: TypeId = TypeId
162
+ /**
163
+ * @since 1.0.0
164
+ */
165
+ static is(u: unknown): u is AiResponse {
166
+ return Predicate.hasProperty(u, TypeId)
167
+ }
168
+ /**
169
+ * @since 1.0.0
170
+ */
171
+ static readonly empty = new AiResponse({
172
+ role: AiRole.model,
173
+ parts: Chunk.empty()
174
+ })
175
+ /**
176
+ * @since 1.0.0
177
+ */
178
+ static fromText(options: { role: AiRole.AiRole; content: string }): AiResponse {
179
+ return new AiResponse({
180
+ role: options.role,
181
+ parts: Chunk.of(TextPart.fromContent(options.content))
182
+ }, constDisableValidation)
183
+ }
184
+ /**
185
+ * @since 1.0.0
186
+ */
187
+ get text(): string {
188
+ let text = ""
189
+ let found = false
190
+ for (const part of this.parts) {
191
+ if (part._tag === "Text") {
192
+ text += found ? "\n\n" + part.content : part.content
193
+ found = true
194
+ }
195
+ }
196
+ return text
197
+ }
198
+ /**
199
+ * @since 1.0.0
200
+ */
201
+ get imageUrl(): Option.Option<string> {
202
+ for (const part of this.parts) {
203
+ if (part._tag === "ImageUrl") {
204
+ return Option.some(part.url)
205
+ }
206
+ }
207
+ return Option.none()
208
+ }
209
+ /**
210
+ * @since 1.0.0
211
+ */
212
+ withToolCallsJson(
213
+ calls: Iterable<{
214
+ readonly id: string
215
+ readonly name: string
216
+ readonly params: string
217
+ }>
218
+ ): Effect.Effect<AiResponse, AiError> {
219
+ return Effect.forEach(calls, (call): Effect.Effect<Part, AiError> => ToolCallPart.fromJson(call)).pipe(
220
+ Effect.map((parts) =>
221
+ new AiResponse({
222
+ role: this.role,
223
+ parts: Chunk.appendAll(this.parts, Chunk.unsafeFromArray(parts))
224
+ }, constDisableValidation)
225
+ )
226
+ )
227
+ }
228
+ /**
229
+ * @since 1.0.0
230
+ */
231
+ withToolCallsUnknown(
232
+ calls: Iterable<{
233
+ readonly id: string
234
+ readonly name: string
235
+ readonly params: unknown
236
+ }>
237
+ ): AiResponse {
238
+ return new AiResponse({
239
+ role: this.role,
240
+ parts: Chunk.fromIterable(calls).pipe(
241
+ Chunk.map((part) => ToolCallPart.fromUnknown(part))
242
+ )
243
+ }, constDisableValidation)
244
+ }
245
+ /**
246
+ * @since 1.0.0
247
+ */
248
+ concat(that: AiResponse): AiResponse {
249
+ if (Chunk.isEmpty(that.parts)) {
250
+ return this
251
+ }
252
+ const lastPart = Chunk.last(this.parts)
253
+ if (Option.isNone(lastPart)) {
254
+ return that
255
+ }
256
+ const newParts: Array<Part> = []
257
+ let content = lastPart.value._tag === "Text" ? lastPart.value.content : ""
258
+ for (const part of that.parts) {
259
+ if (part._tag === "Text") {
260
+ content += part.content
261
+ }
262
+ }
263
+ if (content.length > 0) {
264
+ newParts.push(TextPart.fromContent(content))
265
+ }
266
+ return newParts.length === 0 ? this : new AiResponse({
267
+ role: that.role,
268
+ parts: Chunk.appendAll(
269
+ Chunk.dropRight(this.parts, 1),
270
+ Chunk.unsafeFromArray(newParts)
271
+ )
272
+ }, constDisableValidation)
273
+ }
274
+ }
275
+
276
+ /**
277
+ * @since 1.0.0
278
+ * @category tools
279
+ */
280
+ export const WithResolvedTypeId: unique symbol = Symbol("@effect/ai/AiResponse/WithResolved")
281
+
282
+ /**
283
+ * @since 1.0.0
284
+ * @category tools
285
+ */
286
+ export type WithResolvedTypeId = typeof WithResolvedTypeId
287
+
288
+ /**
289
+ * @since 1.0.0
290
+ * @category tools
291
+ */
292
+ export class WithResolved<A> extends Data.Class<{
293
+ readonly response: AiResponse
294
+ readonly resolved: ReadonlyMap<ToolCallId, A>
295
+ readonly encoded: ReadonlyMap<ToolCallId, unknown>
296
+ }> {
297
+ /**
298
+ * @since 1.0.0
299
+ */
300
+ readonly [WithResolvedTypeId]: WithResolvedTypeId = WithResolvedTypeId
301
+ /**
302
+ * @since 1.0.0
303
+ */
304
+ static is<A>(u: unknown): u is WithResolved<A> {
305
+ return Predicate.hasProperty(u, WithResolvedTypeId)
306
+ }
307
+ /**
308
+ * @since 1.0.0
309
+ */
310
+ static readonly empty = new WithResolved<never>({
311
+ response: AiResponse.empty,
312
+ resolved: new Map<never, never>(),
313
+ encoded: new Map<never, never>()
314
+ })
315
+ /**
316
+ * @since 1.0.0
317
+ */
318
+ get values(): Array<A> {
319
+ return Array.from(this.resolved.values())
320
+ }
321
+ /**
322
+ * @since 1.0.0
323
+ */
324
+ get value(): Option.Option<A> {
325
+ return Iterable.head(this.resolved.values())
326
+ }
327
+ /**
328
+ * @since 1.0.0
329
+ */
330
+ get unsafeValue(): A {
331
+ return Iterable.unsafeHead(this.resolved.values())
332
+ }
333
+ /**
334
+ * @since 1.0.0
335
+ */
336
+ concat<B>(that: WithResolved<B>): WithResolved<A | B> {
337
+ return new WithResolved({
338
+ response: this.response.concat(that.response),
339
+ resolved: that.resolved.size === 0 ? this.resolved : new Map([...this.resolved, ...that.resolved] as any),
340
+ encoded: that.encoded.size === 0 ? this.encoded : new Map([...this.encoded, ...that.encoded] as any)
341
+ })
342
+ }
343
+ }
package/src/AiRole.ts ADDED
@@ -0,0 +1,122 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import * as Schema from "@effect/schema/Schema"
5
+ import * as Option from "effect/Option"
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
+ )