# NousResearch/hermes-agent · OpenRouter Grok prompt caching header investigation and fix

## Open now

- 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.

## TL;DR

- 3 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 1 PR(s) closed without merging.
- A fix was merged to main in PR #22809. Verify it addresses your case.
- **Recommended:** read PR #22809 (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: `resolved` · deciding PR(s): `pr-22809`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.67`: 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.

## Closed / duplicate issues

- #22705: OpenRouter Grok prompt caching likely misses xAI server-affinity header

## Prior & competing PRs

- **#22809: fix(openrouter): add x-grok-conv-id header for Grok models (carve-out of #22708)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `agent/transports/chat_completions.py`, `plugins/model-providers/openrouter/__init__.py`, `scripts/release.py`, `tests/providers/test_provider_profiles.py`
  - fix hunks:
  - `agent/transports/chat_completions.py`

    ```diff
    @@ -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`

    ```diff
    @@ -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`

    ```diff
    @@ -67,6 +67,7 @@
         "[redacted:email]": "Qwinty",
         "[redacted:email]": "CalmProton",
         "308068+mbac@users.noreply.github.com": "mbac",
    +    "[redacted:email]": "Ninso112",
         "[redacted:email]": "wesleysimplicio",
         "[redacted:email]": "SiliconID",
         "[redacted:email]": "xieNniu",
    ```
  - `tests/providers/test_provider_profiles.py`

    ```diff
    @@ -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):
    ```
- **#22708: fix(openrouter): add x-grok-conv-id header for Grok models to improve prompt cache hit rates**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `#22809`, `#22802`

## Fix status

- Merged to main in PR #22809 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-05-09`.
