NousResearch/hermes-agent

Gemini streaming incompatibility with stream_options argument

Cluster 14387 · agent. Data as of

Nothing open on GitHub. Fix merged in #54653 on 29 Jun 2026. Check it covers your case.

The short answer

0open issues
0open PRs
4items grouped
Known?
Yes. 4 related items grouped here, 1 issue already closed.
Fix event
A fix was merged to main in PR #54653. Check it covers your case. No release data is tracked.
Tracker
The maintainers' tracker marks this resolved, deciding PR #54653. That is separate from the fix event.
Still open
Nothing open on GitHub.

A bug was identified where stream_options is passed to Gemini's completions API, which does not support that keyword argument. Multiple fix attempts address omitting stream_options specifically for Gemini streaming calls.

Open issues0

No open issues.

Open PRs0

No open pull requests.

Fixes on record

Merged to main. A stamp counts the issues a fix is linked to.

  • #54653 fix(agent): omit stream_options for native Gemini streaming

    merged to main

    files: agent/chat_completion_helpers.py, tests/run_agent/test_streaming.py

    Show the diff
    • agent/chat_completion_helpers.py
      @@ -28,6 +28,7 @@
       from hermes_cli.timeouts import get_provider_request_timeout, get_provider_stale_timeout
       from hermes_constants import PARTIAL_STREAM_STUB_ID, FINISH_REASON_LENGTH
       from agent.error_classifier import FailoverReason
      +from agent.gemini_native_adapter import is_native_gemini_base_url
       from agent.model_metadata import is_local_endpoint
       from agent.message_sanitization import (
           _sanitize_surrogates,
      @@ -1911,7 +1912,6 @@ def _call_chat_completions():
               stream_kwargs = {
                   **api_kwargs,
                   "stream": True,
      -            "stream_options": {"include_usage": True},
                   "timeout": _httpx.Timeout(
                       connect=_conn_cap,
                       read=_stream_read_timeout,
      @@ -1919,6 +1919,14 @@ def _call_chat_completions():
                       pool=_conn_cap,
                   ),
               }
      +        # OpenAI's `stream_options={"include_usage": True}` drives usage
      +        # accounting on OpenAI-compatible endpoints (incl. the Gemini OpenAI
      +        # compat shim and aggregators like OpenRouter).  Google's *native*
      +        # Gemini REST endpoint rejects the keyword outright
      +        # (`Completions.create() got an unexpected keyword argument
      +        # 'stream_options'`), so omit it only for that endpoint.
      +        if not is_native_gemini_base_url(agent.base_url):
      +            stream_kwargs["stream_options"] = {"include_usage": True}
               request_client = _set_request_client(
                   agent._create_request_openai_client(
                       reason="chat_completion_stream_request",
    • tests/run_agent/test_streaming.py
      @@ -95,6 +95,99 @@ def test_text_only_response(self, mock_close, mock_create):
               assert response.usage is not None
               assert response.usage.completion_tokens == 3
       
      +    @patch("run_agent.AIAgent._create_request_openai_client")
      +    @patch("run_agent.AIAgent._close_request_openai_client")
      +    def test_native_gemini_endpoint_omits_stream_options(self, mock_close, mock_create):
      +        """Google's native Gemini REST endpoint rejects OpenAI-only stream_options."""
      +        from run_agent import AIAgent
      +
      +        mock_client = MagicMock()
      +        mock_client.chat.completions.create.return_value = iter([
      +            _make_stream_chunk(content="Paris", finish_reason="stop", model="gemini"),
      +        ])
      +        mock_create.return_value = mock_client
      +
      +        agent = AIAgent(
      +            api_key="[redacted:secret-assignment]",
      +            base_url="https://generativelanguage.googleapis.com/v1beta",
      +            model="gemini-3-flash-preview",
      +            provider="gemini",
      +            quiet_mode=True,
      +            skip_context_files=True,
      +            skip_memory=True,
      +        )
      +        agent.api_mode = "chat_completions"
      +        agent._interrupt_requested = False
      +
      +        response = agent._interruptible_streaming_api_call({})
      +
      +        assert response.choices[0].message.content == "Paris"
      +        call_kwargs = mock_client.chat.completions.create.call_args.kwargs
      +        assert call_kwargs["stream"] is True
      +        assert "stream_options" not in call_kwargs
      +
      +    @patch("run_agent.AIAgent._create_request_openai_client")
      +    @patch("run_agent.AIAgent._close_request_openai_client")
      +    def test_gemini_openai_compat_shim_keeps_stream_options(self, mock_close, mock_create):
      +        """The Gemini OpenAI-compat shim (.../openai) accepts stream_options."""
      +        from run_agent import AIAgent
      +
      +        mock_client = MagicMock()
      +        mock_client.chat.completions.create.return_value = iter([
      +            _make_stream_chunk(content="ok", finish_reason="stop", model="gemini"),
      +            _make_empty_chunk(usage=SimpleNamespace(prompt_tokens=2, completion_tokens=1)),
      +        ])
      +        mock_create.return_value = mock_client
      +
      +        agent = AIAgent(
      +            api_key="[redacted:secret-assignment]",
      +            base_url="https://generativelanguage.googleapis.com/v1beta/openai",
      +            model="gemini-3-flash-preview",
      +            provider="gemini",
      +            quiet_mode=True,
      +            skip_context_files=True,
      +            skip_memory=True,
      +        )
      +        agent.api_mode = "chat_completions"
      +        agent._interrupt_requested = False
      +
      +        response = agent._interruptible_streaming_api_call({})
      +
      +        assert response.choices[0].message.content == "ok"
      +        call_kwargs = mock_client.chat.completions.create.call_args.kwargs
      +        assert call_kwargs["stream_options"] == {"include_usage": True}
      +
      +    @patch("run_agent.AIAgent._create_request_openai_client")
      +    @patch("run_agent.AIAgent._close_request_openai_client")
      +    def test_openai_compatible_streaming_keeps_stream_options(self, mock_close, mock_create):
      +        """OpenAI-compatible aggregators still request final usage chunks."""
      +        from run_agent import AIAgent
      +
      +        mock_client = MagicMock()
      +        mock_client.chat.completions.create.return_value = iter([
      +            _make_stream_chunk(content="ok", finish_reason="stop", model="test-model"),
      +            _make_empty_chunk(usage=SimpleNamespace(prompt_tokens=2, completion_tokens=1)),
      +        ])
      +        mock_create.return_value = mock_client
      +
      +        agent = AIAgent(
      +            api_key="[redacted:secret-assignment]",
      +            base_url="https://openrouter.ai/api/v1",
      +            model="test/model",
      +            provider="openrouter",
      +            quiet_mode=True,
      +            skip_context_files=True,
      +            skip_memory=True,
      +        )
      +        agent.api_mode = "chat_completions"
      +        agent._interrupt_requested = False
      +
      +        response = agent._interruptible_streaming_api_call({})
      +
      +        assert response.choices[0].message.content == "ok"
      +        call_kwargs = mock_client.chat.completions.create.call_args.kwargs
      +        assert call_kwargs["stream_options"] == {"include_usage": True}
      +
           @patch("run_agent.AIAgent._create_request_openai_client")
           @patch("run_agent.AIAgent._close_request_openai_client")
           def test_tool_call_response(self, mock_close, mock_create):

2 PRs closed without merging

From the close comments: duplicate 1 · merged via another change 1

  • #14392 fix(agent): omit stream_options for Gemini streaming · merged via another change → 032d702, #54653, #14387
  • #14460 fix(agent): skip stream_options for Gemini — unsupported keyword · duplicate → #14392, #14387
Closed issues · 1
  • Closed#14387[Bug]: 📝 Error: Completions.create() got an unexpected keyword argument 'stream_options'
How this cluster was grouped
  • Link evidence (structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
  • Pairwise link density 0.50: the share of item 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.

Pick up a Lab task

Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.

Open the Lab

At a glance

Subsystem
agent
Merged PRs
#54653
Closed issues
1
Attempts
2 PRs closed without merging
Fix link checked
29 Jun 2026

For your agent

The same facts, typed.