///
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import { Worker, WorkerEnvironment } from "../Workers/Worker.ts";
import type { Gateway as GatewayResource } from "./Gateway.ts";
import { makeLanguageModelLayer } from "./LanguageModel.ts";
import {
GatewayError,
QueryGateway,
type QueryGatewayClient,
} from "./QueryGateway.ts";
/**
* Runtime layer for {@link QueryGateway}.
*/
export const QueryGatewayBinding = Layer.effect(
QueryGateway,
Effect.gen(function* () {
const env = yield* WorkerEnvironment;
const host = yield* Worker;
return Effect.fn(function* (gateway: GatewayResource) {
if (!globalThis.__ALCHEMY_RUNTIME__) {
yield* host.bind`${gateway}`({
bindings: [
{
type: "ai",
name: gateway.LogicalId,
},
],
});
}
const gatewayIdAccessor = yield* gateway.gatewayId;
const ai = Effect.sync(
() => (env as Record)[gateway.LogicalId]!,
);
const runtimeGateway = yield* Effect.zip(ai, gatewayIdAccessor).pipe(
Effect.map(([ai, gatewayId]) => ai.gateway(gatewayId)),
Effect.cached,
);
const use = (
fn: (gateway: AiGateway) => Promise,
): Effect.Effect =>
runtimeGateway.pipe(
Effect.flatMap((gateway) => tryPromise(() => fn(gateway))),
);
const self: QueryGatewayClient = {
raw: ai,
gateway: runtimeGateway,
id: gatewayIdAccessor,
patchLog: (logId, data) =>
use((gateway) => gateway.patchLog(logId, data)),
getLog: (logId) => use((gateway) => gateway.getLog(logId)),
getUrl: (provider) => use((gateway) => gateway.getUrl(provider)),
run: (data, options) => use((gateway) => gateway.run(data, options)),
model: (options) =>
makeLanguageModelLayer({
...options,
client: self,
}),
} satisfies QueryGatewayClient;
return self;
});
}),
);
const tryPromise = (fn: () => Promise): Effect.Effect =>
Effect.tryPromise({
try: fn,
catch: (error) =>
new GatewayError({
message:
error instanceof Error
? error.message
: "Unknown AI Gateway runtime error",
cause: error,
}),
});