# NousResearch/hermes-agent · Gemini reasoning config mapping and visibility bugs

## Open now

- 1 issue, 2 PRs open on GitHub.
- #64035: \[Bug\]: Gemini/Vertex thought summaries leak into user-visible content with display.show_reasoning: false (effort and visibility coupled via include_thoughts)
- PR #64036: fix(gemini): decouple reasoning effort from thought-summary visibility
- PR #91008: fix(vertex): route Gemini thought deltas to the reasoning stream, not visible content

These issues and fixes address how reasoning/thinking configuration is bridged and mapped for Gemini and Vertex routes, including thought summaries incorrectly appearing in user-visible content and reasoning effort being incorrectly coupled with thought-summary visibility.

## TL;DR

- 6 member(s): 1 open issue(s), 1 closed issue(s), 2 open PR(s), 2 merged PR(s), 0 PR(s) closed without merging.
- A fix was merged to main in PR #16999. Verify it addresses your case.
- **Recommended:** read PR #16999 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `partially_resolved` · deciding PR(s): `pr-16999`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_PARTIAL`): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text.
- Members outside that structural core may belong to a different underlying problem.
- Pairwise link density `0.29`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Open related issues

- #64035: \[Bug\]: Gemini/Vertex thought summaries leak into user-visible content with display.show_reasoning: false (effort and visibility coupled via include_thoughts)

## Closed / duplicate issues

- #16941: \[Bug\]: Gemini chat-completions route does not bridge reasoning_config into thinking_config, so Discord show_reasoning stays empty

## Prior & competing PRs

- **#16999: fix(gemini): bridge reasoning_config into thinking_config for chat-completions routes**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`; implication `superseded`
  - files: `agent/transports/chat_completions.py`, `run_agent.py`, `tests/agent/transports/test_chat_completions.py`
  - fix hunks:
  - `agent/transports/chat_completions.py`

    ```diff
    @@ -18,6 +18,58 @@
     from agent.transports.types import NormalizedResponse, ToolCall, Usage
     
     
    +def _build_gemini_thinking_config(model: str, reasoning_config: dict | None) -> dict | None:
    +    """Translate Hermes/OpenRouter-style reasoning config to Gemini thinkingConfig.
    +
    +    Gemini native/cloud-code adapters do not read ``extra_body.reasoning``.
    +    They only inspect ``extra_body.thinking_config`` / ``thinkingConfig`` and
    +    then request thought parts with ``includeThoughts`` enabled.
    +    """
    +    if reasoning_config is None or not isinstance(reasoning_config, dict):
    +        return None
    +
    +    if reasoning_config.get("enabled") is False:
    +        # Gemini can hide thought parts even when internal thinking still
    +        # happens; omit thinkingLevel to avoid model-specific validation quirks.
    +        return {"includeThoughts": False}
    +
    +    effort = str(reasoning_config.get("effort", "medium") or "medium").strip().lower()
    +    if effort == "none":
    +        return {"includeThoughts": False}
    +
    +    thinking_config: Dict[str, Any] = {"includeThoughts": True}
    +    normalized_model = (model or "").strip().lower()
    +    if normalized_model.startswith("google/"):
    +        normalized_model = normalized_model.split("/", 1)[1]
    +
    +    # Gemini 2.5 accepts thinkingBudget; don't guess a budget from Hermes'
    +    # coarse effort levels. ``includeThoughts`` alone is enough to surface
    +    # thought parts without risking request validation errors.
    +    if normalized_model.startswith("gemini-2.5-"):
    +        return thinking_config
    +
    +    if effort not in {"minimal", "low", "medium", "high", "xhigh"}:
    +        effort = "medium"
    +
    +    # Gemini 3 Flash documents low/medium/high thinking levels; Gemini 3 Pro
    +    # is stricter (low/high). Clamp Hermes' wider effort set to what each
    +    # family accepts so we never forward an undocumented level verbatim.
    +    if normalized_model.startswith(("gemini-3", "gemini-3.1")):
    +        if "flash" in normalized_model:
    +            if effort in {"minimal", "low"}:
    +                thinking_config["thinkingLevel"] = "low"
    +            elif effort in {"high", "xhigh"}:
    +                thinking_config["thinkingLevel"] = "high"
    +            else:
    +                thinking_config["thinkingLevel"] = "medium"
    +        elif "pro" in normalized_model:
    +            thinking_config["thinkingLevel"] = (
    +                "high" if effort in {"high", "xhigh"} else "low"
    +            )
    +
    +    return thinking_config
    +
    +
     class ChatCompletionsTransport(ProviderTransport):
         """Transport for api_mode='chat_completions'.
     
    ```

    ```diff
    @@ -241,6 +293,7 @@ def build_kwargs(
             is_openrouter = params.get("is_openrouter", False)
             is_nous = params.get("is_nous", False)
             is_github_models = params.get("is_github_models", False)
    +        provider_name = str(params.get("provider_name") or "").strip().lower()
     
             provider_prefs = params.get("provider_preferences")
             if provider_prefs and is_openrouter:
    ```

    ```diff
    @@ -293,6 +346,11 @@ def build_kwargs(
             if is_qwen:
                 extra_body["vl_high_resolution_images"] = True
     
    +        if provider_name in {"gemini", "google-gemini-cli"}:
    +            thinking_config = _build_gemini_thinking_config(model, reasoning_config)
    +            if thinking_config:
    +                extra_body["thinking_config"] = thinking_config
    +
             # Merge any pre-built extra_body additions
             additions = params.get("extra_body_additions")
             if additions:
    ```
  - `run_agent.py`

    ```diff
    @@ -8094,6 +8094,7 @@ def _build_api_kwargs(self, api_messages: list) -> dict:
                 supports_reasoning=self._supports_reasoning_extra_body(),
                 github_reasoning_extra=self._github_models_reasoning_extra_body() if _is_gh else None,
                 anthropic_max_output=_ant_max,
    +            provider_name=self.provider,
             )
     
         def _supports_reasoning_extra_body(self) -> bool:
    ```
  - `tests/agent/transports/test_chat_completions.py`

    ```diff
    @@ -4,7 +4,7 @@
     from types import SimpleNamespace
     
     from agent.transports import get_transport
    -from agent.transports.types import NormalizedResponse, ToolCall
    +from agent.transports.types import NormalizedResponse
     
     
     @pytest.fixture
    ```

    ```diff
    @@ -122,6 +122,90 @@ def test_custom_think_false(self, transport):
             )
             assert kw["extra_body"]["think"] is False
     
    +    def test_gemini_without_explicit_reasoning_config_keeps_existing_behavior(self, transport):
    +        msgs = [{"role": "user", "content": "Hi"}]
    +        kw = transport.build_kwargs(
    +            model="gemini-3-flash-preview",
    +            messages=msgs,
    +            provider_name="gemini",
    +        )
    +        assert "thinking_config" not in kw.get("extra_body", {})
    +
    +    def test_gemini_flash_reasoning_maps_to_thinking_config(self, transport):
    +        msgs = [{"role": "user", "content": "Hi"}]
    +        kw = transport.build_kwargs(
    +            model="gemini-3-flash-preview",
    +            messages=msgs,
    +            provider_name="gemini",
    +            reasoning_config={"enabled": True, "effort": "high"},
    +        )
    +        assert kw["extra_body"]["thinking_config"] == {
    +            "includeThoughts": True,
    +            "thinkingLevel": "high",
    +        }
    +
    +    def test_gemini_25_reasoning_only_enables_visible_thoughts(self, transport):
    +        msgs = [{"role": "user", "content": "Hi"}]
    +        kw = transport.build_kwargs(
    +            model="gemini-2.5-flash",
    +            messages=msgs,
    +            provider_name="gemini",
    +            reasoning_config={"enabled": True, "effort": "high"},
    +        )
    +        assert kw["extra_body"]["thinking_config"] == {
    +            "includeThoughts": True,
    +        }
    +
    +    def test_gemini_pro_reasoning_clamps_to_supported_levels(self, transport):
    +        msgs = [{"role": "user", "content": "Hi"}]
    +        kw = transport.build_kwargs(
    +            model="google/gemini-3.1-pro-preview",
    +            messages=msgs,
    +            provider_name="gemini",
    +            reasoning_config={"enabled": True, "effort": "medium"},
    +        )
    +        assert kw["extra_body"]["thinking_config"] == {
    +            "includeThoughts": True,
    +            "thinkingLevel": "low",
    +        }
    +
    +    def test_gemini_disabled_reasoning_hides_thoughts(self, transport):
    +        msgs = [{"role": "user", "content": "Hi"}]
    +        kw = transport.build_kwargs(
    +            model="gemini-3-flash-preview",
    +            messages=msgs,
    +            provider_name="gemini",
    +            reasoning_config={"enabled": False},
    +        )
    +        assert kw["extra_body"]["thinking_config"] == {
    +            "includeThoughts": False,
    +        }
    +
    +    def test_gemini_xhigh_clamps_to_high(self, transport):
    +        msgs = [{"role": "user", "content": "Hi"}]
    +        kw = transport.build_kwargs(
    +            model="gemini-3-flash-preview",
    +            messages=msgs,
    +            provider_name="gemini",
    +            reasoning_config={"enabled": True, "effort": "xhigh"},
    +        )
    +        assert kw["extra_body"]["thinking_config"]["thinkingLevel"] == "high"
    +
    +    def test_gemini_flash_minimal_clamps_to_low(self, transport):
    +        # Gemini 3 Flash documents low/medium/high; "minimal" isn't accepted,
    +        # so clamp it down to "low" rather than forwarding it verbatim.
    +        msgs = [{"role": "user", "content": "Hi"}]
    +        kw = transport.build_kwargs(
    +            model="gemini-3-flash-preview",
    +            messages=msgs,
    +            provider_name="gemini",
    +            reasoning_config={"enabled": True, "effort": "minimal"},
    +        )
    +        assert kw["extra_body"]["thinking_config"] == {
    +            "includeThoughts": True,
    +            "thinkingLevel": "low",
    +        }
    +
         def test_max_tokens_with_fn(self, transport):
             msgs = [{"role": "user", "content": "Hi"}]
             kw = transport.build_kwargs(
    ```
- **#17605: fix(gemini): nest OpenAI-compat thinking config under google (salvage #17389)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`; implication `superseded`
  - files: `agent/auxiliary_client.py`, `agent/transports/chat_completions.py`, `run_agent.py`, `scripts/release.py`, `tests/agent/transports/test_chat_completions.py`, `tests/run_agent/test_provider_parity.py`
  - fix hunks:
  - `agent/auxiliary_client.py`

    ```diff
    @@ -101,6 +101,14 @@ def __repr__(self):
     logger = logging.getLogger(__name__)
     
     
    +def _safe_isinstance(obj: Any, maybe_type: Any) -> bool:
    +    """Return False instead of raising when a patched symbol is not a type."""
    +    try:
    +        return isinstance(obj, maybe_type)
    +    except TypeError:
    +        return False
    +
    +
     def _extract_url_query_params(url: str):
         """Extract query params from URL, return (clean_url, default_query dict or None)."""
         parsed = urlparse(url)
    ```

    ```diff
    @@ -861,20 +869,20 @@ def _maybe_wrap_anthropic(
         - The ``anthropic`` SDK is not installed (falls back to OpenAI wire).
         """
         # Already wrapped — don't double-wrap.
    -    if isinstance(client_obj, AnthropicAuxiliaryClient):
    +    if _safe_isinstance(client_obj, AnthropicAuxiliaryClient):
             return client_obj
         # Other specialized adapters we should never re-dispatch.
    -    if isinstance(client_obj, CodexAuxiliaryClient):
    +    if _safe_isinstance(client_obj, CodexAuxiliaryClient):
             return client_obj
         try:
             from agent.gemini_native_adapter import GeminiNativeClient
    -        if isinstance(client_obj, GeminiNativeClient):
    +        if _safe_isinstance(client_obj, GeminiNativeClient):
                 return client_obj
         except ImportError:
             pass
         try:
             from agent.copilot_acp_client import CopilotACPClient
    -        if isinstance(client_obj, CopilotACPClient):
    +        if _safe_isinstance(client_obj, CopilotACPClient):
                 return client_obj
         except ImportError:
             pass
    ```
  - `agent/transports/chat_completions.py`

    ```diff
    @@ -20,12 +20,7 @@
     
     
     def _build_gemini_thinking_config(model: str, reasoning_config: dict | None) -> dict | None:
    -    """Translate Hermes/OpenRouter-style reasoning config to Gemini thinkingConfig.
    -
    -    Gemini native/cloud-code adapters do not read ``extra_body.reasoning``.
    -    They only inspect ``extra_body.thinking_config`` / ``thinkingConfig`` and
    -    then request thought parts with ``includeThoughts`` enabled.
    -    """
    +    """Translate Hermes/OpenRouter-style reasoning config to Gemini thinkingConfig."""
         if reasoning_config is None or not isinstance(reasoning_config, dict):
             return None
     
    ```

    ```diff
    @@ -71,6 +66,30 @@ def _build_gemini_thinking_config(model: str, reasoning_config: dict | None) ->
         return thinking_config
     
     
    +def _snake_case_gemini_thinking_config(config: dict | None) -> dict | None:
    +    """Convert Gemini thinking config keys to the OpenAI-compat field names."""
    +    if not isinstance(config, dict) or not config:
    +        return None
    +
    +    translated: Dict[str, Any] = {}
    +    if isinstance(config.get("includeThoughts"), bool):
    +        translated["include_thoughts"] = config["includeThoughts"]
    +    if isinstance(config.get("thinkingLevel"), str) and config["thinkingLevel"].strip():
    +        translated["thinking_level"] = config["thinkingLevel"].strip().lower()
    +    if isinstance(config.get("thinkingBudget"), (int, float)):
    +        translated["thinking_budget"] = int(config["thinkingBudget"])
    +    return translated or None
    +
    +
    +def _is_gemini_openai_compat_base_url(base_url: Any) -> bool:
    +    normalized = str(base_url or "").strip().rstrip("/").lower()
    +    if not normalized:
    +        return False
    +    if "generativelanguage.googleapis.com" not in normalized:
    +        return False
    +    return normalized.endswith("/openai")
    +
    +
     class ChatCompletionsTransport(ProviderTransport):
         """Transport for api_mode='chat_completions'.
     
    ```

    ```diff
    @@ -309,6 +328,7 @@ def build_kwargs(
             is_nous = params.get("is_nous", False)
             is_github_models = params.get("is_github_models", False)
             provider_name = str(params.get("provider_name") or "").strip().lower()
    +        base_url = params.get("base_url")
     
             provider_prefs = params.get("provider_preferences")
             if provider_prefs and is_openrouter:
    ```

    ```diff
    @@ -362,7 +382,19 @@ def build_kwargs(
             if is_qwen:
                 extra_body["vl_high_resolution_images"] = True
     
    -        if provider_name in {"gemini", "google-gemini-cli"}:
    +        if provider_name == "gemini":
    +            raw_thinking_config = _build_gemini_thinking_config(model, reasoning_config)
    +            if _is_gemini_openai_compat_base_url(base_url):
    +                thinking_config = _snake_case_gemini_thinking_config(raw_thinking_config)
    +                if thinking_config:
    +                    openai_compat_extra = extra_body.get("extra_body", {})
    +                    google_extra = openai_compat_extra.get("google", {})
    +                    google_extra["thinking_config"] = thinking_config
    +                    openai_compat_extra["google"] = google_extra
    +                    extra_body["extra_body"] = openai_compat_extra
    +            elif raw_thinking_config:
    +                extra_body["thinking_config"] = raw_thinking_config
    +        elif provider_name == "google-gemini-cli":
                 thinking_config = _build_gemini_thinking_config(model, reasoning_config)
                 if thinking_config:
                     extra_body["thinking_config"] = thinking_config
    ```
  - `run_agent.py`

    ```diff
    @@ -8266,6 +8266,7 @@ def _build_api_kwargs(self, api_messages: list) -> dict:
                 model=self.model,
                 messages=_msgs_for_chat,
                 tools=self.tools,
    +            base_url=self.base_url,
                 timeout=self._resolved_api_call_timeout(),
                 max_tokens=[redacted:secret-assignment]
                 ephemeral_max_output_tokens=[redacted:secret-assignment]
    ```
  - `scripts/release.py`

    ```diff
    @@ -66,6 +66,7 @@
         "[redacted:email]": "dlkakbs",
         "[redacted:email]": "BeliefanX",
         "[redacted:email]": "Mind-Dragon",
    +    "[redacted:email]": "Nanako0129",
         "[redacted:email]": "westers",
         "[redacted:email]": "yeyitech",
         "[redacted:email]": "beenherebefore",
    ```
  - `tests/agent/transports/test_chat_completions.py`

    ```diff
    @@ -122,21 +122,25 @@ def test_custom_think_false(self, transport):
             )
             assert kw["extra_body"]["think"] is False
     
    -    def test_gemini_without_explicit_reasoning_config_keeps_existing_behavior(self, transport):
    +    def test_gemini_native_without_explicit_reasoning_config_keeps_existing_behavior(self, transport):
             msgs = [{"role": "user", "content": "Hi"}]
             kw = transport.build_kwargs(
                 model="gemini-3-flash-preview",
                 messages=msgs,
                 provider_name="gemini",
    +            base_url="https://generativelanguage.googleapis.com/v1beta",
             )
             assert "thinking_config" not in kw.get("extra_body", {})
    +        assert "google" not in kw.get("extra_body", {})
    +        assert "extra_body" not in kw.get("extra_body", {})
     
    -    def test_gemini_flash_reasoning_maps_to_thinking_config(self, transport):
    +    def test_gemini_native_flash_reasoning_maps_to_top_level_thinking_config(self, transport):
             msgs = [{"role": "user", "content": "Hi"}]
             kw = transport.build_kwargs(
                 model="gemini-3-flash-preview",
                 messages=msgs,
                 provider_name="gemini",
    +            base_url="https://generativelanguage.googleapis.com/v1beta",
                 reasoning_config={"enabled": True, "effort": "high"},
             )
             assert kw["extra_body"]["thinking_config"] == {
    ```

    ```diff
    @@ -144,52 +148,85 @@ def test_gemini_flash_reasoning_maps_to_thinking_config(self, transport):
                 "thinkingLevel": "high",
             }
     
    -    def test_gemini_25_reasoning_only_enables_visible_thoughts(self, transport):
    +    def test_gemini_openai_compat_flash_reasoning_maps_to_nested_google_thinking_config(self, transport):
    +        msgs = [{"role": "user", "content": "Hi"}]
    +        kw = transport.build_kwargs(
    +            model="gemini-3-flash-preview",
    +            messages=msgs,
    +            provider_name="gemini",
    +            base_url="https://generativelanguage.googleapis.com/v1beta/openai",
    +            reasoning_config={"enabled": True, "effort": "high"},
    +        )
    +        assert "thinking_config" not in kw["extra_body"]
    +        assert kw["extra_body"]["extra_body"]["google"]["thinking_config"] == {
    +            "include_thoughts": True,
    +            "thinking_level": "high",
    +        }
    +
    +    def test_gemini_native_25_reasoning_only_enables_visible_thoughts(self, transport):
             msgs = [{"role": "user", "content": "Hi"}]
             kw = transport.build_kwargs(
                 model="gemini-2.5-flash",
                 messages=msgs,
                 provider_name="gemini",
    +            base_url="https://generativelanguage.googleapis.com/v1beta",
                 reasoning_config={"enabled": True, "effort": "high"},
             )
             assert kw["extra_body"]["thinking_config"] == {
                 "includeThoughts": True,
             }
     
    -    def test_gemini_pro_reasoning_clamps_to_supported_levels(self, transport):
    +    def test_gemini_openai_compat_pro_reasoning_clamps_to_supported_levels(self, transport):
             msgs = [{"role": "user", "content": "Hi"}]
             kw = transport.build_kwargs(
                 model="google/gemini-3.1-pro-preview",
                 messages=msgs,
                 provider_name="gemini",
    +            base_url="https://generativelanguage.googleapis.com/v1beta/openai",
                 reasoning_config={"enabled": True, "effort": "medium"},
             )
    -        assert kw["extra_body"]["thinking_config"] == {
    -            "includeThoughts": True,
    -            "thinkingLevel": "low",
    +        assert kw["extra_body"]["extra_body"]["google"]["thinking_config"] == {
    +            "include_thoughts": True,
    +            "thinking_level": "low",
             }
     
    -    def test_gemini_disabled_reasoning_hides_thoughts(self, transport):
    +    def test_gemini_native_disabled_reasoning_hides_thoughts(self, transport):
             msgs = [{"role": "user", "content": "Hi"}]
             kw = transport.build_kwargs(
                 model="gemini-3-flash-preview",
                 messages=msgs,
                 provider_name="gemini",
    +            base_url="https://generativelanguage.googleapis.com/v1beta",
                 reasoning_config={"enabled": False},
             )
             assert kw["extra_body"]["thinking_config"] == {
                 "includeThoughts": False,
             }
     
    -    def test_gemini_xhigh_clamps_to_high(self, transport):
    +    def test_gemini_openai_compat_xhigh_clamps_to_high(self, transport):
             msgs = [{"role": "user", "content": "Hi"}]
             kw = transport.build_kwargs(
                 model="gemini-3-flash-preview",
                 messages=msgs,
                 provider_name="gemini",
    +            base_url="https://generativelanguage.googleapis.com/v1beta/openai",
                 reasoning_config={"enabled": True, "effort": "xhigh"},
             )
    -        assert kw["extra_body"]["thinking_config"]["thinkingLevel"] == "high"
    +        assert kw["extra_body"]["extra_body"]["google"]["thinking_config"]["thinking_level"] == "high"
    +
    +    def test_google_gemini_cli_keeps_top_level_thinking_config(self, transport):
    +        msgs = [{"role": "user", "content": "Hi"}]
    +        kw = transport.build_kwargs(
    +            model="gemini-3-flash-preview",
    +            messages=msgs,
    +            provider_name="google-gemini-cli",
    +            reasoning_config={"enabled": True, "effort": "high"},
    +        )
    +        assert kw["extra_body"]["thinking_config"] == {
    +            "includeThoughts": True,
    +            "thinkingLevel": "high",
    +        }
    +        assert "google" not in kw["extra_body"]
     
         def test_gemini_flash_minimal_clamps_to_low(self, transport):
             # Gemini 3 Flash documents low/medium/high; "minimal" isn't accepted,
    ```

    ```diff
    @@ -199,11 +236,12 @@ def test_gemini_flash_minimal_clamps_to_low(self, transport):
                 model="gemini-3-flash-preview",
                 messages=msgs,
                 provider_name="gemini",
    +            base_url="https://generativelanguage.googleapis.com/v1beta/openai",
                 reasoning_config={"enabled": True, "effort": "minimal"},
             )
    -        assert kw["extra_body"]["thinking_config"] == {
    -            "includeThoughts": True,
    -            "thinkingLevel": "low",
    +        assert kw["extra_body"]["extra_body"]["google"]["thinking_config"] == {
    +            "include_thoughts": True,
    +            "thinking_level": "low",
             }
     
         def test_max_tokens_with_fn(self, transport):
    ```
  - `tests/run_agent/test_provider_parity.py`

    ```diff
    @@ -144,6 +144,36 @@ def test_strips_codex_only_tool_call_fields_from_chat_messages(self, monkeypatch
             assert messages[1]["tool_calls"][0]["response_item_id"] == "fc_123"
             assert "codex_reasoning_items" in messages[1]
     
    +    def test_gemini_native_passes_base_url_for_top_level_thinking_config(self, monkeypatch):
    +        agent = _make_agent(
    +            monkeypatch,
    +            "gemini",
    +            base_url="https://generativelanguage.googleapis.com/v1beta",
    +            model="gemini-3-flash-preview",
    +        )
    +        agent.reasoning_config = {"enabled": True, "effort": "high"}
    +        kwargs = agent._build_api_kwargs([{"role": "user", "content": "hi"}])
    +        assert kwargs["extra_body"]["thinking_config"] == {
    +            "includeThoughts": True,
    +            "thinkingLevel": "high",
    +        }
    +        assert "extra_body" not in kwargs["extra_body"]
    +
    +    def test_gemini_openai_compat_passes_base_url_for_nested_google_thinking_config(self, monkeypatch):
    +        agent = _make_agent(
    +            monkeypatch,
    +            "gemini",
    +            base_url="https://generativelanguage.googleapis.com/v1beta/openai",
    +            model="gemini-3.1-pro-preview",
    +        )
    +        agent.reasoning_config = {"enabled": True, "effort": "high"}
    +        kwargs = agent._build_api_kwargs([{"role": "user", "content": "hi"}])
    +        assert "thinking_config" not in kwargs["extra_body"]
    +        assert kwargs["extra_body"]["extra_body"]["google"]["thinking_config"] == {
    +            "include_thoughts": True,
    +            "thinking_level": "high",
    +        }
    +
         def test_should_sanitize_tool_calls_codex_vs_chat(self, monkeypatch):
             """Codex API should NOT sanitize, all other APIs should sanitize."""
             # Codex mode should NOT need sanitization
    ```
- **#64036: fix(gemini): decouple reasoning effort from thought-summary visibility**. open
  - maintainer direction: category `partial_fix`; implication `needs_llm`; refs `1a1f7378bbf6`, `#64035`, `#64036`, `#64036`, `#64036`, `#374151`, `#64035`, `#64036`
  - files: `agent/chat_completion_helpers.py`, `agent/transports/chat_completions.py`, `cli-config.yaml.example`, `cli.py`, `gateway/platforms/api_server.py`, `gateway/run.py`, `hermes_cli/cli_commands_mixin.py`, `plugins/model-providers/gemini/__init__.py`, `plugins/model-providers/nous/__init__.py`, `plugins/model-providers/openrouter/__init__.py`, `plugins/model-providers/vertex/__init__.py`, `tests/agent/transports/test_gemini_reasoning_visibility.py`, `tests/cli/test_reasoning_command.py`, `tests/gateway/test_reasoning_command.py`, `tests/gateway/test_reasoning_config_per_model.py`, `tests/test_tui_gateway_server.py`, `tests/tui_gateway/test_reasoning_session_scope.py`, `tests/tui_gateway/test_reasoning_visibility.py`, `tui_gateway/server.py`, `website/docs/user-guide/configuration.md`
- **#91008: fix(vertex): route Gemini thought deltas to the reasoning stream, not visible content**. open
  - maintainer direction: category `uncategorized`; implication `needs_llm`
  - files: `agent/chat_completion_helpers.py`, `tests/run_agent/test_streaming.py`

## Fix status

- Merged to main in PR #16999 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-04-29`.
- Subsystem: `agent`
