1/// <reference types="@cloudflare/workers-types" />
2
3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";
5import { Worker, WorkerEnvironment } from "../Workers/Worker.ts";
6import type { Gateway as GatewayResource } from "./Gateway.ts";
7import { makeLanguageModelLayer } from "./LanguageModel.ts";
8import {
9 GatewayError,
10 QueryGateway,
11 type QueryGatewayClient,
12} from "./QueryGateway.ts";
13
14/**
15 * Runtime layer for {@link QueryGateway}.
16 */
17export const QueryGatewayBinding = Layer.effect(
18 QueryGateway,
19 Effect.gen(function* () {
20 const env = yield* WorkerEnvironment;
21 const host = yield* Worker;
22
23 return Effect.fn(function* (gateway: GatewayResource) {
24 if (!globalThis.__ALCHEMY_RUNTIME__) {
25 yield* host.bind`${gateway}`({
26 bindings: [
27 {
28 type: "ai",
29 name: gateway.LogicalId,
30 },
31 ],
32 });
33 }
34
35 const gatewayIdAccessor = yield* gateway.gatewayId;
36 const ai = Effect.sync(
37 () => (env as Record<string, Ai>)[gateway.LogicalId]!,
38 );
39 const runtimeGateway = yield* Effect.zip(ai, gatewayIdAccessor).pipe(
40 Effect.map(([ai, gatewayId]) => ai.gateway(gatewayId)),
41 Effect.cached,
42 );
43
44 const use = <T>(
45 fn: (gateway: AiGateway) => Promise<T>,
46 ): Effect.Effect<T, GatewayError> =>
47 runtimeGateway.pipe(
48 Effect.flatMap((gateway) => tryPromise(() => fn(gateway))),
49 );
50
51 const self: QueryGatewayClient = {
52 raw: ai,
53 gateway: runtimeGateway,
54 id: gatewayIdAccessor,
55 patchLog: (logId, data) =>
56 use((gateway) => gateway.patchLog(logId, data)),
57 getLog: (logId) => use((gateway) => gateway.getLog(logId)),
58 getUrl: (provider) => use((gateway) => gateway.getUrl(provider)),
59 run: (data, options) => use((gateway) => gateway.run(data, options)),
60 model: (options) =>
61 makeLanguageModelLayer({
62 ...options,
63 client: self,
64 }),
65 } satisfies QueryGatewayClient;
66 return self;
67 });
68 }),
69);
70
71const tryPromise = <T>(fn: () => Promise<T>): Effect.Effect<T, GatewayError> =>
72 Effect.tryPromise({
73 try: fn,
74 catch: (error) =>
75 new GatewayError({
76 message:
77 error instanceof Error
78 ? error.message
79 : "Unknown AI Gateway runtime error",
80 cause: error,
81 }),
82 });