Files
opencode-antigravity-auth/docs/ANTIGRAVITY_API_SPEC.md
2026-02-18 20:18:21 +00:00

635 lines
16 KiB
Markdown

# Antigravity Unified Gateway API Specification
**Version:** 1.0
**Last Updated:** December 13, 2025
**Status:** Verified by Direct API Testing
---
## Overview
Antigravity is Google's **Unified Gateway API** for accessing multiple AI models (Claude, Gemini, GPT-OSS) through a single, consistent Gemini-style interface. It is NOT the same as Vertex AI's direct model APIs.
### Key Characteristics
- **Single API format** for all models (Gemini-style)
- **Project-based access** via Google Cloud authentication
- **Internal routing** to model backends (Vertex AI for Claude, Gemini API for Gemini)
- **Unified response format** (`candidates[]` structure for all models)
---
## Endpoints
| Environment | URL | Status |
|-------------|-----|--------|
| **Daily (Sandbox)** | `https://daily-cloudcode-pa.sandbox.googleapis.com` | ✅ Active |
| **Production** | `https://cloudcode-pa.googleapis.com` | ✅ Active |
| **Autopush (Sandbox)** | `https://autopush-cloudcode-pa.sandbox.googleapis.com` | ❌ Unavailable |
### API Actions
| Action | Path | Description |
|--------|------|-------------|
| Generate Content | `/v1internal:generateContent` | Non-streaming request |
| Stream Generate | `/v1internal:streamGenerateContent?alt=sse` | Streaming (SSE) request |
| Load Code Assist | `/v1internal:loadCodeAssist` | Project discovery |
| Onboard User | `/v1internal:onboardUser` | User onboarding |
---
## Authentication
### OAuth 2.0 Setup
```
Authorization URL: https://accounts.google.com/o/oauth2/auth
Token URL: https://oauth2.googleapis.com/token
```
### Required Scopes
```
https://www.googleapis.com/auth/cloud-platform
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/cclog
https://www.googleapis.com/auth/experimentsandconfigs
```
### Required Headers
```http
Authorization: Bearer {access_token}
Content-Type: application/json
User-Agent: antigravity/1.15.8 windows/amd64
X-Goog-Api-Client: google-cloud-sdk vscode_cloudshelleditor/0.1
Client-Metadata: {"ideType":"ANTIGRAVITY","platform":"MACOS","pluginType":"GEMINI"}
```
For streaming requests, also include:
```http
Accept: text/event-stream
```
---
## Available Models
| Model Name | Model ID | Type | Status |
|------------|----------|------|--------|
| Claude Sonnet 4.6 | `claude-sonnet-4-6` | Anthropic | ✅ Verified |
| Claude Opus 4.6 Thinking | `claude-opus-4-6-thinking` | Anthropic | ✅ Verified |
| Gemini 3 Pro High | `gemini-3-pro-high` | Google | ✅ Verified |
| Gemini 3 Pro Low | `gemini-3-pro-low` | Google | ✅ Verified |
| GPT-OSS 120B Medium | `gpt-oss-120b-medium` | Other | ✅ Verified |
---
## Request Format
### Basic Structure
```json
{
"project": "{project_id}",
"model": "{model_id}",
"request": {
"contents": [...],
"generationConfig": {...},
"systemInstruction": {...},
"tools": [...]
},
"userAgent": "antigravity",
"requestId": "{unique_id}"
}
```
### Contents Array (REQUIRED)
**⚠️ IMPORTANT: Must use Gemini-style format. Anthropic-style `messages` array is NOT supported.**
```json
{
"contents": [
{
"role": "user",
"parts": [
{ "text": "Your message here" }
]
},
{
"role": "model",
"parts": [
{ "text": "Assistant response" }
]
}
]
}
```
#### Role Values
- `user` - Human/user messages
- `model` - Assistant responses (NOT `assistant`)
### Generation Config
```json
{
"generationConfig": {
"maxOutputTokens": 1000,
"temperature": 0.7,
"topP": 0.95,
"topK": 40,
"stopSequences": ["STOP"],
"thinkingConfig": {
"thinkingBudget": 8000,
"includeThoughts": true
}
}
}
```
| Field | Type | Description |
|-------|------|-------------|
| `maxOutputTokens` | number | Maximum tokens in response |
| `temperature` | number | Randomness (0.0 - 2.0) |
| `topP` | number | Nucleus sampling threshold |
| `topK` | number | Top-K sampling |
| `stopSequences` | string[] | Stop generation triggers |
| `thinkingConfig` | object | Extended thinking config |
### System Instructions
**⚠️ Must be an object with `parts`, NOT a plain string.**
```json
// ✅ CORRECT
{
"systemInstruction": {
"parts": [
{ "text": "You are a helpful assistant." }
]
}
}
// ❌ WRONG - Will return 400 error
{
"systemInstruction": "You are a helpful assistant."
}
```
### Tools / Function Calling
```json
{
"tools": [
{
"functionDeclarations": [
{
"name": "get_weather",
"description": "Get weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name"
}
},
"required": ["location"]
}
}
]
}
]
}
```
### Google Search Grounding
Gemini models support Google Search grounding, but **it cannot be combined with function declarations** in the same request. This plugin implements a dedicated `google_search` tool that makes separate API calls.
#### How the `google_search` Tool Works
The model can call `google_search(query, urls?, thinking?)` which:
1. Makes a **separate API call** to Antigravity with only `{ googleSearch: {} }` (no function declarations)
2. Parses the `groundingMetadata` from the response
3. Returns formatted markdown with sources and citations
**Tool Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `query` | string | ✅ | The search query or question |
| `urls` | string[] | ❌ | URLs to analyze (adds `urlContext` tool) |
| `thinking` | boolean | ❌ | Enable deep thinking (default: true) |
**Example Response:**
```markdown
## Search Results
Spain won Euro 2024, defeating England 2-1 in the final...
### Sources
- [UEFA Euro 2024](https://uefa.com/...)
- [Al Jazeera](https://aljazeera.com/...)
### Search Queries Used
- "UEFA Euro 2024 winner"
```
#### Raw API Format (for reference)
The underlying API uses these tool formats:
**New API (Gemini 2.0+ / Gemini 3):**
```json
{
"tools": [
{ "googleSearch": {} }
]
}
```
**Legacy API (Gemini 1.5 only - deprecated):**
```json
{
"tools": [
{
"googleSearchRetrieval": {
"dynamicRetrievalConfig": {
"mode": "MODE_DYNAMIC",
"dynamicThreshold": 0.3
}
}
}
]
}
```
**Response includes `groundingMetadata`:**
```json
{
"groundingMetadata": {
"webSearchQueries": ["query1", "query2"],
"searchEntryPoint": { "renderedContent": "..." },
"groundingChunks": [{ "web": { "uri": "...", "title": "..." } }],
"groundingSupports": [{ "segment": {...}, "groundingChunkIndices": [...] }]
}
}
```
> **Important:** `googleSearch` and `urlContext` tools **cannot be combined with `functionDeclarations`** in the same request. This is why the plugin uses a separate API call.
```
### Function Name Rules
| Rule | Description |
|------|-------------|
| First character | Must be a letter (a-z, A-Z) or underscore (_) |
| Allowed characters | `a-zA-Z0-9`, underscores (`_`), dots (`.`), colons (`:`), dashes (`-`) |
| Max length | 64 characters |
| Not allowed | Slashes (`/`), spaces, other special characters |
**Examples:**
- ✅ `get_weather` - Valid
- ✅ `mcp:mongodb.query` - Valid (colons and dots allowed)
- ✅ `read-file` - Valid (dashes allowed)
- ❌ `mcp/query` - Invalid (slashes not allowed)
- ❌ `123_tool` - Invalid (must start with letter or underscore)
### JSON Schema Support
| Feature | Status | Notes |
|---------|--------|-------|
| `type` | ✅ Supported | `object`, `string`, `number`, `integer`, `boolean`, `array` |
| `properties` | ✅ Supported | Object properties |
| `required` | ✅ Supported | Required fields array |
| `description` | ✅ Supported | Field descriptions |
| `enum` | ✅ Supported | Enumerated values |
| `items` | ✅ Supported | Array item schema |
| `anyOf` | ✅ Supported | Converted to `any_of` internally |
| `allOf` | ✅ Supported | Converted to `all_of` internally |
| `oneOf` | ✅ Supported | Converted to `one_of` internally |
| `additionalProperties` | ✅ Supported | Additional properties schema |
| `const` | ❌ NOT Supported | Use `enum: [value]` instead |
| `$ref` | ❌ NOT Supported | Inline the schema instead |
| `$defs` / `definitions` | ❌ NOT Supported | Inline definitions instead |
| `$schema` | ❌ NOT Supported | Strip from schema |
| `$id` | ❌ NOT Supported | Strip from schema |
| `default` | ❌ NOT Supported | Strip from schema |
| `examples` | ❌ NOT Supported | Strip from schema |
| `title` (nested) | ⚠️ Caution | May cause issues in nested objects |
**⚠️ IMPORTANT:** The following features will cause a 400 error if sent to the API:
- `const` - Convert to `enum: [value]` instead
- `$ref` / `$defs` - Inline the schema definitions
- `$schema` / `$id` - Strip these metadata fields
- `default` / `examples` - Strip these documentation fields
```json
// ❌ WRONG - Will return 400 error
{ "type": { "const": "email" } }
// ✅ CORRECT - Use enum instead
{ "type": { "enum": ["email"] } }
```
**Note:** The plugin automatically handles these conversions via the `schema-transform.ts` module.
---
## Response Format
### Non-Streaming Response
```json
{
"response": {
"candidates": [
{
"content": {
"role": "model",
"parts": [
{ "text": "Response text here" }
]
},
"finishReason": "STOP"
}
],
"usageMetadata": {
"promptTokenCount": 16,
"candidatesTokenCount": 4,
"totalTokenCount": 20
},
"modelVersion": "claude-sonnet-4-6",
"responseId": "msg_vrtx_..."
},
"traceId": "abc123..."
}
```
### Streaming Response (SSE)
Content-Type: `text/event-stream`
```
data: {"response": {"candidates": [{"content": {"role": "model", "parts": [{"text": "Hello"}]}}], "usageMetadata": {...}, "modelVersion": "...", "responseId": "..."}, "traceId": "..."}
data: {"response": {"candidates": [{"content": {"role": "model", "parts": [{"text": " world"}]}, "finishReason": "STOP"}], "usageMetadata": {...}}, "traceId": "..."}
```
### Response Fields
| Field | Description |
|-------|-------------|
| `response.candidates` | Array of response candidates |
| `response.candidates[].content.role` | Always `"model"` |
| `response.candidates[].content.parts` | Array of content parts |
| `response.candidates[].finishReason` | `STOP`, `MAX_TOKENS`, `OTHER` |
| `response.usageMetadata.promptTokenCount` | Input tokens |
| `response.usageMetadata.candidatesTokenCount` | Output tokens |
| `response.usageMetadata.totalTokenCount` | Total tokens |
| `response.usageMetadata.thoughtsTokenCount` | Thinking tokens (Gemini) |
| `response.modelVersion` | Actual model used |
| `response.responseId` | Request ID (format varies by model) |
| `traceId` | Trace ID for debugging |
### Response ID Formats
| Model Type | Format | Example |
|------------|--------|---------|
| Claude | `msg_vrtx_...` | `msg_vrtx_01UDKZG8PWPj9mjajje8d7u7` |
| Gemini | Base64-like | `ypM9abPqFKWl0-kPvamgqQw` |
| GPT-OSS | Base64-like | `y5M9aZaSKq6z2roPoJ7pEA` |
---
## Function Call Response
When the model wants to call a function:
```json
{
"response": {
"candidates": [
{
"content": {
"role": "model",
"parts": [
{
"functionCall": {
"name": "get_weather",
"args": {
"location": "Paris"
},
"id": "toolu_vrtx_01PDbPTJgBJ3AJ8BCnSXvUqk"
}
}
]
},
"finishReason": "OTHER"
}
]
}
}
```
### Providing Function Results
```json
{
"contents": [
{ "role": "user", "parts": [{ "text": "What's the weather?" }] },
{ "role": "model", "parts": [{ "functionCall": { "name": "get_weather", "args": {...}, "id": "..." } }] },
{ "role": "user", "parts": [{ "functionResponse": { "name": "get_weather", "id": "...", "response": { "temperature": "22C" } } }] }
]
}
```
---
## Thinking / Extended Reasoning
### Thinking Config
For thinking-capable models (`*-thinking`), use:
```json
{
"generationConfig": {
"maxOutputTokens": 10000,
"thinkingConfig": {
"thinkingBudget": 8000,
"includeThoughts": true
}
}
}
```
**⚠️ IMPORTANT: `maxOutputTokens` must be GREATER than `thinkingBudget`**
### Thinking Response (Gemini)
Gemini models return thinking with signatures:
```json
{
"parts": [
{
"thoughtSignature": "ErADCq0DAXLI2nx...",
"text": "Let me think about this..."
},
{
"text": "The answer is..."
}
]
}
```
### Thinking Response (Claude)
Claude thinking models may include `thought: true` parts:
```json
{
"parts": [
{
"thought": true,
"text": "Reasoning process...",
"thoughtSignature": "..."
},
{
"text": "Final answer..."
}
]
}
```
---
## Error Responses
### Error Structure
```json
{
"error": {
"code": 400,
"message": "Error description",
"status": "INVALID_ARGUMENT",
"details": [...]
}
}
```
### Common Error Codes
| Code | Status | Description |
|------|--------|-------------|
| 400 | `INVALID_ARGUMENT` | Invalid request format |
| 401 | `UNAUTHENTICATED` | Invalid/expired token |
| 403 | `PERMISSION_DENIED` | No access to resource |
| 404 | `NOT_FOUND` | Model not found |
| 429 | `RESOURCE_EXHAUSTED` | Rate limit exceeded |
### Rate Limit Response
```json
{
"error": {
"code": 429,
"message": "You have exhausted your capacity on this model. Your quota will reset after 3s.",
"status": "RESOURCE_EXHAUSTED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.RetryInfo",
"retryDelay": "3.957525076s"
}
]
}
}
```
---
## NOT Supported
The following Anthropic/Vertex AI features are **NOT supported**:
| Feature | Error |
|---------|-------|
| `anthropic_version` | Unknown field |
| `messages` array | Unknown field |
| `max_tokens` | Unknown field |
| Plain string `systemInstruction` | Invalid value |
| `system_instruction` (snake_case at root) | Unknown field |
| JSON Schema `const` | Unknown field (use `enum: [value]`) |
| JSON Schema `$ref` | Not supported (inline instead) |
| JSON Schema `$defs` | Not supported (inline instead) |
| Tool names with `/` | Invalid (use `_` or `:` instead) |
| Tool names starting with digit | Invalid (must start with letter/underscore) |
---
## Complete Request Example
```json
{
"project": "my-project-id",
"model": "claude-sonnet-4-6",
"request": {
"contents": [
{
"role": "user",
"parts": [
{ "text": "Hello, how are you?" }
]
}
],
"systemInstruction": {
"parts": [
{ "text": "You are a helpful assistant." }
]
},
"generationConfig": {
"maxOutputTokens": 1000,
"temperature": 0.7
}
},
"userAgent": "antigravity",
"requestId": "agent-abc123"
}
```
---
## Response Headers
| Header | Description |
|--------|-------------|
| `x-cloudaicompanion-trace-id` | Trace ID for debugging |
| `server-timing` | Request duration |
---
## Comparison: Antigravity vs Vertex AI Anthropic
| Feature | Antigravity | Vertex AI Anthropic |
|---------|-------------|---------------------|
| Endpoint | `cloudcode-pa.googleapis.com` | `aiplatform.googleapis.com` |
| Request format | Gemini-style `contents` | Anthropic `messages` |
| `anthropic_version` | Not used | Required |
| Model names | Simple (`claude-sonnet-4-6`) | Versioned (`claude-4-5@date`) |
| Response format | `candidates[]` | Anthropic `content[]` |
| Multi-model support | Yes (Claude, Gemini, etc.) | Anthropic only |
---
## Changelog
- **2025-12-14**: Added function calling quirks, JSON Schema support matrix, tool name rules
- **2025-12-13**: Initial specification based on direct API testing