[BUG] Fable 5: mid-turn assistant text blocks intermittently delivered as summarized thinking blocks (turn appears silent)

Status Open
Reported on v2.1.201
Maintainer reply None cached
Activity 11 comments · opened Jul 5, 2026

Environment

  • Claude Code: 2.1.201
  • Model: claude-fable-5
  • Platform: Linux (WSL2), Anthropic API (subscription)
  • Observed both in the on-disk transcript (~/.claude/projects/**/<session>.jsonl) and in a --output-format stream-json consumer rendering the same stream

Summary

On Fable 5, when the model emits thinking → text → tool_use within a turn, the client intermittently never receives the text block. Instead it receives an extra short thinking block, with a valid signature, whose content is a paraphrase of the missing user-facing text — i.e. the summarized-thinking pipeline appears to absorb the model's text block into the thinking summary stream.

Because Claude Code hides thinking by default, affected turns look completely silent: the model works through tool calls with no visible narration, and text clearly written for the user (status updates, sometimes even instructions) is only discoverable by expanding thinking blocks in a client that renders them.

Evidence

From one session (4a80f3d4-eb8a-4e4b-b791-9efa8bd31171), block composition per assistant message id:

msg_01RGLsVsMqW1fTGEDHuMRExz ['thinking', 'text', 'tool_use']   <- text delivered (ok)
msg_01X1PEtb6xF27hJuFHwmBTUm ['thinking', 'thinking', 'tool_use'] <- text swallowed
msg_013UEULaCURMbNGfpWYLazSL ['thinking', 'thinking', 'tool_use'] <- text swallowed
msg_01CDBLob3BAqEb6u25XB47vS ['thinking', 'thinking', 'tool_use'] <- text swallowed
msg_017k9JmCVezg4Vt4YAMALSk2 ['thinking', 'thinking', 'tool_use'] <- text swallowed
msg_015ggGe2xFVcFCS7LT7W7sVW ['thinking', 'text', 'tool_use']   <- text delivered (ok)
msg_019JkXNVEyRcKPbgQY42Vevn ['thinking', 'thinking', 'tool_use'] <- text swallowed

Example (msg_01X1PEtb6xF27hJuFHwmBTUm, requestId req_011CcjR4DNPhEkZKdZBWafVA, 2026-07-05T18:52:50Z):

  • The model's intended user-facing text for that turn (confirmed because the model quotes it verbatim in later turns — it exists in the model-side conversation) was:

> "You caught a live specimen — this very session. Let me look at the raw transcript on disk to see what those two blocks actually are on the wire."

  • What the client received instead was a second thinking block (88 chars, signed):

> "I'll check the raw transcript to see what those two blocks actually contain on the wire."

  • The verbatim text appears nowhere in the stream or transcript (grep -c "live specimen" <transcript> → 0), while the paraphrase arrived typed as thinking.

The paraphrase-not-verbatim relationship (same content, different, shorter wording) is the fingerprint of the thinking summarizer, and the valid signature on the block means it was typed as thinking server-side — the client cannot mint signed thinking blocks, so this is not a client-side mislabeling.

Expected

Assistant text blocks are always delivered to the client as text content blocks, regardless of the thinking display mode. The thinking summary should cover only the chain of thought, not absorb the model's user-facing output.

Impact

  • Fable 5 frequently appears to "go silent" in Claude Code — long tool-calling stretches with zero visible narration, because the narration was emitted but delivered as hidden thinking.
  • User-directed content (including, occasionally, instructions the model wants the user to follow) lands in thinking blocks the default UI never shows.
  • Clients that do render thinking (custom stream-json consumers) show a confusing "double thinking block" pattern where the second block reads like it was addressed to the user — because it was.

Frequency

5 of 7 text-bearing tool-calling turns in the session above. Intermittent within a single session, so unlikely to be a per-request configuration difference.

Related (distinct) issues

  • #21751 — assistant text missing from transcript persistence (text was received but not written). Different failure: here the text never arrives on the wire at all, and a signed thinking paraphrase arrives in its place.
  • #66887 — Fable 5 thinking blocks render as empty stubs in the VS Code extension (display/omitted rendering issue, not content misrouting).

View original on GitHub ↗

7 Comments

carrotRakko · 1 month ago

Can confirm, with corpus-scale numbers. I grouped assistant JSONL entries by message.id and counted block-sequence shapes per API response.

Corpus, to be precise about scale: 788 transcript files under ~/.claude/projects/**/*.jsonl — that is 154 main sessions + 634 subagent transcripts, mixed CLI versions up to 2.1.201, and mixed models, so the per-model response counts below are the meaningful denominators. The Fable 5 portion is 5,908 API responses across 38 files. Non-Anthropic models present in the corpus were excluded from the comparison.

Rate

Among Fable 5 responses that continue after a tool result and carry a mid-turn note, the note lands in a second thinking block more often than in a text block:

| shape | count |
|---|---|
| [thinking, thinking, tool_use, …] (note swallowed) | 1,688 |
| [thinking, text, tool_use, …] (note delivered) | 1,402 |

That is ~55% of mid-turn narration never surfaces as text (1,688 of 5,908 total Fable 5 responses, ~29%, are the swallowed shape). The pattern is strikingly regular: always exactly two thinking blocks, never three or more (0 occurrences), and the second one is short (median ~91 chars displayed) and stylistically identical to the text blocks in the delivered variant — a one-or-two-sentence status update ("X is done, checking Y next").

Cross-model comparison (same corpus, same method)

| model | responses | […, thinking, thinking, …] |
|---|---|---|
| claude-fable-5 | 5,908 | 1,688 (29%) |
| claude-opus-4-7 | 13,082 | 0 |
| claude-opus-4-8 | 480 | 1 — dated 2026-06-09 |
| claude-haiku-4-5 | 56 (subagent turns only) | 0 |

The single Opus 4.8 occurrence predates the fix referenced in #74176 (#66112 was the Opus report, now closed); after that date my Opus corpus is clean while Fable 5 reproduces daily. This independently corroborates "fixed for Opus, still broken on Fable".

Two further observations

  1. Expanding thinking does not recover the original text. The displayed thinking is the summarized form, so even clients that render thinking show a paraphrase of the swallowed note rather than the note itself. In one of my sessions a Japanese status update surfaced as a shorter English summary; in another, a casual first-person sentence was displayed as a terse third-person rewrite. The user-facing words are not recoverable from any client surface.
  2. The model's self-model treats the note as delivered. When later asked what it had reported, the model quoted the swallowed notes verbatim as things it had "said to the user", matching the behavioral evidence in #74176. So instructions like "give brief status updates between tool calls" are, from the model's point of view, being followed — the content just never leaves the thinking channel.

Repro / measurement

Anyone can measure their own rate:

import json, glob, os, collections
seqs = collections.Counter()
for f in glob.glob(os.path.expanduser("~/.claude/projects/**/*.jsonl"), recursive=True):
    resp = {}
    for line in open(f, errors="replace"):
        if '"assistant"' not in line: continue
        try: e = json.loads(line)
        except ValueError: continue
        if e.get("type") != "assistant": continue
        m = e.get("message") or {}
        if m.get("model") != "claude-fable-5" or not isinstance(m.get("content"), list): continue
        resp.setdefault(m["id"], []).extend(b["type"] for b in m["content"])
    for types in resp.values():
        seqs[tuple(types[:3])] += 1
print("swallowed:", seqs[("thinking", "thinking", "tool_use")],
      "delivered:", seqs[("thinking", "text", "tool_use")])

Related: #74176, #66112 (Opus, closed), #65620, #74260 (possibly the same root cause observed from the rendering side).

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

abdulrehman-11 · 1 month ago

Independent reproduction and extended characterization — Windows 11, Claude Code 2.1.212, claude-fable-5, Anthropic API, xhigh effort. Same persisted fingerprint as the OP: ['thinking','thinking','tool_use'] where ['thinking','text','tool_use'] was emitted, second thinking block validly signed, text block absent from the wire and from the session .jsonl.

We ran 44 controlled tests (unique token + 5 marker lines per probe, visibility confirmed by a human each run, then cross-checked against the session file). Findings:

The behavior is purely positional within a turn:

| Position of assistant text | Result | Controlled record |
|---|---|---|
| First text block of the turn (before any tool call) | renders | 14/14 (incl. 6/6 directly before AskUserQuestion) |
| Mid-turn (after any tool result, before the next tool call) | absorbed | 18/18 lost |
| Final text block of the turn (nothing after it) | renders | 100%, incl. a >2K-token block |

Ruled out by direct test:

  • Text length: a ~35-character mid-turn one-liner was absorbed.
  • The following tool: Bash vs AskUserQuestion — identical. "Anchoring" the text to an immediately-following trivial tool call, double anchors, and sandwiching the text between two tool calls all failed; the persisted sequence shows the text was adjacent to tool_use on emission and still vanished.
  • Renderer: default and fullscreen TUI behave identically (transcript mode also lacks the text — it's absent from the data, not the paint).
  • Client environment: no hooks matching the tools involved, stock binary across three auto-updated versions, reproduced fresh each time.
  • Model control: Opus 4.8 is immune — 2/2 clean on the exact shape (tool_result → text → tool_use) that failed 18/18 on Fable 5 in the same session. Consistent with the summarized-interleaved-thinking pipeline being the locus.

Severity note: this is data loss, not a cosmetic issue. The absorbed text is absent from the session .jsonl, so --resume, compaction, and /export permanently lose it — including for the model, whose context is rebuilt from that file. Higher effort levels amplify the trigger rate (more interleaved thinking → more text → thinking adjacencies), which may explain why reports are rare: at default effort the turn merely looks "quiet" occasionally.

Workaround (validated end-to-end, incl. a >2K-token payload and a timer expiring mid-stream): keep user-facing text out of mid-turn positions, and use background-task auto-resume as a turn splitter when text must precede a tool call after other tool use. Exact snippet we now carry in the global CLAUDE.md:

### FOR FABLE MODELS ONLY — mid-turn text absorption (non-Fable models: skip this entire subsection)

This subsection, including every numbered rule inside it, applies ONLY when the running model is a Fable model. (Verified 2026-07-18, 44 tests; upstream anthropics/claude-code#74558; server-side, unfixable client-side.)

Fable's thinking-summarizer absorbs any assistant text emitted between a tool result and the next tool call — the user never sees it (18/18 in controlled tests, regardless of length or which tool follows). Only a turn's FIRST text block and FINAL text block render reliably. AskUserQuestion's own question/option text always renders. When running as Fable, follow these rules (no other model may adopt them):

1. Never emit user-facing text between tool calls. Everything the user must read goes in the turn's first text block or its final text block; restate in the final block anything accidentally narrated mid-turn.
2. Explain-then-ask in a fresh turn (no tool calls yet): write the explanation, then call AskUserQuestion — turn-initial text is safe.
3. Explain-then-ask after any tool use (mid-turn): use the **timer-split** — (a) arm `sleep 2; echo "timer done"` via Bash `run_in_background: true` BEFORE writing anything user-facing, (b) end the turn with the explanation as the final text block, (c) when the task notification auto-resumes, open the fresh turn with AskUserQuestion directly (no text before it). Never write text after arming — it becomes mid-turn text and dies.

The ordering constraint in rule 3 is load-bearing and was verified separately: text emitted before arming the timer is mid-turn text and is absorbed; armed-first with the text as the turn's final block survives every time.

Happy to provide the full per-test log (tokens, persisted block sequences, message IDs) if useful.

rbardak · 1 month ago

+1 I am also affected by this issue. It seems to be getting worse. Just now, I had fable run a full implementation task on a ticket, and all I saw was

me: /layered-build implement COP-82
Fable: alright I will load the skill first.
...
about 15 tool calls with absolutely no messages
...
Fable: Task completed, submitting close-out commit.

That was it - and after asking what was going on, Fable reported that it had indeed sent walls of text and in-turn status updates to me - they never showed up in the TUI.

yuanzhi1203 · 1 month ago

This is a server side behaviour called connector text summarization, only described in https://docs.aws.amazon.com/bedrock/latest/userguide/claude-messages-adaptive-thinking.html

Here are some details about an experiment around it: https://matrix.dev/blog-2026-06-10

UNIVAC-Colonel-Panic · 1 month ago

Adding independent confirmation with evidence at two layers, including a terminal byte-capture.

Environment

  • Claude Code 2.1.220, macOS (darwin), model claude-fable-5
  • Viewed over SSH from a Windows terminal client (AbsoluteTelnet) — relevant only because the client's session logging gave us a raw byte capture of everything the TUI wrote to the terminal

What we saw

3-for-3 reproduction with this turn shape: a long multi-paragraph markdown text block (bold, numbered list, inline code) emitted between two Bash tool calls — i.e. thinking → tool_use → [text] → tool_use → text. The bracketed mid-turn text block silently never appears; text before the first tool call and after the last tool call renders normally. The same content re-emitted later as an end-of-turn message renders fine.

Where the missing narration should have been, the UI showed only a thinking spinner summary ("Cogitated for 36s").

Initially we suspected the terminal client was dropping the text (it had a history of rendering issues since fixed), so we captured client-side logs during two deliberate repro runs — one with a mid-turn user message injected, one without (both swallowed; mid-turn input ruled out as a trigger).

Evidence

  1. Terminal byte capture (client session log, raw stream incl. escape sequences): zero bytes of the missing text block in either run's capture, while every piece of text that did render on screen is present. The TUI never wrote the block to the terminal.
  2. On-disk transcript (~/.claude/projects/**/<session>.jsonl): the missing blocks appear nowhere as content (verified with self-contamination-proof greps — patterns like control can procee[d] so the probe can't match its own tool-call echo). Delivered text blocks from the same turns are present as normal text content.

So the block was absent from the wire, not mis-rendered — consistent with the OP's finding that the text is absorbed server-side into the summarized-thinking stream (our spinner-summary observation matches the "signed thinking paraphrase" fingerprint).

Repro recipe that hit 3/3 for us

Ask for a turn structured as: short text → tool call (a few seconds) → long formatted text block (bold + numbered list + inline code, ~1–2 KB) → another tool call → short closing text. In our sessions the mid-turn block was swallowed every time with this shape, while dozens of ordinary turns with short mid-turn status lines rendered fine — suggesting long/formatted mid-turn text blocks (or the amount of preceding thinking) raise the absorption probability well above the OP's "intermittent".

williamrobotma · 1 month ago

v2.1.220 repro with a 4-model control experiment: the text loss is Fable-only.

Setup

  • Claude Code: 2.1.220 (current release)
  • API: Anthropic
  • OS: Linux (WSL2), fullscreen terminal UI
  • Constant: single session throughout; only /model changed between runs

Method

  1. Per run: emit 3 uniquely-worded one-line marker texts inside one turn, at fixed positions:
  • A - start of turn, before the first tool call
  • B - mid-turn, between two tool calls
  • C - immediately before an AskUserQuestion tool call
  1. Record which markers display live in the terminal.
  2. Grep each marker's unique wording in the transcript: ~/.claude/projects/**/<session>.jsonl.
  3. Compare displayed vs stored, per marker.

Results

| Run | Model | Effort | A (start) | B (mid) | C (pre-question) |
|---|---|---|---|---|---|
| 1 | claude-fable-5[1m] | xhigh | delivered | lost | lost |
| 2 | claude-sonnet-5 | xhigh | delivered | delivered | delivered |
| 3 | claude-fable-5[1m] | xhigh | lost | lost | lost |
| 4 | claude-opus-4-8 | xhigh | delivered | delivered | delivered |
| 5 | claude-opus-5 | xhigh | delivered | delivered | delivered |
| 6 | claude-fable-5[1m] | low | lost | lost | lost |
| 7 | claude-fable-5 (no 1m) | xhigh | delivered | lost | lost |

Legend

  • delivered = displayed live, and present in the transcript file
  • lost = not displayed, and absent from the transcript file

Findings

  • Fable, mid-turn markers (B + C): 8/8 lost
  • Fable, start-of-turn markers (A): 2/4 lost
  • Sonnet 5 / Opus 4.8 / Opus 5, all positions: 9/9 delivered
  • End-of-turn text, all models, entire session: 0 lost
  • Display-vs-storage agreement: 21/21 markers - every marker that displayed was stored,

every marker that didn't display is absent from the file; the renderer is exonerated,
lost text never reached the client

  • [1m] long-context flag: no effect - loss identical with and without it
  • Effort level (xhigh vs low): no effect - loss identical at both

This issue's open questions

  • Other models affected? No - Fable-only under this procedure
  • Effort correlation? None - see Findings
  • Thinking correlation? Confounded - Fable's stream carried many thinking blocks during

the runs, Sonnet/Opus near zero; "Fable the model" vs "active thinking summarization"
is not separable from this data

  • Summarized-thinking substitution? Not reproduced - zero paraphrases of any lost marker

found in any stored thinking block; the lost text left no trace

  • Caveat: this transcript stores one content block per line, so in-message block order

(the [thinking, thinking, tool_use] fingerprint) was not checkable

Notes

  • Billing: lost text was generated and billed, but never delivered - same complaint

as #64129

  • #74260: likely the same failure class; refinement from this data - mid-turn text

before a following tool call survived 0/8, end-of-turn text survived 100%

  • Available on request: full session transcript, exact marker wordings, timestamps

Drafted by Claude Fable 5 (the affected model), directed and reviewed by the reporter, who performed all observations.

DannyGelf · 1 month ago

Confirming on macOS (Darwin 25.5.0), VSCode 1.131.0, extension anthropic.claude-code 2.1.220 (also observed on 2.1.207), CLI 2.1.197, model claude-fable-5.

Mid-turn assistant text blocks — text emitted between tool calls within a single turn — never render in the extension UI. They collapse under "Thought for Xs" rows (frequently a "Thought for 0s" entry with nothing expandable). Only turn-final text and AskUserQuestion dialog contents render visibly.

Hit in two separate sessions on the same day (2026-07-31). In one, a multi-section review report plus a rationale paragraph before each of four consecutive AskUserQuestion calls were all invisible — I answered the questions without ever seeing the context that preceded them. The same interaction patterns render fine with Opus models in the same extension.

Happy to provide session JSONL excerpts if useful.

Showing cached comments. Read the full discussion on GitHub ↗