Skip to content

fix(inputs): let Gemini and router-prefixed models accept required tool choice - #36

Merged
Alex-vonAllmen merged 1 commit into
mainfrom
fix/gemini-required-tool-choice
Sep 16, 2026
Merged

Alex-vonAllmen merged 1 commit into
mainfrom
fix/gemini-required-tool-choice

Conversation

@Alex-vonAllmen

Copy link
Copy Markdown
Owner

Makes force_required_tool_choice actually reachable for Gemini, and fixes the same mistake for openrouter/-routed OpenAI models.

Context and measurements are in the commit message and in usestrix#1322: Gemini 3.8 Flash ended 2.5–4.9% of turns with no tool call where GLM 5.3 and Opus 4.8 ended 0.0% on the same target and recipe, and agents that do that finish clean having recorded no coverage.

Verified against the provider that tool_choice: "required" forces a tool call on google/gemini-3.8-flash where auto does not, so the flag is the right lever — it simply could not reach the model.

Does not change any default: force_required_tool_choice remains opt-in via STRIX_FORCE_REQUIRED_TOOL_CHOICE.

Refs usestrix#1322

…ol choice

`force_required_tool_choice` exists so an operator can stop agents ending turns
without a tool call, but `_accepts_required_tool_choice` gated it to bare
`openai/`. Two consequences, both silent — the setting is accepted and then
dropped, with nothing logged.

**Gemini never qualified.** Measured on a deep scan: Gemini 3.8 Flash ended
2.5% of its turns with no tool call, rising to 4.9% on a rerun with a healthy
provider, against 0.0% for GLM 5.3 and Opus 4.8 on the same target and recipe.
A turn with no tool call records no coverage and calls no lifecycle tool, so
agents finished clean having produced nothing: 4 of 4 children raised
`agent_recorded_no_coverage` while the run still reported `scan_completed: true`.

The provider does honour the parameter. Against `google/gemini-3.8-flash`
through OpenRouter, `tool_choice: "required"` produced a tool call even from a
prompt that explicitly asked for none, while `auto` on the same prompt produced
text and no call. So the flag is the right lever; it just could not reach.

**`openrouter/` was never a stripped routing prefix,** so an OpenAI model
reached through OpenRouter read as an unknown provider and was dropped too.
Fixed in the same place, since it is the same mistake: treating a router as a
provider.

Both prefix lists are now named constants with the reasoning attached, so the
next provider is a one-line change rather than a re-derivation.

Tests cover the three Gemini spellings (bare, OpenRouter-routed, and the
`gemini/` form upstream usestrix#1295 reports against), the OpenRouter-routed OpenAI
case, and two negatives — routed Anthropic and routed z-ai still return False,
so stripping the router does not widen the gate to everything behind it.

Note: pytest is not available in the environment this was written in, so the
new cases were not executed here; the gate was verified directly against the
same 14-case matrix, including both negatives.

Refs usestrix#1322

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKKGDUHDR2aSpCQWBtAnor
@Alex-vonAllmen
Alex-vonAllmen merged commit 1ea52b0 into main Sep 16, 2026
6 checks passed
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