Skip to main content

Module opencode_session

Module opencode_session 

Expand description

x-opencode-session — OpenCode relay session-affinity header.

The OpenCode relay (opencode.ai, serving both the Zen and Go endpoints) uses x-opencode-session to pin the requests of one conversation to the same upstream backend, which is what keeps that backend’s prompt cache warm across the turns of a conversation. Upstream documents the header under its guidance for keeping an account from being flagged, and at least one Go model (deepseek-v4-flash) rejects header-less requests outright with HTTP 400 Model is unavailable.

Every OpenCode inference request, on both wires and on both streaming and non-streaming paths, resolves its value through session_token so the header cannot drift per code path. Model-catalog and warmup requests (GET /models) do not carry it: they are not a conversation turn, so there is no backend to pin.

§Value derivation

Upstream specifies no format, length, or lifetime for the value; its only normative statement is that a tool “includes the x-opencode-session header so we can optimize prompt caching”. The one datum on accepted values is that a random UUID is sufficient to turn the 400 above into a 200. This module therefore emits a 128-bit lowercase hex digest: opaque, fixed-length, unambiguously safe as an HTTP header value, and non-reversible.

The digest is taken over the ambient conversation scope (zeroclaw_api::TOOL_LOOP_SESSION_KEY) rather than over a cached random token, so the value is resolved from the canonical source at use time and this module holds no per-session lookup table.

§Why the scope is hashed rather than sent

Session keys embed channel and user identifiers — sanitize_session_key covers inputs shaped like whatsapp_123@g.us_alice and slack_C123_1.2_user one. Forwarding one verbatim would hand a third-party relay a cross-service-linkable per-user identifier, which the privacy contract in docs/book/src/contributing/privacy.md forbids. Hashing keeps the affinity behavior while sending nothing but an opaque token.

The digest is domain-separated but unsalted, so it is deterministic across restarts — which is what preserves cache affinity for a conversation that spans a daemon restart. The tradeoff is explicit: this prevents plaintext exposure of channel and user identifiers, but it is not a defense against a party who knows ZeroClaw’s session-key format brute-forcing a low-entropy key space. Defeating that would require a per-install salt, which would cost the cross-restart affinity this is for; it is deliberately out of scope here.

Constants§

OPENCODE_SESSION_HEADER
The affinity header OpenCode reads to pin a conversation to one backend.

Functions§

is_opencode_target
True when base_url addresses the OpenCode relay.
operator_pinned_session
True when extra_headers pins an x-opencode-session value that will actually reach the wire.
redirect_policy
Redirect policy for clients whose requests may carry the session header.
restrict_redirects
Apply redirect_policy to builder when endpoint is an OpenCode target. Every other provider keeps reqwest’s default redirect handling.
session_token
Affinity token for the calling conversation, or None when base_url is not an OpenCode target.