# Cache-Safe Mode Diagram

## Core Problem

DeepSeek cache hits depend on an exact prefix match. If injected content changes every round, the prefix after that point changes as well, and the cache breaks from the injection point onward.

## Turn 1 -> Turn 2 -> Turn 3 Comparison

### Parity Mode: Dynamic plan-body injection

```text
Turn 1:  [SYS, USER_1, INJECT("Phase 1: Setup..."), A1, TOOL1, ...]
                     ^^^^^^  content 1: "Phase 1"
Turn 2:  [SYS, USER_1, INJECT("Phase 1: Setup..."), A1, TOOL1, ...,
           INJECT("Phase 2: Build..."), A2, TOOL2, ...]
           ^^^^^^  content 2: "Phase 2"  <- changed here

[Cache status]  Turn 1 -> Turn 2:
    SYS                           -> hit  (never changed)
    USER_1 + INJECT("Phase 1")   -> hit  (matches the end of Turn 1)
    A1 + TOOL1 + ... + INJECT("Phase 2")
                                  -> break (INJECT content differs from Phase 1)
    Everything after that         -> MISS
```

### Cache-Safe Mode: Fixed reminder injection

```text
Turn 1:  [SYS, USER_1, REMINDER, A1, TOOL1, ...]
                     ^^^^^^^^  fixed: "Read task_plan.md..."
Turn 2:  [SYS, USER_1, REMINDER, A1, TOOL1, ...,
           REMINDER, A2, TOOL2, ...]
           ^^^^^^^^  still exactly the same string

[Cache status]  Turn 1 -> Turn 2:
    SYS                           -> hit
    USER_1 + REMINDER             -> hit (matches the end of Turn 1)
    A1 + TOOL1 + ... + REMINDER   -> hit (content is identical to Turn 1)
    A2 + TOOL2 + ...              -> break (new content was never cached)

  Note: the first half of Turn 2 (up to the second REMINDER) is still fully
  cached. Only the new assistant/tool content is a miss.
  Compared with parity mode, this preserves a much larger prefix.
```

## Message-Array View

### Parity: dynamic injection -> INJECT changes every round -> prefix break

```mermaid
sequenceDiagram
    participant SYS as System (static)
    participant U1 as User Turn 1
    participant INJ1 as INJECT "Phase 1..."
    participant A1 as Assistant Turn 1
    participant T1 as Tool Turn 1
    participant INJ2 as INJECT "Phase 2..."
    participant A2 as Assistant Turn 2
    participant T2 as Tool Turn 2
    participant INJ3 as INJECT "Phase 3..."

    Note over SYS,U1: Stable prefix (cache hit)
    Note over INJ1,T1: Stable prefix (cache hit)
    Note over INJ2: Content changed! (cache break)
    Note over A2,T2: Full miss
    Note over INJ3: INJECT differs every round (cache keeps breaking)
```

### Cache-safe: constant REMINDER -> stable prefix -> cache continues

```mermaid
sequenceDiagram
    participant SYS as System (static)
    participant U1 as User Turn 1
    participant R1 as REMINDER "Read task_plan.md..."
    participant A1 as Assistant Turn 1
    participant T1 as Tool Turn 1
    participant R2 as REMINDER "Read task_plan.md..."
    participant A2 as Assistant Turn 2
    participant T2 as Tool Turn 2
    participant R3 as REMINDER "Read task_plan.md..."
    participant A3 as Assistant Turn 3

    Note over SYS,R1: Stable prefix (cache hit)
    Note over A1,T1,R2: REMINDER content unchanged (cache continues)
    Note over A2,T2,R3: REMINDER still unchanged (cache continues)
    Note over A3: Only new assistant content misses (small cost)
```

## What This Means

```text
parity mode:  [SYS, U, "Phase 1...", A1, "Phase 2...", A2, "Phase 3...", A3]
                                      ^^^^^^          ^^^^^^
                                      different every round -> full miss from the first break

cache-safe:   [SYS, U, REMINDER, A1, REMINDER, A2, REMINDER, A3]
                         ^^^^^^^^   ^^^^^^^^   ^^^^^^^^
                         identical    identical    identical -> prefix continues -> many hits

Hit difference: parity usually only reuses the first 2 messages.
                cache-safe can reuse 4-5 messages each round, which is a large token savings.
```

## Code-Level Implementation

### Parity mode injection content (changes every round)

```typescript
// runtime.ts - buildParityPlanInjection()
// The payload includes the actual plan body and progress data.
// As the plan phase updates, the content changes.
"[planning-with-files] ACTIVE PLAN - current state:\n" +
"===BEGIN PLAN DATA===\n" +
"# Task Plan: Backend Refactor\n\n...\n\nPhase 1: Setup  (complete)\nPhase 2: Core   (in_progress)\n" +
"===END PLAN DATA===\n" +
"=== recent progress ===\n..."
```

### Cache-safe mode injection content (constant)

```typescript
// constants.ts - CACHE_SAFE_REMINDER
// A string that never changes.
"[planning-with-files] Read task_plan.md for current phase and status. " +
"Read findings.md for research context. Read progress.md for recent changes. " +
"Continue from the current phase."
```

Because `CACHE_SAFE_REMINDER` is identical every time, it becomes part of DeepSeek's **cache prefix unit**, and later requests can match the prefix of earlier requests exactly.

The real plan content in `task_plan.md`, `progress.md`, and `findings.md` is read by the agent through the `read` tool. That is a **filesystem access path**, not part of the message prefix, so it does not affect cache reuse.

## Additional Advantage

In cache-safe mode, both `before_agent_start` injection and `tool_call` injection use the same fixed constants:

- `CACHE_SAFE_REMINDER` after the user speaks
- `PRE_TOOL_CACHE_SAFE_REMINDER` before each tool call

These strings always appear in the same positions with the same content. Over time, DeepSeek's **common-prefix detection** merges them into their own cache units, shrinking the MISS region even further.
