fix(ai): cloudflare gateway type, include workers

Fixes https://github.com/earendil-works/pi/actions/runs/32825925694/job/97733792662?pr=8605 build error
This commit is contained in:
Cristina Poncela Cubeiro 2026-08-25 11:03:13 +02:00
parent c5de2cc67f
commit e8c632ef64
2 changed files with 41 additions and 4 deletions

View file

@ -1666,6 +1666,7 @@ async function loadModelsDevData(): Promise<Model<any>[]> {
}
// Process Cloudflare AI Gateway models
const cloudflareAIGatewayModelIds = new Set<string>();
if (data["cloudflare-ai-gateway"]?.models) {
for (const [prefixedId, model] of Object.entries(data["cloudflare-ai-gateway"].models)) {
const m = model as ModelsDevModel;
@ -1700,6 +1701,7 @@ async function loadModelsDevData(): Promise<Model<any>[]> {
const compat =
upstream === "anthropic" || upstream === "workers-ai" ? { sendSessionAffinityHeaders: true } : undefined;
cloudflareAIGatewayModelIds.add(id);
models.push({
id,
name: m.name || id,
@ -1722,6 +1724,41 @@ async function loadModelsDevData(): Promise<Model<any>[]> {
}
}
// models.dev may omit Workers AI passthroughs from the AI Gateway provider
// list even though the gateway /compat endpoint supports routing to them.
// Mirror the Workers AI catalog under the documented workers-ai/ prefix so
// the gateway keeps its OpenAI-compatible /compat models stable.
if (data["cloudflare-workers-ai"]?.models) {
for (const [modelId, model] of Object.entries(data["cloudflare-workers-ai"].models)) {
const m = model as ModelsDevModel;
if (m.tool_call !== true) continue;
const id = `workers-ai/${modelId}`;
if (cloudflareAIGatewayModelIds.has(id)) continue;
cloudflareAIGatewayModelIds.add(id);
models.push({
id,
name: m.name || id,
api: "openai-completions",
provider: "cloudflare-ai-gateway",
baseUrl: CLOUDFLARE_AI_GATEWAY_COMPAT_BASE_URL,
reasoning: m.reasoning === true,
input: m.modalities?.input?.includes("image") ? ["text", "image"] : ["text"],
cost: {
input: m.cost?.input || 0,
output: m.cost?.output || 0,
cacheRead: m.cost?.cache_read || 0,
cacheWrite: m.cost?.cache_write || 0,
},
contextWindow: m.limit?.context || 4096,
maxTokens: m.limit?.output || 4096,
compat: { sendSessionAffinityHeaders: true },
});
recordModelsDevReasoningOptions("cloudflare-ai-gateway", id, m);
}
}
// Process xAi models
if (data.xai?.models) {
for (const [modelId, model] of Object.entries(data.xai.models)) {

View file

@ -6,10 +6,10 @@ import { CLOUDFLARE_AI_GATEWAY_MODELS } from "./cloudflare-ai-gateway.models.ts"
import { cloudflareAIGatewayAuth } from "./cloudflare-auth.ts";
import { cloudflareStreams } from "./cloudflare-stream.ts";
export function cloudflareAIGatewayProvider(): Provider<
"anthropic-messages" | "openai-completions" | "openai-responses"
> {
return createProvider({
type CloudflareAIGatewayApi = "anthropic-messages" | "openai-completions" | "openai-responses";
export function cloudflareAIGatewayProvider(): Provider<CloudflareAIGatewayApi> {
return createProvider<CloudflareAIGatewayApi>({
id: "cloudflare-ai-gateway",
name: "Cloudflare AI Gateway",
auth: { apiKey: cloudflareAIGatewayAuth() },