Skip to content

fix(session): keep prompt cache prefixes stable across working directories - #1517

Open
anandgupta42 wants to merge 2 commits into
mainfrom
fix/stable-system-prompt-cwd
Open

anandgupta42 wants to merge 2 commits into
mainfrom
fix/stable-system-prompt-cwd

Conversation

@anandgupta42

@anandgupta42 anandgupta42 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Issue for this PR

Closes #1490

Type of change

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

What does this PR do?

Why: prompt caching only helps when the request prefix (system message and tool definitions) is byte-identical between sessions. Working directory and date text sat at the front of the system message and in the bash tool schema, so opening the same project from a different directory (or on a different day) invalidated the cached prefix.

Root cause:

  • SystemPrompt.environment() (directory, workspace root, date) was assembled before skills and project instructions in the single system message.
  • The bash tool workdir description interpolated Instance.directory, changing the serialized tool schema per directory. (The ${directory} replacement in the description was already a no-op.)

Before -> after:

  • Environment context is passed as environment to LLM.stream and appended as a separate trailing system message after plugin transformation, so the cache markers sit before it and directory/date still reach the model. Output-budget estimation still counts it.
  • bash workdir describes its default generically; execution still resolves params.workdir || Instance.directory.

Deferred / limits:

  • No live cache-hit measurement; tests mock transport and verify stable prefixes and marker placement only.
  • Instruction source paths and skill locations still embed absolute paths, so prefixes can legitimately differ across checkouts with path-bearing instructions or skills (follow-up; review noted tests use constant instructions).
  • Unused adapter session/llm/request.ts unchanged.

Upstream-shared files (session/llm.ts, session/prompt.ts, tool/bash.ts) exist in the v1.4 baseline tree; all changes are wrapped in altimate_change upstream_fix markers. The analyzer reports nothing to check against upstream v2, so markers were audited manually.

How did you verify your code works?

  • bun test test/tool test/session test/provider/transform.test.ts test/memory/injection.test.ts test/altimate/enhance-prompt.test.ts test/acp/tool.test.ts test/branding/build-integrity.test.ts (packages/opencode, unsandboxed): 2086 pass, 0 fail, 33 skip, 45 todo.
  • bun run typecheck: clean. git diff --check: clean.
  • New tests failed before the fix and pass after. Independent Codex review: no P0/P1; one P2 (test coverage for path-bearing instructions/skills) noted above.

Screenshots / recordings

N/A

Checklist

  • I have added tests that prove my fix works
  • New and existing tests pass locally
  • I have not committed models-snapshot.ts

🤖 Generated with Claude Code


Note

Medium Risk
Changes how system messages and tool schemas are serialized for every LLM turn; behavior is well-tested but any missed caller of environment or path-bearing instructions could still break cache stability.

Overview
Fixes prompt cache invalidation when the same project is opened from a different cwd or on a new day. Directory, workspace root, and date used to live inside the reusable system-instructions prefix (and in the bash tool schema), so the byte-identical prefix providers cache on could change every session.

Session / LLM: SystemPrompt.environment() is no longer merged into the main system array in prompt.ts. It is passed as optional environment on LLM.stream and appended as a trailing system segment after plugin system transforms, so Anthropic/Bedrock cache markers stay on the stable instruction prefix while ambient <env> context still reaches the model.

Bash tool: Tool description and workdir parameter text no longer embed Instance.directory; defaults are described generically and cwd is still resolved at execute time (params.workdir || Instance.directory).

Tests: Coverage for identical system/tool prefixes across directories (including cache marker placement), prompt loop wiring of environment vs system/messages, and stable bash definitions plus runtime workdir behavior.

Reviewed by Cursor Bugbot for commit 01f4c63. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Fixes prompt cache invalidation caused by working directory and date text appearing in the cached request prefix, so reusing the prefix across directories and days works as intended.

  • Passes the environment section (directory, workspace root, date) to LLM.stream separately and places it after the cached instructions: as a trailing system message for providers with explicit cache breakpoints (Anthropic, Bedrock, Alibaba) and appended to the single system message for others.
  • Extracts usesExplicitCacheBreakpoints so the split only applies where cache breakpoints are explicit; plugin-transformed instructions stay ahead of the environment.
  • Removes the instance directory from the bash tool workdir description and the no-op ${directory} substitution; execution still resolves the default directory at runtime.
  • Adds regression tests for bash tool schemas, prompt loop wiring, and Anthropic/Bedrock/OpenAI/Google request assembly.

Closes #1490.

Written for commit 994d11d. Summary will update on new commits.

View guided diff Turn on auto-fix

Summary by CodeRabbit

  • Improvements
    • Working-directory and date context are now provided separately from reusable system instructions, helping keep system prompt prefixes consistent across directories.
    • Bash tool descriptions and parameter details no longer vary by working directory. Commands still run in the current directory by default, or in an explicitly selected directory.

…ories

- Pass the environment section (directory, workspace root, date) to `LLM.stream` separately and append it as a trailing system message after the cache-marked instructions
- Remove the instance directory from the `bash` tool `workdir` description and drop the no-op `${directory}` substitution, so serialized tool schemas are identical across directories
- Add regression tests for the bash schema, the prompt loop wiring, and Anthropic/Bedrock request assembly

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cursor

cursor Bot commented Oct 15, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 65bda672-42b5-4edb-b25f-b9ae64ba8ece)

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-15T18:19:44.105737Z 994d11d New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

@coderabbitai

coderabbitai Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 29 seconds.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 28b38170-182b-4b9c-8145-75acf00d7602
📥 Commits

Reviewing files that changed from the base of the PR and between 01f4c63 and 994d11d.

📒 Files selected for processing: 3
  • packages/opencode/src/provider/transform.ts
  • packages/opencode/src/session/llm.ts
  • packages/opencode/test/session/llm-system-cache.test.ts

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: e15e08ca-8b82-41eb-bd4e-105bd5f35a32
📥 Commits

Reviewing files that changed from the base of the PR and between 346f0f8 and 01f4c63.

📒 Files selected for processing: 6
  • packages/opencode/src/session/llm.ts
  • packages/opencode/src/session/prompt.ts
  • packages/opencode/src/tool/bash.ts
  • packages/opencode/test/session/llm-system-cache.test.ts
  • packages/opencode/test/session/prompt.test.ts
  • packages/opencode/test/tool/bash.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 1 remain after this review.

📝 Walkthrough

The session prompt now passes environment context separately from the reusable system prompt. The Bash tool descriptions no longer include the session directory. Tests check prompt caching across directories and Bash working-directory behavior.

Changes: Session context and Bash working directory

Layer / File(s) Summary
Pass environment context separately
packages/opencode/src/session/llm.ts, packages/opencode/src/session/prompt.ts, packages/opencode/test/session/llm-system-cache.test.ts, packages/opencode/test/session/prompt.test.ts
LLM.StreamInput accepts an optional environment array. SessionPrompt.loop passes environment context separately, and LLM.stream appends it as a separate system-message segment. Tests check that directory and date context stay out of the reusable system prefix and that the prefix matches across directories.
Keep Bash descriptions directory-independent
packages/opencode/src/tool/bash.ts, packages/opencode/test/tool/bash.test.ts
Bash tool descriptions no longer include the session directory. Tests check that descriptions match across directories and that execution uses the instance directory by default or an explicitly provided workdir.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant SessionPrompt
  participant processor.process
  participant LLM.stream
  participant Model
  SessionPrompt->>processor.process: pass environment separately
  processor.process->>LLM.stream: provide environment and system prompt
  LLM.stream->>Model: send system prompt with environment segment
Loading

Suggested reviewers: sahrizvi

Merge Risk: ⚪ Minimal · up to 01f4c

No actionable merge-blocking issue is established. The prompt and Bash changes are ready for normal checks; a live provider cache hit remains unmeasured.

Pre-merge checks: Passed 4 · Inconclusive 1

Failed Failed checks: 1 inconclusive

Check name Status Explanation Resolution
Linked Issues check Inconclusive The source changes satisfy the coding requirements that the reviewed evidence can establish for [#1490]. LLM.stream appends environment after plugin transformation, the environment remains in inpu… Provide a supported-provider validation with two sessions in different working directories and record cacheRead > 0 on the second session's first generation. The current evidence is sufficient for prefix and schema behavior but not for th…
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the primary change: keeping prompt-cache prefixes stable across working directories.
Description check Passed The description includes the issue, change type, implementation details, verification results, screenshots status, and checklist information. It explains the root cause, fix, limitations, and test cov…
Out of Scope Changes check Passed The reviewed source changes and tests directly support [#1490]. They move environment context out of the reusable system prefix, stabilize the bash schema, preserve runtime working-directory behavio…
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 6 files.
Full details: Linked Issues check

Explanation

The source changes satisfy the coding requirements that the reviewed evidence can establish for [#1490]. LLM.stream appends environment after plugin transformation, the environment remains in input-token estimation, and BashTool no longer embeds Instance.directory in its schema while execution still uses it as the default. The added tests check stable tool definitions, stable cache-marked system prefixes, and environment placement. The evidence does not establish the issue's provider-backed acceptance check that the second session's first generation reports cacheRead &gt; 0; the PR explicitly reports no live cache-hit measurement.

Resolution

Provide a supported-provider validation with two sessions in different working directories and record cacheRead &gt; 0 on the second session's first generation. The current evidence is sufficient for prefix and schema behavior but not for the live cache result.

✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit checks the prompt at dawn,
The changing path is neatly drawn.
The system prefix stays in line,
While dates and directories shine.
Bash finds its workdir when called,
And cache tests hop through them all.

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

1 similar comment
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@kilo-code-bot

kilo-code-bot Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (7 files)
  • packages/opencode/src/provider/transform.ts
  • packages/opencode/src/session/llm.ts
  • packages/opencode/src/session/prompt.ts
  • packages/opencode/src/tool/bash.ts
  • packages/opencode/test/session/llm-system-cache.test.ts
  • packages/opencode/test/session/prompt.test.ts
  • packages/opencode/test/tool/bash.test.ts
Previous Review Summary (commit 01f4c63)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 01f4c63)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (6 files)
  • packages/opencode/src/session/llm.ts
  • packages/opencode/src/session/prompt.ts
  • packages/opencode/src/tool/bash.ts
  • packages/opencode/test/session/llm-system-cache.test.ts
  • packages/opencode/test/session/prompt.test.ts
  • packages/opencode/test/tool/bash.test.ts

Reviewed by gemini-4-argon · Input: 100K · Output: 2.5K · Cached: 441.6K

Review guidance: REVIEW.md from base branch main

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 6 files

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread packages/opencode/test/session/prompt.test.ts
Comment thread packages/opencode/src/session/prompt.ts
…akpoint providers

- Add `ProviderTransform.usesExplicitCacheBreakpoints` (extracted from `message`) and use it in `LLM.stream`
- Anthropic-style providers keep the trailing environment system message after the marked prefix; all other providers keep a single system message with the environment last
- Pass the environment block through `experimental.chat.system.transform` again and keep it last after plugin additions
- Extend request tests to OpenAI-style and Google-style providers

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cursor

cursor Bot commented Oct 15, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: d956af07-b318-40f3-b686-7d1be44539b3)

@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@anandgupta42

Copy link
Copy Markdown
Contributor Author

Addressed independent review in 994d11d:

  • The trailing environment system message is now used only for providers with explicit cache breakpoints (new ProviderTransform.usesExplicitCacheBreakpoints, shared with ProviderTransform.message). Other providers keep a single system message with the environment last.
  • The environment block passes through experimental.chat.system.transform again (and stays last after plugin additions), and is included in the system array used for budget estimation.
  • Added OpenAI-style and Google-style request tests. test/session, test/tool, and related files pass; typecheck clean.

@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

1 similar comment
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 994d11ddd7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/opencode/src/session/prompt.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 3 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread packages/opencode/test/session/llm-system-cache.test.ts
Comment thread packages/opencode/src/session/llm.ts

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Per-session working directory in the system prompt and bash tool description defeats prompt caching on every new session

1 participant