Pre-submission checklist
Model used
Other (specify in description)
Exact error message
Request contains an invalid argument.
[Debug Info]
Requested Model: antigravity-gemini-3.1-pro
Effective Model: gemini-3.1-pro-low
Project: rising-fact-p41fc
Endpoint: https://cloudcode-pa.googleapis.com/v1internal:streamGenerateContent?alt=sse
Status: 400
Request ID: N/A
Tool Debug Missing: 1
Tool Debug Summary: idx=0, hasCustom=true, customSchema=true, hasFunction=false, functionSchema=false
Tool Debug Payload: [{"functionDeclarations":[{"name":"bash","description":"Executes a given bash command in a persistent shell session with optional timeout, ensuring proper handling and security measures.\n\nAll commands run in /Users/miracthis/Desktop/HumayLojistik/humay-lojistik by default. Use the `workdir` parameter if you need to run a command in a different directory. AVOID using `cd <directory> && <command>` patterns - use `workdir` instead.\n\nIMPORTANT: This tool is for terminal operations like git, npm, docker, etc. DO NOT use it for file operations (reading, writing, editing, searching, finding files) - use the specialized tools for this instead.\n\nBefore executing the command, please follow these steps:\n\n1. Directory Verification:\n - If the command will create new directories or files, first use `ls` to verify the parent directory exists and is the correct location\n - For example, before running \"mkdir foo/bar\", first use `ls foo` to check that \"foo\" exists and is the intended parent directory\n\n2. Command Execution:\n - Always quote file paths that contain spaces with double quotes (e.g., rm \"path with spaces/file.txt\")\n - Examples of proper quoting:\n - mkdir \"/Users/name/My Documents\" (correct)\n - mkdir /Users/name/My Documents (incorrect - will fail)\n - python \"/path/with spaces/script.py\" (correct)\n - python /path/with spaces/script.py (incorrect - will fail)\n - After ensuring proper quoting, execute the command.\n - Capture the output of the command.\n\nUsage notes:\n - The command argument is required.\n - You can specify an optional timeout in milliseconds.
Bug description
Issue 1: Variant Routing Bug
Title: Gemini 3.1 Pro "high" variant falls back to "low" — resolveModelWithVariant ignores thinkingLevel
Body:
Bug
When using antigravity-gemini-3.1-pro with variant "high", the effective model becomes gemini-3.1-pro-low instead of gemini-3.1-pro-high.
Debug Output
Requested Model: antigravity-gemini-3.1-pro
Effective Model: gemini-3.1-pro-low
Root Cause
resolveModelWithVariant() in model-resolver.ts (line ~311) checks only for thinkingBudget and returns early if it's missing — completely ignoring thinkingLevel:
// model-resolver.ts — resolveModelWithVariant()
if (!variantConfig.thinkingBudget) {
return base; // ← BUG: thinkingLevel is never checked
}
When opencode.json defines a Gemini 3 variant with thinkingLevel (the correct format for Gemini 3):
high: {
thinkingLevel: high
}
…the function exits early at line 311 because thinkingBudget is undefined, returning the base config which defaults to thinkingLevel: "low" (line 186).
Note: request.ts line ~664 has a separate path that correctly handles thinkingLevel for Gemini 3, but by that point the model NAME has already been resolved with the -low suffix by resolveModelWithVariant.
Expected Fix
Add thinkingLevel check before the thinkingBudget guard:
export function resolveModelWithVariant(requestedModel, variantConfig) {
const base = resolveModelWithTier(requestedModel);
if (!variantConfig) return base;
if (variantConfig.googleSearch) { ... }
// FIX: Handle thinkingLevel for Gemini 3 models
if (variantConfig.thinkingLevel) {
const isGemini3 = base.actualModel.toLowerCase().includes("gemini-3");
if (isGemini3) {
const level = variantConfig.thinkingLevel;
const isAntigravityPro = base.quotaPreference === "antigravity"
&& isGemini3ProModel(base.actualModel);
let actualModel = base.actualModel;
if (isAntigravityPro) {
const baseModel = base.actualModel.replace(/-(low|medium|high)$/, "");
actualModel = `${baseModel}-${level}`;
}
return { ...base, actualModel, thinkingLevel: level, configSource: "variant" };
}
}
if (!variantConfig.thinkingBudget) return base;
// ... rest unchanged
}
Environment
- opencode-antigravity-auth: 1.6.0 (@latest)
- opencode: 1.2.15
- Platform: macOS (darwin/arm64)
---
### Issue 2: Tool Schema 400 Error
**Title:** `normalizeGeminiTools deletes custom wrapper without creating function field — causes 400 on custom-only tools`
**Body:**
Bug
Gemini API returns 400 "Request contains an invalid argument" when a tool has only a custom field (no function field), which is the standard format for MCP tools.
Debug Output
Status: 400
Tool Debug Missing: 1
Tool Debug Summary: idx=0, hasCustom=true, customSchema=true, hasFunction=false, functionSchema=false
Root Cause
In normalizeGeminiTools() (gemini.ts), the logic handles three cases but misses one critical path:
// Case 1: function EXISTS → update its schema ✅
if (newTool.function && schema) {
newTool.function.input_schema = schema;
}
// Case 2: function EXISTS, custom MISSING → create custom from function ✅
if (!newTool.custom && newTool.function) { ... }
// Case 3: BOTH missing → create custom ✅
if (!newTool.custom && !newTool.function) { ... }
// THEN: delete custom wrapper (Gemini only accepts function-style)
if (newTool.custom) {
delete newTool.custom; // ← custom DELETED
}
// ⛔ MISSING CASE: custom EXISTS, function MISSING
// → custom gets deleted, function never created
// → tool becomes empty → 400
When a tool arrives with ONLY custom (standard MCP format):
1. Case 1 skipped (no function)
2. Case 2 skipped (custom exists)
3. Case 3 skipped (custom exists)
4. custom gets deleted
5. No function field was ever created → empty tool → API rejects
Expected Fix
Add a case for custom-only tools that creates the function field:
// After Case 2, add:
// Case 2b: custom EXISTS, function MISSING → create function from custom
if (newTool.custom && !newTool.function) {
const c = newTool.custom;
newTool.function = {
name: c.name || nameCandidate,
description: c.description,
input_schema: schema,
};
}
Environment
- opencode-antigravity-auth: 1.6.0 (@latest)
- opencode: 1.2.15
- Platform: macOS (darwin/arm64)
---
### Steps to reproduce
gemini 3.1 pro high variant issue sub agent call
### Did this ever work?
Worked before, now broken (regression)
### Number of Google accounts configured
1
### Reproducibility
Always (100%)
### Plugin version
opencode-antigravity-auth: 1.6.0 (@latest)
### OpenCode version
opencode: 1.2.15
### Operating System
macOs
### Node.js version
latest
### Environment type
Standard (native terminal)
### MCP servers installed
_No response_
### Debug logs (REQUIRED)
```text
Request contains an invalid argument.
[Debug Info]
Requested Model: antigravity-gemini-3.1-pro
Effective Model: gemini-3.1-pro-low
Project: rising-fact-p41fc
Endpoint: https://cloudcode-pa.googleapis.com/v1internal:streamGenerateContent?alt=sse
Status: 400
Request ID: N/A
Tool Debug Missing: 1
Tool Debug Summary: idx=0, hasCustom=true, customSchema=true, hasFunction=false, functionSchema=false
Tool Debug Payload: [{"functionDeclarations":[{"name":"bash","description":"Executes a given bash command in a persistent shell session with optional timeout, ensuring proper handling and security measures.\n\nAll commands run in /Users/miracthis/Desktop/HumayLojistik/humay-lojistik by default. Use the `workdir` parameter if you need to run a command in a different directory. AVOID using `cd <directory> && <command>` patterns - use `workdir` instead.\n\nIMPORTANT: This tool is for terminal operations like git, npm, docker, etc. DO NOT use it for file operations (reading, writing, editing, searching, finding files) - use the specialized tools for this instead.\n\nBefore executing the command, please follow these steps:\n\n1. Directory Verification:\n - If the command will create new directories or files, first use `ls` to verify the parent directory exists and is the correct location\n - For example, before running \"mkdir foo/bar\", first use `ls foo` to check that \"foo\" exists and is the intended parent directory\n\n2. Command Execution:\n - Always quote file paths that contain spaces with double quotes (e.g., rm \"path with spaces/file.txt\")\n - Examples of proper quoting:\n - mkdir \"/Users/name/My Documents\" (correct)\n - mkdir /Users/name/My Documents (incorrect - will fail)\n - python \"/path/with spaces/script.py\" (correct)\n - python /path/with spaces/script.py (incorrect - will fail)\n - After ensuring proper quoting, execute the command.\n - Capture the output of the command.\n\nUsage notes:\n - The command argument is required.\n - You can specify an optional timeout in milliseconds.
Configuration (optional)
Compliance
Additional context
No response
Pre-submission checklist
Model used
Other (specify in description)
Exact error message
Bug description
Issue 1: Variant Routing Bug
Title: Gemini 3.1 Pro "high" variant falls back to "low" — resolveModelWithVariant ignores thinkingLevel
Body:
Bug
When using
antigravity-gemini-3.1-prowith variant"high", the effective model becomesgemini-3.1-pro-lowinstead ofgemini-3.1-pro-high.Debug Output
Requested Model: antigravity-gemini-3.1-pro
Effective Model: gemini-3.1-pro-low
Root Cause
resolveModelWithVariant()inmodel-resolver.ts(line ~311) checks only forthinkingBudgetand returns early if it's missing — completely ignoringthinkingLevel:Configuration (optional)
Compliance
Additional context
No response