Transform Google's Gemini models into OpenAI-compatible endpoints using Cloudflare Workers. Access Google's most advanced AI models through familiar OpenAI API patterns, powered by OAuth2 authentication and the same infrastructure that drives the official Gemini CLI.
| Model ID | Context Window | Max Tokens | Thinking Support | Description |
|---|---|---|---|---|
gemini-2.5-pro |
1M | 65K | ✅ | Latest Gemini 2.5 Pro model with reasoning capabilities |
gemini-2.5-flash |
1M | 65K | ✅ | Fast Gemini 2.5 Flash model with reasoning capabilities |
gemini-2.5-flash-lite |
1M | 65K | ✅ | Lightweight version of Gemini 2.5 Flash model with reasoning capabilities |
Note: Gemini 2.5 models have thinking enabled by default. The API automatically manages this: - When real thinking is disabled (environment), thinking budget is set to 0 to disable it - When real thinking is enabled (environment), thinking budget defaults to -1 (dynamic allocation by Gemini)
Thinking support has two modes: - Fake thinking: Set
ENABLE_FAKE_THINKING=trueto generate synthetic reasoning text (good for testing) - Real thinking: SetENABLE_REAL_THINKING=trueto use Gemini's native reasoning capabilitiesReal thinking is controlled entirely by the
ENABLE_REAL_THINKINGenvironment variable. You can optionally set a"thinking_budget"in your request (token limit for reasoning, -1 for dynamic allocation, 0 to disable thinking entirely).
reasoning_effort in the request body (e.g., extra_body or model_params). This parameter allows you to fine-tune the model's internal reasoning process, balancing between speed and depth of thought.none: Disables thinking (thinking_budget = 0).low: Sets thinking_budget = 1024.medium: Sets thinking_budget = 12288 for flash models, 16384 for other models.high: Sets thinking_budget = 24576 for flash models, 32768 for other models.Set
STREAM_THINKING_AS_CONTENT=trueto stream reasoning as content with<thinking>tags (DeepSeek R1 style) instead of using the reasoning field.
npm install -g wrangler)You need OAuth2 credentials from a Google account that has accessed Gemini. The easiest way to get these is through the official Gemini CLI.
Install Gemini CLI:
bash
npm install -g @google/gemini-cli
Start the Gemini CLI:
bash
gemini
Select ● Login with Google.
A browser window will now open prompting you to login with your Google account.
Windows:
C:\Users\USERNAME\.gemini\oauth_creds.json
macOS/Linux:
~/.gemini/oauth_creds.json
json
{
"access_token": "ya29.a0AS3H6Nx...",
"refresh_token": "1//09FtpJYpxOd...",
"scope": "https://www.googleapis.com/auth/cloud-platform ...",
"token_type": "Bearer",
"id_token": "eyJhbGciOiJSUzI1NiIs...",
"expiry_date": 1750927763467
}# Create a KV namespace for token caching
wrangler kv namespace create "GEMINI_CLI_KV"
Note the namespace ID returned.
Update wrangler.toml with your KV namespace ID:
kv_namespaces = [
{ binding = "GEMINI_CLI_KV", id = "your-kv-namespace-id" }
]
Create a .dev.vars file:
# Required: OAuth2 credentials JSON from Gemini CLI authentication
GCP_SERVICE_ACCOUNT={"access_token":"ya29...","refresh_token":"1//...","scope":"...","token_type":"Bearer","id_token":"eyJ...","expiry_date":1750927763467}
# Optional: Google Cloud Project ID (auto-discovered if not set)
# GEMINI_PROJECT_ID=your-project-id
# Optional: API key for authentication (if not set, API is public)
# When set, clients must include "Authorization: Bearer <your-api-key>" header
# Example: sk-1234567890abcdef1234567890abcdef
OPENAI_API_KEY=sk-your-secret-api-key-here
For production, set the secrets:
wrangler secret put GCP_SERVICE_ACCOUNT
wrangler secret put OPENAI_API_KEY # Optional, only if you want authentication
# Install dependencies
npm install
# Deploy to Cloudflare Workers
npm run deploy
# Or run locally for development
npm run dev
| Variable | Required | Description |
|---|---|---|
GCP_SERVICE_ACCOUNT |
✅ | OAuth2 credentials JSON string. |
GEMINI_PROJECT_ID |
❌ | Google Cloud Project ID (auto-discovered if not set). |
OPENAI_API_KEY |
❌ | API key for authentication. If not set, the API is public. |
| Variable | Description |
|---|---|
ENABLE_FAKE_THINKING |
Enable synthetic thinking output for testing (set to "true"). |
ENABLE_REAL_THINKING |
Enable real Gemini thinking output (set to "true"). |
STREAM_THINKING_AS_CONTENT |
Stream thinking as content with <thinking> tags (DeepSeek R1 style). |
| Variable | Description |
|---|---|
ENABLE_AUTO_MODEL_SWITCHING |
Enable automatic fallback from pro to flash models on rate limits (set to "true"). |
ENABLE_GEMINI_NATIVE_TOOLS |
Master switch to enable all native tools (set to "true"). |
ENABLE_GOOGLE_SEARCH |
Enable Google Search native tool (set to "true"). |
ENABLE_URL_CONTEXT |
Enable URL Context native tool (set to "true"). |
GEMINI_TOOLS_PRIORITY |
Set tool priority: "native_first" or "custom_first". |
ALLOW_REQUEST_TOOL_CONTROL |
Allow request parameters to override tool settings (set to "false" to disable). |
ENABLE_INLINE_CITATIONS |
Inject markdown citations for search results (set to "true" to enable). |
INCLUDE_GROUNDING_METADATA |
Include raw grounding metadata in the stream (set to "false" to disable). |
| Variable | Description |
|---|---|
GEMINI_MODERATION_HARASSMENT_THRESHOLD |
Sets the moderation threshold for harassment content. |
GEMINI_MODERATION_HATE_SPEECH_THRESHOLD |
Sets the moderation threshold for hate speech content. |
GEMINI_MODERATION_SEXUALLY_EXPLICIT_THRESHOLD |
Sets the moderation threshold for sexually explicit content. |
GEMINI_MODERATION_DANGEROUS_CONTENT_THRESHOLD |
Sets the moderation threshold for dangerous content. |
For safety thresholds, valid options are: BLOCK_NONE, BLOCK_FEW, BLOCK_SOME, BLOCK_ONLY_HIGH, HARM_BLOCK_THRESHOLD_UNSPECIFIED.
Authentication Security:
- When OPENAI_API_KEY is set, all /v1/* endpoints require authentication.
- Clients must include the header: Authorization: Bearer <your-api-key>.
- Without this environment variable, the API is publicly accessible.
- Recommended format: sk- followed by a random string (e.g., sk-1234567890abcdef...).
Thinking Models:
- Fake Thinking: When ENABLE_FAKE_THINKING is set to "true", models marked with thinking: true will generate synthetic reasoning text before their actual response.
- Real Thinking: When ENABLE_REAL_THINKING is set to "true", requests with include_reasoning: true will use Gemini's native thinking capabilities.
- Real thinking provides genuine reasoning from Gemini and requires thinking-capable models (like Gemini 2.5 Pro/Flash).
- You can control the reasoning token budget with the thinking_budget parameter.
- By default, reasoning output is streamed as reasoning chunks in the OpenAI-compatible response format.
- When STREAM_THINKING_AS_CONTENT is also set to "true", reasoning will be streamed as regular content wrapped in <thinking></thinking> tags (DeepSeek R1 style).
- Optimized UX: The </thinking> tag is only sent when the actual LLM response begins, eliminating awkward pauses between thinking and response.
- If neither thinking mode is enabled, thinking models will behave like regular models.
Auto Model Switching:
- When ENABLE_AUTO_MODEL_SWITCHING is set to "true", the system will automatically fall back from gemini-2.5-pro to gemini-2.5-flash when encountering rate limit errors (HTTP 429 or 503).
- This provides seamless continuity when the Pro model quota is exhausted.
- The fallback is indicated in the response with a notification message.
- Only applies to supported model pairs (currently: pro → flash).
- Works for both streaming and non-streaming requests.
| Binding | Purpose |
|---|---|
GEMINI_CLI_KV |
Token caching and session management |
401 Authentication Error - Check if your OAuth2 credentials are valid - Ensure the refresh token is working - Verify the credentials format matches exactly
Token Refresh Failed - Credentials might be from wrong OAuth2 client - Refresh token might be expired or revoked - Check the debug cache endpoint for token status
Project ID Discovery Failed
- Set GEMINI_PROJECT_ID environment variable manually
- Ensure your Google account has access to Gemini
Cline is a powerful AI assistant extension for VS Code. You can easily configure it to use your Gemini models:
Install Cline in VS Code from the Extensions marketplace
Configure OpenAI API settings:
https://your-worker.workers.dev/v1Set API Key to: sk-your-secret-api-key-here (use your OPENAI_API_KEY if authentication is enabled)
Select a model:
gemini-2.5-pro for complex reasoning tasksgemini-2.5-flash for faster responseshttps://your-worker.workers.dev/v1API Key: sk-your-secret-api-key-here (use your OPENAI_API_KEY if authentication is enabled)
Configure models:
Open WebUI will automatically discover available Gemini models through the /v1/models endpoint.
Start chatting: Use any Gemini model just like you would with OpenAI models!
LiteLLM works seamlessly with this worker, especially when using the DeepSeek R1-style thinking streams:
import litellm
# Configure LiteLLM to use your worker
litellm.api_base = "https://your-worker.workers.dev/v1"
litellm.api_key = "sk-your-secret-api-key-here"
# Use thinking models with LiteLLM
response = litellm.completion(
model="gemini-2.5-flash",
messages=[
{"role": "user", "content": "Solve this step by step: What is 15 * 24?"}
],
stream=True
)
for chunk in response:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
Pro Tip: Set STREAM_THINKING_AS_CONTENT=true for optimal LiteLLM compatibility. The <thinking> tags format works better with LiteLLM's parsing and various downstream tools.
```python from openai import OpenAI
client = OpenAI( base_url="https://your-worker.workers.dev/v1", api_key="sk-your-secret-api-key-here" # Use your OPENAI_API_KEY if authentication is enabled )
response = client.chat.completions.create( model="gemini-2.5-flash", messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Explain machine learning in simple terms"} ], stream=True )
for chunk in response: if chunk.choices[0].delta.content: print(chunk.choices[0].delta.content, end="")
response = client.chat.completions.create( model="gemini-2.5-pro", messages=[ {"role": "user", "content": "Solve this step by step: What is the derivative of x^3 + 2x^2 - 5x + 3?"} ], extra_body={ "include_reasoning": True, "thinking_budget": 1024 }, stream=True )
for chunk in response: # Real thinking appears in the reasoning field if hasattr(chunk.choices[0].delta, 'reasoning') and chunk.choices[0].delta.reasoning: print(f"[Thinking] {chunk.choices[0].delta.reasoning}") if chunk.cho
$ claude mcp add gemini-cli-openai \
-- python -m otcore.mcp_server <graph>