|
|
|
@@ -0,0 +1,68 @@
|
|
|
|
|
import { Config, Context, Effect, Layer } from "effect"
|
|
|
|
|
import type { OpenAI } from "openai"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export class OpenAIClient extends Context.Tag("OpenAIClient")<OpenAIClient, OpenAIClientService>() {}
|
|
|
|
|
|
|
|
|
|
export class OpenAIClientService {
|
|
|
|
|
constructor(
|
|
|
|
|
readonly openai: Effect.Effect.Success<typeof importOpenAI>,
|
|
|
|
|
readonly client: OpenAI,
|
|
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
try<A>(
|
|
|
|
|
try_: (
|
|
|
|
|
client: OpenAI,
|
|
|
|
|
signal: AbortSignal,
|
|
|
|
|
) => Promise<A>
|
|
|
|
|
) {
|
|
|
|
|
return Effect.tryPromise({
|
|
|
|
|
try: signal => try_(this.client, signal),
|
|
|
|
|
catch: e => e instanceof this.openai.OpenAIError
|
|
|
|
|
? e
|
|
|
|
|
: new Error(`Unknown OpenAIClient error: ${ e }`),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const importOpenAI = Effect.tryPromise({
|
|
|
|
|
try: () => import("openai"),
|
|
|
|
|
catch: cause => new Error("Could not import 'openai'. Make sure it is installed.", { cause }),
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
export const OpenAIClientLive = (
|
|
|
|
|
config: {
|
|
|
|
|
readonly apiKey: Config.Config<string>
|
|
|
|
|
readonly organization?: Config.Config<string | undefined>
|
|
|
|
|
readonly project?: Config.Config<string | undefined>
|
|
|
|
|
readonly baseURL?: Config.Config<string | undefined>
|
|
|
|
|
readonly timeout?: Config.Config<number | undefined>
|
|
|
|
|
readonly maxRetries?: Config.Config<number | undefined>
|
|
|
|
|
|
|
|
|
|
readonly httpAgent?: any
|
|
|
|
|
readonly fetch?: any
|
|
|
|
|
readonly defaultHeaders?: { [x: string]: string }
|
|
|
|
|
readonly defaultQuery?: { [x: string]: string }
|
|
|
|
|
}
|
|
|
|
|
) => Layer.effect(OpenAIClient, Effect.gen(function*() {
|
|
|
|
|
const openai = yield* importOpenAI
|
|
|
|
|
|
|
|
|
|
return new OpenAIClientService(
|
|
|
|
|
openai,
|
|
|
|
|
|
|
|
|
|
new openai.OpenAI({
|
|
|
|
|
apiKey: yield* config.apiKey,
|
|
|
|
|
organization: (yield* config.organization || Config.succeed(undefined)) || null,
|
|
|
|
|
project: (yield* config.project || Config.succeed(undefined)) || null,
|
|
|
|
|
baseURL: (yield* config.baseURL || Config.succeed(undefined)) || "https://api.openai.com/v1",
|
|
|
|
|
timeout: yield* config.timeout || Config.succeed(undefined),
|
|
|
|
|
maxRetries: yield* config.maxRetries || Config.succeed(undefined),
|
|
|
|
|
|
|
|
|
|
httpAgent: config.httpAgent,
|
|
|
|
|
fetch: config.fetch,
|
|
|
|
|
defaultHeaders: config.defaultHeaders,
|
|
|
|
|
defaultQuery: config.defaultQuery,
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
}))
|