NousResearch/hermes-agent

OpenRouter Grok prompt caching header investigation and fix

Cluster 22705. Data as of

Nothing open on GitHub. Fix merged in #22809 on 9 May 2026. Check it covers your case.

The short answer

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

These items concern a missing xAI server-affinity header (x-grok-conv-id) when routing Grok models through OpenRouter, which may reduce prompt cache hit rates. They include an issue identifying the gap and at least two related fix attempts or variants.

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.

  • #22809 fix(openrouter): add x-grok-conv-id header for Grok models (carve-out of #22708)

    merged to main

    files: agent/transports/chat_completions.py, plugins/model-providers/openrouter/__init__.py, scripts/release.py, tests/providers/test_provider_profiles.py

    Show the diff
    • agent/transports/chat_completions.py
      @@ -448,6 +448,7 @@ def _build_kwargs_from_profile(self, profile, model, sanitized, tools, params):
                       qwen_session_metadata=params.get("qwen_session_metadata"),
                       model=model,
                       ollama_num_ctx=params.get("ollama_num_ctx"),
      +                session_id=params.get("session_id"),
                   )
               )
               api_kwargs.update(top_level_from_profile)
    • plugins/model-providers/openrouter/__init__.py
      @@ -53,16 +53,28 @@ def build_api_kwargs_extras(
               *,
               reasoning_config: dict | None = None,
               supports_reasoning: bool = False,
      +        model: str | None = None,
      +        session_id: str | None = None,
               **context: Any,
           ) -> tuple[dict[str, Any], dict[str, Any]]:
      -        """OpenRouter passes the full reasoning_config dict as extra_body.reasoning."""
      +        """OpenRouter passes the full reasoning_config dict as extra_body.reasoning.
      +
      +        For xAI Grok models routed through OpenRouter, attach the
      +        ``x-grok-conv-id`` header so that xAI's prompt cache stays pinned to
      +        the same backend server across turns.
      +        """
               extra_body: dict[str, Any] = {}
               if supports_reasoning:
                   if reasoning_config is not None:
                       extra_body["reasoning"] = dict(reasoning_config)
                   else:
                       extra_body["reasoning"] = {"enabled": True, "effort": "medium"}
      -        return extra_body, {}
      +
      +        extra_headers: dict[str, Any] = {}
      +        if session_id and model and model.startswith(("x-ai/grok-", "xai/grok-")):
      +            extra_headers["x-grok-conv-id"] = session_id
      +
      +        return extra_body, {"extra_headers": extra_headers} if extra_headers else {}
       
       
       openrouter = OpenRouterProfile(
    • scripts/release.py
      @@ -67,6 +67,7 @@
           "[redacted:email]": "Qwinty",
           "[redacted:email]": "CalmProton",
           "[email protected]": "mbac",
      +    "[redacted:email]": "Ninso112",
           "[redacted:email]": "wesleysimplicio",
           "[redacted:email]": "SiliconID",
           "[redacted:email]": "xieNniu",
    • tests/providers/test_provider_profiles.py
      @@ -121,6 +121,52 @@ def test_default_reasoning(self):
               eb, _ = p.build_api_kwargs_extras(supports_reasoning=True)
               assert eb["reasoning"] == {"enabled": True, "effort": "medium"}
       
      +    def test_grok_session_id_sets_cache_affinity_header(self):
      +        """OpenRouter + Grok model + session_id => x-grok-conv-id header."""
      +        p = get_provider_profile("openrouter")
      +        _, tl = p.build_api_kwargs_extras(
      +            model="x-ai/grok-4",
      +            session_id="sess-abc123",
      +        )
      +        assert tl["extra_headers"]["x-grok-conv-id"] == "sess-abc123"
      +
      +    def test_grok_xai_prefix_also_supported(self):
      +        """xai/ prefix (without dash) should also get the header."""
      +        p = get_provider_profile("openrouter")
      +        _, tl = p.build_api_kwargs_extras(
      +            model="xai/grok-3",
      +            session_id="sess-xyz",
      +        )
      +        assert tl["extra_headers"]["x-grok-conv-id"] == "sess-xyz"
      +
      +    def test_non_grok_model_no_affinity_header(self):
      +        """OpenRouter + non-Grok model => no x-grok-conv-id header."""
      +        p = get_provider_profile("openrouter")
      +        _, tl = p.build_api_kwargs_extras(
      +            model="anthropic/claude-sonnet-4.6",
      +            session_id="sess-abc123",
      +        )
      +        assert "extra_headers" not in tl
      +        assert "x-grok-conv-id" not in tl
      +
      +    def test_grok_without_session_id_no_header(self):
      +        """Grok model but no session_id => no header (nothing to pin)."""
      +        p = get_provider_profile("openrouter")
      +        _, tl = p.build_api_kwargs_extras(model="x-ai/grok-4")
      +        assert "extra_headers" not in tl
      +
      +    def test_grok_reasoning_and_header_together(self):
      +        """Reasoning extra_body and Grok header should coexist."""
      +        p = get_provider_profile("openrouter")
      +        eb, tl = p.build_api_kwargs_extras(
      +            model="x-ai/grok-4",
      +            session_id="sess-123",
      +            supports_reasoning=True,
      +            reasoning_config={"enabled": True, "effort": "high"},
      +        )
      +        assert eb["reasoning"] == {"enabled": True, "effort": "high"}
      +        assert tl["extra_headers"]["x-grok-conv-id"] == "sess-123"
      +
       
       class TestNousProfile:
           def test_tags(self):

1 PR closed without merging

From the close comments: merged via another change 1

  • #22708 fix(openrouter): add x-grok-conv-id header for Grok models to improve prompt cache hit rates · merged via another change → #22809, #22802
Closed issues · 1
  • Closed#22705OpenRouter Grok prompt caching likely misses xAI server-affinity header
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.67: 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

Merged PRs
#22809
Closed issues
1
Attempts
1 PR closed without merging
Fix link checked
9 May 2026

For your agent

The same facts, typed.