Skip to content

feat: add X-Session-Id header for proxy cache routing affinity#31511

Merged
rekram1-node merged 1 commit into
anomalyco:devfrom
songchaow:feat/x-session-id-header
Jun 9, 2026
Merged

feat: add X-Session-Id header for proxy cache routing affinity#31511
rekram1-node merged 1 commit into
anomalyco:devfrom
songchaow:feat/x-session-id-header

Conversation

@songchaow

Copy link
Copy Markdown
Contributor

Issue for this PR

Closes N/A (improvement — no existing issue)

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Adds an X-Session-Id header (set to the session ID) alongside the existing x-session-affinity header for all non-opencode providers.

Why: Anthropic API proxies (e.g. enterprise gateways that front multiple upstream Anthropic accounts) use X-Session-Id to implement routing affinity — pinning all requests from the same session to the same upstream account. This maximizes KV-Cache hit rate on the upstream side because the cached prompt prefix lives on that specific account.

Without this header, multi-turn conversations get scattered across different upstream accounts by the load balancer, causing frequent prompt cache misses and significantly higher latency + cost.

The header name X-Session-Id is the convention used by Anthropic-compatible proxy providers (documented in their API specs). It is sent unconditionally for non-opencode providers — providers that do not recognize it will simply ignore an unknown header, so there is no behavioral change for direct Anthropic API usage or other providers.

The change is a single line addition in packages/opencode/src/session/llm/request.ts.

How did you verify your code works?

  1. Built locally with bun run build --skip-embed-web-ui --single
  2. Set up an HTTP header inspection proxy between opencode and the API endpoint — confirmed X-Session-Id is present in all outgoing requests
  3. Ran an end-to-end cache hit test: two sequential requests with the same session ID and same system prompt showed cache_creation_input_tokens: 1538 on request 1, then cache_read_input_tokens: 1538 on request 2 — confirming the routing affinity enables cache hits
  4. Full typecheck passed (23/23 packages)

Screenshots / recordings

N/A — backend-only change, no UI impact.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@songchaow songchaow force-pushed the feat/x-session-id-header branch from 35e9346 to 9b67f1c Compare June 9, 2026 12:18
Providers like LLM++ (TimiAI) use X-Session-Id to route requests from
the same session to the same upstream account, maximizing KV-Cache hit
rate. Without this header, multi-turn conversations get scattered across
different upstream accounts, causing frequent cache misses.

The header is sent alongside the existing x-session-affinity header for
all non-opencode providers.
@songchaow songchaow force-pushed the feat/x-session-id-header branch from 9b67f1c to e1e97f4 Compare June 9, 2026 13:24
@rekram1-node

Copy link
Copy Markdown
Collaborator

which providers are requiring this one?

@rekram1-node rekram1-node merged commit 80c0b06 into anomalyco:dev Jun 9, 2026
8 checks passed
shoootyou added a commit to shoootyou/opencode that referenced this pull request Jun 10, 2026
* test(core): cover skill directory output (anomalyco#31263)

* fix(opencode): avoid duplicate skill catalog (anomalyco#31269)

* chore(opencode): update MCP SDK to 1.29.0 (anomalyco#31268)

* chore: generate

* chore: update nix node_modules hashes

* run: make minimal mode more minimal (anomalyco#31227)

* chore: generate

* chore: update web and desktop code owners (anomalyco#31289)

* fix(desktop): few WSL bugs (anomalyco#31095)

* chore: generate

* fix(opencode): respect MCP server capabilities (anomalyco#31271)

* console: update email

* zen: fix

* fix(opencode): include acp pending tool input (anomalyco#31321)

* fix(lsp): resolve JDTLS root to topmost pom.xml in Java Maven multi-module projects (anomalyco#28761)

Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>

* chore: generate

* fix(session): merge per-call tool rules into session permission (anomalyco#30529)

Co-authored-by: Simon Klee <hello@simonklee.dk>

* docs(go): update MiniMax M3 pricing (anomalyco#31350)

* fix: speed up fff file search (anomalyco#31366)

* chore: generate

* fix(stats): show new for leaderboard deltas

* fix: stabilize fff file results (anomalyco#31369)

* chore: generate

* fix(core): restore npm proxy agent patch (anomalyco#31373)

* chore: update nix node_modules hashes

* chore: upgrade OpenTUI to v0.3.4 (anomalyco#31326)

* chore: update nix node_modules hashes

* fix(core): disable fff trace logs (anomalyco#31380)

* fix(session): avoid sticky prompt tool overrides (anomalyco#31394)

* fix(opencode): await run event loop (anomalyco#31389)

* refactor(core): replace legacy logger with Effect logging (anomalyco#31310)

* chore: generate

* fix(tui): trim select footer action highlight (anomalyco#31411)

* fix(opencode): support MiniMax M3 thinking toggle (anomalyco#31426)

* fix: adjust item id stripping to happen prior to request signing (anomalyco#31429)

* fix(opencode): generate reasoning variants for all OpenRouter models. (anomalyco#30332)

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>

* feat(app): add draft tab support to tabs store (anomalyco#31343)

* chore: generate

* fix(opencode): paginate MCP catalogs (anomalyco#31442)

* fix(opencode): pass abort signal to MCP tool calls (anomalyco#31455)

* feat(app): draft prompt state (anomalyco#31452)

* chore: generate

* feat(app): tabs help button (anomalyco#31454)

* feat: add "reasoning" as interleaved field option for vLLM providers (anomalyco#30477)

Co-authored-by: Ben Sandbrook <1126483+delta9000@users.noreply.github.com>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>

* fix(app): clip rounded session panels (anomalyco#31462)

* core: fix idle CPU use in file logger (anomalyco#31478)

* docs: add uninstall troubleshooting steps (anomalyco#31424)

Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>

* leave a breadcrumb comment about batchWindow zero (anomalyco#31508)

* chore: stats -> data

* test(core): avoid Windows worker close race (anomalyco#31532)

* refactor(tui): centralize application exit (anomalyco#31524)

* chore: generate

* feat(opencode): configure Cohere North model (anomalyco#31536)

* refactor(core): consolidate references (anomalyco#31539)

* feat(tui): show project copy in session list (anomalyco#31421)

* chore: generate

* fix(stats): use data branding assets

* drop citation_options from cohere (anomalyco#31543)

* zen: add north mini code model

* fix(data): timestamp formatting

* fix(opencode): support Claude Fable reasoning (anomalyco#31546)

* fix(mcp): log actionable connection statuses (anomalyco#31544)

* refactor(core): simplify location filesystem (anomalyco#31545)

* chore: generate

* chore: update nix node_modules hashes

* fix(opencode): restore effect error logging (anomalyco#31551)

* chore: generate

* feat(opencode): add typed application layer graph (anomalyco#31531)

* zen: add claude fable 5

* chore: generate

* refactor(mcp): simplify service helpers (anomalyco#31549)

* feat: add X-Session-Id header for proxy cache routing affinity (anomalyco#31511)

* zen: update email

* fix(desktop): update Electron stack and panel layout (anomalyco#31571)

* chore: generate

* chore: update nix node_modules hashes

---------

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Simon Klee <hello@simonklee.dk>
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
Co-authored-by: Filip <34747899+neriousy@users.noreply.github.com>
Co-authored-by: Frank <frank@anoma.ly>
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
Co-authored-by: huangli <areyouok@gmail.com>
Co-authored-by: Tommy D. Rossi <beats.by.morse@gmail.com>
Co-authored-by: Jack <jack@anoma.ly>
Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>
Co-authored-by: Dax <mail@thdxr.com>
Co-authored-by: James Long <longster@gmail.com>
Co-authored-by: Anthony Lau <anthony.lau2000@live.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
Co-authored-by: Ben Sandbrook <sandbrookvt@gmail.com>
Co-authored-by: Ben Sandbrook <1126483+delta9000@users.noreply.github.com>
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Sebastian <hasta84@gmail.com>
Co-authored-by: Songchao Wang <songchaow@outlook.com>
Co-authored-by: yui-soul <yui-soul@users.noreply.github.com>
@songchaow

Copy link
Copy Markdown
Contributor Author

which providers are requiring this one?

Seems to be zenlayer.

@ItsNilDev

Copy link
Copy Markdown

does this also maximize KV-Cache hit rate for deepseek-v4 models?

BYK added a commit to BYK/loreai that referenced this pull request Jun 11, 2026
…#687)

## Summary

Adds first-class support for OpenCode v1.17+'s new `X-Session-Id` header
for deterministic Tier-1 session identification, and simplifies the
vestigial client-type detection code.

## Context

OpenCode v1.17.0
([#31511](anomalyco/opencode#31511)) added an
`X-Session-Id` header alongside the existing `x-session-affinity` header
for proxy setups that need sticky routing. Both carry the same stable
session ID value. The gateway already recognized `x-session-affinity`,
so this was functionally handled — but only through the legacy name.
Adding explicit `x-session-id` recognition future-proofs against
OpenCode dropping the legacy header and supports any other client
adopting the standard name.

## Changes

- **Add `x-session-id` to `KNOWN_SESSION_HEADERS`** (`session.ts`):
ranked above `x-session-affinity` so the standard name wins when both
are present. Intentionally **not** added to `GATEWAY_MANAGED_HEADERS` —
the header is forwarded upstream as designed for sticky cache routing.
- **Fix stale `x-session-affinity` comment**: was described as "nanoid,
volatile — regenerated on restart" which is no longer accurate (current
OpenCode sets it to the stable DB session ID).
- **Replace `detectClientType()` with `isClaudeCodeClient()`**: the
tri-state `ClientType` (`claude-code` / `opencode` / `generic`) was
vestigial — nothing branched on `=== "opencode"`. The only behavioral
question is "is this Claude Code?" (for `max_tokens` sizing), which is
now a simple boolean. Removes the `ClientType` type export entirely.
- **Update tests**: replaced `detectClientType` tests with
`isClaudeCodeClient` tests, including coverage for the new
`x-session-id` header returning false (session identity ≠ client
identity).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants