FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Prompt loop DB reload breaks Anthropic cache after tool calls (63% of spend) · Issue #24841 · anomalyco/opencode · GitHub

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

Description

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

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


    Back | FazBrowse Home | New Git URL