fix(models): give Gemini 3.8 Flash its own output spec (#13195)

Straightforward and well-scoped: a live catalog model falling through to the conservative 16384 clamp because `MODEL_SPECS` never got a 3.8 entry. Keeping the fallback for genuinely unknown ids is right, and the note on how this relates to #12663, #12499 and #12672 saved the review.

---

Validated in one consolidated worktree cut from `release/v3.8.51`, boarded with the other 19 PRs of this batch. Two in-batch conflicts, both additive and resolved by keeping each side: the `ENVIRONMENT.md` table (#13035 + #13011) and the `chatHelpers.ts` import block (#12975 on the tip + #13017).

- `typecheck:core` clean; `check:dashboard-typecheck` OK (206 pre-existing, within baseline); `check:changelog-integrity` OK; `check:docs-counts` migrations ✓
- complexity 2816 / baseline 3218 and cognitive-complexity 1271 / baseline 1437 — both under baseline
- 531 of 532 focused assertions green across the batch's 46 test files
- `check-file-size` rebaselined for the batch's real growth (annotation `_rebaseline_2026_09_11_mergebatch_v3851_houminxi`, landed on #13038), attributed per PR

The single red is **not this batch**: `tests/unit/combo/quota-weighted-strategy.test.ts` → "A/B isolation: 7 hard-empty + 2 at 0.5% + 1 at 40%, floor=1" asserts an order between two connections of identical weight and flakes on the pure tip too — 2 failures in 4 runs at `origin/release/v3.8.51` with nothing from this batch applied.

⚠️ base-red inherited: #12732 — `Docs Gates`, `Merge integrity`, `No new ESLint warnings`, `Unit Tests fast-path` and `Fast Quality Gates` reproduce on the pure tip (provider count 356 vs the 358 the modules define, SKILL.md drift, and `open-sse/utils/stream.ts` at 3115 > frozen 3098, untouched here).

Thanks @HouMinXi — the live evidence on these (X500 logs, `storage.sqlite` state, real `/v1/models` probes, the 36-minute outage write-up) is what let a 20-PR batch be reviewed as a unit.
This commit is contained in:
Bob.Hou
2026-09-11 18:28:13 -04:00
committed by GitHub
parent 9b4210a53f
commit 0cd88ec998
3 changed files with 104 additions and 3 deletions

View File

@@ -0,0 +1 @@
- **fix(models):** give discoverable Gemini 3.8 Flash ids their own 65536 output spec so Antigravity no longer clamps them to 16384 ([#13195](https://github.com/diegosouzapw/OmniRoute/pull/13195)) — thanks @HouMinXi

View File

@@ -181,9 +181,56 @@ export const MODEL_SPECS: Record<string, ModelSpec> = {
supportsTools: true,
supportsVision: true,
},
// ── Gemini 3.7 Flash (current Antigravity/AGY live tiers) ─────────
// The tier suffix configures the thinking budget passed to the upstream
// gemini-3.7-flash-tiered backend (high: 24.5k, medium: 8k, low: 1k).
// Output limit published at https://ai.google.dev/gemini-api/docs/models/gemini-3.8-flash.
// Thinking budgets follow the 3.7 Flash high/medium/low/tiered split.
"gemini-3.8-flash-high": {
maxOutputTokens: 65536,
contextWindow: 1048576,
defaultThinkingBudget: 24576,
thinkingBudgetCap: 24576,
supportsThinking: true,
supportsTools: true,
supportsVision: true,
},
"gemini-3.8-flash-medium": {
maxOutputTokens: 65536,
contextWindow: 1048576,
defaultThinkingBudget: 8192,
thinkingBudgetCap: 24576,
supportsThinking: true,
supportsTools: true,
supportsVision: true,
},
"gemini-3.8-flash-low": {
maxOutputTokens: 65536,
contextWindow: 1048576,
defaultThinkingBudget: 1024,
thinkingBudgetCap: 24576,
supportsThinking: true,
supportsTools: true,
supportsVision: true,
},
"gemini-3.8-flash": {
maxOutputTokens: 65536,
contextWindow: 1048576,
defaultThinkingBudget: 8192,
thinkingBudgetCap: 24576,
supportsThinking: true,
supportsTools: true,
supportsVision: true,
aliases: ["gemini-3.8-flash-tiered"],
},
"gemini-3.8-flash-tiered": {
maxOutputTokens: 65536,
contextWindow: 1048576,
defaultThinkingBudget: 8192,
thinkingBudgetCap: 24576,
supportsThinking: true,
supportsTools: true,
supportsVision: true,
},
// Gemini 3.7 Flash tiers: high 24.5k, medium 8k, low 1k thinking tokens.
"gemini-3.7-flash-high": {
maxOutputTokens: 65536,
contextWindow: 1048576,

View File

@@ -20,6 +20,7 @@ import {
ANTIGRAVITY_MODEL_ALIASES,
ANTIGRAVITY_PUBLIC_MODELS,
} from "../../open-sse/config/antigravityModelAliases.ts";
import { getResolvedModelCapabilities } from "../../src/lib/modelCapabilities.ts";
function generationConfigOf(request: unknown): Record<string, unknown> {
const gc = (request as Record<string, unknown>)?.generationConfig;
@@ -197,6 +198,57 @@ test("an aliased id is capped by the model it resolves to", async () => {
}
});
test("Gemini 3.8 Flash retains its output allowance above the thinking budget", async () => {
const executor = new AntigravityExecutor();
for (const model of [
"gemini-3.8-flash-high",
"gemini-3.8-flash-medium",
"gemini-3.8-flash-low",
"gemini-3.8-flash-tiered",
]) {
const result = await executor.transformRequest(
`antigravity/${model}`,
{
request: {
contents: [{ role: "user", parts: [{ text: "Hello" }] }],
generationConfig: {
maxOutputTokens: 65536,
thinkingConfig: { thinkingBudget: 24576, includeThoughts: true },
},
},
},
true,
{ projectId: "project-1" }
);
if (result instanceof Response) throw new Error("Unexpected Response from transformRequest");
const config = generationConfigOf(result.request);
assert.equal(config.maxOutputTokens, 65536, model);
assert.equal((config.thinkingConfig as Record<string, unknown>).thinkingBudget, 24576, model);
}
});
test("Gemini 3.8 Flash static spec keeps thinking and context, not only the output cap", () => {
const expectedBudget: Record<string, number> = {
"gemini-3.8-flash-high": 24576,
"gemini-3.8-flash-medium": 8192,
"gemini-3.8-flash-low": 1024,
"gemini-3.8-flash-tiered": 8192,
};
for (const model of Object.keys(expectedBudget)) {
const caps = getResolvedModelCapabilities({
provider: "antigravity",
model,
});
assert.equal(caps.maxOutputTokens, 65536, model);
assert.equal(caps.supportsThinking, true, model);
assert.equal(caps.supportsTools, true, model);
assert.equal(caps.supportsVision, true, model);
assert.equal(caps.contextWindow, 1048576, model);
assert.equal(caps.defaultThinkingBudget, expectedBudget[model], model);
assert.equal(caps.thinkingBudgetCap, 24576, model);
}
});
test("the executor's cap differs per model on the same code path", async () => {
const executor = new AntigravityExecutor();
@@ -227,6 +279,7 @@ test("a provider-prefixed model id resolves to the model's ceiling, not the fall
["agy/gemini-3.1-pro-high", 65535],
["antigravity/gemini-3.1-pro-high", 65535],
["agy/gemini-3.7-flash-high", 65536],
["agy/gemini-3.8-flash-high", 65536],
["agy/gpt-oss-120b-medium", 32768],
];