fix(opencode): use official ai-gateway-provider package for Cloudflare AI Gateway (#12014)
This commit is contained in:
@@ -92,6 +92,7 @@
|
||||
"@standard-schema/spec": "1.0.0",
|
||||
"@zip.js/zip.js": "2.7.62",
|
||||
"ai": "catalog:",
|
||||
"ai-gateway-provider": "2.3.1",
|
||||
"bonjour-service": "1.3.0",
|
||||
"bun-pty": "0.4.4",
|
||||
"chokidar": "4.0.3",
|
||||
|
||||
@@ -461,52 +461,36 @@ export namespace Provider {
|
||||
|
||||
if (!accountId || !gateway) return { autoload: false }
|
||||
|
||||
// Get API token from env or auth prompt
|
||||
// Get API token from env or auth - required for authenticated gateways
|
||||
const apiToken = await (async () => {
|
||||
const envToken = Env.get("CLOUDFLARE_API_TOKEN")
|
||||
const envToken = Env.get("CLOUDFLARE_API_TOKEN") || Env.get("CF_AIG_TOKEN")
|
||||
if (envToken) return envToken
|
||||
const auth = await Auth.get(input.id)
|
||||
if (auth?.type === "api") return auth.key
|
||||
return undefined
|
||||
})()
|
||||
|
||||
if (!apiToken) {
|
||||
throw new Error(
|
||||
"CLOUDFLARE_API_TOKEN (or CF_AIG_TOKEN) is required for Cloudflare AI Gateway. " +
|
||||
"Set it via environment variable or run `opencode auth cloudflare-ai-gateway`.",
|
||||
)
|
||||
}
|
||||
|
||||
// Use official ai-gateway-provider package (v2.x for AI SDK v5 compatibility)
|
||||
const { createAiGateway } = await import("ai-gateway-provider")
|
||||
const { createUnified } = await import("ai-gateway-provider/providers/unified")
|
||||
|
||||
const aigateway = createAiGateway({ accountId, gateway, apiKey: apiToken })
|
||||
const unified = createUnified()
|
||||
|
||||
return {
|
||||
autoload: true,
|
||||
async getModel(sdk: any, modelID: string, _options?: Record<string, any>) {
|
||||
return sdk.languageModel(modelID)
|
||||
},
|
||||
options: {
|
||||
baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gateway}/compat`,
|
||||
headers: {
|
||||
// Cloudflare AI Gateway uses cf-aig-authorization for authenticated gateways
|
||||
// This enables Unified Billing where Cloudflare handles upstream provider auth
|
||||
...(apiToken ? { "cf-aig-authorization": `Bearer ${apiToken}` } : {}),
|
||||
"HTTP-Referer": "https://opencode.ai/",
|
||||
"X-Title": "opencode",
|
||||
},
|
||||
// Custom fetch to handle parameter transformation and auth
|
||||
fetch: async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
const headers = new Headers(init?.headers)
|
||||
// Strip Authorization header - AI Gateway uses cf-aig-authorization instead
|
||||
headers.delete("Authorization")
|
||||
|
||||
// Transform max_tokens to max_completion_tokens for newer models
|
||||
if (init?.body && init.method === "POST") {
|
||||
try {
|
||||
const body = JSON.parse(init.body as string)
|
||||
if (body.max_tokens !== undefined && !body.max_completion_tokens) {
|
||||
body.max_completion_tokens = body.max_tokens
|
||||
delete body.max_tokens
|
||||
init = { ...init, body: JSON.stringify(body) }
|
||||
}
|
||||
} catch (e) {
|
||||
// If body parsing fails, continue with original request
|
||||
}
|
||||
}
|
||||
|
||||
return fetch(input, { ...init, headers })
|
||||
},
|
||||
async getModel(_sdk: any, modelID: string, _options?: Record<string, any>) {
|
||||
// Model IDs use Unified API format: provider/model (e.g., "anthropic/claude-sonnet-4-5")
|
||||
return aigateway(unified(modelID))
|
||||
},
|
||||
options: {},
|
||||
}
|
||||
},
|
||||
cerebras: async () => {
|
||||
|
||||
Reference in New Issue
Block a user