mirror of
https://github.com/NoeFabris/opencode-antigravity-auth.git
synced 2026-05-13 15:46:05 +00:00
feat: add legacy Gemini 3 model support for Antigravity quota and implement E2E test suite
This commit is contained in:
89
README.md
89
README.md
@@ -107,6 +107,21 @@ Create `~/.config/opencode/opencode.json`:
|
||||
"limit": { "context": 1048576, "output": 65536 },
|
||||
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
|
||||
},
|
||||
"gemini-3-pro-low": {
|
||||
"name": "Gemini 3 Pro Low (Antigravity)",
|
||||
"limit": { "context": 1048576, "output": 65535 },
|
||||
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
|
||||
},
|
||||
"gemini-3-pro-high": {
|
||||
"name": "Gemini 3 Pro High (Antigravity)",
|
||||
"limit": { "context": 1048576, "output": 65535 },
|
||||
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
|
||||
},
|
||||
"gemini-3-flash": {
|
||||
"name": "Gemini 3 Flash (Antigravity)",
|
||||
"limit": { "context": 1048576, "output": 65536 },
|
||||
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
|
||||
},
|
||||
"antigravity-claude-sonnet-4-5": {
|
||||
"name": "Claude Sonnet 4.5 (Antigravity)",
|
||||
"limit": { "context": 200000, "output": 64000 },
|
||||
@@ -141,7 +156,7 @@ Create `~/.config/opencode/opencode.json`:
|
||||
"name": "Claude Opus 4.5 Think High (Antigravity)",
|
||||
"limit": { "context": 200000, "output": 64000 },
|
||||
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,17 +190,18 @@ Models with `antigravity-` prefix use Antigravity quota:
|
||||
| `google/antigravity-claude-opus-4-5-thinking-medium` | Opus with 16K thinking budget |
|
||||
| `google/antigravity-claude-opus-4-5-thinking-high` | Opus with 32K thinking budget |
|
||||
|
||||
> **Backward compatibility:** Old model names (`gemini-3-pro-low`, `gemini-3-pro-high`, `gemini-3-flash`) still work as a fallback. However, you should update to the `antigravity-` prefix for stability. See [Migration Guide](#migration-guide-v127).
|
||||
|
||||
### Gemini CLI Quota
|
||||
|
||||
Models without `antigravity-` prefix use Gemini CLI quota:
|
||||
Models with `-preview` suffix use Gemini CLI quota:
|
||||
|
||||
| Model | Description |
|
||||
|-------|-------------|
|
||||
| `google/gemini-2.5-flash` | Gemini 2.5 Flash |
|
||||
| `google/gemini-2.5-pro` | Gemini 2.5 Pro |
|
||||
| `google/gemini-3-flash` | Gemini 3 Flash |
|
||||
| `google/gemini-3-pro-low` | Gemini 3 Pro with low thinking |
|
||||
| `google/gemini-3-pro-high` | Gemini 3 Pro with high thinking |
|
||||
| `google/gemini-3-flash-preview` | Gemini 3 Flash (preview) |
|
||||
| `google/gemini-3-pro-preview` | Gemini 3 Pro (preview) |
|
||||
|
||||
<details>
|
||||
<summary><b>Full models configuration</b></summary>
|
||||
@@ -212,6 +228,21 @@ Models without `antigravity-` prefix use Gemini CLI quota:
|
||||
"limit": { "context": 1048576, "output": 65536 },
|
||||
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
|
||||
},
|
||||
"gemini-3-pro-low": {
|
||||
"name": "Gemini 3 Pro Low (Antigravity)",
|
||||
"limit": { "context": 1048576, "output": 65535 },
|
||||
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
|
||||
},
|
||||
"gemini-3-pro-high": {
|
||||
"name": "Gemini 3 Pro High (Antigravity)",
|
||||
"limit": { "context": 1048576, "output": 65535 },
|
||||
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
|
||||
},
|
||||
"gemini-3-flash": {
|
||||
"name": "Gemini 3 Flash (Antigravity)",
|
||||
"limit": { "context": 1048576, "output": 65536 },
|
||||
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
|
||||
},
|
||||
"antigravity-claude-sonnet-4-5": {
|
||||
"name": "Claude Sonnet 4.5 (Antigravity)",
|
||||
"limit": { "context": 200000, "output": 64000 },
|
||||
@@ -247,6 +278,26 @@ Models without `antigravity-` prefix use Gemini CLI quota:
|
||||
"limit": { "context": 200000, "output": 64000 },
|
||||
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
|
||||
},
|
||||
"gemini-2.5-flash": {
|
||||
"name": "Gemini 2.5 Flash (CLI)",
|
||||
"limit": { "context": 1048576, "output": 65536 },
|
||||
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
|
||||
},
|
||||
"gemini-2.5-pro": {
|
||||
"name": "Gemini 2.5 Pro (CLI)",
|
||||
"limit": { "context": 1048576, "output": 65536 },
|
||||
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
|
||||
},
|
||||
"gemini-3-flash-preview": {
|
||||
"name": "Gemini 3 Flash Preview (CLI)",
|
||||
"limit": { "context": 1048576, "output": 65536 },
|
||||
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
|
||||
},
|
||||
"gemini-3-pro-preview": {
|
||||
"name": "Gemini 3 Pro Preview (CLI)",
|
||||
"limit": { "context": 1048576, "output": 65535 },
|
||||
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -415,14 +466,30 @@ When spawning parallel subagents, multiple processes may select the same account
|
||||
|
||||
If upgrading from v1.2.6 or earlier:
|
||||
|
||||
### Breaking Changes
|
||||
### What Changed
|
||||
|
||||
| Old (v1.2.6) | New (v1.2.7+) |
|
||||
|--------------|---------------|
|
||||
| `gemini-3-pro` | `google/antigravity-gemini-3-pro-low` |
|
||||
| `claude-sonnet-4-5` | `google/antigravity-claude-sonnet-4-5` |
|
||||
v1.2.7+ uses explicit prefixes to distinguish quota sources:
|
||||
|
||||
### Step 1: Clear Old Tokens (Optional do this if you have issue cannot call models)
|
||||
| Model Type | New Name (Recommended) | Old Name (Still Works) |
|
||||
|------------|------------------------|------------------------|
|
||||
| Gemini 3 (Antigravity) | `antigravity-gemini-3-pro-low` | `gemini-3-pro-low` |
|
||||
| Gemini 3 (Antigravity) | `antigravity-gemini-3-pro-high` | `gemini-3-pro-high` |
|
||||
| Gemini 3 (Antigravity) | `antigravity-gemini-3-flash` | `gemini-3-flash` |
|
||||
| Gemini 3 (CLI) | `gemini-3-pro-preview` | N/A |
|
||||
| Claude | `antigravity-claude-sonnet-4-5` | `claude-sonnet-4-5` |
|
||||
|
||||
### Action Required
|
||||
|
||||
**Update your config to use `antigravity-` prefix:**
|
||||
|
||||
```diff
|
||||
- "gemini-3-pro-low": { ... }
|
||||
+ "antigravity-gemini-3-pro-low": { ... }
|
||||
```
|
||||
|
||||
> **Why update?** Old names work now as a fallback, but this depends on Gemini CLI using `-preview` suffix. If Google removes `-preview` in the future, old names may route to the wrong quota. The `antigravity-` prefix is explicit and stable.
|
||||
|
||||
### Step 1: Clear Old Tokens (Optional - do this if you have issues calling models)
|
||||
|
||||
```bash
|
||||
rm -rf ~/.config/opencode/antigravity-account.json
|
||||
|
||||
171
script/test-gemini-cli-e2e.sh
Executable file
171
script/test-gemini-cli-e2e.sh
Executable file
@@ -0,0 +1,171 @@
|
||||
#!/bin/bash
|
||||
# Gemini CLI E2E Test Suite
|
||||
# Tests gemini-cli models routing through cloudcode-pa.googleapis.com/v1internal
|
||||
#
|
||||
# Models tested:
|
||||
# 1. google/gemini-2.5-pro
|
||||
# 2. google/gemini-2.5-flash
|
||||
# 3. google/gemini-3-pro-preview
|
||||
# 4. google/gemini-3-flash-preview
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
SKIP=0
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[0;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
log_pass() { echo -e "${GREEN}✓ PASS${NC}: $1"; ((PASS++)); }
|
||||
log_fail() { echo -e "${RED}✗ FAIL${NC}: $1"; ((FAIL++)); }
|
||||
log_skip() { echo -e "${YELLOW}○ SKIP${NC}: $1"; ((SKIP++)); }
|
||||
log_info() { echo -e " ${BLUE}→${NC} $1"; }
|
||||
|
||||
# Check for common errors
|
||||
check_auth_error() {
|
||||
grep -qiE "insufficient.*scope|authentication|unauthorized|403|401" "$1" 2>/dev/null && return 0 || return 1
|
||||
}
|
||||
|
||||
check_quota_error() {
|
||||
grep -qiE "quota|rate.limit|429|resource.exhausted" "$1" 2>/dev/null && return 0 || return 1
|
||||
}
|
||||
|
||||
check_model_error() {
|
||||
grep -qiE "model.*not.found|invalid.*model|404" "$1" 2>/dev/null && return 0 || return 1
|
||||
}
|
||||
|
||||
# Test a single model
|
||||
test_model() {
|
||||
local model="$1"
|
||||
local test_name="$2"
|
||||
local log_file="/tmp/gemini-cli-e2e-${test_name}.log"
|
||||
|
||||
log_info "Testing $model..."
|
||||
|
||||
# Run opencode with a simple prompt
|
||||
timeout 60 opencode run -m "$model" \
|
||||
"Reply with exactly: GEMINI_CLI_OK" \
|
||||
2>&1 > "$log_file" || true
|
||||
|
||||
# Check for various error conditions
|
||||
if check_auth_error "$log_file"; then
|
||||
log_fail "$test_name - Authentication/scope error (check OAuth scopes)"
|
||||
log_info "This likely means routing to wrong endpoint"
|
||||
return 1
|
||||
elif check_quota_error "$log_file"; then
|
||||
log_skip "$test_name - Quota exhausted (not a routing issue)"
|
||||
return 0
|
||||
elif check_model_error "$log_file"; then
|
||||
log_fail "$test_name - Model not found"
|
||||
return 1
|
||||
elif grep -qi "GEMINI_CLI_OK\|working\|ok\|hello" "$log_file"; then
|
||||
log_pass "$test_name"
|
||||
return 0
|
||||
elif grep -qi "error\|exception\|failed" "$log_file"; then
|
||||
log_fail "$test_name - Unknown error"
|
||||
log_info "Check $log_file for details"
|
||||
return 1
|
||||
else
|
||||
# No obvious error, assume success
|
||||
log_pass "$test_name"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
echo "════════════════════════════════════════════════════════════"
|
||||
echo " Gemini CLI E2E Test Suite"
|
||||
echo " Testing cloudcode-pa.googleapis.com/v1internal routing"
|
||||
echo "════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
echo "Test 1: google/gemini-2.5-flash"
|
||||
test_model "google/gemini-2.5-flash" "gemini-2.5-flash" || true
|
||||
echo ""
|
||||
|
||||
echo "Test 2: google/gemini-2.5-pro"
|
||||
test_model "google/gemini-2.5-pro" "gemini-2.5-pro" || true
|
||||
echo ""
|
||||
|
||||
echo "Test 3: google/gemini-3-flash-preview"
|
||||
test_model "google/gemini-3-flash-preview" "gemini-3-flash-preview" || true
|
||||
echo ""
|
||||
|
||||
echo "Test 4: google/gemini-3-pro-preview"
|
||||
test_model "google/gemini-3-pro-preview" "gemini-3-pro-preview" || true
|
||||
echo ""
|
||||
|
||||
# Test 5: Cross-model session (gemini-cli → antigravity)
|
||||
echo "Test 5: Cross-model session (gemini-cli → antigravity-gemini)"
|
||||
log_info "Step 1: Start with gemini-2.5-flash..."
|
||||
timeout 60 opencode run -m google/gemini-2.5-flash \
|
||||
"Say: SESSION_START" \
|
||||
2>&1 > /tmp/gemini-cli-e2e-cross-s1.log || true
|
||||
|
||||
# Get session ID
|
||||
sleep 1
|
||||
SID=$(opencode session list 2>/dev/null | grep -oP 'ses_[a-zA-Z0-9]+' | head -1 || true)
|
||||
|
||||
if [ -z "$SID" ]; then
|
||||
log_fail "Test 5 - No session ID created"
|
||||
else
|
||||
log_info "Session: $SID"
|
||||
log_info "Step 2: Switch to antigravity-gemini-3-flash..."
|
||||
timeout 60 opencode run -s "$SID" -m google/antigravity-gemini-3-flash \
|
||||
"Say: SESSION_CONTINUE" \
|
||||
2>&1 > /tmp/gemini-cli-e2e-cross-s2.log || true
|
||||
|
||||
if check_auth_error /tmp/gemini-cli-e2e-cross-s2.log; then
|
||||
log_fail "Test 5 - Auth error on cross-model switch"
|
||||
else
|
||||
log_pass "Test 5 - Cross-model session (gemini-cli → antigravity)"
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 6: Reverse cross-model (antigravity → gemini-cli)
|
||||
echo "Test 6: Cross-model session (antigravity → gemini-cli)"
|
||||
log_info "Step 1: Start with antigravity-gemini-3-pro-low..."
|
||||
timeout 60 opencode run -m google/antigravity-gemini-3-pro-low \
|
||||
"Say: ANTIGRAVITY_START" \
|
||||
2>&1 > /tmp/gemini-cli-e2e-reverse-s1.log || true
|
||||
|
||||
sleep 1
|
||||
SID=$(opencode session list 2>/dev/null | grep -oP 'ses_[a-zA-Z0-9]+' | head -1 || true)
|
||||
|
||||
if [ -z "$SID" ]; then
|
||||
log_fail "Test 6 - No session ID created"
|
||||
else
|
||||
log_info "Session: $SID"
|
||||
log_info "Step 2: Switch to gemini-2.5-pro..."
|
||||
timeout 60 opencode run -s "$SID" -m google/gemini-2.5-pro \
|
||||
"Say: GEMINI_CLI_CONTINUE" \
|
||||
2>&1 > /tmp/gemini-cli-e2e-reverse-s2.log || true
|
||||
|
||||
if check_auth_error /tmp/gemini-cli-e2e-reverse-s2.log; then
|
||||
log_fail "Test 6 - Auth error on reverse cross-model switch"
|
||||
else
|
||||
log_pass "Test 6 - Cross-model session (antigravity → gemini-cli)"
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "════════════════════════════════════════════════════════════"
|
||||
echo " Test Results Summary"
|
||||
echo "════════════════════════════════════════════════════════════"
|
||||
echo -e " ${GREEN}Passed${NC}: $PASS"
|
||||
echo -e " ${RED}Failed${NC}: $FAIL"
|
||||
echo -e " ${YELLOW}Skipped${NC}: $SKIP"
|
||||
echo ""
|
||||
|
||||
if [ $FAIL -gt 0 ]; then
|
||||
echo -e "${RED}Some tests failed!${NC}"
|
||||
echo "Log files: /tmp/gemini-cli-e2e-*.log"
|
||||
exit 1
|
||||
else
|
||||
echo -e "${GREEN}All Gemini CLI tests passed!${NC}"
|
||||
exit 0
|
||||
fi
|
||||
@@ -71,6 +71,26 @@ const QUOTA_PREFIX_REGEX = /^antigravity-/i;
|
||||
*/
|
||||
const ANTIGRAVITY_ONLY_MODELS = /^(claude|gpt)/i;
|
||||
|
||||
/**
|
||||
* Legacy Gemini 3 model names that should route to Antigravity quota.
|
||||
*
|
||||
* Backward compatibility: Since Gemini CLI now uses -preview suffix
|
||||
* (gemini-3-pro-preview, gemini-3-flash-preview), old model names
|
||||
* without -preview can safely route to Antigravity quota.
|
||||
*
|
||||
* Matches:
|
||||
* - gemini-3-pro-low, gemini-3-pro-high
|
||||
* - gemini-3-flash, gemini-3-flash-low, gemini-3-flash-medium, gemini-3-flash-high
|
||||
*
|
||||
* Does NOT match:
|
||||
* - gemini-3-pro-preview (Gemini CLI)
|
||||
* - gemini-3-flash-preview (Gemini CLI)
|
||||
* - antigravity-gemini-3-* (already handled by prefix)
|
||||
*
|
||||
* WARNING: This may break if Google/Opencode removes the -preview suffix.
|
||||
*/
|
||||
const LEGACY_ANTIGRAVITY_GEMINI3 = /^gemini-3-(pro-(low|high)|flash(-low|-medium|-high)?)$/i;
|
||||
|
||||
/**
|
||||
* Models that support thinking tier suffixes.
|
||||
* Only these models should have -low/-medium/-high stripped as thinking tiers.
|
||||
@@ -129,17 +149,20 @@ function isThinkingCapableModel(model: string): boolean {
|
||||
/**
|
||||
* Resolves a model name with optional tier suffix and quota prefix to its actual API model name
|
||||
* and corresponding thinking configuration.
|
||||
*
|
||||
*
|
||||
* Quota routing:
|
||||
* - "antigravity-" prefix → Antigravity quota
|
||||
* - Claude/GPT models → Antigravity quota (auto, these only exist on Antigravity)
|
||||
* - Legacy Gemini 3 names (gemini-3-pro-low, gemini-3-flash, etc.) → Antigravity quota (backward compat)
|
||||
* - Other models → Gemini CLI quota (default)
|
||||
*
|
||||
*
|
||||
* Examples:
|
||||
* - "gemini-2.5-flash" → { actualModel: "gemini-2.5-flash", quotaPreference: "gemini-cli" }
|
||||
* - "antigravity-gemini-3-pro-high" → { actualModel: "gemini-3-pro", thinkingLevel: "high", quotaPreference: "antigravity" }
|
||||
* - "claude-sonnet-4-5-thinking-medium" → { actualModel: "claude-sonnet-4-5-thinking", thinkingBudget: 16384, quotaPreference: "antigravity" }
|
||||
*
|
||||
* - "gemini-2.5-flash" → { quotaPreference: "gemini-cli" }
|
||||
* - "gemini-3-pro-preview" → { quotaPreference: "gemini-cli" } (Gemini CLI uses -preview)
|
||||
* - "gemini-3-pro-low" → { quotaPreference: "antigravity" } (legacy name, backward compat)
|
||||
* - "antigravity-gemini-3-pro-high" → { quotaPreference: "antigravity" } (explicit prefix)
|
||||
* - "claude-sonnet-4-5-thinking-medium" → { quotaPreference: "antigravity" } (Claude only on Antigravity)
|
||||
*
|
||||
* @param requestedModel - The model name from the request
|
||||
* @returns Resolved model with thinking configuration
|
||||
*/
|
||||
@@ -151,7 +174,8 @@ export function resolveModelWithTier(requestedModel: string): ResolvedModel {
|
||||
const baseName = tier ? modelWithoutQuota.replace(TIER_REGEX, "") : modelWithoutQuota;
|
||||
|
||||
const isAntigravityOnly = ANTIGRAVITY_ONLY_MODELS.test(modelWithoutQuota);
|
||||
const quotaPreference = isAntigravity || isAntigravityOnly ? "antigravity" : "gemini-cli";
|
||||
const isLegacyAntigravity = LEGACY_ANTIGRAVITY_GEMINI3.test(modelWithoutQuota);
|
||||
const quotaPreference = isAntigravity || isAntigravityOnly || isLegacyAntigravity ? "antigravity" : "gemini-cli";
|
||||
const explicitQuota = isAntigravity;
|
||||
|
||||
const isGemini3 = modelWithoutQuota.toLowerCase().startsWith("gemini-3");
|
||||
|
||||
Reference in New Issue
Block a user