Support Libraries
Write an AI feature once and choose its model for each request. A model created by one library is a valid argument for another, because both use the contract types defined here. Support.Workers adds checked fetch helpers for Durable Objects.
- Libraries
Support.AI.V4.ProviderSupport.AI.V4.OpenAICompatibleSupport.AI.V3.ProviderSupport.Workers - npm
@ai-sdk/provider4.0.10 and 3.0.15,@ai-sdk/openai-compatible3.0.44
Model Switch
workersModel and endpointModel use different libraries to create their models. createOpenAICompatible builds a provider for an endpoint that exposes an OpenAI-compatible API. Both functions have the return type LanguageModelV4, so either model can be the result of modelFor. Prompt code written against LanguageModelV4, like the Summarizer's on the AI page, type-checks with either model.
open Fable.Core
module Workers = FSharp.CloudEdge.Runtime.Workers
module WorkersAI = FSharp.CloudEdge.Runtime.WorkersAIProvider
module Compatible = FSharp.CloudEdge.Support.AI.V4.OpenAICompatible
module V4 = FSharp.CloudEdge.Support.AI.V4.Provider
type Env =
abstract AI: Workers.Ai<Workers.AiModels>
abstract LLM_URL: string
abstract LLM_KEY: string
abstract LLM_MODEL: string
let workersModel (env: Env) : V4.LanguageModelV4 =
let settings = WorkersAI.WorkersAISettings2.Create(binding = env.AI)
let workersai = WorkersAI.Exports.createWorkersAI(U2.Case1 settings)
workersai.chat(U2.Case1 "@cf/meta/llama-3.3-70b-instruct-fp8-fast")
let endpointModel (env: Env) : V4.LanguageModelV4 =
let settings =
Compatible.OpenAICompatibleProviderSettings.Create(
baseURL = env.LLM_URL,
name = "own-llm",
apiKey = env.LLM_KEY
)
let endpoint = Compatible.Exports.createOpenAICompatible settings
endpoint.chatModel env.LLM_MODEL
let modelFor (env: Env) (plan: string) =
if plan = "pro" then endpointModel env else workersModel env
Needs a Workers AI binding named AI and a secret named LLM_KEY. The variables LLM_URL and LLM_MODEL hold the endpoint's address and its model. Worker Upload shows how to declare them.
Emitted JavaScript
import { createWorkersAI } from "workers-ai-provider";
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
export function workersModel(env) {
const workersai = createWorkersAI({
binding: env.AI,
});
return workersai.chat("@cf/meta/llama-3.3-70b-instruct-fp8-fast");
}
export function endpointModel(env) {
const endpoint = createOpenAICompatible({
baseURL: env.LLM_URL,
name: "own-llm",
apiKey: env.LLM_KEY,
});
return endpoint.chatModel(env.LLM_MODEL);
}
export function modelFor(env, plan) {
if (plan === "pro") {
return endpointModel(env);
}
else {
return workersModel(env);
}
}
Usage Meter
AI Search models implement version 3 of the AI SDK contract, and Support.AI.V3.Provider defines its F# types. Workers AI and AI Gateway models implement version 4, and the two versions are separate F# types. askWithUsage takes any LanguageModelV3, such as the AI Search model in Help Center Answers on the AI page. The result contains the answer and the call's token counts. finish is the reason that generation stopped, such as stop or length.
open Fable.Core
module V3 = FSharp.CloudEdge.Support.AI.V3.Provider
let askWithUsage (model: V3.LanguageModelV3) (question: string) =
async {
let part = V3.LanguageModelV3Message3.Content.Item.Text(question, None)
let prompt = [| V3.LanguageModelV3Message.User([| part |], None) |]
let options = V3.LanguageModelV3CallOptions.Create(prompt = prompt, maxOutputTokens = 400.)
let! result = model.doGenerate options |> Async.AwaitPromise
let answer =
result.content
|> Array.choose (function
| V3.LanguageModelV3Content.Text(text, _) -> Some text
| _ -> None)
|> String.concat ""
return
{| answer = answer
inputTokens = result.usage.inputTokens.total |> Option.defaultValue 0.
outputTokens = result.usage.outputTokens.total |> Option.defaultValue 0.
finish = result.finishReason.unified |}
}
|> Async.StartAsPromise
Room Status
The Worker reads a room's name from the URL path. getFetchByName derives the Durable Object's ID from that name and returns the object's stub as a FetchTransport, whose fetch method forwards a request to the room. Here the Worker sends a GET request for the same URL and answers with the room's response.
open Fable.Core
module Workers = FSharp.CloudEdge.Runtime.Workers
module Transport = FSharp.CloudEdge.Support.Workers.DurableObjects
type Env =
abstract ROOMS: Workers.DurableObjectNamespace<obj>
[<ExportDefault>]
let worker: Workers.ExportedHandler<Env, obj, obj, obj> =
Workers.ExportedHandler.Create(
fetch = fun request env _ ->
let room = Workers.Exports.URL(U2.Case1 request.url).pathname.Substring(1)
let transport = Transport.getFetchByName env.ROOMS room
transport.fetch(Workers.Exports.Request.Create(U3.Case1 request.url)) |> U2.Case1
)
Needs a Durable Object binding named ROOMS. Durable Objects covers the room's class, and Worker Upload shows how to declare the binding.
Regional Room
get takes options for the stub, such as a location hint. With weur, the Worker requests western Europe for a new room. The hint takes effect only on the first get for each room, as Cloudflare's data location reference describes.
open Fable.Core
module Workers = FSharp.CloudEdge.Runtime.Workers
module Transport = FSharp.CloudEdge.Support.Workers.DurableObjects
type Env =
abstract ROOMS: Workers.DurableObjectNamespace<obj>
let westernEurope =
Workers.DurableObjectNamespaceGetDurableObjectOptions.Create(
locationHint = Workers.DurableObjectLocationHint.Weur
)
[<ExportDefault>]
let worker: Workers.ExportedHandler<Env, obj, obj, obj> =
Workers.ExportedHandler.Create(
fetch = fun request env _ ->
let room = Workers.Exports.URL(U2.Case1 request.url).pathname.Substring(1)
let stub = env.ROOMS.get(env.ROOMS.idFromName room, westernEurope)
let transport = Transport.requireFetchTransport stub
transport.fetch(Workers.Exports.Request.Create(U3.Case1 request.url)) |> U2.Case1
)
requireFetchTransport checks that the stub has a fetch function and returns it as a FetchTransport. For any other value, it throws a TypeError. getFetchByName and getFetchById run the same check.
Emitted JavaScript
import { substring } from "./fable_modules/fable-library-js.5.13.0/String.js";
import { requireFetchTransport } from "./fable_modules/FSharp.CloudEdge.Support.Workers.0.1.0/DurableObjects.fs.js";
export const westernEurope = {
locationHint: "weur",
};
export const worker = {
fetch: (request, env, _arg) => {
const room = substring((new URL(request.url)).pathname, 1);
const transport = requireFetchTransport(env.ROOMS.get(env.ROOMS.idFromName(room), westernEurope));
return transport.fetch(new globalThis.Request(request.url));
},
};
export default worker;
Library Table
| Library | npm package | What it covers |
|---|---|---|
Support.AI.V4.Provider |
@ai-sdk/provider 4.0.10 |
v4 model contracts |
Support.AI.V4.OpenAICompatible |
@ai-sdk/openai-compatible 3.0.44 |
OpenAI-compatible models |
Support.AI.V3.Provider |
@ai-sdk/provider 3.0.15 |
v3 model contracts |
Support.Workers |
Handwritten, no package | Durable Object fetch |
Related Pages
NuGet packages
Runtime.Workers 0.1.0, Runtime.WorkersAIProvider 0.1.0, Support.AI.V3.Provider 0.1.0, Support.AI.V4.OpenAICompatible 0.1.0, Support.AI.V4.Provider 0.1.0, Support.Workers 0.1.0.