mirror of
https://github.com/usamashehab/antigravity-proxy.git
synced 2026-10-25 01:14:18 +00:00
Add AGENTS.md for AI-assisted setup, optimize README with SEO and badges
- AGENTS.md: step-by-step instructions for LLM agents to guide users through install, configure, and troubleshoot - README.md: SEO-optimized with keywords (Gemini 3.5 Flash, Claude Sonnet, OpenAI-compatible, free API, LLM proxy), collapsible config sections, badges, AI-assisted setup callout - Topics: 20 SEO tags added via GitHub API
This commit is contained in:
1 parent
3e664884af
commit
9db90a538c
2 files changed
+417
-164
No files matched your search
@@ -0,0 +1,140 @@
|
||||
# AGENTS.md — LLM Agent Instructions
|
||||
|
||||
> **If you are an AI assistant (Claude, GPT, Gemini, etc.) helping a user set up this proxy, read this file first. It contains everything you need to guide the user through installation, configuration, and troubleshooting.**
|
||||
|
||||
---
|
||||
|
||||
## What This Project Is
|
||||
|
||||
A local proxy server that translates OpenAI-compatible API calls into Google Antigravity's internal Cloud Code Assist API format. It lets any tool that speaks OpenAI format use Gemini and Claude models for free, authenticated via the Antigravity CLI's OAuth token.
|
||||
|
||||
The proxy listens on `http://127.0.0.1:8877` and exposes two endpoints:
|
||||
- `POST /v1/chat/completions` — OpenAI chat format (messages, tools, streaming)
|
||||
- `POST /v1beta/models/{model}:generateContent` — native Gemini passthrough (images, structured output)
|
||||
|
||||
---
|
||||
|
||||
## How to Guide a User Through Setup
|
||||
|
||||
### Step 1 — Check Prerequisites
|
||||
|
||||
Ask the user:
|
||||
1. **Do you have Python 3.10+?** Check with `python3 --version`
|
||||
2. **Do you have the Antigravity CLI (`agy`) installed and authenticated?** Check with `ls ~/.gemini/antigravity-cli/antigravity-oauth-token`
|
||||
|
||||
If they don't have `agy`, tell them to install it:
|
||||
- **macOS/Linux:** `curl -fsSL https://storage.googleapis.com/antigravity-releases/install.sh | bash`
|
||||
- **Windows:** Download from [antigravity.google](https://antigravity.google/)
|
||||
|
||||
Then authenticate: run `agy` once, sign in with Google account.
|
||||
|
||||
### Step 2 — Clone and Start
|
||||
|
||||
```bash
|
||||
git clone https://github.com/usamashehab/antigravity-proxy.git
|
||||
cd antigravity-proxy
|
||||
python3 antigravity_proxy.py
|
||||
```
|
||||
|
||||
Verify it's running:
|
||||
```bash
|
||||
curl http://127.0.0.1:8877/health
|
||||
# Should return: {"status": "ok", "service": "antigravity-proxy"}
|
||||
```
|
||||
|
||||
### Step 3 — Configure Their Tool
|
||||
|
||||
Ask what tool they want to connect. Apply these settings:
|
||||
|
||||
| Tool Type | Base URL | API Key | Model |
|
||||
|-------------------|---------------------------------------|-----------------|-------------------|
|
||||
| OpenAI SDK | `http://127.0.0.1:8877/v1` | Any string | See model table |
|
||||
| Continue.dev | `http://127.0.0.1:8877/v1` | Any string | |
|
||||
| Aider | `--openai-api-base http://127.0.0.1:8877/v1` | Any string | |
|
||||
| Hermes Agent | `hermes config set ...` | Any string | |
|
||||
| Claude Code | `ANTHROPIC_BASE_URL` env var | N/A | `claude-sonnet-4.6` |
|
||||
|
||||
### Step 4 — Verify It Works
|
||||
|
||||
Have them run a test request:
|
||||
```bash
|
||||
curl http://127.0.0.1:8877/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"model": "gemini-3.5-flash", "messages": [{"role": "user", "content": "Say hello"}]}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Available Models
|
||||
|
||||
```
|
||||
gemini-3.1-pro Gemini 3.1 Pro (thinking: low)
|
||||
gemini-3.1-pro-high Gemini 3.1 Pro (thinking: high)
|
||||
gemini-3-flash Gemini 3 Flash
|
||||
gemini-3.5-flash Gemini 3.5 Flash
|
||||
gemini-2.5-pro Gemini 2.5 Pro
|
||||
gemini-2.5-flash Gemini 2.5 Flash
|
||||
claude-sonnet-4.6 Claude Sonnet 4.6
|
||||
claude-opus-4.6 Claude Opus 4.6 (thinking enabled)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Issues and Solutions
|
||||
|
||||
### "Token file not found"
|
||||
The user hasn't authenticated with `agy` yet. Run `agy` and sign in.
|
||||
|
||||
### "No refresh_token in token file"
|
||||
The token file is corrupted or incomplete. Delete it and re-run `agy`:
|
||||
```bash
|
||||
rm ~/.gemini/antigravity-cli/antigravity-oauth-token
|
||||
agy # re-authenticate
|
||||
```
|
||||
|
||||
### 401 / auth errors after working for a while
|
||||
The OAuth refresh token has expired. Re-run `agy` and restart the proxy.
|
||||
|
||||
### Model returns empty response or 404
|
||||
The model name doesn't exist on the Antigravity backend. Use a name from the model table above. When in doubt, `gemini-3-flash` or `gemini-3.5-flash` are the most reliable.
|
||||
|
||||
### Proxy is slow on first request
|
||||
The first request discovers the project ID (extra network call). Subsequent requests are faster.
|
||||
|
||||
### Requests timeout
|
||||
The Antigravity backend can be slow, especially for thinking models. This is not a proxy issue — it's upstream latency.
|
||||
|
||||
---
|
||||
|
||||
## Architecture (for context)
|
||||
|
||||
```
|
||||
Client (OpenAI format)
|
||||
→ Proxy translates to Gemini format
|
||||
→ Wraps in Antigravity envelope
|
||||
→ Forwards to cloudcode-pa.googleapis.com
|
||||
→ Response unwrapped, converted to OpenAI format
|
||||
→ Returned to client
|
||||
```
|
||||
|
||||
The proxy auto-refreshes the OAuth token when it expires. It uses Python stdlib only — no dependencies to install.
|
||||
|
||||
---
|
||||
|
||||
## File Reference
|
||||
|
||||
| File | Purpose |
|
||||
|-----------------------------|--------------------------------------------------|
|
||||
| `antigravity_proxy.py` | Main proxy server (single file, stdlib only) |
|
||||
| `antigravity-proxy.service` | systemd user service template |
|
||||
| `README.md` | Full human-readable documentation |
|
||||
| `AGENTS.md` | This file — instructions for AI assistants |
|
||||
|
||||
---
|
||||
|
||||
## Security Notes
|
||||
|
||||
- The proxy binds to `127.0.0.1` by default — only accessible locally
|
||||
- No API key or authentication layer (relies on localhost binding)
|
||||
- OAuth token stays on the user's machine, never sent anywhere except Google
|
||||
- The `CLIENT_ID` and `CLIENT_SECRET` constants are the same values embedded in every Antigravity CLI binary — they are not personal secrets
|
||||
@@ -1,138 +1,127 @@
|
||||
<div align="center">
|
||||
|
||||
# Antigravity Proxy
|
||||
|
||||
An OpenAI-compatible proxy that bridges any OpenAI-compatible client to **Google Antigravity's** internal Cloud Code Assist API. Uses the OAuth token from the [Antigravity CLI](https://antigravity.google/) (`agy`) — no API key, no billing.
|
||||
**Free Gemini 3.5 Flash, Claude Sonnet 4.6 & more — through a local OpenAI-compatible proxy**
|
||||
|
||||
Access **Gemini 3.5 Flash**, **Gemini 3.1 Pro**, **Claude Sonnet 4.6**, **Claude Opus 4.6**, and more through a single local endpoint.
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://www.python.org/downloads/)
|
||||
[](#requirements)
|
||||
[](CONTRIBUTING.md)
|
||||
|
||||
## Features
|
||||
[Features](#features) · [Quick Start](#quick-start) · [Models](#available-models) · [Configuration](#configuration) · [Docs](#how-it-works)
|
||||
|
||||
- **OpenAI-compatible** `/v1/chat/completions` endpoint (streaming + non-streaming)
|
||||
- **Native Gemini passthrough** `/v1beta/models/{model}:generateContent` endpoint
|
||||
- **Tool/function calling** support (OpenAI tools → Gemini functionDeclarations, round-tripped)
|
||||
- **Model auto-mapping** — use friendly names (`gemini-3.5-flash`), the proxy translates to backend names automatically
|
||||
- **Token auto-refresh** — OAuth token refreshed automatically when expired
|
||||
- **Zero dependencies** — pure Python 3.10+, stdlib only
|
||||
- **systemd integration** — run as a background service
|
||||
|
||||
## Available Models
|
||||
|
||||
| Friendly Name | Backend Model | Notes |
|
||||
|----------------------|----------------------------|--------------------------------|
|
||||
| `gemini-3.1-pro` | `gemini-3.1-pro-low` | Thinking level: low |
|
||||
| `gemini-3.1-pro-high`| `gemini-3.1-pro-low` | Thinking level: high |
|
||||
| `gemini-3-flash` | `gemini-3-flash` | |
|
||||
| `gemini-3.5-flash` | `gemini-3.5-flash-low` | |
|
||||
| `gemini-2.5-pro` | `gemini-2.5-pro` | |
|
||||
| `gemini-2.5-flash` | `gemini-2.5-flash` | |
|
||||
| `claude-sonnet-4.6` | `claude-sonnet-4-6` | Via Antigravity backend |
|
||||
| `claude-opus-4.6` | `claude-opus-4-6-thinking` | Thinking enabled |
|
||||
|
||||
Model names are mapped automatically on both endpoints. You always use the friendly name in your client config.
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
## What is this?
|
||||
|
||||
You need the **Antigravity CLI** (`agy`) installed and authenticated. The proxy reads the OAuth token that `agy` stores on disk.
|
||||
A lightweight **OpenAI-compatible proxy** that bridges any AI tool to **Google Antigravity's** internal Cloud Code Assist API. Authenticate once with the [Antigravity CLI](https://antigravity.google/), then use **Gemini** and **Claude** models from any OpenAI-compatible client — **no API key, no billing, no credit card**.
|
||||
|
||||
### Install Antigravity CLI
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
curl -fsSL https://storage.googleapis.com/antigravity-releases/install.sh | bash
|
||||
```
|
||||
Your Tool (OpenAI format) → Antigravity Proxy (localhost:8877) → Gemini / Claude models
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
Download from [antigravity.google](https://antigravity.google/) or use `winget`:
|
||||
```
|
||||
winget install Google.Antigravity
|
||||
```
|
||||
### Why use this?
|
||||
|
||||
### Authenticate
|
||||
- **Free** — uses the OAuth token from the Antigravity CLI, no paid API key
|
||||
- **Universal** — works with any OpenAI-compatible tool (Aider, Continue, Hermes, Claude Code, OpenAI SDK, LangChain, etc.)
|
||||
- **No dependencies** — pure Python stdlib, no `pip install` needed
|
||||
- **Two endpoints** — OpenAI chat completions + native Gemini passthrough (for images & structured output)
|
||||
- **Tool/function calling** — full support, including round-trip through conversation history
|
||||
- **Streaming** — SSE streaming support for real-time token generation
|
||||
|
||||
Run the CLI once to complete the Google OAuth flow:
|
||||
```bash
|
||||
agy
|
||||
```
|
||||
This opens a browser, you sign in with your Google account, and the token is saved to `~/.gemini/antigravity-cli/antigravity-oauth-token`.
|
||||
---
|
||||
|
||||
> **Note:** The proxy supports both consumer Google accounts and Google Workspace accounts.
|
||||
## Features
|
||||
|
||||
- **OpenAI-compatible** `POST /v1/chat/completions` — streaming + non-streaming
|
||||
- **Native Gemini passthrough** `POST /v1beta/models/{model}:generateContent` — images, structured JSON output
|
||||
- **Tool/function calling** — OpenAI tools format → Gemini functionDeclarations, with round-trip encoding
|
||||
- **Model auto-mapping** — use friendly names (`gemini-3.5-flash`), the proxy translates to backend names automatically
|
||||
- **OAuth token auto-refresh** — token refreshed automatically when expired, no manual intervention
|
||||
- **Zero pip dependencies** — Python 3.10+ standard library only
|
||||
- **systemd service** included — run as a background service on Linux
|
||||
|
||||
---
|
||||
|
||||
## Available Models
|
||||
|
||||
| Friendly Name | Backend Model | Thinking | Type |
|
||||
|-----------------------|----------------------------|----------------|---------|
|
||||
| `gemini-3.1-pro` | `gemini-3.1-pro-low` | Low | Gemini |
|
||||
| `gemini-3.1-pro-high` | `gemini-3.1-pro-low` | High | Gemini |
|
||||
| `gemini-3-flash` | `gemini-3-flash` | — | Gemini |
|
||||
| `gemini-3.5-flash` | `gemini-3.5-flash-low` | — | Gemini |
|
||||
| `gemini-2.5-pro` | `gemini-2.5-pro` | — | Gemini |
|
||||
| `gemini-2.5-flash` | `gemini-2.5-flash` | — | Gemini |
|
||||
| `claude-sonnet-4.6` | `claude-sonnet-4-6` | — | Claude |
|
||||
| `claude-opus-4.6` | `claude-opus-4-6-thinking` | Enabled | Claude |
|
||||
|
||||
You always use the **friendly name** in your client. The proxy handles translation.
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Option A: Run directly
|
||||
### Prerequisites
|
||||
|
||||
1. **Python 3.10+** — check with `python3 --version`
|
||||
2. **Antigravity CLI** — install and authenticate (one-time):
|
||||
|
||||
```bash
|
||||
# Install agy (macOS/Linux)
|
||||
curl -fsSL https://storage.googleapis.com/antigravity-releases/install.sh | bash
|
||||
|
||||
# Authenticate (opens browser, sign in with Google)
|
||||
agy
|
||||
```
|
||||
|
||||
> Windows: download from [antigravity.google](https://antigravity.google/)
|
||||
|
||||
### Install & Run
|
||||
|
||||
```bash
|
||||
git clone https://github.com/usamashehab/antigravity-proxy.git
|
||||
cd antigravity-proxy
|
||||
|
||||
# Start the proxy
|
||||
python3 antigravity_proxy.py
|
||||
```
|
||||
|
||||
The proxy starts on `http://127.0.0.1:8877`.
|
||||
|
||||
### Option B: Run as a systemd service (recommended)
|
||||
|
||||
```bash
|
||||
# 1. Clone to a permanent location
|
||||
git clone https://github.com/usamashehab/antigravity-proxy.git ~/antigravity-proxy
|
||||
|
||||
# 2. Copy the service file
|
||||
mkdir -p ~/.config/systemd/user
|
||||
cp ~/antigravity-proxy/antigravity-proxy.service ~/.config/systemd/user/
|
||||
|
||||
# 3. If you use a venv, edit the ExecStart path in the service file to point to your python
|
||||
|
||||
# 4. Reload systemd and start
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable antigravity-proxy
|
||||
systemctl --user start antigravity-proxy
|
||||
|
||||
# 5. Verify
|
||||
systemctl --user status antigravity-proxy
|
||||
# Verify it's running
|
||||
curl http://127.0.0.1:8877/health
|
||||
# → {"status": "ok", "service": "antigravity-proxy"}
|
||||
```
|
||||
|
||||
### Option C: Run with custom host/port
|
||||
That's it. The proxy is now listening on `http://127.0.0.1:8877`.
|
||||
|
||||
```bash
|
||||
python3 antigravity_proxy.py --port 9000 --host 0.0.0.0
|
||||
```
|
||||
### Connect Your Tool
|
||||
|
||||
> **Warning:** Binding to `0.0.0.0` exposes the proxy to your network. The proxy has no authentication layer — anyone who can reach it can use your Antigravity quota. Use `127.0.0.1` unless you know what you're doing.
|
||||
Any OpenAI-compatible client works. Set base URL to `http://127.0.0.1:8877/v1` and use any model from the table above. The API key can be any string (the proxy doesn't check it).
|
||||
|
||||
---
|
||||
<details>
|
||||
<summary><b>OpenAI Python SDK</b></summary>
|
||||
|
||||
## Configuration
|
||||
|
||||
### Point your client at the proxy
|
||||
|
||||
Any OpenAI-compatible client works. Set:
|
||||
|
||||
| Setting | Value |
|
||||
|-------------|--------------------------------|
|
||||
| Base URL | `http://127.0.0.1:8877/v1` |
|
||||
| API Key | `antigravity` (any string) |
|
||||
| Model | Any name from the table above |
|
||||
|
||||
#### Examples
|
||||
|
||||
**OpenAI Python SDK:**
|
||||
```python
|
||||
from openai import OpenAI
|
||||
|
||||
client = OpenAI(
|
||||
base_url="http://127.0.0.1:8877/v1",
|
||||
api_key="antigravity",
|
||||
)
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="gemini-3.5-flash",
|
||||
messages=[{"role": "user", "content": "Hello!"}],
|
||||
)
|
||||
print(response.choices[0].message.content)
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>curl</b></summary>
|
||||
|
||||
**curl:**
|
||||
```bash
|
||||
curl http://127.0.0.1:8877/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
@@ -141,36 +130,131 @@ curl http://127.0.0.1:8877/v1/chat/completions \
|
||||
"messages": [{"role": "user", "content": "Hello!"}]
|
||||
}'
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Aider</b></summary>
|
||||
|
||||
```bash
|
||||
export OPENAI_API_BASE=http://127.0.0.1:8877/v1
|
||||
export OPENAI_API_KEY=antigravity
|
||||
aider --model gemini-3.5-flash
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Continue.dev (VS Code)</b></summary>
|
||||
|
||||
In `~/.continue/config.json`:
|
||||
```json
|
||||
{
|
||||
"models": [{
|
||||
"title": "Antigravity",
|
||||
"provider": "openai",
|
||||
"model": "gemini-3.5-flash",
|
||||
"apiBase": "http://127.0.0.1:8877/v1",
|
||||
"apiKey": "antigravity"
|
||||
}]
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Hermes Agent</b></summary>
|
||||
|
||||
**Hermes Agent:**
|
||||
```bash
|
||||
hermes config set model.provider custom
|
||||
hermes config set model.base_url http://127.0.0.1:8877/v1
|
||||
hermes config set model.api_key antigravity
|
||||
hermes config set model.default gemini-3.5-flash
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Claude Code</b></summary>
|
||||
|
||||
**Claude Code:**
|
||||
```bash
|
||||
export ANTHROPIC_BASE_URL=http://127.0.0.1:8877/v1
|
||||
claude # uses claude-sonnet-4.6 through the proxy
|
||||
```
|
||||
</details>
|
||||
|
||||
**Continue / Aider / any OpenAI-compatible tool:** Set base URL to `http://127.0.0.1:8877/v1` and use any model from the table.
|
||||
<details>
|
||||
<summary><b>LangChain</b></summary>
|
||||
|
||||
```python
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
llm = ChatOpenAI(
|
||||
base_url="http://127.0.0.1:8877/v1",
|
||||
api_key="antigravity",
|
||||
model="gemini-3.5-flash",
|
||||
)
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Two Endpoints
|
||||
## AI-Assisted Setup 🤖
|
||||
|
||||
The proxy serves two distinct API surfaces:
|
||||
**Using an AI assistant (Claude, GPT, Gemini, etc.) to set this up?**
|
||||
|
||||
### 1. OpenAI Chat Completions (default)
|
||||
This repo includes [`AGENTS.md`](AGENTS.md) — a complete instruction file for AI agents. Just tell your AI assistant:
|
||||
|
||||
> "Help me install and configure the antigravity-proxy from https://github.com/usamashehab/antigravity-proxy"
|
||||
|
||||
The AI will read `AGENTS.md` and guide you through every step: prerequisites check, installation, tool configuration, and troubleshooting.
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### CLI Arguments
|
||||
|
||||
```
|
||||
python3 antigravity_proxy.py [--port PORT] [--host HOST]
|
||||
|
||||
--port PORT Port to listen on (default: 8877)
|
||||
--host HOST Host to bind to (default: 127.0.0.1)
|
||||
```
|
||||
|
||||
### Run as a systemd Service (Linux)
|
||||
|
||||
```bash
|
||||
# Clone to permanent location
|
||||
git clone https://github.com/usamashehab/antigravity-proxy.git ~/antigravity-proxy
|
||||
|
||||
# Install service
|
||||
mkdir -p ~/.config/systemd/user
|
||||
cp ~/antigravity-proxy/antigravity-proxy.service ~/.config/systemd/user/
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable antigravity-proxy
|
||||
systemctl --user start antigravity-proxy
|
||||
|
||||
# Check status
|
||||
systemctl --user status antigravity-proxy
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Default | Description |
|
||||
|------------------------------|---------|------------------------------------|
|
||||
| `ANTIGRAVITY_CLIENT_ID` | built-in| Override OAuth client ID |
|
||||
| `ANTIGRAVITY_CLIENT_SECRET` | built-in| Override OAuth client secret |
|
||||
|
||||
The default client credentials are the same values embedded in every Antigravity CLI binary — you only need these env vars if you're using a custom build.
|
||||
|
||||
---
|
||||
|
||||
## Two API Endpoints
|
||||
|
||||
### 1. OpenAI Chat Completions
|
||||
|
||||
```
|
||||
POST /v1/chat/completions
|
||||
```
|
||||
|
||||
Standard OpenAI format. Messages, tools, streaming — all supported. Use this for any OpenAI-compatible client.
|
||||
Standard OpenAI format with messages, tools, and streaming. Use this for any OpenAI-compatible client.
|
||||
|
||||
### 2. Native Gemini Passthrough
|
||||
|
||||
@@ -178,11 +262,15 @@ Standard OpenAI format. Messages, tools, streaming — all supported. Use this f
|
||||
POST /v1beta/models/{model}:generateContent
|
||||
```
|
||||
|
||||
Accepts the exact same request format as Google's `generativelanguage.googleapis.com` API. Supports `inline_data` (images), `responseSchema` (structured output), `thinkingConfig`, and everything else — all passed through untouched.
|
||||
Accepts the exact same format as Google's Generative Language API. Use this for:
|
||||
|
||||
Use this when you need features that don't map to OpenAI format (image inputs, structured JSON schema output, etc.).
|
||||
- **Image inputs** (`inline_data` with base64-encoded images)
|
||||
- **Structured output** (`responseSchema` for enforced JSON schema)
|
||||
- **Thinking control** (`thinkingConfig`)
|
||||
|
||||
<details>
|
||||
<summary><b>Structured output example</b></summary>
|
||||
|
||||
**Example — structured output with a response schema:**
|
||||
```bash
|
||||
curl http://127.0.0.1:8877/v1beta/models/gemini-3.5-flash:generateContent \
|
||||
-H "Content-Type: application/json" \
|
||||
@@ -202,64 +290,50 @@ curl http://127.0.0.1:8877/v1beta/models/gemini-3.5-flash:generateContent \
|
||||
}
|
||||
}'
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Image input example</b></summary>
|
||||
|
||||
```bash
|
||||
# Base64-encode an image and send it
|
||||
B64=$(base64 -w0 photo.jpg)
|
||||
|
||||
curl http://127.0.0.1:8877/v1beta/models/gemini-3.5-flash:generateContent \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"contents\": [{
|
||||
\"parts\": [
|
||||
{\"text\": \"What is in this image?\"},
|
||||
{\"inline_data\": {\"mime_type\": \"image/jpeg\", \"data\": \"$B64\"}}
|
||||
]
|
||||
}]
|
||||
}"
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Management
|
||||
|
||||
### Check health
|
||||
```bash
|
||||
# Health check
|
||||
curl http://127.0.0.1:8877/health
|
||||
# {"status": "ok", "service": "antigravity-proxy"}
|
||||
```
|
||||
|
||||
### List available models
|
||||
```bash
|
||||
# List models
|
||||
curl http://127.0.0.1:8877/v1/models
|
||||
```
|
||||
|
||||
### View logs (systemd)
|
||||
```bash
|
||||
# View logs (systemd)
|
||||
journalctl --user -u antigravity-proxy -f
|
||||
```
|
||||
|
||||
### Restart
|
||||
```bash
|
||||
# Restart / stop
|
||||
systemctl --user restart antigravity-proxy
|
||||
```
|
||||
|
||||
### Stop
|
||||
```bash
|
||||
systemctl --user stop antigravity-proxy
|
||||
|
||||
# Re-authenticate when token expires
|
||||
agy && systemctl --user restart antigravity-proxy
|
||||
```
|
||||
|
||||
### Token expired?
|
||||
|
||||
If the proxy logs show authentication errors, re-authenticate with the Antigravity CLI:
|
||||
```bash
|
||||
agy # opens browser for re-login
|
||||
systemctl --user restart antigravity-proxy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Adding / Updating Models
|
||||
|
||||
Edit `MODEL_MAP` at the top of `antigravity_proxy.py`:
|
||||
|
||||
```python
|
||||
MODEL_MAP = {
|
||||
"gemini-3.5-flash": ("gemini-3.5-flash-low", None),
|
||||
# format: "friendly-name": ("backend-name", thinking_level_or_None)
|
||||
}
|
||||
```
|
||||
|
||||
- **Friendly name**: what clients send (e.g. `gemini-3.5-flash`)
|
||||
- **Backend name**: the model ID Antigravity's API expects (e.g. `gemini-3.5-flash-low`)
|
||||
- **Thinking level**: `"low"`, `"high"`, or `None`
|
||||
|
||||
After editing, restart the proxy.
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
@@ -269,24 +343,47 @@ Your Client (OpenAI format)
|
||||
│
|
||||
▼
|
||||
Antigravity Proxy (localhost:8877)
|
||||
│ ┌─ Translates OpenAI → Gemini format
|
||||
│ ┌─ Translates OpenAI messages → Gemini contents
|
||||
│ ├─ Converts OpenAI tools → Gemini functionDeclarations
|
||||
│ ├─ Manages OAuth token (auto-refresh)
|
||||
│ └─ Wraps in Antigravity envelope
|
||||
│ ├─ Maps friendly model names → backend model names
|
||||
│ └─ Wraps in Antigravity envelope {project, model, request}
|
||||
│
|
||||
▼
|
||||
cloudcode-pa.googleapis.com (Google's internal Code Assist API)
|
||||
cloudcode-pa.googleapis.com
|
||||
│
|
||||
▼
|
||||
Gemini / Claude models
|
||||
Gemini / Claude models → Response unwrapped → OpenAI format → Your client
|
||||
```
|
||||
|
||||
The proxy:
|
||||
1. Reads the OAuth token from `~/.gemini/antigravity-cli/antigravity-oauth-token`
|
||||
2. Refreshes it automatically via `oauth2.googleapis.com` when expired
|
||||
3. Discovers your Cloud Code Assist project ID via `v1internal:loadCodeAssist`
|
||||
4. Wraps each request in the Antigravity envelope (`{project, model, request, requestType}`)
|
||||
5. Forwards to `v1internal:generateContent` (or `streamGenerateContent`)
|
||||
6. Unwraps the response and converts back to OpenAI format
|
||||
<details>
|
||||
<summary><b>Technical details</b></summary>
|
||||
|
||||
1. Reads OAuth token from `~/.gemini/antigravity-cli/antigravity-oauth-token`
|
||||
2. Refreshes expired access tokens via `oauth2.googleapis.com/token`
|
||||
3. Discovers Cloud Code Assist project ID via `v1internal:loadCodeAssist`
|
||||
4. Wraps each request in the Antigravity envelope: `{project, model, request, requestType, userAgent, requestId}`
|
||||
5. Forwards to `v1internal:generateContent` or `v1internal:streamGenerateContent?alt=sse`
|
||||
6. Unwraps the `{response: {...}}` envelope
|
||||
7. Converts Gemini response → OpenAI format (choices, message, usage)
|
||||
8. For tool calls, encodes Gemini's `functionCall.id` + `thoughtSignature` into OpenAI `tool_call.id` for round-tripping
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Adding or Updating Models
|
||||
|
||||
Edit `MODEL_MAP` at the top of `antigravity_proxy.py`:
|
||||
|
||||
```python
|
||||
MODEL_MAP = {
|
||||
"gemini-3.5-flash": ("gemini-3.5-flash-low", None),
|
||||
# "friendly-name": ("backend-name", thinking_level),
|
||||
# thinking_level: "low", "high", or None
|
||||
}
|
||||
```
|
||||
|
||||
Restart the proxy after editing.
|
||||
|
||||
---
|
||||
|
||||
@@ -294,34 +391,50 @@ The proxy:
|
||||
|
||||
- Python 3.10+
|
||||
- Antigravity CLI (`agy`) installed and authenticated
|
||||
- No pip dependencies — stdlib only
|
||||
- No pip dependencies
|
||||
|
||||
---
|
||||
|
||||
## FAQ
|
||||
|
||||
**Is this legal?**
|
||||
<details>
|
||||
<summary><b>Is this legal to use?</b></summary>
|
||||
|
||||
The proxy uses the same OAuth token and API endpoints that the Antigravity CLI itself uses. It does not bypass authentication or payment — you still need a valid Google account with Antigravity access. Multiple similar projects exist on GitHub. That said, Google's terms of service may restrict programmatic API access. Use at your own discretion.
|
||||
The proxy uses the same OAuth token and API endpoints that the Antigravity CLI itself uses. It does not bypass authentication — you need a valid Google account with Antigravity access. Multiple similar projects exist publicly on GitHub. However, Google's terms of service may restrict programmatic API access. Use at your own discretion.
|
||||
</details>
|
||||
|
||||
**Does it support streaming?**
|
||||
<details>
|
||||
<summary><b>Does it support streaming?</b></summary>
|
||||
|
||||
Yes. Both SSE streaming (`stream: true`) on the OpenAI endpoint and the native Gemini stream endpoint.
|
||||
Yes. SSE streaming (`"stream": true`) on the OpenAI endpoint, and the native Gemini stream endpoint.
|
||||
</details>
|
||||
|
||||
**Can I use it with images?**
|
||||
<details>
|
||||
<summary><b>Can I send images?</b></summary>
|
||||
|
||||
Yes, through the native Gemini passthrough endpoint (`/v1beta/models/{model}:generateContent`). Send `inline_data` with base64-encoded images, exactly like Google's API. The OpenAI chat endpoint does not currently support image inputs.
|
||||
Yes, through the native Gemini passthrough endpoint (`/v1beta/models/{model}:generateContent`). Send `inline_data` with base64-encoded images, exactly like Google's API.
|
||||
</details>
|
||||
|
||||
**Is there a rate limit?**
|
||||
<details>
|
||||
<summary><b>Is there a rate limit?</b></summary>
|
||||
|
||||
Rate limits are determined by Google's Antigravity quota, not the proxy. The proxy itself is multithreaded and has no concurrency limit.
|
||||
Rate limits are determined by Google's Antigravity quota, not the proxy. The proxy itself is multithreaded with no concurrency limit.
|
||||
</details>
|
||||
|
||||
**Does the token expire?**
|
||||
<details>
|
||||
<summary><b>Does the token expire?</b></summary>
|
||||
|
||||
Yes, the OAuth access token expires (~1 hour). The proxy auto-refreshes it using the refresh token. The refresh token itself can expire if unused for extended periods — re-run `agy` if that happens.
|
||||
The OAuth access token expires (~1 hour). The proxy auto-refreshes it. The refresh token can expire if unused for extended periods — re-run `agy` if that happens.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Can I bind to 0.0.0.0?</b></summary>
|
||||
|
||||
Yes, but **the proxy has no authentication layer**. Anyone who can reach it can use your Antigravity quota. Only bind to a non-localhost address if you understand the risk.
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
[MIT](LICENSE)
|
||||
Reference in new issue
Block a user