Skip to content

OpenAI prompt cache key is not stable across forked sessions #36098

Closed as not planned

Description

@chandreshphirke

Description

Description

When using OpenAI/ChatGPT OAuth GPT models, OpenCode sets the OpenAI promptCacheKey from the current session id. Forking creates a new session and clones the messages, so each fork sends the same prompt prefix but a different cache key/session affinity.

This makes prompt-cache reuse across forks unreliable.

Observed locally on opencode 1.17.13:

  • Base session with gpt-5.5
  • 5 forked first calls
  • 4/5 forks had cache.read = 0
  • 1/5 had cache.read = 3584, so reuse appears opportunistic rather than stable

Expected

Forked sessions should preserve a stable cache root/parent key for provider prompt-cache affinity, while still keeping their own session id for UI/history identity.

Possible fix

When forking, store an inherited cache root id in session metadata, then use that value for OpenAI promptCacheKey / cache-affinity headers. Fall back to current session id when no cache root exists.

Plugins

None

OpenCode version

1.17.13

Steps to reproduce

Steps to reproduce

Prerequisites:

  • OpenCode is logged in with OpenAI / ChatGPT Pro or Plus OAuth.
  • OpenCode version: 1.17.13
  • Model: openai/gpt-5.5 or another OpenAI GPT model.
  • Use --format json so token usage can be inspected.
  1. Create a base session with a prompt large enough for prompt caching.
opencode run \
  --model openai/gpt-5.5 \
  --format json \
  "Cache repro base. Read this static context and reply only: base ready.

  <paste 2000+ tokens of stable text here>"
  1. Note the created session id from the JSON output.

Example:

ses_xxx
  1. Fork the same base session multiple times and run the same first prompt in each fork.
opencode run --model openai/gpt-5.5 --session ses_xxx --fork --format json "Fork cache probe. Reply only: ok."
opencode run --model openai/gpt-5.5 --session ses_xxx --fork --format json "Fork cache probe. Reply only: ok."
opencode run --model openai/gpt-5.5 --session ses_xxx --fork --format json "Fork cache probe. Reply only: ok."
opencode run --model openai/gpt-5.5 --session ses_xxx --fork --format json "Fork cache probe. Reply only: ok."
opencode run --model openai/gpt-5.5 --session ses_xxx --fork --format json "Fork cache probe. Reply only: ok."
  1. Inspect each JSON output’s token usage.

Check:

tokens.cache.read

Actual result:
Most fork first calls report tokens.cache.read = 0, with occasional opportunistic hits.

Expected result:
Forked sessions that share the same copied prompt prefix should preserve stable OpenAI prompt-cache affinity, so cache reuse across forks is more reliable.

Additional local observation:
In my local repro on OpenCode 1.17.13 with openai/gpt-5.5, 5 fork first calls produced:

  • 4 forks: cache.read = 0
  • 1 fork: cache.read = 3584

Screenshot and/or share link

No response

Operating System

No response

Terminal

No response

Activity

  1. Zaczero commented on Aug 18, 2026

    @Zaczero

    This still reproduces by construction on 0.0.0-beta-17498, and the fix surface is smaller than the
    original report assumed.

    The key is a pure function of the session id and nothing else:

    export const make = (sessionID: SessionSchema.ID) =>
    /^ses_[0-9a-f]{64}$/.test(sessionID) ? sessionID.slice(4) : sessionID

    Every call site passes the live session id — model-request.ts:223, generate-node.ts:72,
    compaction.ts:277 — so a fork, being a new session id, necessarily gets a new key while sending the
    parent's prefix.

    The suggested fix is already supported by the schema without new storage: session_v2 carries
    fork_session_id and fork_boundary columns, and make() consults neither. Resolving the fork chain
    to its root inside make() would fix all three call sites at once, since they all go through it.

    One thing worth deciding at the same time. That single key is shared by the main conversation,
    compaction and title generation, and compaction in particular sends a deliberately divergent prefix
    under it — tools: [], one user message, a different serialization
    (compaction.ts:274-282).
    So the question isn't only "which id should a fork key on" but "what is this key scoped to at all". A
    fix that resolves fork roots and separates the auxiliary calls into their own keyspace would settle
    both; fixing forks alone leaves the second half in place.

  2. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions