Skip to content

Integrate #13: what a current Gemini model refuses - #19

Merged
rokbenko merged 4 commits into
mainfrom
integrate/gemini-3-thought-signatures
Sep 14, 2026
Merged

rokbenko merged 4 commits into
mainfrom
integrate/gemini-3-thought-signatures

Conversation

@rokbenko

Copy link
Copy Markdown
Owner

Integration branch for #13 (@Bayway), handled the way CONTRIBUTING describes: merged with git merge, never squashed or rebased, his commit verbatim, corrections on top in named commits.

Commits

e570573 Massimiliano Fiorifix(gemini): a current Gemini model as the pilot
7d92378 the merge (conflicts resolved to his side)
fb19360 fix(gemini): the catalogue already chose the model
f3cdd94 test(gemini): the verbs quackd actually sends, not a schema written here

What of his was kept

Two of his three fixes, and both are live on the default path — the catalogue's first Gemini entry is gemini-3.8-flash, a Gemini 3 model:

  • exclusiveMinimum / exclusiveMaximum not stripped. pydantic writes gt=0 that way and google-genai 2.x refuses the declaration. move and go_to are core verbs and both carry a bound, so this was every robot, not some.
  • Gemini 3 thought signatures. Each function_call is signed and the next turn is refused with a 400 unless the signature comes back on that same call.

What was corrected, and why

His third fix pointed DEFAULT_MODEL at the gemini-pro-latest alias because gemini-2.5-pro had started answering "no longer available to new users". Real problem — but ADR-0031 solved it differently while the PR was open, replacing the per-provider constant with the model catalogue. The constant this branch reintroduced was dead on arrival: the constructor takes default_model_for("gemini"). Removed, and the test assertion put back on the catalogue rather than a literal.

The CHANGELOG entry said "Three things"; it says two, and now records that both remaining fixes are on the default path.

Test added

Rule 4 — anything the review found by reading, the next review should find by failing. His schema test uses a hand-written dict; the new one runs default_registry().tool_schemas() (the real fifteen) and asserts nothing in UNSUPPORTED_SCHEMA_KEYS survives. It also asserts some verb still carries a bound, so it cannot pass for the wrong reason later. Mutation-checked: drop the two keys and exclusiveMinimum leaks.

Gate, on the merged result

ruff check · ruff format --check (against git archive bytes, not the CRLF tree) · mypy on 3.11 and 3.12 · full pytest — all green locally on Windows. This PR exists to get macOS, Linux and the physics job too.

Older breakage this surfaced

Rule 5. The Gemini path has been broken on main since google-genai 2.x — every robot, every Gemini run, not only Gemini 3. Worth saying in the release note.

🤖 Generated with Claude Code

Bayway and others added 4 commits September 11, 2026 10:13
Three faults between the provider and Gemini 3, found by pointing a duck at
gemini-3.5-flash.

The schema cleaner did not strip exclusiveMinimum/exclusiveMaximum. pydantic
writes gt=0 that way, so every verb with a timeout_s or a duration_s carried one,
and google-genai 2.x validates the declaration and refuses the keyword. The
executor still enforces the bound on the way in.

The default model, gemini-2.5-pro, answers 'no longer available to new users'.
The default is now the gemini-pro-latest alias, on purpose: a default that 404s
is worse than one that moves.

Gemini 3 signs each function call with a thought_signature that the next turn
must hand back on that same call, or the request is refused with a 400. ToolCall
carries it as base64 text (signature, empty for every other provider) and
render_contents puts the bytes back on the function_call part.

Verified with a two-step run to success on gemini-3.5-flash with thought
summaries on; ruff, mypy and the full suite are green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…fuses

Bayway's three fixes, merged whole. Conflicts were resolved to his side so his
diff lands as written; what main solved differently since is corrected in the
commit after this one, not in his lines.

Conflicts: gemini.py (main replaced DEFAULT_MODEL with the model catalogue),
tests/test_providers.py (the same assertion), CHANGELOG.md (both sides added
entries under Unreleased; both are kept).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Bayway's third fix pointed the default at the `gemini-pro-latest` alias because
`gemini-2.5-pro` had started answering "no longer available to new users". Main
solved the same problem differently while the PR was open: ADR-0031 replaced the
per-provider constant with the model catalogue, and `default_model_for("gemini")`
now returns its first entry.

So the constant this branch reintroduced was dead on arrival -- nothing read it,
because the constructor takes the catalogue's answer. Removed, with the test
assertion put back on `default_model_for("gemini")` rather than a literal, which
is what keeps it honest when the catalogue's first entry moves again.

The CHANGELOG entry loses that third item and says two. It gains the thing that
matters more now: the catalogue's first Gemini entry is a Gemini 3 model, so both
remaining fixes are on the default path rather than an opt-in one. The schema bug
is every robot, not some -- `move` and `go_to` are core verbs and both carry a
`gt=0` bound.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CONTRIBUTING says anything the review found by reading, the next review should
find by failing. This one was found by reading: `move` and `go_to` are core
verbs, both bound `gt=0`, so pydantic gave both an exclusiveMinimum and Gemini
refused the declaration on every robot.

The existing test proves `clean_schema` handles a schema written in the test.
This one runs `default_registry().tool_schemas()` -- the real fifteen -- and
asserts no key in UNSUPPORTED_SCHEMA_KEYS survives. It also asserts that some
verb still carries a bound before cleaning, because the day none does this test
would pass for the wrong reason and quietly stop guarding the agreement between
quackd/verbs/core.py and that set.

Checked it fails without the fix: drop the two keys and exclusiveMinimum leaks.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rokbenko
rokbenko merged commit c9199d0 into main Sep 14, 2026
7 checks passed
@rokbenko
rokbenko deleted the integrate/gemini-3-thought-signatures branch September 14, 2026 14:17
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.

2 participants