@effect/ai 0.8.1 → 0.8.2

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.
@@ -0,0 +1,143 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import { dataLoader } from "@effect/experimental/RequestResolver"
5
+ import * as Context from "effect/Context"
6
+ import type * as Duration from "effect/Duration"
7
+ import * as Effect from "effect/Effect"
8
+ import { identity } from "effect/Function"
9
+ import * as Option from "effect/Option"
10
+ import * as Request from "effect/Request"
11
+ import * as RequestResolver from "effect/RequestResolver"
12
+ import * as Schema from "effect/Schema"
13
+ import { AiError } from "./AiError.js"
14
+
15
+ /**
16
+ * @since 1.0.0
17
+ * @category tags
18
+ */
19
+ export class Embeddings extends Context.Tag("@effect/ai/Embeddings")<
20
+ Embeddings,
21
+ Embeddings.Service
22
+ >() {}
23
+
24
+ /**
25
+ * @since 1.0.0
26
+ * @category models
27
+ */
28
+ export declare namespace Embeddings {
29
+ /**
30
+ * @since 1.0.0
31
+ * @category models
32
+ */
33
+ export interface Service {
34
+ readonly embed: (input: string) => Effect.Effect<Array<number>, AiError>
35
+ }
36
+
37
+ /**
38
+ * @since 1.0.0
39
+ * @category models
40
+ */
41
+ export interface Result {
42
+ readonly index: number
43
+ readonly embeddings: Array<number>
44
+ }
45
+ }
46
+
47
+ class EmbeddingRequest extends Schema.TaggedRequest<EmbeddingRequest>()("EmbeddingRequest", {
48
+ failure: AiError,
49
+ success: Schema.mutable(Schema.Array(Schema.Number)),
50
+ payload: { input: Schema.String }
51
+ }) {}
52
+
53
+ const makeBatchedResolver = (
54
+ embedMany: (input: ReadonlyArray<string>) => Effect.Effect<Array<Embeddings.Result>, AiError>
55
+ ) =>
56
+ RequestResolver.makeBatched(
57
+ (requests: ReadonlyArray<EmbeddingRequest>) =>
58
+ embedMany(requests.map((request) => request.input)).pipe(
59
+ Effect.flatMap(
60
+ Effect.forEach(
61
+ ({ embeddings, index }) => Request.succeed(requests[index], embeddings),
62
+ { discard: true }
63
+ )
64
+ ),
65
+ Effect.catchAll((error) =>
66
+ Effect.forEach(
67
+ requests,
68
+ (request) => Request.fail(request, error),
69
+ { discard: true }
70
+ )
71
+ )
72
+ )
73
+ )
74
+
75
+ /**
76
+ * @since 1.0.0
77
+ * @category constructors
78
+ */
79
+ export const make = (options: {
80
+ readonly embedMany: (input: ReadonlyArray<string>) => Effect.Effect<Array<Embeddings.Result>, AiError>
81
+ readonly maxBatchSize?: number
82
+ readonly cache?: {
83
+ readonly capacity: number
84
+ readonly timeToLive: Duration.DurationInput
85
+ }
86
+ }) =>
87
+ Effect.gen(function*() {
88
+ const cache = yield* Option.fromNullable(options.cache).pipe(
89
+ Effect.flatMap((config) => Request.makeCache(config)),
90
+ Effect.optionFromOptional
91
+ )
92
+
93
+ const resolver = makeBatchedResolver(options.embedMany).pipe(
94
+ options.maxBatchSize ? RequestResolver.batchN(options.maxBatchSize) : identity
95
+ )
96
+
97
+ function embed(input: string) {
98
+ const request = Effect.request(new EmbeddingRequest({ input }), resolver)
99
+ return Option.match(cache, {
100
+ onNone: () => request,
101
+ onSome: (cache) =>
102
+ request.pipe(
103
+ Effect.withRequestCaching(true),
104
+ Effect.withRequestCache(cache)
105
+ )
106
+ }).pipe(Effect.withSpan("Embeddings.embed", { captureStackTrace: false }))
107
+ }
108
+
109
+ return Embeddings.of({
110
+ embed
111
+ })
112
+ })
113
+
114
+ /**
115
+ * Creates an `Embeddings` service which will aggregate all `embed` requests
116
+ * received during the specified `window` (up to a maximum of `maxBatchSize`
117
+ * requests, if specified) and execute them as a single batch.
118
+ *
119
+ * @since 1.0.0
120
+ * @category constructors
121
+ */
122
+ export const makeDataLoader = (options: {
123
+ readonly embedMany: (input: ReadonlyArray<string>) => Effect.Effect<Array<Embeddings.Result>, AiError>
124
+ readonly window: Duration.DurationInput
125
+ readonly maxBatchSize?: number
126
+ }) =>
127
+ Effect.gen(function*() {
128
+ const resolver = makeBatchedResolver(options.embedMany)
129
+ const resolverDelayed = yield* dataLoader(resolver, {
130
+ window: options.window,
131
+ maxBatchSize: options.maxBatchSize
132
+ })
133
+
134
+ function embed(input: string) {
135
+ return Effect.request(new EmbeddingRequest({ input }), resolverDelayed).pipe(
136
+ Effect.withSpan("Embeddings.embed", { captureStackTrace: false })
137
+ )
138
+ }
139
+
140
+ return Embeddings.of({
141
+ embed
142
+ })
143
+ })
package/src/index.ts CHANGED
@@ -23,6 +23,11 @@ export * as AiResponse from "./AiResponse.js"
23
23
  */
24
24
  export * as AiRole from "./AiRole.js"
25
25
 
26
+ /**
27
+ * @since 1.0.0
28
+ */
29
+ export * as AiTelemetry from "./AiTelemetry.js"
30
+
26
31
  /**
27
32
  * @since 1.0.0
28
33
  */
@@ -33,6 +38,11 @@ export * as AiToolkit from "./AiToolkit.js"
33
38
  */
34
39
  export * as Completions from "./Completions.js"
35
40
 
41
+ /**
42
+ * @since 1.0.0
43
+ */
44
+ export * as Embeddings from "./Embeddings.js"
45
+
36
46
  /**
37
47
  * @since 1.0.0
38
48
  */