diff --git a/docs/configurations.md b/docs/configurations.md index 68b3e876..0ade649f 100644 --- a/docs/configurations.md +++ b/docs/configurations.md @@ -83,7 +83,7 @@ When both `oh-my-opencode.jsonc` and `oh-my-opencode.json` files exist, `.jsonc` ## Google Auth -**Recommended**: For Google Gemini authentication, install the [`opencode-antigravity-auth`](https://github.com/NoeFabris/opencode-antigravity-auth) plugin. It provides multi-account load balancing, more models (including Claude via Antigravity), and active maintenance. See [Installation > Google Gemini](../README.md#google-gemini-antigravity-oauth). +**Recommended**: For Google Gemini authentication, install the [`opencode-antigravity-auth`](https://github.com/NoeFabris/opencode-antigravity-auth) plugin (`@latest`). It provides multi-account load balancing, variant-based thinking levels, dual quota system (Antigravity + Gemini CLI), and active maintenance. See [Installation > Google Gemini](docs/guide/installation.md#google-gemini-antigravity-oauth). ## Agents diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 32cced2b..f3cfae19 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -132,7 +132,7 @@ First, add the opencode-antigravity-auth plugin: { "plugin": [ "oh-my-opencode", - "opencode-antigravity-auth@1.2.8" + "opencode-antigravity-auth@latest" ] } ``` @@ -140,7 +140,7 @@ First, add the opencode-antigravity-auth plugin: ##### Model Configuration You'll also need full model settings in `opencode.json`. -Read the [opencode-antigravity-auth documentation](https://github.com/NoeFabris/opencode-antigravity-auth), copy provider/models config from the README, and merge carefully to avoid breaking the user's existing setup. +Read the [opencode-antigravity-auth documentation](https://github.com/NoeFabris/opencode-antigravity-auth), copy the full model configuration from the README, and merge carefully to avoid breaking the user's existing setup. The plugin now uses a **variant system** — models like `antigravity-gemini-3-pro` support `low`/`high` variants instead of separate `-low`/`-high` model entries. ##### oh-my-opencode Agent Model Override @@ -154,7 +154,17 @@ The `opencode-antigravity-auth` plugin uses different model names than the built } ``` -**Available model names**: `google/antigravity-gemini-3-pro-high`, `google/antigravity-gemini-3-pro-low`, `google/antigravity-gemini-3-flash`, `google/antigravity-claude-sonnet-4-5`, `google/antigravity-claude-sonnet-4-5-thinking-low`, `google/antigravity-claude-sonnet-4-5-thinking-medium`, `google/antigravity-claude-sonnet-4-5-thinking-high`, `google/antigravity-claude-opus-4-5-thinking-low`, `google/antigravity-claude-opus-4-5-thinking-medium`, `google/antigravity-claude-opus-4-5-thinking-high`, `google/gemini-3-pro`, `google/gemini-3-flash`, `google/gemini-2.5-pro`, `google/gemini-2.5-flash` +**Available models (Antigravity quota)**: +- `google/antigravity-gemini-3-pro` — variants: `low`, `high` +- `google/antigravity-gemini-3-flash` — variants: `minimal`, `low`, `medium`, `high` +- `google/antigravity-claude-sonnet-4-5` — no variants +- `google/antigravity-claude-sonnet-4-5-thinking` — variants: `low`, `max` +- `google/antigravity-claude-opus-4-5-thinking` — variants: `low`, `max` + +**Available models (Gemini CLI quota)**: +- `google/gemini-2.5-flash`, `google/gemini-2.5-pro`, `google/gemini-3-flash-preview`, `google/gemini-3-pro-preview` + +> **Note**: Legacy tier-suffixed names like `google/antigravity-gemini-3-pro-high` still work but variants are recommended. Use `--variant=high` with the base model name instead. Then authenticate: diff --git a/src/cli/config-manager.test.ts b/src/cli/config-manager.test.ts index 99a4261b..cd4d5ec2 100644 --- a/src/cli/config-manager.test.ts +++ b/src/cli/config-manager.test.ts @@ -170,7 +170,7 @@ describe("fetchNpmDistTags", () => { }) describe("config-manager ANTIGRAVITY_PROVIDER_CONFIG", () => { - test("Gemini models include full spec (limit + modalities)", () => { + test("all models include full spec (limit + modalities + Antigravity label)", () => { const google = (ANTIGRAVITY_PROVIDER_CONFIG as any).google expect(google).toBeTruthy() @@ -178,9 +178,11 @@ describe("config-manager ANTIGRAVITY_PROVIDER_CONFIG", () => { expect(models).toBeTruthy() const required = [ - "antigravity-gemini-3-pro-high", - "antigravity-gemini-3-pro-low", + "antigravity-gemini-3-pro", "antigravity-gemini-3-flash", + "antigravity-claude-sonnet-4-5", + "antigravity-claude-sonnet-4-5-thinking", + "antigravity-claude-opus-4-5-thinking", ] for (const key of required) { @@ -198,6 +200,43 @@ describe("config-manager ANTIGRAVITY_PROVIDER_CONFIG", () => { expect(Array.isArray(model.modalities.output)).toBe(true) } }) + + test("Gemini models have variant definitions", () => { + // #given the antigravity provider config + const models = (ANTIGRAVITY_PROVIDER_CONFIG as any).google.models as Record + + // #when checking Gemini Pro variants + const pro = models["antigravity-gemini-3-pro"] + // #then should have low and high variants + expect(pro.variants).toBeTruthy() + expect(pro.variants.low).toBeTruthy() + expect(pro.variants.high).toBeTruthy() + + // #when checking Gemini Flash variants + const flash = models["antigravity-gemini-3-flash"] + // #then should have minimal, low, medium, high variants + expect(flash.variants).toBeTruthy() + expect(flash.variants.minimal).toBeTruthy() + expect(flash.variants.low).toBeTruthy() + expect(flash.variants.medium).toBeTruthy() + expect(flash.variants.high).toBeTruthy() + }) + + test("Claude thinking models have variant definitions", () => { + // #given the antigravity provider config + const models = (ANTIGRAVITY_PROVIDER_CONFIG as any).google.models as Record + + // #when checking Claude thinking variants + const sonnetThinking = models["antigravity-claude-sonnet-4-5-thinking"] + const opusThinking = models["antigravity-claude-opus-4-5-thinking"] + + // #then both should have low and max variants + for (const model of [sonnetThinking, opusThinking]) { + expect(model.variants).toBeTruthy() + expect(model.variants.low).toBeTruthy() + expect(model.variants.max).toBeTruthy() + } + }) }) describe("generateOmoConfig - model fallback system", () => { diff --git a/src/cli/config-manager.ts b/src/cli/config-manager.ts index 1bfb4e26..ef7e6284 100644 --- a/src/cli/config-manager.ts +++ b/src/cli/config-manager.ts @@ -497,38 +497,61 @@ export async function runBunInstallWithDetails(): Promise { * * IMPORTANT: Model names MUST use `antigravity-` prefix for stability. * - * The opencode-antigravity-auth plugin supports two naming conventions: - * - `antigravity-gemini-3-pro-high` (RECOMMENDED, explicit Antigravity quota routing) - * - `gemini-3-pro-high` (LEGACY, backward compatible but may break in future) + * Since opencode-antigravity-auth v1.3.0, models use a variant system: + * - `antigravity-gemini-3-pro` with variants: low, high + * - `antigravity-gemini-3-flash` with variants: minimal, low, medium, high * - * Legacy names rely on Gemini CLI using `-preview` suffix for disambiguation. - * If Google removes `-preview`, legacy names may route to wrong quota. + * Legacy tier-suffixed names (e.g., `antigravity-gemini-3-pro-high`) still work + * but variants are the recommended approach. * - * @see https://github.com/NoeFabris/opencode-antigravity-auth#migration-guide-v127 + * @see https://github.com/NoeFabris/opencode-antigravity-auth#models */ export const ANTIGRAVITY_PROVIDER_CONFIG = { google: { name: "Google", models: { - "antigravity-gemini-3-pro-high": { - name: "Gemini 3 Pro High (Antigravity)", - thinking: true, - attachment: true, - limit: { context: 1048576, output: 65535 }, - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - }, - "antigravity-gemini-3-pro-low": { - name: "Gemini 3 Pro Low (Antigravity)", - thinking: true, - attachment: true, + "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-flash": { name: "Gemini 3 Flash (Antigravity)", - attachment: true, limit: { context: 1048576, output: 65536 }, modalities: { input: ["text", "image", "pdf"], output: ["text"] }, + variants: { + minimal: { thinkingLevel: "minimal" }, + low: { thinkingLevel: "low" }, + medium: { thinkingLevel: "medium" }, + high: { thinkingLevel: "high" }, + }, + }, + "antigravity-claude-sonnet-4-5": { + name: "Claude Sonnet 4.5 (Antigravity)", + limit: { context: 200000, output: 64000 }, + modalities: { input: ["text", "image", "pdf"], output: ["text"] }, + }, + "antigravity-claude-sonnet-4-5-thinking": { + name: "Claude Sonnet 4.5 Thinking (Antigravity)", + limit: { context: 200000, output: 64000 }, + modalities: { input: ["text", "image", "pdf"], output: ["text"] }, + variants: { + low: { thinkingConfig: { thinkingBudget: 8192 } }, + max: { thinkingConfig: { thinkingBudget: 32768 } }, + }, + }, + "antigravity-claude-opus-4-5-thinking": { + name: "Claude Opus 4.5 Thinking (Antigravity)", + limit: { context: 200000, output: 64000 }, + modalities: { input: ["text", "image", "pdf"], output: ["text"] }, + variants: { + low: { thinkingConfig: { thinkingBudget: 8192 } }, + max: { thinkingConfig: { thinkingBudget: 32768 } }, + }, }, }, }, diff --git a/src/hooks/background-compaction/index.ts b/src/hooks/background-compaction/index.ts deleted file mode 100644 index e03d74e8..00000000 --- a/src/hooks/background-compaction/index.ts +++ /dev/null @@ -1,87 +0,0 @@ -import type { BackgroundManager } from "../../features/background-agent" - -interface CompactingInput { - sessionID: string -} - -interface CompactingOutput { - context: string[] - prompt?: string -} - -/** - * Background agent compaction hook - preserves task state during context compaction. - * - * When OpenCode compacts session context to save tokens, this hook injects - * information about running and recently completed background tasks so the - * agent doesn't lose awareness of delegated work. - */ -export function createBackgroundCompactionHook(manager: BackgroundManager) { - return { - "experimental.session.compacting": async ( - input: CompactingInput, - output: CompactingOutput - ): Promise => { - const { sessionID } = input - - // Get running tasks for this session - const running = manager.getRunningTasks() - .filter(t => t.parentSessionID === sessionID) - .map(t => ({ - id: t.id, - agent: t.agent, - description: t.description, - startedAt: t.startedAt, - })) - - // Get recently completed tasks (still in memory within 5-min retention) - const completed = manager.getCompletedTasks() - .filter(t => t.parentSessionID === sessionID) - .slice(-10) // Last 10 completed - .map(t => ({ - id: t.id, - agent: t.agent, - description: t.description, - status: t.status, - })) - - // Early exit if nothing to preserve - if (running.length === 0 && completed.length === 0) return - - const sections: string[] = [""] - - // Running tasks section - if (running.length > 0) { - sections.push("## Running Background Tasks") - sections.push("") - for (const t of running) { - const elapsed = t.startedAt - ? Math.floor((Date.now() - t.startedAt.getTime()) / 1000) - : 0 - sections.push(`- **\`${t.id}\`** (${t.agent}): ${t.description} [${elapsed}s elapsed]`) - } - sections.push("") - sections.push("> **Note:** You WILL be notified when tasks complete.") - sections.push("> Do NOT poll - continue productive work.") - sections.push("") - } - - // Completed tasks section - if (completed.length > 0) { - sections.push("## Recently Completed Tasks") - sections.push("") - for (const t of completed) { - const statusLabel = t.status === "completed" ? "[DONE]" : t.status === "error" ? "[ERROR]" : "[PENDING]" - sections.push(`- ${statusLabel} **\`${t.id}\`**: ${t.description}`) - } - sections.push("") - } - - sections.push("## Retrieval") - sections.push('Use `background_output(task_id="")` to retrieve task results.') - sections.push("") - - output.context.push(sections.join("\n")) - } - } -}