Skip to content

REPL hides assistant text under 'Thinking (0 chars hidden)' when fronted by an Anthropic-compatible proxy (CCR + deepseek transformer) #2982

@vikarag

Description

@vikarag

Summary

When claw runs in interactive REPL mode against an Anthropic-compatible proxy that re-emits streaming responses (in my case claude-code-router v2.0.0 with the built-in deepseek transformer in front of DeepSeek), the assistant's text response is hidden behind the Thinking (0 chars hidden) ✔ Done indicator. The text does arrive — it is written into the session JSONL as a normal {"type":"text"} block — so the receiver/persistence layer is correct, but the live REPL renderer is misclassifying the streamed deltas.

The same proxy and model work correctly in non-interactive claw prompt mode, which suggests the bug is in the REPL streaming-event parser, not in the network/auth/transport layers.

Environment

  • claw v0.1.0, git SHA 8e45f18 (HEAD of main, 2026-05-01)
  • Built with cargo build --release --workspace
  • rustc 1.94.1, Ubuntu 24.04.4 LTS, x86_64
  • Proxy: @musistudio/claude-code-router@2.0.0 running on http://127.0.0.1:3456
  • Upstream provider: DeepSeek (https://api.deepseek.com/chat/completions, model deepseek-v4-pro) via CCR's deepseek transformer
  • Env vars used by claw:
    • ANTHROPIC_BASE_URL=http://127.0.0.1:3456
    • ANTHROPIC_AUTH_TOKEN=<ccr-bearer>

Reproduction

  1. Stand up CCR with a config whose default route maps to deepseek,deepseek-v4-pro and uses the built-in deepseek transformer.
  2. ANTHROPIC_BASE_URL=http://127.0.0.1:3456 \
    ANTHROPIC_AUTH_TOKEN=<token> \
    ./target/release/claw
  3. At the prompt: > ping!

Observed

REPL output:

> ping!
⠋ 🦀 Thinking...
▶ Thinking (0 chars hidden)
✔ ✨ Done

>

But the corresponding entry in ~/.claw/sessions/<wsid>/<session>.jsonl contains the actual text:

{
  "message": {
    "blocks": [{"text": "pong!", "type": "text"}],
    "role": "assistant",
    "usage": {
      "cache_creation_input_tokens": 0,
      "cache_read_input_tokens": 4864,
      "input_tokens": 26,
      "output_tokens": 32
    }
  },
  "type": "message"
}

So the assistant returned a normal text block, but the REPL streaming UI counted 0 visible chars and stuffed everything into the (hidden) thinking section.

CCR side confirms the upstream call succeeded (HTTP 200 in ~1.9 s, model deepseek-v4-pro, stream: true, with tools present in the request). Both --model sonnet and the default claude-opus-4-6 reproduce the issue in the REPL.

Expected

The assistant text (pong! here) should render in the REPL the same way it gets persisted to the session JSONL.

Works around the bug

  • claw prompt 'ping!' (non-interactive) — prints pong! correctly.
  • Reading the session JSONL after a REPL turn — text is there.

So this is reproducible only on the live streaming render path of the REPL.

Hypothesis

CCR's deepseek transformer likely emits SSE events with names/shapes that the REPL parser maps to a thinking block instead of a text block (perhaps content_block_delta with a delta.type other than text_delta, or a thinking_delta event substituted because the upstream emits a reasoning_content field). The receiver path that writes the JSONL appears to look at the final assembled message blocks and is unaffected; the live REPL parser is the divergence point.

If a maintainer can point me at the streaming event handler in the REPL (likely under crates/rusty-claude-cli or wherever the SSE consumer lives), I can capture the raw upstream SSE stream from CCR and attach it to this issue to nail down which event the parser is misclassifying.

Why this matters

Anthropic-compatible proxies (CCR, LiteLLM, OpenRouter's Anthropic shim, etc.) are a primary use case for using claw with non-Anthropic providers. The REPL is unusable against them today even though the underlying model is responding fine.

Metadata

Metadata

Assignees

No one assigned

    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