mpfaffenberger / mpfaffenberger/code_puppy
Feature: Extended thinking floods console with no suppression option — add config to silence ThinkingPart rendering while preserving telemetry
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 814
- Forks
- 278
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 76
Description
Problem
When using models with extended thinking enabled (e.g. Claude with thinking
budget), every thinking block streams directly to the console in real time.
There is no way to suppress it.
This causes two concrete UX problems:
-
Context loss — thinking output can be thousands of lines. It pushes
prior prompts and responses completely off-screen with no way to collapse
or hide it. Users lose their place in the conversation. -
No suppression path exists — there is no config flag, no plugin hook,
and no built-in mechanism to silence thinking output on the console.
The only working workaround today requires monkey-patching internal module
bindings (_runtime.event_stream_handler, _builder.event_stream_handler)
which is fragile, breaks on internal refactors, and is not appropriate for
a plugin or user-facing config.
What We Need
-
A config flag (show_thinking = false in puppy.cfg) that suppresses
ThinkingPart and ThinkingPartDelta content from rendering to the console. -
Optionally, when thinking is suppressed, route it to a per-session temp
file (e.g. /tmp/cp-thinking-.log) so the user can still inspect it
via tail -f without it polluting the main console.
Hard Constraint — Telemetry Must Not Be Affected
The existing stream_event callback hook is used for token counting, TTFT
measurement, and frontend telemetry (run_stats.py, frontend_emitter).
These must continue to fire regardless of whether thinking is shown on
the console.
This means the suppression must happen at the render level, not at the
event stream level. The fix belongs inside event_stream_handler.py in the
ThinkingPart render branches — not upstream of the handler where it would
also block stream_event callbacks.
Root Cause
In event_stream_handler.py, for both PartStartEvent and PartDeltaEvent,
the code structure is:
_fire_stream_event(...) # ← telemetry fires here (correct, keep this)
if isinstance(part, ThinkingPart):
await _print_thinking_banner() # ← these need to be gated
_emit_thinking(...) # ← these need to be gated
_fire_stream_event uses asyncio.create_task() — it fires and returns
immediately. The render calls below it are synchronous. The two concerns
(telemetry vs console output) are already separated in the code; they just
need an explicit gate on the render side.
Out of Scope for This Issue
This issue is specifically about console render suppression via config.
A separate, complementary enhancement would be a wrap_stream_events plugin
hook that lets plugins intercept and transform the event stream for other
use cases. That is tracked separately. The two features are independent.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading event_stream_handler.py, focusing on the PartStartEvent and PartDeltaEvent ThinkingPart render branches and the existing puppy.cfg configuration path. Gate only the thinking banner and emitted content while keeping _fire_stream_event callbacks active for telemetry; done means show_thinking=false suppresses console thinking output without affecting telemetry.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- cli
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100