3739cf3b86
POST /v1/responses and POST /v1/runs parse and authenticate the client's X-Hermes-Session-Key, pass it downstream for memory scoping, and then mint a throwaway physical session id anyway whenever the client manages its own history (no previous_response_id chain to carry one forward). Every conversation-affinity hint Hermes sends is derived from that physical id, so all four re-keyed on every single reply: prompt_cache_key on both OpenAI-wire transports, the OpenRouter and Nous sticky session_id, and xAI's x-grok-conv-id. The conversation never landed back on a warm prefix. Fix the identity rather than the four consumers. The declared key resolves to its live session through find_latest_gateway_session_for_peer -- the same reset-fenced recovery every native gateway platform already uses -- and the turn records the row it ended on through record_gateway_session_peer, which AIAgent._ensure_db_session never did (it knows the key and writes the row unkeyed, so the mapping the next reply needs did not exist). Because the lookup is fenced on sessions.end_reason, the generation that must rotate is already durable: session_reset (/new), session_switch, idle, daily, suspended and resume_pending_expired all return None, so a new conversation gets a new id and a cold affinity scope, and a retired generation can never be resolved again. No counter, no new persisted field, and no new precedence rule in the cache-scope resolver -- /branch, delegate and tool children keep the isolation of #79161/#79017 byte for byte. Precedence is unchanged where it already worked: an explicit body session_id and the previous_response_id chain both still outrank the declared key, and a request that declares nothing keeps its per-request id. Recording is opt-in (bind_declared_conversation), so no other _run_agent caller's rows change. Refs #96811 (cherry picked from commit e7c83dddf36784d1012bf483240ebc7f6b2ef9aa)