Skip to content

fix(antigravity): strip trailing model turn for native Gemini requests too - #10436

Merged
diegosouzapw merged 3 commits into
release/v3.8.50from
fix/10104-antigravity-trailing-model-turn
Aug 18, 2026
Merged

diegosouzapw merged 3 commits into
release/v3.8.50from
fix/10104-antigravity-trailing-model-turn

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Closes #10104

Root cause

AntigravityExecutor.transformRequest() in open-sse/executors/antigravity.ts only
wired stripTrailingAntigravityAssistantTurn() into the isClaude branch. A native
Gemini model routed through Antigravity (agy/gemini-*, e.g. gemini-3-flash-agent)
that ends the conversation on a role: "model" turn keeps that trailing entry
unchanged, and newer Gemini endpoints reject that shape with HTTP 400 "Requests
ending with a model turn are not supported."

stripTrailingAntigravityAssistantTurn (already correct, guarded pop-loop, never
empties contents) is now also applied on an isGemini branch
(upstreamModel.toLowerCase().includes("gemini")), independent of the
sanitizeAntigravityGeminiRequest() Claude-only field whitelist. The Claude path is
byte-identical to before — this only widens the strip to native Gemini requests.

Regression test

tests/unit/antigravity-claude-prefill-strip.test.ts:

Fail→pass evidence (same test file, run against pre-fix vs post-fix
antigravity.ts):

# pre-fix (HEAD~1 antigravity.ts, same test file)
✖ (b2) native Gemini agent tier (gemini-3-flash-agent, #10104) also gets the strip
  AssertionError [ERR_ASSERTION]: trailing model turn should be stripped for native Gemini
  2 !== 1

# post-fix
✔ (a) strips a single trailing assistant (model) turn for Claude models
✔ (b) strips a trailing model turn for native Gemini models too (#10104)
✔ (b2) native Gemini agent tier (gemini-3-flash-agent, #10104) also gets the strip
✔ (c) a Claude conversation already ending on user is unchanged
✔ (d) multiple trailing model turns are all stripped
✔ (e) never strips contents down to empty
✔ empty/missing contents does not throw
7 pass, 0 fail

Gates run

  • npm run typecheck:core — clean
  • npx eslint --suppressions-location config/quality/eslint-suppressions.json open-sse/executors/antigravity.ts tests/unit/antigravity-claude-prefill-strip.test.ts — clean
  • node scripts/check/check-file-size.mjs — no new violations on touched files
  • node scripts/check/check-test-discovery.mjs — OK, test file discovered
  • Targeted suite node --import tsx/esm --test tests/unit/antigravity-claude-prefill-strip.test.ts — 7/7 pass
  • node scripts/check/check-complexity.mjs, check-cognitive-complexity.mjs, and the full npm run test:unit were kicked off but did not finish within this session due to extreme host contention (13 parallel worktree sessions running the same checks concurrently, load average ~209). No failures observed in the partial output before the session ended; the change is a small, additive conditional branch unlikely to move complexity/cognitive thresholds. Recommend a follow-up CI run confirms these before merge.

Notes

⚠️ base-red inherited: #9985 — ESLint errors (2) from #10250 (unrelated to this change, do not chase).

…s too

Newer Gemini endpoints reject a request ending on a model turn with HTTP
400 'Requests ending with a model turn are not supported' — the same
rejection class Claude hits via Vertex. transformRequest() previously
wired stripTrailingAntigravityAssistantTurn() only into the isClaude
branch, so native Gemini models routed through Antigravity kept a
trailing role:model entry and hit the 400.

Extend the guarded strip (never empties contents) to native Gemini
models too, gated by upstreamModel including "gemini". The Claude
path is untouched (byte-identical), preserving PR #6114's live
validation against Vertex Claude.

Flips tests/unit/antigravity-claude-prefill-strip.test.ts test (b),
which previously asserted the buggy pass-through, and adds (b2) for
the gemini-3-flash-agent tier.

Closes #10104
@diegosouzapw

Copy link
Copy Markdown
Owner Author

The focused suite passes (7/7), and the Claude path remains covered. I found one plausible correctness concern: upstreamModel.includes("gemini") now strips the trailing model turn for every Gemini-named Antigravity model, including catalogued Gemini 2.5/image IDs, while the issue evidence is specifically about newer endpoints; please narrow or justify that scope. Also, issue #10104's validation plan calls out Gemini 3.6 Flash tiers, but the added tests cover only Gemini 3.1 Pro and gemini-3-flash-agent. The PR notes that no live Antigravity 400→200 check was possible; the focused TDD evidence should remain the basis for the claim unless live validation is added.

adevwithpurpose and others added 2 commits August 17, 2026 10:43
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
@diegosouzapw
diegosouzapw merged commit 5240afe into release/v3.8.50 Aug 18, 2026
11 checks passed
@diegosouzapw
diegosouzapw deleted the fix/10104-antigravity-trailing-model-turn branch August 19, 2026 18:47
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 20, 2026
…s too (diegosouzapw#10436)

* fix(antigravity): strip trailing model turn for native Gemini requests too

Newer Gemini endpoints reject a request ending on a model turn with HTTP
400 'Requests ending with a model turn are not supported' — the same
rejection class Claude hits via Vertex. transformRequest() previously
wired stripTrailingAntigravityAssistantTurn() only into the isClaude
branch, so native Gemini models routed through Antigravity kept a
trailing role:model entry and hit the 400.

Extend the guarded strip (never empties contents) to native Gemini
models too, gated by upstreamModel including "gemini". The Claude
path is untouched (byte-identical), preserving PR diegosouzapw#6114's live
validation against Vertex Claude.

Flips tests/unit/antigravity-claude-prefill-strip.test.ts test (b),
which previously asserted the buggy pass-through, and adds (b2) for
the gemini-3-flash-agent tier.

Closes diegosouzapw#10104

* fix(antigravity): scope Gemini trailing-turn workaround

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: adevwithpurpose <adevwithpurpose@users.noreply.github.com>
giauphan pushed a commit to giauphan/OmniRoute that referenced this pull request Aug 20, 2026
…s too (diegosouzapw#10436)

* fix(antigravity): strip trailing model turn for native Gemini requests too

Newer Gemini endpoints reject a request ending on a model turn with HTTP
400 'Requests ending with a model turn are not supported' — the same
rejection class Claude hits via Vertex. transformRequest() previously
wired stripTrailingAntigravityAssistantTurn() only into the isClaude
branch, so native Gemini models routed through Antigravity kept a
trailing role:model entry and hit the 400.

Extend the guarded strip (never empties contents) to native Gemini
models too, gated by upstreamModel including "gemini". The Claude
path is untouched (byte-identical), preserving PR diegosouzapw#6114's live
validation against Vertex Claude.

Flips tests/unit/antigravity-claude-prefill-strip.test.ts test (b),
which previously asserted the buggy pass-through, and adds (b2) for
the gemini-3-flash-agent tier.

Closes diegosouzapw#10104

* fix(antigravity): scope Gemini trailing-turn workaround

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: adevwithpurpose <adevwithpurpose@users.noreply.github.com>
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…s too (diegosouzapw#10436)

* fix(antigravity): strip trailing model turn for native Gemini requests too

Newer Gemini endpoints reject a request ending on a model turn with HTTP
400 'Requests ending with a model turn are not supported' — the same
rejection class Claude hits via Vertex. transformRequest() previously
wired stripTrailingAntigravityAssistantTurn() only into the isClaude
branch, so native Gemini models routed through Antigravity kept a
trailing role:model entry and hit the 400.

Extend the guarded strip (never empties contents) to native Gemini
models too, gated by upstreamModel including "gemini". The Claude
path is untouched (byte-identical), preserving PR diegosouzapw#6114's live
validation against Vertex Claude.

Flips tests/unit/antigravity-claude-prefill-strip.test.ts test (b),
which previously asserted the buggy pass-through, and adds (b2) for
the gemini-3-flash-agent tier.

Closes diegosouzapw#10104

* fix(antigravity): scope Gemini trailing-turn workaround

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: adevwithpurpose <adevwithpurpose@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] Antigravity Gemini requests can end on a model turn and fail with 400

2 participants