diff --git a/README.md b/README.md index dda426f..ff79986 100644 --- a/README.md +++ b/README.md @@ -112,11 +112,11 @@ opencode run "Hello" --model=google/antigravity-claude-opus-4-6-thinking --varia | Model | Variants | Notes | |-------|----------|-------| -| `antigravity-gemini-3-pro` | low, high | Gemini 3 Pro with thinking | | `antigravity-gemini-3.1-pro` | low, high | Gemini 3.1 Pro with thinking (rollout-dependent) | | `antigravity-gemini-3-flash` | minimal, low, medium, high | Gemini 3 Flash with thinking | | `antigravity-claude-sonnet-4-6` | — | Claude Sonnet 4.6 | -| `antigravity-claude-opus-4-6-thinking` | low, max | Claude Opus 4.6 with extended thinking | +| `antigravity-claude-sonnet-4-6-thinking` | low, medium, high | Claude Sonnet 4.6 with extended thinking | +| `antigravity-claude-opus-4-6-thinking` | low, medium, high, max | Claude Opus 4.6 with extended thinking | **Gemini CLI quota** (separate from Antigravity; used when `cli_first` is true or as fallback): @@ -125,7 +125,7 @@ opencode run "Hello" --model=google/antigravity-claude-opus-4-6-thinking --varia | `gemini-2.5-flash` | Gemini 2.5 Flash | | `gemini-2.5-pro` | Gemini 2.5 Pro | | `gemini-3-flash-preview` | Gemini 3 Flash (preview) | -| `gemini-3-pro-preview` | Gemini 3 Pro (preview) | +| `gemini-3-pro-preview` | Gemini 3 Pro Preview | | `gemini-3.1-pro-preview` | Gemini 3.1 Pro (preview, rollout-dependent) | | `gemini-3.1-pro-preview-customtools` | Gemini 3.1 Pro Preview Custom Tools (preview, rollout-dependent) | @@ -155,15 +155,6 @@ Add this to your `~/.config/opencode/opencode.json`: "provider": { "google": { "models": { - "antigravity-gemini-3-pro": { - "name": "Gemini 3 Pro (Antigravity)", - "limit": { "context": 1048576, "output": 65535 }, - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, - "variants": { - "low": { "thinkingLevel": "low" }, - "high": { "thinkingLevel": "high" } - } - }, "antigravity-gemini-3.1-pro": { "name": "Gemini 3.1 Pro (Antigravity)", "limit": { "context": 1048576, "output": 65535 }, @@ -189,13 +180,25 @@ Add this to your `~/.config/opencode/opencode.json`: "limit": { "context": 200000, "output": 64000 }, "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] } }, + "antigravity-claude-sonnet-4-6-thinking": { + "name": "Claude Sonnet 4.6 Thinking (Antigravity)", + "limit": { "context": 200000, "output": 64000 }, + "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "variants": { + "low": { "thinkingConfig": { "thinkingBudget": 8192 } }, + "medium": { "thinkingConfig": { "thinkingBudget": 16384 } }, + "high": { "thinkingConfig": { "thinkingBudget": 32768 } } + } + }, "antigravity-claude-opus-4-6-thinking": { "name": "Claude Opus 4.6 Thinking (Antigravity)", "limit": { "context": 200000, "output": 64000 }, "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, "variants": { "low": { "thinkingConfig": { "thinkingBudget": 8192 } }, - "max": { "thinkingConfig": { "thinkingBudget": 32768 } } + "medium": { "thinkingConfig": { "thinkingBudget": 16384 } }, + "high": { "thinkingConfig": { "thinkingBudget": 32768 } }, + "max": { "thinkingConfig": { "thinkingBudget": 65536 } } } }, "gemini-2.5-flash": { @@ -422,7 +425,7 @@ If you encounter errors during a session: { "google_auth": false, "agents": { - "frontend-ui-ux-engineer": { "model": "google/antigravity-gemini-3-pro" }, + "frontend-ui-ux-engineer": { "model": "google/antigravity-gemini-3.1-pro" }, "document-writer": { "model": "google/antigravity-gemini-3-flash" } } } @@ -560,7 +563,7 @@ Disable built-in auth and override agent models in `oh-my-opencode.json`: { "google_auth": false, "agents": { - "frontend-ui-ux-engineer": { "model": "google/antigravity-gemini-3-pro" }, + "frontend-ui-ux-engineer": { "model": "google/antigravity-gemini-3.1-pro" }, "document-writer": { "model": "google/antigravity-gemini-3-flash" }, "multimodal-looker": { "model": "google/antigravity-gemini-3-flash" } } diff --git a/docs/ANTIGRAVITY_API_SPEC.md b/docs/ANTIGRAVITY_API_SPEC.md index 8200d63..42eaa7a 100644 --- a/docs/ANTIGRAVITY_API_SPEC.md +++ b/docs/ANTIGRAVITY_API_SPEC.md @@ -79,9 +79,8 @@ Accept: text/event-stream | Model Name | Model ID | Type | Status | |------------|----------|------|--------| | Claude Sonnet 4.6 | `claude-sonnet-4-6` | Anthropic | ✅ Verified | +| Claude Sonnet 4.6 Thinking | `claude-sonnet-4-6-thinking` | Anthropic | ⏳ Pending Rollout | | 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 | --- diff --git a/docs/MODEL-VARIANTS.md b/docs/MODEL-VARIANTS.md index 6f3c2d6..8811cd0 100644 --- a/docs/MODEL-VARIANTS.md +++ b/docs/MODEL-VARIANTS.md @@ -50,8 +50,8 @@ The plugin accepts different variant formats depending on the model family: Gemini 3 models use string-based thinking levels. Available levels differ by model: -| Level | Flash | Pro | Description | -|-------|-------|-----|-------------| +| Level | Flash | Pro (3.1) | Description | +|-------|-------|-------------|-------------| | `minimal` | ✅ | ❌ | Minimal thinking, lowest latency | | `low` | ✅ | ✅ | Light thinking | | `medium` | ✅ | ❌ | Balanced thinking | @@ -59,22 +59,6 @@ Gemini 3 models use string-based thinking levels. Available levels differ by mod > **Note:** The API rejects invalid levels (e.g., `"minimal"` on Pro). Configure variants accordingly. -### Gemini 3 Pro Example - -```json -{ - "antigravity-gemini-3-pro": { - "name": "Gemini 3 Pro (Antigravity)", - "limit": { "context": 1048576, "output": 65535 }, - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, - "variants": { - "low": { "thinkingLevel": "low" }, - "high": { "thinkingLevel": "high" } - } - } -} -``` - ### Gemini 3 Flash Example ```json @@ -99,22 +83,34 @@ Gemini 3 models use string-based thinking levels. Available levels differ by mod Claude models use token-based thinking budgets: -| Variant | Budget | Description | -|---------|--------|-------------| -| `low` | 8192 | Light thinking | -| `max` | 32768 | Maximum thinking | +| Model | Variants | Budgets | +|-------|----------|---------| +| `antigravity-claude-opus-4-6-thinking` | `low`, `medium`, `high`, `max` | 8192, 16384, 32768, 65536 | +| `antigravity-claude-sonnet-4-6-thinking` | `low`, `medium`, `high` | 8192, 16384, 32768 | ### Claude Example ```json { + "antigravity-claude-sonnet-4-6-thinking": { + "name": "Claude Sonnet 4.6 Thinking (Antigravity)", + "limit": { "context": 200000, "output": 64000 }, + "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "variants": { + "low": { "thinkingConfig": { "thinkingBudget": 8192 } }, + "medium": { "thinkingConfig": { "thinkingBudget": 16384 } }, + "high": { "thinkingConfig": { "thinkingBudget": 32768 } } + } + }, "antigravity-claude-opus-4-6-thinking": { "name": "Claude Opus 4.6 Thinking (Antigravity)", "limit": { "context": 200000, "output": 64000 }, "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, "variants": { "low": { "thinkingConfig": { "thinkingBudget": 8192 } }, - "max": { "thinkingConfig": { "thinkingBudget": 32768 } } + "medium": { "thinkingConfig": { "thinkingBudget": 16384 } }, + "high": { "thinkingConfig": { "thinkingBudget": 32768 } }, + "max": { "thinkingConfig": { "thinkingBudget": 65536 } } } } } @@ -157,9 +153,10 @@ Tier-suffixed model names are still accepted: - `antigravity-claude-opus-4-6-thinking-low` - `antigravity-claude-opus-4-6-thinking-medium` - `antigravity-claude-opus-4-6-thinking-high` -- `antigravity-gemini-3-pro-low` -- `antigravity-gemini-3-pro-high` -- `gemini-3-pro-low` +- `antigravity-claude-opus-4-6-thinking-max` +- `antigravity-claude-sonnet-4-6-thinking-low` +- `antigravity-claude-sonnet-4-6-thinking-medium` +- `antigravity-claude-sonnet-4-6-thinking-high` - `gemini-3-flash-medium` However, **we recommend using simplified model names with variants** for: diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index 9482b2e..fd195c8 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -431,7 +431,7 @@ v1.2.7+ uses explicit `antigravity-` prefix: | Old Name | New Name | |----------|----------| -| `gemini-3-pro-low` | `antigravity-gemini-3-pro` | +| `gemini-3.1-pro-low` | `antigravity-gemini-3.1-pro` | | `claude-sonnet-4-6` | `antigravity-claude-sonnet-4-6` | Use the `antigravity-` prefixed model names shown above. diff --git a/script/test-cross-model-e2e.sh b/script/test-cross-model-e2e.sh index 073c74d..f76dcc6 100755 --- a/script/test-cross-model-e2e.sh +++ b/script/test-cross-model-e2e.sh @@ -3,7 +3,7 @@ # Tests fix for "Invalid `signature` in `thinking` block" error # # Models tested: -# 1. Gemini (google/antigravity-gemini-3-pro-low, gemini-3-flash) +# 1. Gemini (google/antigravity-gemini-3.1-pro-low, gemini-3-flash) # 2. Claude via Anthropic (anthropic/claude-opus-4-5) # 3. Claude via Google (google/antigravity-claude-*-thinking-*) # 4. OpenAI (openai/gpt-5.2-medium) @@ -42,7 +42,7 @@ echo "" # Test 1: Gemini → Anthropic Claude (original bug + direct Anthropic API) echo "Test 1: Gemini Pro → Anthropic Claude Opus (direct API)" log_info "Step 1: Gemini with thinking + tool..." -opencode run -m google/antigravity-gemini-3-pro-low \ +opencode run -m google/antigravity-gemini-3.1-pro-low \ "Run: echo 'Test1-Gemini'. Think about sequences." \ > /tmp/e2e-t1-s1.log 2>&1 || true @@ -67,7 +67,7 @@ echo "" # Test 2: Gemini → Google Claude (Google-hosted Claude) echo "Test 2: Gemini Pro → Google Claude Opus Thinking" log_info "Step 1: Gemini with thinking + tool..." -opencode run -m google/antigravity-gemini-3-pro-low \ +opencode run -m google/antigravity-gemini-3.1-pro-low \ "Run: echo 'Test2-Gemini'. Think about this." \ > /tmp/e2e-t2-s1.log 2>&1 || true @@ -92,7 +92,7 @@ echo "" # Test 3: Gemini → OpenAI echo "Test 3: Gemini Pro → OpenAI GPT-5.2" log_info "Step 1: Gemini with thinking + tool..." -opencode run -m google/antigravity-gemini-3-pro-low \ +opencode run -m google/antigravity-gemini-3.1-pro-low \ "Run: echo 'Test3-Gemini'. Think about AI models." \ > /tmp/e2e-t3-s1.log 2>&1 || true @@ -129,7 +129,7 @@ if [ -z "$SID" ]; then else log_info "Session: $SID" log_info "Step 2: Gemini + thinking + tool..." - opencode run -s "$SID" -m google/antigravity-gemini-3-pro-low \ + opencode run -s "$SID" -m google/antigravity-gemini-3.1-pro-low \ "Run: echo 'Test4-Gemini'. Think about reversal." \ > /tmp/e2e-t4-s2.log 2>&1 || true @@ -173,7 +173,7 @@ echo "" # Test 6: 5-Model Round-Robin (all models in sequence) echo "Test 6: 5-Model Round-Robin" log_info "Turn 1: Gemini Pro Low..." -opencode run -m google/antigravity-gemini-3-pro-low \ +opencode run -m google/antigravity-gemini-3.1-pro-low \ "Run: echo 'Turn1'. Think about the chain." \ > /tmp/e2e-t6-s1.log 2>&1 || true diff --git a/script/test-cross-model.ts b/script/test-cross-model.ts index 6c13731..4452541 100644 --- a/script/test-cross-model.ts +++ b/script/test-cross-model.ts @@ -58,7 +58,7 @@ function runTests(): void { let failed = 0; console.log('Test 1: Model family detection'); - const geminiFamily = getModelFamily('gemini-3-pro-low'); + const geminiFamily = getModelFamily('gemini-3.1-pro-low'); const claudeFamily = getModelFamily('claude-opus-4-6-thinking-medium'); if (geminiFamily === 'gemini' && claudeFamily === 'claude') { console.log(' ✅ PASS: Model families detected correctly'); diff --git a/script/test-gemini-cli-e2e.sh b/script/test-gemini-cli-e2e.sh index 6cc4664..572e21c 100755 --- a/script/test-gemini-cli-e2e.sh +++ b/script/test-gemini-cli-e2e.sh @@ -5,8 +5,9 @@ # 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 +# 3. google/gemini-3-flash-preview +# 4. google/gemini-3-pro-preview +# 5. google/gemini-3.1-pro-preview set -euo pipefail @@ -98,8 +99,12 @@ 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)" +echo "Test 5: google/gemini-3.1-pro-preview" +test_model "google/gemini-3.1-pro-preview" "gemini-3.1-pro-preview" || true +echo "" + +# Test 6: Cross-model session (gemini-cli → antigravity) +echo "Test 6: 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" \ @@ -110,7 +115,7 @@ 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" + log_fail "Test 6 - No session ID created" else log_info "Session: $SID" log_info "Step 2: Switch to antigravity-gemini-3-flash..." @@ -119,17 +124,17 @@ else 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" + log_fail "Test 6 - Auth error on cross-model switch" else - log_pass "Test 5 - Cross-model session (gemini-cli → antigravity)" + log_pass "Test 6 - 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 \ +# Test 7: Reverse cross-model (antigravity → gemini-cli) +echo "Test 7: Cross-model session (antigravity → gemini-cli)" +log_info "Step 1: Start with antigravity-gemini-3.1-pro-low..." +timeout 60 opencode run -m google/antigravity-gemini-3.1-pro-low \ "Say: ANTIGRAVITY_START" \ 2>&1 > /tmp/gemini-cli-e2e-reverse-s1.log || true @@ -137,7 +142,7 @@ 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" + log_fail "Test 7 - No session ID created" else log_info "Session: $SID" log_info "Step 2: Switch to gemini-2.5-pro..." @@ -146,9 +151,9 @@ else 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" + log_fail "Test 7 - Auth error on reverse cross-model switch" else - log_pass "Test 6 - Cross-model session (antigravity → gemini-cli)" + log_pass "Test 7 - Cross-model session (antigravity → gemini-cli)" fi fi echo "" diff --git a/script/test-models.ts b/script/test-models.ts index 5ce9b87..4d1fd9c 100644 --- a/script/test-models.ts +++ b/script/test-models.ts @@ -10,19 +10,24 @@ const MODELS: ModelTest[] = [ // Gemini CLI (direct Google API) { model: "google/gemini-3-flash-preview", category: "gemini-cli" }, { model: "google/gemini-3-pro-preview", category: "gemini-cli" }, + { model: "google/gemini-3.1-pro-preview", category: "gemini-cli" }, { model: "google/gemini-2.5-pro", category: "gemini-cli" }, { model: "google/gemini-2.5-flash", category: "gemini-cli" }, // Antigravity Gemini - { model: "google/antigravity-gemini-3-pro-low", category: "antigravity-gemini" }, - { model: "google/antigravity-gemini-3-pro-high", category: "antigravity-gemini" }, + { model: "google/antigravity-gemini-3.1-pro-low", category: "antigravity-gemini" }, + { model: "google/antigravity-gemini-3.1-pro-high", category: "antigravity-gemini" }, { model: "google/antigravity-gemini-3-flash", category: "antigravity-gemini" }, // Antigravity Claude { model: "google/antigravity-claude-sonnet-4-6", category: "antigravity-claude" }, + { model: "google/antigravity-claude-sonnet-4-6-thinking-low", category: "antigravity-claude" }, + { model: "google/antigravity-claude-sonnet-4-6-thinking-medium", category: "antigravity-claude" }, + { model: "google/antigravity-claude-sonnet-4-6-thinking-high", category: "antigravity-claude" }, { model: "google/antigravity-claude-opus-4-6-thinking-low", category: "antigravity-claude" }, { model: "google/antigravity-claude-opus-4-6-thinking-medium", category: "antigravity-claude" }, { model: "google/antigravity-claude-opus-4-6-thinking-high", category: "antigravity-claude" }, + { model: "google/antigravity-claude-opus-4-6-thinking-max", category: "antigravity-claude" }, ]; const TEST_PROMPT = "Reply with exactly one word: WORKING"; diff --git a/scripts/setup-opencode-pi.sh b/scripts/setup-opencode-pi.sh index 1c6919c..9cf127c 100755 --- a/scripts/setup-opencode-pi.sh +++ b/scripts/setup-opencode-pi.sh @@ -32,8 +32,8 @@ if [ ! -f "$CONFIG_FILE" ]; then "provider": { "google": { "models": { - "antigravity-gemini-3-pro": { - "name": "Gemini 3 Pro (Antigravity)", + "antigravity-gemini-3.1-pro": { + "name": "Gemini 3.1 Pro (Antigravity)", "limit": { "context": 1048576, "output": 65535 }, "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, "variants": { diff --git a/src/plugin/accounts.test.ts b/src/plugin/accounts.test.ts index ad0b62b..b898d59 100644 --- a/src/plugin/accounts.test.ts +++ b/src/plugin/accounts.test.ts @@ -1863,6 +1863,6 @@ describe("resolveQuotaGroup", () => { it("model takes precedence over family", () => { // Even if family says claude, model determines the quota group expect(resolveQuotaGroup("gemini", "gemini-2.5-flash")).toBe("gemini-flash"); - expect(resolveQuotaGroup("gemini", "gemini-3-pro")).toBe("gemini-pro"); + expect(resolveQuotaGroup("gemini", "gemini-3.1-pro")).toBe("gemini-pro"); }); }); diff --git a/src/plugin/antigravity-first-fallback.test.ts b/src/plugin/antigravity-first-fallback.test.ts index 917872e..a22ff23 100644 --- a/src/plugin/antigravity-first-fallback.test.ts +++ b/src/plugin/antigravity-first-fallback.test.ts @@ -138,14 +138,14 @@ describe("Antigravity-first fallback", () => { const manager = new AccountManager(undefined, stored); const accounts = manager.getAccounts(); - // Mark account 0's antigravity as rate-limited for gemini-3-pro - manager.markRateLimited(accounts[0]!, 60000, "gemini", "antigravity", "gemini-3-pro"); + // Mark account 0's antigravity as rate-limited for gemini-3.1-pro + manager.markRateLimited(accounts[0]!, 60000, "gemini", "antigravity", "gemini-3.1-pro"); - // Account 1 should have antigravity available for gemini-3-pro + // Account 1 should have antigravity available for gemini-3.1-pro const hasOther = manager.hasOtherAccountWithAntigravityAvailable( accounts[0]!.index, "gemini", - "gemini-3-pro" + "gemini-3.1-pro" ); expect(hasOther).toBe(true); diff --git a/src/plugin/config/models.test.ts b/src/plugin/config/models.test.ts index fd5aecc..12ec5ef 100644 --- a/src/plugin/config/models.test.ts +++ b/src/plugin/config/models.test.ts @@ -17,8 +17,8 @@ describe("OPENCODE_MODEL_DEFINITIONS", () => { expect(modelNames).toEqual([ "antigravity-claude-opus-4-6-thinking", "antigravity-claude-sonnet-4-6", + "antigravity-claude-sonnet-4-6-thinking", "antigravity-gemini-3-flash", - "antigravity-gemini-3-pro", "antigravity-gemini-3.1-pro", "gemini-2.5-flash", "gemini-2.5-pro", @@ -30,11 +30,6 @@ describe("OPENCODE_MODEL_DEFINITIONS", () => { }); it("defines Gemini 3 variants for Antigravity models", () => { - expect(getModel("antigravity-gemini-3-pro").variants).toEqual({ - low: { thinkingLevel: "low" }, - high: { thinkingLevel: "high" }, - }); - expect(getModel("antigravity-gemini-3.1-pro").variants).toEqual({ low: { thinkingLevel: "low" }, high: { thinkingLevel: "high" }, @@ -51,7 +46,15 @@ describe("OPENCODE_MODEL_DEFINITIONS", () => { it("defines thinking budget variants for Claude thinking models", () => { expect(getModel("antigravity-claude-opus-4-6-thinking").variants).toEqual({ low: { thinkingConfig: { thinkingBudget: 8192 } }, - max: { thinkingConfig: { thinkingBudget: 32768 } }, + medium: { thinkingConfig: { thinkingBudget: 16384 } }, + high: { thinkingConfig: { thinkingBudget: 32768 } }, + max: { thinkingConfig: { thinkingBudget: 65536 } }, + }); + + expect(getModel("antigravity-claude-sonnet-4-6-thinking").variants).toEqual({ + low: { thinkingConfig: { thinkingBudget: 8192 } }, + medium: { thinkingConfig: { thinkingBudget: 16384 } }, + high: { thinkingConfig: { thinkingBudget: 32768 } }, }); }); }); diff --git a/src/plugin/config/models.ts b/src/plugin/config/models.ts index 641d2e1..f8487a4 100644 --- a/src/plugin/config/models.ts +++ b/src/plugin/config/models.ts @@ -38,15 +38,6 @@ const DEFAULT_MODALITIES: ModelModalities = { }; export const OPENCODE_MODEL_DEFINITIONS: OpencodeModelDefinitions = { - "antigravity-gemini-3-pro": { - name: "Gemini 3 Pro (Antigravity)", - limit: { context: 1048576, output: 65535 }, - modalities: DEFAULT_MODALITIES, - variants: { - low: { thinkingLevel: "low" }, - high: { thinkingLevel: "high" }, - }, - }, "antigravity-gemini-3.1-pro": { name: "Gemini 3.1 Pro (Antigravity)", limit: { context: 1048576, output: 65535 }, @@ -72,13 +63,25 @@ export const OPENCODE_MODEL_DEFINITIONS: OpencodeModelDefinitions = { limit: { context: 200000, output: 64000 }, modalities: DEFAULT_MODALITIES, }, + "antigravity-claude-sonnet-4-6-thinking": { + name: "Claude Sonnet 4.6 Thinking (Antigravity)", + limit: { context: 200000, output: 64000 }, + modalities: DEFAULT_MODALITIES, + variants: { + low: { thinkingConfig: { thinkingBudget: 8192 } }, + medium: { thinkingConfig: { thinkingBudget: 16384 } }, + high: { thinkingConfig: { thinkingBudget: 32768 } }, + }, + }, "antigravity-claude-opus-4-6-thinking": { name: "Claude Opus 4.6 Thinking (Antigravity)", limit: { context: 200000, output: 64000 }, modalities: DEFAULT_MODALITIES, variants: { low: { thinkingConfig: { thinkingBudget: 8192 } }, - max: { thinkingConfig: { thinkingBudget: 32768 } }, + medium: { thinkingConfig: { thinkingBudget: 16384 } }, + high: { thinkingConfig: { thinkingBudget: 32768 } }, + max: { thinkingConfig: { thinkingBudget: 65536 } }, }, }, "gemini-2.5-flash": { diff --git a/src/plugin/config/updater.test.ts b/src/plugin/config/updater.test.ts index 83634ed..7708a56 100644 --- a/src/plugin/config/updater.test.ts +++ b/src/plugin/config/updater.test.ts @@ -66,7 +66,6 @@ describe("updateOpencodeConfig", () => { // Old model should be replaced expect(writtenConfig.provider.google.models["old-model"]).toBeUndefined(); // New models should be present - expect(writtenConfig.provider.google.models["antigravity-gemini-3-pro"]).toBeDefined(); expect(writtenConfig.provider.google.models["antigravity-claude-sonnet-4-6"]).toBeDefined(); }); @@ -235,7 +234,6 @@ describe("updateOpencodeConfig", () => { expect(writtenConfig.plugin).toContain("other-plugin"); expect(writtenConfig.plugin).toContain("opencode-antigravity-auth@latest"); expect(writtenConfig.provider.google.region).toBe("us-central1"); - expect(writtenConfig.provider.google.models["antigravity-gemini-3-pro"]).toBeDefined(); }); test("prefers existing opencode.jsonc when using default config path", async () => { diff --git a/src/plugin/cross-model-integration.test.ts b/src/plugin/cross-model-integration.test.ts index 1dc4567..3478c00 100644 --- a/src/plugin/cross-model-integration.test.ts +++ b/src/plugin/cross-model-integration.test.ts @@ -242,7 +242,7 @@ describe("Cross-Model Session Integration", () => { }; const result = sanitizeCrossModelPayload(payload, { - targetModel: "gemini-3-pro-low", + targetModel: "gemini-3.1-pro-low", }); const sanitized = result.payload as typeof payload; @@ -352,10 +352,10 @@ describe("Cross-Model Session Integration", () => { describe("Model family detection", () => { it("correctly identifies Gemini models", () => { - expect(getModelFamily("gemini-3-pro-low")).toBe("gemini"); + expect(getModelFamily("gemini-3.1-pro-low")).toBe("gemini"); expect(getModelFamily("gemini-3-flash")).toBe("gemini"); expect(getModelFamily("gemini-2.5-pro")).toBe("gemini"); - expect(getModelFamily("gemini-3-pro-high")).toBe("gemini"); + expect(getModelFamily("gemini-3.1-pro-high")).toBe("gemini"); }); it("correctly identifies Claude models", () => { diff --git a/src/plugin/request-helpers.test.ts b/src/plugin/request-helpers.test.ts index 60ecb0e..a8d8db4 100644 --- a/src/plugin/request-helpers.test.ts +++ b/src/plugin/request-helpers.test.ts @@ -171,7 +171,7 @@ describe("isThinkingCapableModel", () => { }); it("returns true for models with 'gemini-3' in name", () => { - expect(isThinkingCapableModel("gemini-3-pro")).toBe(true); + expect(isThinkingCapableModel("gemini-3.1-pro")).toBe(true); expect(isThinkingCapableModel("GEMINI-3-flash")).toBe(true); expect(isThinkingCapableModel("gemini-3")).toBe(true); }); diff --git a/src/plugin/transform/claude.test.ts b/src/plugin/transform/claude.test.ts index e3abef7..2519296 100644 --- a/src/plugin/transform/claude.test.ts +++ b/src/plugin/transform/claude.test.ts @@ -33,7 +33,7 @@ describe("isClaudeModel", () => { }); it("returns false for non-claude models", () => { - expect(isClaudeModel("gemini-3-pro")).toBe(false); + expect(isClaudeModel("gemini-3.1-pro")).toBe(false); expect(isClaudeModel("gpt-4")).toBe(false); expect(isClaudeModel("llama-3")).toBe(false); expect(isClaudeModel("")).toBe(false); @@ -60,6 +60,7 @@ describe("isClaudeThinkingModel", () => { it("returns true for prefixed thinking models", () => { expect(isClaudeThinkingModel("antigravity-claude-sonnet-4-5-thinking")).toBe(true); + expect(isClaudeThinkingModel("antigravity-claude-sonnet-4-6-thinking")).toBe(true); expect(isClaudeThinkingModel("google/claude-opus-4-5-thinking-high")).toBe(true); }); @@ -70,7 +71,7 @@ describe("isClaudeThinkingModel", () => { }); it("returns false for non-claude models", () => { - expect(isClaudeThinkingModel("gemini-3-pro-thinking")).toBe(false); + expect(isClaudeThinkingModel("gemini-3.1-pro-thinking")).toBe(false); expect(isClaudeThinkingModel("gpt-4-thinking")).toBe(false); }); diff --git a/src/plugin/transform/cross-model-sanitizer.test.ts b/src/plugin/transform/cross-model-sanitizer.test.ts index 7be1f32..4de3362 100644 --- a/src/plugin/transform/cross-model-sanitizer.test.ts +++ b/src/plugin/transform/cross-model-sanitizer.test.ts @@ -13,11 +13,12 @@ describe("cross-model-sanitizer", () => { it("identifies Claude models", () => { expect(getModelFamily("claude-opus-4-6-thinking-medium")).toBe("claude"); expect(getModelFamily("claude-sonnet-4-6")).toBe("claude"); + expect(getModelFamily("claude-sonnet-4-6-thinking")).toBe("claude"); expect(getModelFamily("claude-opus-4-6-thinking-low")).toBe("claude"); }); it("identifies Gemini models", () => { - expect(getModelFamily("gemini-3-pro-low")).toBe("gemini"); + expect(getModelFamily("gemini-3.1-pro-low")).toBe("gemini"); expect(getModelFamily("gemini-3-flash")).toBe("gemini"); expect(getModelFamily("gemini-2.5-pro")).toBe("gemini"); }); @@ -328,7 +329,7 @@ describe("cross-model-sanitizer", () => { }; const result = sanitizeCrossModelPayload(payload, { - targetModel: "gemini-3-pro-low", + targetModel: "gemini-3.1-pro-low", }); expect(result.modified).toBe(true); diff --git a/src/plugin/transform/gemini.test.ts b/src/plugin/transform/gemini.test.ts index 4479444..070b151 100644 --- a/src/plugin/transform/gemini.test.ts +++ b/src/plugin/transform/gemini.test.ts @@ -28,8 +28,8 @@ describe("transform/gemini", () => { expect(isGeminiModel("gemini-2.5-flash")).toBe(true); }); - it("returns true for gemini-3-pro-high", () => { - expect(isGeminiModel("gemini-3-pro-high")).toBe(true); + it("returns true for gemini-3.1-pro-high", () => { + expect(isGeminiModel("gemini-3.1-pro-high")).toBe(true); }); it("returns true for uppercase GEMINI-PRO", () => { @@ -62,12 +62,12 @@ describe("transform/gemini", () => { }); describe("isGemini3Model", () => { - it("returns true for gemini-3-pro", () => { - expect(isGemini3Model("gemini-3-pro")).toBe(true); + it("returns true for gemini-3.1-pro", () => { + expect(isGemini3Model("gemini-3.1-pro")).toBe(true); }); - it("returns true for gemini-3-pro-high", () => { - expect(isGemini3Model("gemini-3-pro-high")).toBe(true); + it("returns true for gemini-3.1-pro-high", () => { + expect(isGemini3Model("gemini-3.1-pro-high")).toBe(true); }); it("returns true for gemini-3-flash", () => { @@ -78,8 +78,8 @@ describe("transform/gemini", () => { expect(isGemini3Model("gemini-3.1-pro")).toBe(true); }); - it("returns true for uppercase GEMINI-3-PRO", () => { - expect(isGemini3Model("GEMINI-3-PRO")).toBe(true); + it("returns true for uppercase GEMINI-3.1-PRO", () => { + expect(isGemini3Model("GEMINI-3.1-PRO")).toBe(true); }); it("returns false for gemini-2.5-pro", () => { @@ -116,8 +116,8 @@ describe("transform/gemini", () => { expect(isGemini25Model("GEMINI-2.5-PRO")).toBe(true); }); - it("returns false for gemini-3-pro", () => { - expect(isGemini25Model("gemini-3-pro")).toBe(false); + it("returns false for gemini-3.1-pro", () => { + expect(isGemini25Model("gemini-3.1-pro")).toBe(false); }); it("returns false for gemini-2.0-flash", () => { @@ -376,7 +376,7 @@ describe("transform/gemini", () => { it("applies Gemini 3 thinking config with thinkingLevel", () => { const payload: RequestPayload = { contents: [] }; applyGeminiTransforms(payload, { - model: "gemini-3-pro-high", + model: "gemini-3.1-pro-high", tierThinkingLevel: "high", normalizedThinking: { includeThoughts: true }, }); @@ -425,7 +425,7 @@ describe("transform/gemini", () => { it("does not apply thinking config when normalizedThinking is undefined", () => { const payload: RequestPayload = { contents: [] }; applyGeminiTransforms(payload, { - model: "gemini-3-pro", + model: "gemini-3.1-pro", }); expect(payload.generationConfig).toBeUndefined(); }); @@ -436,7 +436,7 @@ describe("transform/gemini", () => { generationConfig: { temperature: 0.7, maxOutputTokens: 1000 }, }; applyGeminiTransforms(payload, { - model: "gemini-3-pro-medium", + model: "gemini-3.1-pro-medium", tierThinkingLevel: "medium", normalizedThinking: { includeThoughts: true }, }); @@ -464,7 +464,7 @@ describe("transform/gemini", () => { it("defaults includeThoughts to true when not specified", () => { const payload: RequestPayload = { contents: [] }; applyGeminiTransforms(payload, { - model: "gemini-3-pro-low", + model: "gemini-3.1-pro-low", tierThinkingLevel: "low", normalizedThinking: {}, }); @@ -475,7 +475,7 @@ describe("transform/gemini", () => { it("respects includeThoughts false", () => { const payload: RequestPayload = { contents: [] }; applyGeminiTransforms(payload, { - model: "gemini-3-pro-high", + model: "gemini-3.1-pro-high", tierThinkingLevel: "high", normalizedThinking: { includeThoughts: false }, }); @@ -499,7 +499,7 @@ describe("transform/gemini", () => { it("injects googleSearch tool when mode is 'auto'", () => { const payload: RequestPayload = { contents: [], tools: [] }; applyGeminiTransforms(payload, { - model: "gemini-3-pro", + model: "gemini-3.1-pro", googleSearch: { mode: "auto" }, }); const tools = payload.tools as unknown[]; @@ -524,7 +524,7 @@ describe("transform/gemini", () => { it("works without threshold specified", () => { const payload: RequestPayload = { contents: [] }; applyGeminiTransforms(payload, { - model: "gemini-3-pro", + model: "gemini-3.1-pro", googleSearch: { mode: "auto" }, }); const tools = payload.tools as unknown[]; @@ -535,7 +535,7 @@ describe("transform/gemini", () => { it("does not inject search tool when mode is 'off'", () => { const payload: RequestPayload = { contents: [], tools: [] }; applyGeminiTransforms(payload, { - model: "gemini-3-pro", + model: "gemini-3.1-pro", googleSearch: { mode: "off" }, }); const tools = payload.tools as unknown[]; @@ -545,7 +545,7 @@ describe("transform/gemini", () => { it("does not inject search tool when googleSearch is undefined", () => { const payload: RequestPayload = { contents: [], tools: [] }; applyGeminiTransforms(payload, { - model: "gemini-3-pro", + model: "gemini-3.1-pro", }); const tools = payload.tools as unknown[]; expect(tools).toHaveLength(0); @@ -559,7 +559,7 @@ describe("transform/gemini", () => { ], }; applyGeminiTransforms(payload, { - model: "gemini-3-pro", + model: "gemini-3.1-pro", googleSearch: { mode: "auto" }, }); const tools = payload.tools as unknown[]; @@ -571,7 +571,7 @@ describe("transform/gemini", () => { it("search tool is not normalized (skipped by normalizeGeminiTools)", () => { const payload: RequestPayload = { contents: [] }; applyGeminiTransforms(payload, { - model: "gemini-3-pro", + model: "gemini-3.1-pro", googleSearch: { mode: "auto" }, }); const tools = payload.tools as unknown[]; @@ -604,16 +604,17 @@ describe("transform/gemini", () => { expect(isImageGenerationModel("GEMINI-3-PRO-IMAGE")).toBe(true); }); - it("returns false for gemini-3-pro", () => { - expect(isImageGenerationModel("gemini-3-pro")).toBe(false); + it("returns false for gemini-3.1-pro", () => { + expect(isImageGenerationModel("gemini-3.1-pro")).toBe(false); }); it("returns false for gemini-2.5-flash", () => { expect(isImageGenerationModel("gemini-2.5-flash")).toBe(false); }); - it("returns false for claude-sonnet-4-6", () => { + it("returns false for claude-sonnet-4-6 and thinking variants", () => { expect(isImageGenerationModel("claude-sonnet-4-6")).toBe(false); + expect(isImageGenerationModel("claude-sonnet-4-6-thinking")).toBe(false); }); }); @@ -1441,7 +1442,7 @@ describe("transform/gemini", () => { ], }; - applyGeminiTransforms(payload, { model: "gemini-3-pro" }); + applyGeminiTransforms(payload, { model: "gemini-3.1-pro" }); const tools = payload.tools as Array>; expect(tools).toHaveLength(1); @@ -1467,7 +1468,7 @@ describe("transform/gemini", () => { }; applyGeminiTransforms(payload, { - model: "gemini-3-pro", + model: "gemini-3.1-pro", googleSearch: { mode: "auto" }, }); diff --git a/src/plugin/transform/model-resolver.test.ts b/src/plugin/transform/model-resolver.test.ts index e0b9b48..3c48b76 100644 --- a/src/plugin/transform/model-resolver.test.ts +++ b/src/plugin/transform/model-resolver.test.ts @@ -27,12 +27,12 @@ describe("resolveModelWithTier", () => { }); describe("Gemini 3 preview models (Issue #115)", () => { - it("gemini-3-pro-preview gets default thinkingLevel 'low' with antigravity quota", () => { + it("gemini-3-pro-preview resolves as Gemini CLI-first with default thinkingLevel", () => { const result = resolveModelWithTier("gemini-3-pro-preview"); expect(result.actualModel).toBe("gemini-3-pro-preview"); expect(result.thinkingLevel).toBe("low"); - // All Gemini models now default to antigravity - expect(result.quotaPreference).toBe("antigravity"); + expect(result.quotaPreference).toBe("gemini-cli"); + expect(result.thinkingBudget).toBeUndefined(); }); it("gemini-3.1-pro-preview gets default thinkingLevel 'low' with antigravity quota", () => { @@ -78,12 +78,6 @@ describe("resolveModelWithTier", () => { expect(result.quotaPreference).toBe("antigravity"); }); - it("keeps antigravity for image models when cli_first is true", () => { - const result = resolveModelWithTier("gemini-3-pro-image", { cli_first: true }); - expect(result.quotaPreference).toBe("antigravity"); - expect(result.explicitQuota).toBe(true); - }); - it("defaults to antigravity when cli_first is false", () => { const result = resolveModelWithTier("gemini-3-flash", { cli_first: false }); expect(result.quotaPreference).toBe("antigravity"); @@ -91,20 +85,6 @@ describe("resolveModelWithTier", () => { }); describe("Antigravity Gemini 3 with tier suffix", () => { - it("antigravity-gemini-3-pro-low gets thinkingLevel from tier", () => { - const result = resolveModelWithTier("antigravity-gemini-3-pro-low"); - expect(result.actualModel).toBe("gemini-3-pro-low"); - expect(result.thinkingLevel).toBe("low"); - expect(result.quotaPreference).toBe("antigravity"); - }); - - it("antigravity-gemini-3-pro-high gets thinkingLevel from tier", () => { - const result = resolveModelWithTier("antigravity-gemini-3-pro-high"); - expect(result.actualModel).toBe("gemini-3-pro-high"); - expect(result.thinkingLevel).toBe("high"); - expect(result.quotaPreference).toBe("antigravity"); - }); - it("antigravity-gemini-3-flash-medium gets thinkingLevel from tier", () => { const result = resolveModelWithTier("antigravity-gemini-3-flash-medium"); expect(result.actualModel).toBe("gemini-3-flash"); @@ -119,13 +99,53 @@ describe("resolveModelWithTier", () => { }); describe("Claude thinking models default budget", () => { - it("antigravity-claude-opus-4-6-thinking gets default max budget (32768)", () => { + it("antigravity-claude-opus-4-6-thinking gets default high budget (32768)", () => { const result = resolveModelWithTier("antigravity-claude-opus-4-6-thinking"); expect(result.actualModel).toBe("claude-opus-4-6-thinking"); expect(result.thinkingBudget).toBe(32768); expect(result.isThinkingModel).toBe(true); expect(result.quotaPreference).toBe("antigravity"); }); + + it("antigravity-claude-sonnet-4-6-thinking gets default max budget (32768)", () => { + const result = resolveModelWithTier("antigravity-claude-sonnet-4-6-thinking"); + expect(result.actualModel).toBe("claude-sonnet-4-6-thinking"); + expect(result.thinkingBudget).toBe(32768); + expect(result.isThinkingModel).toBe(true); + expect(result.quotaPreference).toBe("antigravity"); + }); + + it("antigravity-claude-opus-4-6-thinking-max gets max budget (65536)", () => { + const result = resolveModelWithTier("antigravity-claude-opus-4-6-thinking-max"); + expect(result.actualModel).toBe("claude-opus-4-6-thinking"); + expect(result.thinkingBudget).toBe(65536); + expect(result.isThinkingModel).toBe(true); + expect(result.quotaPreference).toBe("antigravity"); + }); + + it("antigravity-claude-sonnet-4-6-thinking-low gets low budget (8192)", () => { + const result = resolveModelWithTier("antigravity-claude-sonnet-4-6-thinking-low"); + expect(result.actualModel).toBe("claude-sonnet-4-6-thinking"); + expect(result.thinkingBudget).toBe(8192); + expect(result.isThinkingModel).toBe(true); + expect(result.quotaPreference).toBe("antigravity"); + }); + + it("antigravity-claude-sonnet-4-6-thinking-medium gets medium budget (16384)", () => { + const result = resolveModelWithTier("antigravity-claude-sonnet-4-6-thinking-medium"); + expect(result.actualModel).toBe("claude-sonnet-4-6-thinking"); + expect(result.thinkingBudget).toBe(16384); + expect(result.isThinkingModel).toBe(true); + expect(result.quotaPreference).toBe("antigravity"); + }); + + it("antigravity-claude-sonnet-4-6-thinking-high gets high budget (32768)", () => { + const result = resolveModelWithTier("antigravity-claude-sonnet-4-6-thinking-high"); + expect(result.actualModel).toBe("claude-sonnet-4-6-thinking"); + expect(result.thinkingBudget).toBe(32768); + expect(result.isThinkingModel).toBe(true); + expect(result.quotaPreference).toBe("antigravity"); + }); }); describe("Claude Sonnet 4.6 (non-thinking)", () => { @@ -155,17 +175,9 @@ describe("resolveModelWithTier", () => { }); describe("Image models", () => { - it("marks antigravity-gemini-3-pro-image as explicit quota", () => { - const result = resolveModelWithTier("antigravity-gemini-3-pro-image"); - expect(result.actualModel).toBe("gemini-3-pro-image"); - expect(result.isImageModel).toBe(true); - expect(result.explicitQuota).toBe(true); - expect(result.quotaPreference).toBe("antigravity"); - }); - - it("marks gemini-3-pro-image as explicit quota", () => { - const result = resolveModelWithTier("gemini-3-pro-image"); - expect(result.actualModel).toBe("gemini-3-pro-image"); + it("marks image models as explicit quota", () => { + const result = resolveModelWithTier("gemini-3-flash-image"); + expect(result.actualModel).toBe("gemini-3-flash-image"); expect(result.isImageModel).toBe(true); expect(result.explicitQuota).toBe(true); expect(result.quotaPreference).toBe("antigravity"); @@ -182,12 +194,6 @@ describe("resolveModelWithVariant", () => { expect(result.configSource).toBeUndefined(); }); - it("falls back to tier resolution for Gemini 3 models", () => { - const result = resolveModelWithVariant("gemini-3-pro-high"); - expect(result.actualModel).toBe("gemini-3-pro"); - expect(result.thinkingLevel).toBe("high"); - expect(result.configSource).toBeUndefined(); - }); }); describe("with variant config", () => { @@ -200,16 +206,6 @@ describe("resolveModelWithVariant", () => { expect(result.configSource).toBe("variant"); }); - it("maps budget to thinkingLevel for Gemini 3 - low", () => { - const result = resolveModelWithVariant("antigravity-gemini-3-pro", { - thinkingBudget: 8000, - }); - expect(result.actualModel).toBe("gemini-3-pro-low"); - expect(result.thinkingLevel).toBe("low"); - expect(result.thinkingBudget).toBeUndefined(); - expect(result.configSource).toBe("variant"); - }); - it("maps budget to thinkingLevel for Gemini 3 Flash - medium (no tier suffix)", () => { const result = resolveModelWithVariant("antigravity-gemini-3-flash", { thinkingBudget: 12000, @@ -219,14 +215,6 @@ describe("resolveModelWithVariant", () => { expect(result.configSource).toBe("variant"); }); - it("maps budget to thinkingLevel for Gemini 3 - high", () => { - const result = resolveModelWithVariant("antigravity-gemini-3-pro", { - thinkingBudget: 32000, - }); - expect(result.thinkingLevel).toBe("high"); - expect(result.configSource).toBe("variant"); - }); - it("uses budget directly for non-Gemini 3 models", () => { const result = resolveModelWithVariant("gemini-2.5-pro", { thinkingBudget: 20000, diff --git a/src/plugin/transform/model-resolver.ts b/src/plugin/transform/model-resolver.ts index dd635c3..82b7556 100644 --- a/src/plugin/transform/model-resolver.ts +++ b/src/plugin/transform/model-resolver.ts @@ -1,7 +1,7 @@ /** * Model Resolution with Thinking Tier Support * - * Resolves model names with tier suffixes (e.g., gemini-3-pro-high, claude-opus-4-6-thinking-low) + * Resolves model names with tier suffixes (e.g., gemini-3.1-pro-high, claude-opus-4-6-thinking-low) * to their actual API model names and corresponding thinking configurations. */ @@ -16,7 +16,7 @@ export interface ModelResolverOptions { * Claude and Gemini 2.5 Pro use numeric budgets. */ export const THINKING_TIER_BUDGETS = { - claude: { low: 8192, medium: 16384, high: 32768 }, + claude: { low: 8192, medium: 16384, high: 32768, max: 65536 }, "gemini-2.5-pro": { low: 8192, medium: 16384, high: 32768 }, "gemini-2.5-flash": { low: 6144, medium: 12288, high: 24576 }, default: { low: 4096, medium: 8192, high: 16384 }, @@ -33,15 +33,13 @@ export const GEMINI_3_THINKING_LEVELS = ["minimal", "low", "medium", "high"] as * Model aliases - maps user-friendly names to API model names. * * Format: - * - Gemini 3 Pro variants: gemini-3-pro-{low,medium,high} + * - Gemini 3 Pro variants: gemini-3.1-pro-{low,medium,high} * - Claude thinking variants: claude-{model}-thinking-{low,medium,high} * - Claude non-thinking: claude-{model} (no -thinking suffix) */ export const MODEL_ALIASES: Record = { // Gemini 3 variants - for Gemini CLI only (tier stripped, thinkingLevel used) // For Antigravity, these are bypassed and full model name is kept - "gemini-3-pro-low": "gemini-3-pro", - "gemini-3-pro-high": "gemini-3-pro", "gemini-3.1-pro-low": "gemini-3.1-pro", "gemini-3.1-pro-high": "gemini-3.1-pro", "gemini-3-flash-low": "gemini-3-flash", @@ -52,6 +50,10 @@ export const MODEL_ALIASES: Record = { "gemini-claude-opus-4-6-thinking-low": "claude-opus-4-6-thinking", "gemini-claude-opus-4-6-thinking-medium": "claude-opus-4-6-thinking", "gemini-claude-opus-4-6-thinking-high": "claude-opus-4-6-thinking", + "gemini-claude-opus-4-6-thinking-max": "claude-opus-4-6-thinking", + "gemini-claude-sonnet-4-6-thinking-low": "claude-sonnet-4-6-thinking", + "gemini-claude-sonnet-4-6-thinking-medium": "claude-sonnet-4-6-thinking", + "gemini-claude-sonnet-4-6-thinking-high": "claude-sonnet-4-6-thinking", "gemini-claude-sonnet-4-6": "claude-sonnet-4-6", // Image generation models - only gemini-3-pro-image is available via Antigravity API @@ -59,7 +61,7 @@ export const MODEL_ALIASES: Record = { // Reference: Antigravity-Manager/src-tauri/src/proxy/common/model_mapping.rs }; -const TIER_REGEX = /-(minimal|low|medium|high)$/; +const TIER_REGEX = /-(minimal|low|medium|high|max)$/; const QUOTA_PREFIX_REGEX = /^antigravity-/i; const GEMINI_3_PRO_REGEX = /^gemini-3(?:\.\d+)?-pro/i; const GEMINI_3_FLASH_REGEX = /^gemini-3(?:\.\d+)?-flash/i; @@ -149,8 +151,8 @@ function isGemini3FlashModel(model: string): boolean { * * Examples: * - "gemini-2.5-flash" → { quotaPreference: "antigravity" } - * - "gemini-3-pro-preview" → { quotaPreference: "antigravity" } - * - "antigravity-gemini-3-pro-high" → { quotaPreference: "antigravity", explicitQuota: true } + * - "gemini-3.1-pro-preview" → { quotaPreference: "antigravity" } + * - "antigravity-gemini-3.1-pro-high" → { quotaPreference: "antigravity", explicitQuota: true } * - "claude-opus-4-6-thinking-medium" → { quotaPreference: "antigravity" } * * @param requestedModel - The model name from the request @@ -166,10 +168,14 @@ export function resolveModelWithTier(requestedModel: string, options: ModelResol const isImageModel = IMAGE_GENERATION_MODELS.test(modelWithoutQuota); const isClaudeModel = modelWithoutQuota.toLowerCase().includes("claude"); + const isGeminiCliOnlyModel = modelWithoutQuota.toLowerCase() === "gemini-3-pro-preview"; // All models default to Antigravity quota unless cli_first is enabled // Fallback to gemini-cli happens at the account rotation level when Antigravity is exhausted - const preferGeminiCli = options.cli_first === true && !isAntigravity && !isImageModel && !isClaudeModel; + const preferGeminiCli = (options.cli_first === true || isGeminiCliOnlyModel) + && !isAntigravity + && !isImageModel + && !isClaudeModel; const quotaPreference = preferGeminiCli ? "gemini-cli" as const : "antigravity" as const; const explicitQuota = isAntigravity || isImageModel; @@ -177,7 +183,7 @@ export function resolveModelWithTier(requestedModel: string, options: ModelResol const skipAlias = isAntigravity && isGemini3; // For Antigravity Gemini 3 Pro models without explicit tier, append default tier - // Antigravity API: gemini-3-pro requires tier suffix (gemini-3-pro-low/high) + // Antigravity API: gemini-3.1-pro requires tier suffix (gemini-3.1-pro-low/high) // gemini-3-flash uses bare name + thinkingLevel param // Pro defaults to -low unless an explicit tier is provided const isGemini3Pro = isGemini3ProModel(modelWithoutQuota); @@ -254,7 +260,7 @@ export function resolveModelWithTier(requestedModel: string, options: ModelResol const budgetFamily = getBudgetFamily(resolvedModel); const budgets = THINKING_TIER_BUDGETS[budgetFamily]; - const thinkingBudget = budgets[tier]; + const thinkingBudget = (budgets as Record)[tier]; return { actualModel: resolvedModel, @@ -304,7 +310,7 @@ function budgetToGemini3Level(budget: number): "low" | "medium" | "high" { * * Issue #103: When quota fallback occurs, model names need to be transformed: * - gemini-3-flash-preview (gemini-cli) → gemini-3-flash (antigravity) - * - gemini-3-pro-preview (gemini-cli) → gemini-3-pro-low (antigravity) + * - gemini-3.1-pro-preview (gemini-cli) → gemini-3.1-pro-low (antigravity) * - gemini-3-flash (antigravity) → gemini-3-flash-preview (gemini-cli) */ export function resolveModelForHeaderStyle( @@ -325,7 +331,7 @@ export function resolveModelForHeaderStyle( .replace(/^antigravity-/i, ""); const isGemini3Pro = isGemini3ProModel(transformedModel); - const hasTierSuffix = /-(low|medium|high)$/i.test(transformedModel); + const hasTierSuffix = /-(low|medium|high|max)$/i.test(transformedModel); const isImageModel = IMAGE_GENERATION_MODELS.test(transformedModel); // Don't add tier suffix to image models - they don't support thinking @@ -340,7 +346,7 @@ export function resolveModelForHeaderStyle( if (headerStyle === "gemini-cli") { let transformedModel = requestedModel .replace(/^antigravity-/i, "") - .replace(/-(low|medium|high)$/i, ""); + .replace(/-(low|medium|high|max)$/i, ""); const hasPreviewSuffix = /-preview($|-)/i.test(transformedModel); if (!hasPreviewSuffix) { @@ -390,7 +396,7 @@ export function resolveModelWithVariant( let actualModel = base.actualModel; if (isAntigravityGemini3Pro) { - const baseModel = base.actualModel.replace(/-(low|medium|high)$/, ""); + const baseModel = base.actualModel.replace(/-(low|medium|high|max)$/, ""); actualModel = `${baseModel}-${level}`; } diff --git a/src/plugin/transform/types.ts b/src/plugin/transform/types.ts index a86753b..1770e52 100644 --- a/src/plugin/transform/types.ts +++ b/src/plugin/transform/types.ts @@ -2,7 +2,7 @@ import type { HeaderStyle } from "../../constants"; export type ModelFamily = "claude" | "gemini-flash" | "gemini-pro"; -export type ThinkingTier = "low" | "medium" | "high"; +export type ThinkingTier = "low" | "medium" | "high" | "max"; /** * Context for request transformation.