Skip to content

fix: move dynamic ACP injections to suffix message for prefix cache stability#6

Merged
ranxianglei merged 5 commits into
masterfrom
2026-05-30_prefix-cache-fix
May 30, 2026
Merged

fix: move dynamic ACP injections to suffix message for prefix cache stability#6
ranxianglei merged 5 commits into
masterfrom
2026-05-30_prefix-cache-fix

Conversation

@ranxianglei
Copy link
Copy Markdown
Owner

Summary

  • Move all dynamic ACP metadata injection (context usage, visible IDs, block guidance, anchored nudges) from historical user messages to a new synthetic suffix message at the end of the message list
  • Add isSyntheticMessage() to make synthetic messages invisible to getLastUserMessage and findLastNonIgnoredMessage

Fixes #5

Problem

ACP injected dynamic per-turn metadata into the last user message on every chat.messages.transform call. Because OpenAI Responses uses prefix-based caching, modifying an early user message invalidated the cache for all subsequent content. Cache read tokens would plateau at ~25.6K while total prompt tokens grew from 38K to 83K.

Fix

Before: ACP modifies early user message -> cache breaks for all subsequent content

After: ACP appends synthetic message at end -> historical messages stay byte-stable

Files Changed

  • lib/messages/inject/inject.ts - Added createSuffixMessage(), changed 3 injection functions to target suffix
  • lib/messages/inject/utils.ts - Added suffixMessage param to applyAnchoredNudges()
  • lib/messages/query.ts - Added isSyntheticMessage(), updated getLastUserMessage()
  • tests/e2e-blocks-nudges.test.ts - Updated 3 tests for suffix message
  • tests/e2e-message-transform.test.ts - Updated 3 tests for message counts

Test Results

  • npm run typecheck: PASS
  • npm run build: PASS
  • npm run test: 350/350 pass

ranxianglei and others added 5 commits May 30, 2026 20:07
…tability

Dynamic metadata (context usage, visible IDs, block guidance, anchored
nudges) was injected into the last user message on every transform call.
This invalidated OpenAI Responses prefix cache for all subsequent content.

Move all dynamic injections to a synthetic suffix message at the end of
the message list so historical messages remain byte-stable across turns.

Fixes: #5

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Context usage and visible ID range are now injected into a suffix message
at the end of the message list instead of the last user message. Update
test assertions to check suffix message and account for +1 message count.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…e-dcp to opencode-acp

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@ranxianglei ranxianglei merged commit 118de2c into master May 30, 2026
3 checks passed
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.

ACP dynamic nudges prevent OpenAI Responses prefix cache from growing

1 participant