1/// <reference types="@cloudflare/workers-types" />
2
3import * as Data from "effect/Data";
4import * as Effect from "effect/Effect";
5import * as Layer from "effect/Layer";
6import type { LanguageModel } from "effect/ai/LanguageModel";
7import * as Binding from "../../Binding.ts";
8import type { RuntimeContext } from "../../RuntimeContext.ts";
9import type { Gateway as GatewayResource } from "./Gateway.ts";
10import { type LanguageModelOptions } from "./LanguageModel.ts";
11
12/**
13 * Binding service that turns a {@link Gateway} resource
14 * into a typed {@link QueryGatewayClient} for Worker runtime code. Wraps
15 * the Cloudflare.AI. Gateway runtime binding so each operation returns
16 * an Effect tagged with {@link GatewayError}, exposes the raw
17 * Workers AI handle for `ai.run(...)`, and provides a `model(options)`
18 * factory that produces an `effect/ai` `LanguageModel`
19 * `Layer`.
20 *
21 * Bind a {@link Gateway} to a Worker and obtain the
22 * Effect-native AI Gateway client (`run`, `getUrl`, `model`, …).
23 *
24 * `QueryGateway` is a single identifier that is simultaneously the binding's
25 * Context tag, its type, and the callable —
26 * `yield* Cloudflare.AI.QueryGateway(gateway)`.
27 *
28 *
29 * ### Calling AI Gateway
30 * **Example:** Run through a gateway
31 * Bind the gateway during the Worker's init phase, then use `run` or
32 * `getUrl` from request handlers.
33 * ```typescript
34 * const aiGateway = yield* Cloudflare.AI.QueryGateway(gateway);
35 *
36 * return {
37 * fetch: Effect.gen(function* () {
38 * return yield* aiGateway.run({
39 * provider: "workers-ai",
40 * endpoint: "@cf/meta/llama-3.1-8b-instruct",
41 * headers: { "content-type": "application/json" },
42 * query: { prompt: "Write a concise status update" },
43 * });
44 * }),
45 * };
46 * ```
47 *
48 * ### Driving Effect AI through the gateway
49 * **Example:** `aiGateway.model(...)` -> Effect AI `LanguageModel`
50 * `model(options)` produces a `Layer<LanguageModel, never,
51 * RuntimeContext>` that translates `LanguageModel.generateText` /
52 * `streamText` calls (including tool calls and structured outputs)
53 * into `ai.run(...)` against the bound Workers AI model, routed
54 * through the gateway.
55 * ```typescript
56 * const aiGateway = yield* Cloudflare.AI.QueryGateway(gateway);
57 *
58 * const languageModel = aiGateway.model({
59 * model: "@cf/meta/llama-3.1-8b-instruct",
60 * parameters: { temperature: 0.7, maxTokens: 1024 },
61 * });
62 *
63 * const response = yield* LanguageModel.generateText({ prompt }).pipe(
64 * Effect.provide(languageModel),
65 * );
66 * ```
67 *
68 * Provide {@link QueryGatewayBinding} in the worker's runtime layer
69 * to resolve the underlying Cloudflare.AI. binding at request time.
70 *
71 * @binding
72 * @product AI Gateway
73 * @category AI
74 */
75export interface QueryGateway extends Binding.Service<
76 QueryGateway,
77 "Cloudflare.AI.QueryGateway",
78 (gateway: GatewayResource) => Effect.Effect<QueryGatewayClient>
79> {}
80
81export const QueryGateway = Binding.Service<QueryGateway>(
82 "Cloudflare.AI.QueryGateway",
83);
84
85// Error raised by AI Gateway runtime operations.
86export class GatewayError extends Data.TaggedError("AiGatewayError")<{
87 /**
88 * Human-readable runtime error message.
89 */
90 message: string;
91 /**
92 * Original error thrown by the Cloudflare runtime binding.
93 */
94 cause: unknown;
95}> {}
96
97/**
98 * Effect-native client for a Cloudflare.AI. Gateway Worker binding.
99 *
100 * Wraps the runtime {@link Gateway} binding so each operation returns an
101 * Effect tagged with {@link GatewayError}. Use
102 * `Cloudflare.AI.QueryGateway(gateway)` inside a Worker's init phase.
103 */
104export interface QueryGatewayClient {
105 /**
106 * Effect resolving to the raw Workers AI binding.
107 */
108 raw: Effect.Effect<Ai, never, RuntimeContext>;
109 /**
110 * Effect resolving to the raw AI Gateway runtime binding.
111 */
112 gateway: Effect.Effect<AiGateway, never, RuntimeContext>;
113 /**
114 * Effect resolving to the gateway id (the resource attribute, captured at
115 * bind time). Useful when calling `ai.run(model, inputs, { gateway: { id } })`
116 * — the in-account path for first-party services like Workers AI.
117 */
118 id: Effect.Effect<string, never, RuntimeContext>;
119 /**
120 * Update metadata on an existing AI Gateway log entry.
121 */
122 patchLog(
123 logId: string,
124 data: Parameters<AiGateway["patchLog"]>[1],
125 ): Effect.Effect<void, GatewayError, RuntimeContext>;
126 /**
127 * Read an AI Gateway log entry by ID.
128 */
129 getLog(
130 logId: string,
131 ): Effect.Effect<AiGatewayLog, GatewayError, RuntimeContext>;
132 /**
133 * Build a provider URL routed through this gateway.
134 */
135 getUrl(
136 provider?: Parameters<AiGateway["getUrl"]>[0],
137 ): Effect.Effect<string, GatewayError, RuntimeContext>;
138 /**
139 * Run an AI Gateway request through the Cloudflare runtime binding.
140 */
141 run(
142 data: Parameters<AiGateway["run"]>[0],
143 options?: Parameters<AiGateway["run"]>[1],
144 ): Effect.Effect<Response, GatewayError, RuntimeContext>;
145
146 model(
147 options: Omit<LanguageModelOptions, "client">,
148 ): Layer.Layer<LanguageModel, never, RuntimeContext>;
149}