diff options
| author | Matt Silverlock <[email protected]> | 2026-02-03 16:18:28 -0500 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-02-03 15:18:28 -0600 |
| commit | 25bdd77b1d765a9cac5d02ede93c075f25d6ca6f (patch) | |
| tree | fe7e08b548fecfa260144484c76ff35ca50d84a3 /packages | |
| parent | 2f12e8ee923ddbdb0050c7ff2f6e85227cdf9b9e (diff) | |
| download | opencode-25bdd77b1d765a9cac5d02ede93c075f25d6ca6f.tar.gz opencode-25bdd77b1d765a9cac5d02ede93c075f25d6ca6f.zip | |
fix(opencode): use official ai-gateway-provider package for Cloudflare AI Gateway (#12014)
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/opencode/package.json | 1 | ||||
| -rw-r--r-- | packages/opencode/src/provider/provider.ts | 56 |
2 files changed, 21 insertions, 36 deletions
diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 08eaae49d..7dd0cbd27 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -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", diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index b85835b69..fc90571fe 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -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 () => { |
