mpfaffenberger / mpfaffenberger/code_puppy

Feature: Extended thinking floods console with no suppression option — add config to silence ThinkingPart rendering while preserving telemetry

Open
#384 0 comments 0 reactions 0 assignees View on GitHub

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:

  1. 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.

  2. 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
  1. A config flag (show_thinking = false in puppy.cfg) that suppresses
    ThinkingPart and ThinkingPartDelta content from rendering to the console.

  2. 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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.