1import { Effect, Predicate, Stream } from "effect"
2import type { AiError, IdGenerator, Response } from "effect/ai"
3import { LanguageModel } from "effect/ai"
4import { dual } from "effect/Function"
5
6interface WithLanguageModelOptions {
7 readonly generateText?:
8 | Array<Response.PartEncoded>
9 | ((options: LanguageModel.ProviderOptions) =>
10 | Array<Response.PartEncoded>
11 | Effect.Effect<Array<Response.PartEncoded>, AiError.AiError, IdGenerator.IdGenerator>)
12 readonly streamText?:
13 | Array<Response.StreamPartEncoded>
14 | ((options: LanguageModel.ProviderOptions) =>
15 | Array<Response.StreamPartEncoded>
16 | Stream.Stream<Response.StreamPartEncoded, AiError.AiError, IdGenerator.IdGenerator>)
17}
18
19export const withLanguageModel: {
20 (options: WithLanguageModelOptions): <A, E, R>(
21 effect: Effect.Effect<A, E, R>
22 ) => Effect.Effect<A, E, Exclude<R, LanguageModel.LanguageModel>>
23 <A, E, R>(
24 effect: Effect.Effect<A, E, R>,
25 options: WithLanguageModelOptions
26 ): Effect.Effect<A, E, Exclude<R, LanguageModel.LanguageModel>>
27} = dual(2, <A, E, R>(
28 effect: Effect.Effect<A, E, R>,
29 options: WithLanguageModelOptions
30): Effect.Effect<A, E, Exclude<R, LanguageModel.LanguageModel>> =>
31 Effect.provideServiceEffect(
32 effect,
33 LanguageModel.LanguageModel,
34 LanguageModel.make({
35 generateText: (opts) => {
36 if (Predicate.isUndefined(options.generateText)) {
37 return Effect.succeed([])
38 }
39 if (Array.isArray(options.generateText)) {
40 return Effect.succeed(options.generateText)
41 }
42 const result = options.generateText(opts)
43 return Effect.isEffect(result) ? result : Effect.succeed(result)
44 },
45 streamText: (opts) => {
46 if (Predicate.isUndefined(options.streamText)) {
47 return Stream.empty
48 }
49 if (Array.isArray(options.streamText)) {
50 return Stream.fromIterable(options.streamText)
51 }
52 const result = options.streamText(opts)
53 return Array.isArray(result) ? Stream.fromIterable(result) : result
54 }
55 })
56 ))