From 33284f822af1f84a10094e6441fb1d89da6378b9 Mon Sep 17 00:00:00 2001 From: elkaix Date: Fri, 14 Aug 2026 01:59:56 -0400 Subject: [PATCH] feat!: default to Gemini 3.7 Flash (High) across all tool chains Bump the default model and every tool routing chain from Gemini 3.6 Flash to Gemini 3.7 Flash. Refresh the README with benchmark highlights and an MCP stack guide, redesign the banner, and add a benchmarks asset. Release v2.0.0. BREAKING CHANGE: the default model and built-in routing chains now target Gemini 3.7 Flash; setups pinned to agy listings without 3.7 models will fall back differently. --- README.md | 113 +++++++++++++++++++++--- assets/banner.svg | 199 ++++++++++++++++++++++++++++++++++-------- assets/benchmarks.svg | 137 +++++++++++++++++++++++++++++ package-lock.json | 4 +- package.json | 2 +- server.json | 6 +- src/config.ts | 2 +- src/server.ts | 2 +- src/tools.ts | 10 +-- test/config.test.ts | 2 +- test/models.test.ts | 22 ++--- test/server.test.ts | 30 +++---- 12 files changed, 440 insertions(+), 89 deletions(-) create mode 100644 assets/benchmarks.svg diff --git a/README.md b/README.md index 8eb0696..d86956c 100644 --- a/README.md +++ b/README.md @@ -12,28 +12,115 @@

Install · + Why Gemini 3.7 Flash? · + MCP Power Stack · Tools · Timeouts · Configuration

-**Claude Code delegates heavy tasks to the Antigravity CLI (`agy`)** — saving Claude's context window and tokens for what matters. +**Claude Code delegates heavy tasks to Google's flagship Gemini 3.7 Flash (High)** via the Antigravity CLI (`agy`) — saving Claude's context window and tokens for what matters. -Claude sends a task → the bridge routes it to the best available model via `agy` → only the answer comes back. Large files, deep git searches, and web lookups never touch Claude's context. +Claude acts as the orchestrator → `claude-agy-mcp` routes compute-heavy sub-tasks to **Gemini 3.7 Flash (High)** → only concise answers return. Large files, deep git searches, and log dumps never pollute Claude's context. ``` -User → Claude Code → claude-agy-mcp (MCP) → agy CLI → Gemini / Claude / GPT-OSS - ← ← ← +User → Claude Code → claude-agy-mcp (MCP) → agy CLI → Gemini 3.7 Flash / Pro / Claude + ← ← ← (Clean answers only) ``` +## Why Gemini 3.7 Flash (High) for Claude Code? + +
+ Gemini 3.7 Flash Benchmarks +
+ +**Gemini 3.7 Flash** is Google's most intelligent workhorse model for coding and agentic execution. It applies deep multi-step planning, rigorous terminal reasoning, and high first-pass code accuracy. + +### Benchmark Highlights + +| Benchmark / Capability | Gemini 3.7 Flash (High) | Prior Generation (3.6 Flash) | Advantage | +| ---------------------- | ----------------------- | ---------------------------- | ----------------------------------------------------------------------------------------- | +| **DeepSWE v1.1** | **65.3%** | 49.0% | **+16.3%** jump in long-horizon repository software engineering | +| **FrontierCode 1.1** | **43.6%** | 34.4% | **+9.2%** improvement in production code quality and first-pass accuracy | +| **Terminal-Bench 2.1** | **85.8%** | 78.0% | **+7.8%** higher resilience in agentic CLI execution & tool chaining | +| **WebDev Arena** | **1588 Elo** | 1538 Elo | **#1 Rank** for fullstack web application and UI design adherence | +| **AutomationBench** | **30.4%** | 17.0% | Surpasses GPT-5.6 Terra (23.6%) and Claude Sonnet 5 (10.7%) in enterprise agent workflows | +| **Context & Window** | **1,000,000 Tokens** | 1,000,000 Tokens | 64K output tokens with 97.0% retrieval on GDM-MRCR v2 (128k) | +| **Token Economics** | **$0.75 / $3.75** (1M) | $1.50 / $7.50 | Up to **10x–20x cheaper** than Claude Opus/Sonnet for background delegation | + +### The Token & Context Multiplier + +When Claude Code directly analyzes a 4,000-line database dump or greps 20 files across git history, those thousands of lines stay permanently in Claude's prompt context, inflating cost and pushing you toward compaction. + +With `claude-agy-mcp`: + +1. Claude calls `analyze_files` or `deep_search`. +2. Gemini 3.7 Flash processes the 100k+ tokens in isolation via `agy`. +3. Only the exact code-level findings and line citations return into Claude's prompt. +4. Subsequent questions reuse the same agy session with `follow_up` without re-sending any files. + +--- + +## The Ultimate AI Engineering MCP Stack + +`claude-agy-mcp` is designed to anchor a modern AI engineer's MCP toolkit alongside complementary specialized servers: + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ Claude Code (Agent) │ +└──────┬──────────────────────┬───────────────────────┬───────────────────────┘ + │ │ │ │ + ▼ ▼ ▼ ▼ +┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ +│claude-agy-mcp│ │ context7 │ │ firecrawl │ │ tavily │ +│ (Gemini 3.7 │ │(Official Docs│ │(Web Scraping │ │(Live Search │ +│ Delegation) │ │ & API Specs)│ │ & Crawling) │ │ & Research) │ +└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ +``` + +| MCP Server | Primary Superpower | When Claude Uses It | +| -------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`claude-agy-mcp`** | **Heavy Compute & Coding Delegation** | Analyzing files >200 lines, repo archaeology (`git log/diff/blame`), adversarial code reviews, and raw execution via Gemini 3.7 Flash. | +| **`context7`** | **Up-to-date Official Documentation** | Fetching latest version-accurate API signatures and documentation for libraries (Next.js, React, Tailwind, Prisma, Vite, etc.) to eliminate hallucinated APIs. | +| **`firecrawl`** | **Clean Web Scraping & Crawling** | Converting dynamic web pages, documentation sites, and GitHub repos into clean, LLM-ready markdown or structured JSON. | +| **`tavily`** | **Fast Live Search & Grounding** | Low-latency web search, current news, error message lookups, and technical research. | + +### Recommended MCP Configuration (`.agents/mcp_config.json` or Claude Code) + +```json +{ + "mcpServers": { + "claude-agy-mcp": { + "command": "npx", + "args": ["-y", "@pymodel/claude-agy-mcp"], + "timeout": 3600000 + }, + "context7": { + "command": "npx", + "args": ["-y", "@upstash/context7-mcp@latest"] + }, + "firecrawl": { + "command": "npx", + "args": ["-y", "firecrawl-mcp"] + }, + "tavily": { + "command": "npx", + "args": ["-y", "tavily-mcp"] + } + } +} +``` + +--- + ## Why this over claude-to-agy? | | claude-to-agy | **claude-agy-mcp** | | --------------- | --------------------------- | ------------------------------------------------------------------------------------ | | Tool surface | 1 generic `delegate_to_agy` | 6 purpose-built tools — Claude self-routes reliably | -| Model selection | none (agy default only) | per-tool routing across all `agy models`, with availability detection and fallback | +| Model selection | none (agy default only) | per-tool routing prioritizing **Gemini 3.7 Flash (High)** with quota failover | | Multi-turn | stateless | session continuity — `follow_up` resumes agy conversations without resending context | | Output safety | unbounded | configurable truncation cap protects Claude's context | | Sandbox | no | optional `--sandbox` mode | @@ -71,12 +158,12 @@ curl -o CLAUDE.md https://raw.githubusercontent.com/PyModel/claude-agy-mcp/main/ | Tool | Use for | Model routing (first available) | | -------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | -| `analyze_files` | Files >200 lines, >3 files at once, logs, dumps, generated code | Gemini 3.6 Flash (High) → Gemini 3.5 Flash (High) → Gemini 3.1 Pro (Low) | -| `deep_search` | git log/diff/blame archaeology, repo-wide greps | Gemini 3.6 Flash (Medium) → Gemini 3.6 Flash (High) → Gemini 3.5 Flash (High) | -| `web_lookup` | Docs, API references, external/current knowledge | Gemini 3.6 Flash (Medium) → Gemini 3.6 Flash (High) → Gemini 3.5 Flash (High) | -| `adversarial_review` | Plan critiques, design and code reviews | Gemini 3.1 Pro (High) → Claude Opus 4.6 (Thinking) → Gemini 3.6 Flash (High) → Gemini 3.5 Flash (High) | +| `analyze_files` | Files >200 lines, >3 files at once, logs, dumps, generated code | Gemini 3.7 Flash (High) → Gemini 3.5 Flash (High) → Gemini 3.1 Pro (Low) | +| `deep_search` | git log/diff/blame archaeology, repo-wide greps | Gemini 3.7 Flash (Medium) → Gemini 3.7 Flash (High) → Gemini 3.5 Flash (High) | +| `web_lookup` | Docs, API references, external/current knowledge | Gemini 3.7 Flash (Medium) → Gemini 3.7 Flash (High) → Gemini 3.5 Flash (High) | +| `adversarial_review` | Plan critiques, design and code reviews | Gemini 3.1 Pro (High) → Claude Opus 4.6 (Thinking) → Gemini 3.7 Flash (High) → Gemini 3.5 Flash (High) | | `follow_up` | Continue a prior session by `session_id` — no context resend | inherits the session | -| `delegate` | Anything else heavy | Gemini 3.6 Flash (High) → Gemini 3.5 Flash (High) | +| `delegate` | Anything else heavy | Gemini 3.7 Flash (High) → Gemini 3.5 Flash (High) | All tools accept optional `cwd` (project root) and `model` (exact name from `agy models`; validated, with available models listed on mismatch). @@ -84,12 +171,12 @@ Every response ends with a footer: ``` --- -[claude-agy-mcp] model: Gemini 3.6 Flash (High) | session: 1f0c…-d4 (use follow_up to continue) +[claude-agy-mcp] model: Gemini 3.7 Flash (High) | session: 1f0c…-d4 (use follow_up to continue) ``` ### Model routing -On first use the bridge runs `agy models` (cached for the process lifetime) and picks the first available model in the tool's preference chain. If none is available it falls back to `AGY_DEFAULT_MODEL`, and finally to agy's own default. agy silently ignores unknown `--model` values, so the bridge validates names up front instead of letting requests land on the wrong model. +On first use the bridge runs `agy models` (cached for the process lifetime) and picks the first available model in the tool's preference chain (defaulting to **Gemini 3.7 Flash (High)**). If none is available it falls back to `AGY_DEFAULT_MODEL`, and finally to agy's own default. agy silently ignores unknown `--model` values, so the bridge validates names up front instead of letting requests land on the wrong model. ### Quota-aware failover @@ -127,7 +214,7 @@ All optional, via environment variables: | `AGY_TIMEOUT` | `AGY_MAX_RUNTIME` | Seconds; overrides the ceiling for every tool, passed as `--print-timeout`, enforced with a 15s kill grace | | `AGY_TIMEOUT_` | `AGY_MAX_RUNTIME` | Seconds; overrides the ceiling for a single tool, e.g. `AGY_TIMEOUT_DEEP_SEARCH=900`. Wins over `AGY_TIMEOUT` | | `AGY_MAX_OUTPUT_CHARS` | `50000` | Truncation cap for tool output | -| `AGY_DEFAULT_MODEL` | Gemini 3.6 Flash (High) | Fallback model when no chain entry is available | +| `AGY_DEFAULT_MODEL` | Gemini 3.7 Flash (High) | Fallback model when no chain entry is available | | `AGY_SKIP_PERMISSIONS` | `true` | Pass `--dangerously-skip-permissions` to agy | | `AGY_SANDBOX` | `false` | Run agy with `--sandbox` | | `AGY_ON_FAILURE` | `fallback` | `strict` appends an instruction to failed-tool errors telling the calling agent not to absorb the work itself | diff --git a/assets/banner.svg b/assets/banner.svg index 618d4f7..b3b22cb 100644 --- a/assets/banner.svg +++ b/assets/banner.svg @@ -1,48 +1,175 @@ - + - - - + + + + + - - + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - claude-agy-mcp + + claude-agy-mcp + + + + v2.0.0 + + + + + Default: Gemini 3.7 Flash (High) + + + Claude Code delegates heavy coding tasks to Google's Antigravity CLI + Context-free file analysis, git archaeology, and adversarial code reviews with quota-aware failover. - - - Claude Code delegates the heavy work to the Antigravity CLI. - 6 tools · quota-aware failover · session continuity - - - - - - - - delegation session - - - - analyze_files14 files · 4,200 lines - ↳ routed → Gemini 3.6 Flash (High) - ↳ 46s · 0 lines entered Claude's context - [claude-agy-mcp] model: Gemini 3.6 Flash (High) · session: 1f0c…d4 + + + + + + + + + + + + + + + + + + claude-code — delegation session [agy bridge] + + + + + + failover ready · quota ok + + + + + + + + analyze_files + [ + "src/server.ts" + , + "src/runner.ts" + , + "src/models.ts" + ] + · 14 files, 4,200 lines (bypasses Claude context) + + + + + + routed to + + Gemini 3.7 Flash (High) + via agy CLI + ✓ 65.3% DeepSWE + · 42s cold start + + + + + + completed + Identified 3 edge cases, ranked by severity with file:line citations + + + + + + + + [ + claude-agy-mcp + ] + model: + Gemini 3.7 Flash (High) + | + session: + 1f0c4a…9d + (use follow_up to continue with 0 context overhead) + + diff --git a/assets/benchmarks.svg b/assets/benchmarks.svg new file mode 100644 index 0000000..e1eeea8 --- /dev/null +++ b/assets/benchmarks.svg @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GOOGLE DEEPMIND · GEMINI 3.7 FLASH + + Google's Flagship Coding & Reasoning Workhorse + Engineered for long-horizon repository execution, multi-step terminal planning, and context-free Claude delegation. + + + + + + + + + + DeepSWE v1.1 + + 65.3% + + + + + + ▲ +16.3% vs 3.6 Flash (49.0%) + Repository-level issue resolution + + + + + + + Terminal-Bench 2.1 + + 85.8% + + + + + + ▲ +7.8% vs 3.6 Flash (78.0%) + Agentic CLI & command execution + + + + + + + WebDev Arena + + 1588 Elo + + + + + + #1 Leaderboard Rank (vs 1538) + Fullstack app & UI synthesis + + + + + + + AutomationBench + + 30.4% + + + + + + ▲ Ahead of Sonnet 5 (10.7%) + Multi-step enterprise workflows + + + + diff --git a/package-lock.json b/package-lock.json index 764e405..f55bc4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@pymodel/claude-agy-mcp", - "version": "1.0.3", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pymodel/claude-agy-mcp", - "version": "1.0.3", + "version": "2.0.0", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.12.0", diff --git a/package.json b/package.json index ba82a83..824d44c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pymodel/claude-agy-mcp", - "version": "1.0.3", + "version": "2.0.0", "description": "MCP bridge that lets Claude Code delegate heavy tasks to the Antigravity CLI (agy) — purpose-built tools, model routing with fallback, and multi-turn session continuity.", "mcpName": "io.github.PyModel/claude-agy-mcp", "type": "module", diff --git a/server.json b/server.json index a9be23c..e75c144 100644 --- a/server.json +++ b/server.json @@ -6,12 +6,12 @@ "url": "https://github.com/PyModel/claude-agy-mcp", "source": "github" }, - "version": "1.0.3", + "version": "2.0.0", "packages": [ { "registryType": "npm", "identifier": "@pymodel/claude-agy-mcp", - "version": "1.0.3", + "version": "2.0.0", "transport": { "type": "stdio" }, @@ -45,7 +45,7 @@ "name": "AGY_MAX_OUTPUT_CHARS" }, { - "description": "Fallback model when no chain entry is available (defaults to Gemini 3.6 Flash (High))", + "description": "Fallback model when no chain entry is available (defaults to Gemini 3.7 Flash (High))", "isRequired": false, "format": "string", "isSecret": false, diff --git a/src/config.ts b/src/config.ts index 2958e5f..9149153 100644 --- a/src/config.ts +++ b/src/config.ts @@ -42,7 +42,7 @@ export function loadConfig(env: Record = process.env perToolTimeouts: loadPerToolTimeouts(env), maxRuntimeSec: positiveInt(env.AGY_MAX_RUNTIME, 3600), maxOutputChars: positiveInt(env.AGY_MAX_OUTPUT_CHARS, 50_000), - defaultModel: env.AGY_DEFAULT_MODEL || "Gemini 3.6 Flash (High)", + defaultModel: env.AGY_DEFAULT_MODEL || "Gemini 3.7 Flash (High)", skipPermissions: env.AGY_SKIP_PERMISSIONS !== "false", sandbox: env.AGY_SANDBOX === "true", onFailure: env.AGY_ON_FAILURE === "strict" ? "strict" : "fallback", diff --git a/src/server.ts b/src/server.ts index 67cce23..0761a44 100644 --- a/src/server.ts +++ b/src/server.ts @@ -12,7 +12,7 @@ import { CooldownRegistry, QuotaError } from "./quota.js"; import { TOOLS, type ToolDef } from "./tools.js"; /** Keep in sync with package.json — test/server.test.ts fails if they drift. */ -export const VERSION = "1.0.3"; +export const VERSION = "2.0.0"; interface ToolResponse { [key: string]: unknown; diff --git a/src/tools.ts b/src/tools.ts index b1ba59e..2d337a0 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -49,7 +49,7 @@ export const TOOLS: ToolDef[] = [ question: z.string().describe("What you want to know about these files."), ...commonShape, }, - chain: ["Gemini 3.6 Flash (High)", "Gemini 3.5 Flash (High)", "Gemini 3.1 Pro (Low)"], + chain: ["Gemini 3.7 Flash (High)", "Gemini 3.5 Flash (High)", "Gemini 3.1 Pro (Low)"], buildPrompt(args, cwd) { const files = resolveFiles(args.files as string[], cwd); return ( @@ -70,7 +70,7 @@ export const TOOLS: ToolDef[] = [ .describe("What to find, e.g. 'when was the auth middleware refactored and why'."), ...commonShape, }, - chain: ["Gemini 3.6 Flash (Medium)", "Gemini 3.6 Flash (High)", "Gemini 3.5 Flash (High)"], + chain: ["Gemini 3.7 Flash (Medium)", "Gemini 3.7 Flash (High)", "Gemini 3.5 Flash (High)"], buildPrompt(args) { return ( `Search this repository to answer the following. Use git log, git diff, git blame, ` + @@ -89,7 +89,7 @@ export const TOOLS: ToolDef[] = [ query: z.string().describe("What to look up on the web."), ...commonShape, }, - chain: ["Gemini 3.6 Flash (Medium)", "Gemini 3.6 Flash (High)", "Gemini 3.5 Flash (High)"], + chain: ["Gemini 3.7 Flash (Medium)", "Gemini 3.7 Flash (High)", "Gemini 3.5 Flash (High)"], buildPrompt(args) { return `Look up on the web: ${args.query}\n\nInclude source URLs for key claims. ${OUTPUT_RULES}`; }, @@ -115,7 +115,7 @@ export const TOOLS: ToolDef[] = [ chain: [ "Gemini 3.1 Pro (High)", "Claude Opus 4.6 (Thinking)", - "Gemini 3.6 Flash (High)", + "Gemini 3.7 Flash (High)", "Gemini 3.5 Flash (High)", ], buildPrompt(args, cwd) { @@ -163,7 +163,7 @@ export const TOOLS: ToolDef[] = [ prompt: z.string().describe("The complete task prompt for agy."), ...commonShape, }, - chain: ["Gemini 3.6 Flash (High)", "Gemini 3.5 Flash (High)"], + chain: ["Gemini 3.7 Flash (High)", "Gemini 3.5 Flash (High)"], buildPrompt(args) { return args.prompt as string; }, diff --git a/test/config.test.ts b/test/config.test.ts index 6f696b4..d249fb8 100644 --- a/test/config.test.ts +++ b/test/config.test.ts @@ -11,7 +11,7 @@ describe("loadConfig", () => { perToolTimeouts: {}, maxRuntimeSec: 3600, maxOutputChars: 50_000, - defaultModel: "Gemini 3.6 Flash (High)", + defaultModel: "Gemini 3.7 Flash (High)", skipPermissions: true, sandbox: false, onFailure: "fallback", diff --git a/test/models.test.ts b/test/models.test.ts index 38e6088..e780c6f 100644 --- a/test/models.test.ts +++ b/test/models.test.ts @@ -2,7 +2,7 @@ import { describe, it, expect } from "vitest"; import { parseModels, ModelRegistry } from "../src/models.js"; const LISTING = `Gemini 3.5 Flash (Medium) -Gemini 3.6 Flash (High) +Gemini 3.7 Flash (High) Gemini 3.5 Flash (High) Gemini 3.1 Pro (High) `; @@ -11,7 +11,7 @@ describe("parseModels", () => { it("returns one trimmed model per non-empty line", () => { expect(parseModels(LISTING)).toEqual([ "Gemini 3.5 Flash (Medium)", - "Gemini 3.6 Flash (High)", + "Gemini 3.7 Flash (High)", "Gemini 3.5 Flash (High)", "Gemini 3.1 Pro (High)", ]); @@ -19,11 +19,11 @@ describe("parseModels", () => { it("returns both the id and the display name from tab-separated listings", () => { const raw = - "gemini-3.6-flash-high\tGemini 3.6 Flash (High)\n" + + "gemini-3.7-flash-high\tGemini 3.7 Flash (High)\n" + "gemini-3.1-pro-low\tGemini 3.1 Pro (Low)\n"; expect(parseModels(raw)).toEqual([ - "gemini-3.6-flash-high", - "Gemini 3.6 Flash (High)", + "gemini-3.7-flash-high", + "Gemini 3.7 Flash (High)", "gemini-3.1-pro-low", "Gemini 3.1 Pro (Low)", ]); @@ -56,9 +56,9 @@ describe("ModelRegistry.resolve", () => { it("picks first available model in chain", async () => { const r = await registry(LISTING).resolve({ - chain: ["Gemini 9.9 Ultra", "Gemini 3.6 Flash (High)"], + chain: ["Gemini 9.9 Ultra", "Gemini 3.7 Flash (High)"], }); - expect(r.model).toBe("Gemini 3.6 Flash (High)"); + expect(r.model).toBe("Gemini 3.7 Flash (High)"); }); it("falls back to defaultModel when chain misses", async () => { @@ -78,7 +78,7 @@ describe("ModelRegistry.resolve", () => { const reg = registry(new Error("boom")); const a = await reg.resolve({ explicit: "Whatever", chain: [] }); expect(a.model).toBe("Whatever"); - const b = await reg.resolve({ chain: ["Gemini 3.6 Flash (High)"] }); + const b = await reg.resolve({ chain: ["Gemini 3.7 Flash (High)"] }); expect(b.model).toBeUndefined(); expect(b.note).toMatch(/could not list/i); }); @@ -120,11 +120,11 @@ describe("ModelRegistry.resolve", () => { return LISTING; }); const [a, b] = await Promise.all([ - reg.resolveChain({ chain: ["Gemini 3.6 Flash (High)"] }), + reg.resolveChain({ chain: ["Gemini 3.7 Flash (High)"] }), reg.resolveChain({ chain: ["Gemini 3.1 Pro (High)"] }), ]); expect(calls).toBe(1); - expect(a.models).toEqual(["Gemini 3.6 Flash (High)"]); + expect(a.models).toEqual(["Gemini 3.7 Flash (High)"]); expect(b.models).toEqual(["Gemini 3.1 Pro (High)"]); }); @@ -146,7 +146,7 @@ describe("ModelRegistry.resolve", () => { calls++; return LISTING; }); - await reg.resolve({ chain: ["Gemini 3.6 Flash (High)"] }); + await reg.resolve({ chain: ["Gemini 3.7 Flash (High)"] }); await reg.resolve({ chain: ["Gemini 3.1 Pro (High)"] }); expect(calls).toBe(1); }); diff --git a/test/server.test.ts b/test/server.test.ts index 44b3064..c5f2ff7 100644 --- a/test/server.test.ts +++ b/test/server.test.ts @@ -21,8 +21,8 @@ const cfg: Config = { }; const LISTING = - "Gemini 3.6 Flash (Medium)\n" + - "Gemini 3.6 Flash (High)\n" + + "Gemini 3.7 Flash (Medium)\n" + + "Gemini 3.7 Flash (High)\n" + "Gemini 3.5 Flash (High)\n" + "Gemini 3.1 Pro (High)\n"; @@ -90,13 +90,13 @@ describe("createToolHandler", () => { const res = await handlerFor("delegate", f)({ prompt: "do x" }); const text = (res.content[0] as { text: string }).text; expect(text).toContain("the answer"); - expect(text).toContain("Gemini 3.6 Flash (High)"); + expect(text).toContain("Gemini 3.7 Flash (High)"); expect(text).toContain("sess-1"); expect(f.runs[0].args).toContain("--model"); }); it("returns timeout details and does not fail over after a timed-out run", async () => { - const f = fakeDeps([], ["Gemini 3.6 Flash (High)"]); + const f = fakeDeps([], ["Gemini 3.7 Flash (High)"]); const res = await handlerFor("delegate", f, { timeoutSec: 0.05, timeoutExplicit: true, @@ -158,41 +158,41 @@ describe("createToolHandler", () => { }); it("fails over to the next chain model on quota exhaustion", async () => { - const f = fakeDeps(["Gemini 3.6 Flash (Medium)"]); + const f = fakeDeps(["Gemini 3.7 Flash (Medium)"]); const res = await handlerFor("web_lookup", f)({ query: "docs" }); const text = (res.content[0] as { text: string }).text; expect(res.isError).toBeUndefined(); expect(f.runs).toHaveLength(2); - expect(f.modelOf(f.runs[0])).toBe("Gemini 3.6 Flash (Medium)"); - expect(f.modelOf(f.runs[1])).toBe("Gemini 3.6 Flash (High)"); + expect(f.modelOf(f.runs[0])).toBe("Gemini 3.7 Flash (Medium)"); + expect(f.modelOf(f.runs[1])).toBe("Gemini 3.7 Flash (High)"); expect(text).toContain("the answer"); - expect(text).toContain("model: Gemini 3.6 Flash (High)"); - expect(text).toMatch(/failover.*Gemini 3.6 Flash \(Medium\).*quota/i); + expect(text).toContain("model: Gemini 3.7 Flash (High)"); + expect(text).toMatch(/failover.*Gemini 3.7 Flash \(Medium\).*quota/i); }); it("skips cooled-down models on subsequent calls without spawning them", async () => { - const f = fakeDeps(["Gemini 3.6 Flash (Medium)"]); + const f = fakeDeps(["Gemini 3.7 Flash (Medium)"]); const cooldowns = new CooldownRegistry(); const handler = handlerFor("web_lookup", f, {}, cooldowns); await handler({ query: "first" }); expect(f.runs).toHaveLength(2); await handler({ query: "second" }); expect(f.runs).toHaveLength(3); - expect(f.modelOf(f.runs[2])).toBe("Gemini 3.6 Flash (High)"); + expect(f.modelOf(f.runs[2])).toBe("Gemini 3.7 Flash (High)"); }); it("errors with reset times when every chain model is quota-exhausted", async () => { const f = fakeDeps([ - "Gemini 3.6 Flash (Medium)", - "Gemini 3.6 Flash (High)", + "Gemini 3.7 Flash (Medium)", + "Gemini 3.7 Flash (High)", "Gemini 3.5 Flash (High)", ]); const res = await handlerFor("web_lookup", f)({ query: "docs" }); expect(res.isError).toBe(true); const text = (res.content[0] as { text: string }).text; expect(text).toMatch(/quota/i); - expect(text).toContain("Gemini 3.6 Flash (Medium)"); - expect(text).toContain("Gemini 3.6 Flash (High)"); + expect(text).toContain("Gemini 3.7 Flash (Medium)"); + expect(text).toContain("Gemini 3.7 Flash (High)"); expect(text).toContain("Gemini 3.5 Flash (High)"); expect(text).toContain("4h24m"); });