Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/add-cloudflare-ai-gateway-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@cloudflare/sandbox': patch
---

Add Cloudflare AI Gateway support to OpenCode integration. Users can now route AI provider requests through Cloudflare AI Gateway for monitoring, caching, and rate limiting by adding a `cloudflareAIGateway` provider configuration with `accountId`, `gatewayId`, and optional `apiToken`.
29 changes: 29 additions & 0 deletions examples/opencode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,33 @@ OpenCode handles everything:
- **Isolated execution** - Code runs in secure sandbox containers
- **Persistent sessions** - Sessions survive across requests

## Advanced: Cloudflare AI Gateway

You can optionally route all AI provider requests through [Cloudflare AI Gateway](https://developers.cloudflare.com/ai-gateway/) for monitoring, caching, and rate limiting. Add these variables to `.dev.vars`:

```bash
CLOUDFLARE_ACCOUNT_ID=your-account-id
CLOUDFLARE_GATEWAY_ID=your-gateway-id
CLOUDFLARE_API_TOKEN=your-api-token # Optional, for authenticated gateways
```

Then uncomment the `cloudflareAIGateway` section in `src/index.ts`:

```typescript
const getConfig = (env: Env): Config => ({
provider: {
anthropic: {
options: { apiKey: env.ANTHROPIC_API_KEY }
},
cloudflareAIGateway: {
options: {
accountId: env.CLOUDFLARE_ACCOUNT_ID,
gatewayId: env.CLOUDFLARE_GATEWAY_ID,
apiToken: env.CLOUDFLARE_API_TOKEN
}
}
}
});
```

Happy hacking!
71 changes: 67 additions & 4 deletions packages/sandbox/src/opencode/opencode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ async function ensureSdkLoaded(): Promise<void> {
} catch {
throw new Error(
'@opencode-ai/sdk is required for OpenCode integration. ' +
'Install it with: npm install @opencode-ai/sdk'
'Install it with: npm install @opencode-ai/sdk'
);
}
}
Expand Down Expand Up @@ -175,6 +175,10 @@ async function startOpencodeServer(
for (const [providerId, providerConfig] of Object.entries(
config.provider
)) {
if (providerId === 'cloudflareAIGateway') {
continue;
}

// Try options.apiKey first (official Config type)
let apiKey = providerConfig?.options?.apiKey;
// Fall back to top-level apiKey for convenience
Expand All @@ -187,6 +191,23 @@ async function startOpencodeServer(
env[envVar] = apiKey;
}
}

const aiGatewayConfig = config.provider.cloudflareAIGateway;
if (aiGatewayConfig?.options) {
const options = aiGatewayConfig.options as Record<string, unknown>;

if (typeof options.accountId === 'string') {
env.CLOUDFLARE_ACCOUNT_ID = options.accountId;
}

if (typeof options.gatewayId === 'string') {
env.CLOUDFLARE_GATEWAY_ID = options.gatewayId;
}

if (typeof options.apiToken === 'string') {
env.CLOUDFLARE_API_TOKEN = options.apiToken;
}
}
}
}

Expand Down Expand Up @@ -244,7 +265,21 @@ async function startOpencodeServer(
* const sandbox = getSandbox(env.Sandbox, 'my-agent')
* const server = await createOpencodeServer(sandbox, {
* directory: '/home/user/my-project',
* config: { provider: { anthropic: { options: { apiKey: env.ANTHROPIC_KEY } } } }
* config: {
* provider: {
* anthropic: {
* options: { apiKey: env.ANTHROPIC_KEY }
* },
* // Optional: Route all providers through Cloudflare AI Gateway
* cloudflareAIGateway: {
* options: {
* accountId: env.CF_ACCOUNT_ID,
* gatewayId: env.CF_GATEWAY_ID,
* apiToken: env.CF_API_TOKEN
* }
* }
* }
* }
* })
*
* // Proxy requests to the web UI
Expand Down Expand Up @@ -295,7 +330,21 @@ export async function createOpencodeServer(
* const sandbox = getSandbox(env.Sandbox, 'my-agent')
* const { client, server } = await createOpencode(sandbox, {
* directory: '/home/user/my-project',
* config: { provider: { anthropic: { options: { apiKey: env.ANTHROPIC_KEY } } } }
* config: {
* provider: {
* anthropic: {
* options: { apiKey: env.ANTHROPIC_KEY }
* },
* // Optional: Route all providers through Cloudflare AI Gateway
* cloudflareAIGateway: {
* options: {
* accountId: env.CF_ACCOUNT_ID,
* gatewayId: env.CF_GATEWAY_ID,
* apiToken: env.CF_API_TOKEN
* }
* }
* }
* }
* })
*
* // Use the SDK client for programmatic access
Expand Down Expand Up @@ -354,7 +403,21 @@ export async function createOpencode<TClient = unknown>(
* const sandbox = getSandbox(env.Sandbox, 'opencode')
* const server = await createOpencodeServer(sandbox, {
* directory: '/home/user/project',
* config: { provider: { anthropic: { options: { apiKey: env.ANTHROPIC_KEY } } } }
* config: {
* provider: {
* anthropic: {
* options: { apiKey: env.ANTHROPIC_KEY }
* },
* // Optional: Route all providers through Cloudflare AI Gateway
* cloudflareAIGateway: {
* options: {
* accountId: env.CF_ACCOUNT_ID,
* gatewayId: env.CF_GATEWAY_ID,
* apiToken: env.CF_API_TOKEN
* }
* }
* }
* }
* })
* return proxyToOpencode(request, sandbox, server)
* }
Expand Down
Loading