Skip to content

Prompt loop DB reload breaks Anthropic cache after tool calls (63% of spend) #24841

Closed as not planned

Description

@BYK

Description

The prompt loop in prompt.ts reloads all messages from the DB (filterCompactedEffect) at the start of every iteration. Between tool-call steps, tool parts transition from pending to completed with output text. When toModelMessages() serializes the conversation for the next API call, the previous assistant message has different bytes:

  • Before tool execution (step N): state: "output-error", errorText: "[Tool execution was interrupted]" (message-v2.ts line 912)
  • After tool execution (step N+1): state: "output-available", output: <actual output> (message-v2.ts line 853)

Anthropic's prompt cache sees different bytes at that message position → invalidates everything after it → the entire remaining context is re-written at cache-write pricing ($6.25/MTok for Opus, 12.5× the cache-read price).

Cost impact from real session data (Opus 4.7, 1M context):

  • 63% of total API spend is cache writes ($2,264 out of $3,584 on April 21st)
  • 95% of rapid cache busts (<60s gap) have a tool call in the preceding message
  • Warm turns: cache_read=614K, cache_write=1K — nearly perfect caching
  • Bust turns: cache_read=54K, cache_write=560K — only system prompt survives
  • Sessions with heavy tool use see 20-84% bust rates

This is likely the same root cause as #20565 (same snapshot hash, mixed cache behavior) and related to #20110 (prompt cache invalidation class).

Plugins

Lore (opencode-lore) — but the issue is in OpenCode core, not the plugin. Lore's gradient transform returns input.messages unmodified at layer 0.

OpenCode version

v1.14.29 (latest dev)

Steps to reproduce

  1. Start a session with Claude Opus 4.7 (1M context)
  2. Have the model make tool calls (read files, run bash, etc.)
  3. Observe token usage: warm turns have cache_write ~1K, but turns immediately after tool execution have cache_write ~500K+
  4. Query the OpenCode DB: SELECT cache_read, cache_write FROM message WHERE session_id = '...' AND role = 'assistant' — the alternating pattern of warm/bust is visible

Screenshot and/or share link

Cache pattern from DB analysis:

msg#  cache_read  cache_write  state
1     0K          595K         COLD (first turn)
2     595K        1K           warm ✓
3     54K         542K         BUST (after tool call)
4     595K        1K           warm ✓
...
22    54K         562K         BUST (after tool call)
23    54K         559K         BUST (after tool call)
24    613K        1K           warm ✓

Operating System

Ubuntu 24.04

Terminal

OpenCode TUI

Activity

  1. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    perfIndicates a performance issue or need for optimization
    on Apr 28, 2026
  2. github-actions commented on Apr 28, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    If this is a distinct enough angle (cache cost impact vs. DB read overhead), feel free to clarify how it differs from #22208 so maintainers can track them separately.

  3. removed
    perfIndicates a performance issue or need for optimization
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on May 3, 2026
  4. github-actions commented on Jul 3, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

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