Skip to content

feat(shell): add thinking effort controls and auto-mode deliberation - #50

Merged
elkaix merged 21 commits into
mainfrom
pr/auto-mode-deliberation-clean
Jun 2, 2026
Merged

feat(shell): add thinking effort controls and auto-mode deliberation#50
elkaix merged 21 commits into
mainfrom
pr/auto-mode-deliberation-clean

Conversation

@elkaix

@elkaix elkaix commented Jun 2, 2026

Copy link
Copy Markdown
Member

Related Issue

N/A

Description

This branch collects the thinking-effort, auto-mode deliberation, shell UI polish, auth status, and recap/report rendering changes that are currently on pr/auto-mode-deliberation-clean.

Highlights:

  • Add first-class thinking effort configuration/runtime plumbing across CLI, ACP, web config, and providers.
  • Add auto-mode deliberation before sensitive AskUserQuestion / destructive-auto approval flows.
  • Polish shell prompt/status/report rendering, shimmer motion, spacing, and login/logout selectors.
  • Update recap wording and tests for the new UI/output behavior.

Verification

CI is pending. I will monitor all checks, CodeRabbit, and PR comments and address root causes until the PR is green.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked the related issue, if any. (No related issue.)
  • I have added tests that prove my fix is effective or that my feature works.
  • I have run make gen-changelog to update the changelog.
  • I have run make gen-docs to update the user documentation.

Summary by CodeRabbit

  • New Features

    • Granular thinking-effort levels (including "minimal") across CLI, server, web API, and subagents; Shift+Tab cycles levels.
    • Auto-deliberate mode: autonomous advisor-assisted deliberation for destructive actions.
  • UI/Visual Improvements

    • Thinking-effort display and prompt styling updated; native-reasoning labeling per model.
    • New traveling-wave + splash shimmer; improved report/panel padding and render layout.
  • Documentation

    • Added shimmer traveling-waves design spec.

elkaix added 19 commits June 1, 2026 17:36
web/static/ is a build output (scripts/build_web.py rmtree's + repopulates it
from the vite build, whose brand files come from web/public/brand). The two
brand assets are force-committed only so the test job — which doesn't run the
web build — has the files the OAuth callback reads. Add a guard asserting those
committed copies stay byte-identical to web/public/brand, so a brand-source
change can't silently leave the branding tests validating a stale fixture.
The OAuth callback page embeds icon.svg/favicon.ico as data URIs. These are
build outputs (web/static) and normally always present, but a broken build
shouldn't crash login over a cosmetic asset. Catch OSError in the data-uri
helper, log a warning, and embed an empty source so the callback still renders.
Add a test for the degraded path.
Under auto_deliberate, an irreversible shell action (rm -rf, git push
--force, git reset --hard, dd, truncate) is bounced once before running --
even under auto/yolo -- so the agent weighs alternatives first. One-shot:
the identical re-issue runs, so deliberation never permanently whitelists
the command. ApprovalResult gains a deliberation variant whose feedback is
not framed as a user rejection.
Pure helpers for the Shift+Tab thinking feature: next_thinking_level()
cycles off->minimal->low->medium->high->xhigh->off, and thinking_frame_color/
thinking_frame_style map each level to a prompt border color (grey->blue->
violet->purple) per theme. Keymap + prompt-handler wiring follows.
Restructure the active-work shimmer into a four-phase loop: a wave
sweeps right-to-left, splashes outward from the middle, sweeps back
left-to-right, splashes again, then repeats. Replaces the previous
single-direction repeating sweep. Stays purely time-derived so the
prompt, activity tree, and pinned-todo renderers animate in sync.
Recolor the active-work shimmer: highlight is now silver (#D8DCE2)
instead of violet, and the verb-spinner/pinned-todo base is a muted
orange-yellow (#D49E5A) instead of golden amber. Point palette tests at
the motion constants so future shade tweaks don't churn test literals.
The per-turn '※ recap:' line quoted the assistant's first sentence,
which is always an intent preamble ('I'll start by gathering...') rather
than what the turn accomplished. Add an outcome-sentence heuristic that
skips intent/offer/question/path-noise lines and prefers the closing
summary, and append factual deltas (N files changed · M steps). Wire the
live view to count files changed per turn from diff display blocks.

Also improve /recap: session bullets lead with the session outcome
instead of the first user message, and a single short no-op session is
reported plainly as a light day rather than padded into a bullet list.
Make "minimal" a first-class ThinkingEffort: OpenAI round-trips it
natively, the Pythinker provider preserves it instead of collapsing to
low, Anthropic clamps it down to its floor (low) rather than up to high,
and Gemini maps it to its lowest thinking level/budget.
… setting

Add a persisted default_thinking_effort alongside the legacy
default_thinking bool, with the effort string as the source of truth
(falling back to the bool only for pre-existing configs). create_llm now
takes an explicit effort, clamps it to model capabilities, preserves
levels like xhigh/minimal instead of collapsing every enabled request to
high, and threads the effort through the CLI, ACP, review, web API,
subagents, login flows, setup, and the /model and /thinking selectors.
Always-thinking models surface native reasoning instead of an effort
dial.
…y effort

Repurpose Shift+Tab from plan-mode toggle to a thinking-effort cycle over
the model's available levels, with a toast and telemetry. The prompt
separator and bottom-toolbar label now reflect the active effort (or
"native reasoning"), and the effort color ramp moves from a grey/violet
scale to a cool-to-warm slate→pink ramp. Tips and keybinding help updated
to match.
…tion

Add an "auto_deliberate" ask-user policy: in auto mode, instead of
silently dismissing AskUserQuestion, run an independent tool-less advisor
that blind-ranks the agent's own options and hand the verdict back so the
agent self-decides. Destructive auto-approved actions are bounced once for
deliberation via a tool-agnostic classifier, and the auto-mode prompt
invites the tool at genuine forks under this policy.
Render report blocks as a rounded, padded Rich panel (a standalone
reading surface) with hanging-indented wrapped locations, and keep a
one-row seam when a report fence follows streamed prose. Ask-question
cards gain blank-row separation between header and questions.
Add a prompt-scoped refresh loop so the pinned-status shimmer stays
frame-based when wire events are sparse (e.g. a long-running subagent),
honoring reduced-motion with a slower interval.
Map each login/logout entry to the managed provider keys that signal it is
configured, so /login and /logout report real status and a bare /logout
opens a selector over only the logged-in providers (with a single OpenAI
entry covering both OAuth and API-key credentials).
Two RunAgents calls differing only in base_prompt produced the same
fingerprint; include it so distinct launches are not deduplicated.
Update rendering tests to match the committed compaction/recap seam
behavior: compaction commits a leading blank row plus block, and turn
recaps are framed by blank rows.
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 74a3ac84-0424-46f5-8a89-1ad7d57aab58

📥 Commits

Reviewing files that changed from the base of the PR and between e968a78 and 158ee96.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • src/pythinker_code/ui/shell/visualize/_blocks.py
  • tests/ui_and_conv/test_streaming_content_block.py

📝 Walkthrough

Walkthrough

Adds provider-neutral thinking-effort levels (including "minimal"), wires effort through providers/LLM/CLI/config/web/UI, introduces auto-deliberation for destructive tools with a blind advisor, redesigns shell shimmer to traveling-waves, updates recap formatting, and adds extensive tests.

Changes

Unified Thinking Effort, Shimmer, and Auto-Deliberation

Layer / File(s) Summary
Thinking-effort contracts and provider mappings
packages/pythinker-core/...
Adds ThinkingEffort including "minimal", updates OpenAI/Anthropic/Google mappings and corresponding tests.
LLM creation and cloning
src/pythinker_code/llm.py, subagents/*, acp/server.py
create_llm/clone_llm_with_model_alias accept/propagate thinking_effort; ACP resolves/persists effective effort when switching models.
Config, CLI, Web API
src/pythinker_code/config.py, cli/*, web/api/config.py, app.py
Adds default_thinking_effort, --thinking-effort CLI flag, PATCH semantics and normalization, and startup logging of thinking effort.
Soul, approval, deliberation advisor
src/pythinker_code/soul/*, tools/ask_user/*
Adds thinking_effort surface on Soul, auto_deliberate policy, deliberation gate that one-shot-bounces destructive actions, and a blind advisor helper used by AskUserQuestion.
Shell UI, prompt, theme, keymap
src/pythinker_code/ui/shell/*, ui/theme.py
Prompt shows and cycles thinking levels (Shift+Tab), thinking-frame styles, shimmer traveling-waves implementation, separators/rules, tips, and keymap changes.
Shimmer implementation and shimmer spec
src/pythinker_code/ui/shell/motion.py, docs/superpowers/specs/*
Implements four-phase traveling-wave + center-out splash shimmer, helper generators, verb_spinner_style(), and TDD spec for shimmer behavior.
Recap and live visualization
src/pythinker_code/session_recap.py, ui/shell/visualize/*
Outcome-based recap extraction, light-day formatting, files-changed tracking, seam/blank-row handling, and related UI adjustments.
Auth and model capabilities
src/pythinker_code/auth/*
Applies login-time thinking defaults, records capabilities for MiniMax/OpenCode Go models, and uses capabilities to determine native thinking availability.
Tests and docs
tests/**/*, docs/*, CHANGELOG.md
Extensive unit/integration tests covering thinking levels, provider mappings, shimmer animation properties, approval/deliberation flows, UI rendering, and API round-trips; adds shimmer design spec and changelog entry.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CLI
  participant ACPServer
  participant LLMFactory
  participant Provider
  participant Soul
  participant Approval
  User->>CLI: start / create_llm(..., thinking_effort)
  CLI->>ACPServer: set_session_model / create request
  ACPServer->>LLMFactory: create_llm(model_id, thinking_effort)
  LLMFactory->>Provider: with_thinking(effort) / extra_body
  Provider-->>LLMFactory: provider kwargs
  LLMFactory-->>ACPServer: LLM instance (thinking, thinking_effort)
  User->>Soul: run tool (possibly destructive)
  Soul->>Approval: request(tool_call)
  Approval->>Approval: deliberation_gate(tool_call) -> maybe bounce
  Approval-->>Soul: ApprovalResult (deliberation or approved)
  Soul->>User: run or bounce with deliberation note
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested labels

enhancement

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pr/auto-mode-deliberation-clean

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pythinker_code/ui/shell/visualize/_blocks.py`:
- Around line 163-165: The helper _starts_with_report_fence currently checks two
prefixes with two startswith calls; simplify and optimize by replacing the OR
chain with a single tuple-based startswith call on the local variable stripped
(i.e., use stripped.startswith(("```report", "~~~report"))), preserving the
existing lstrip().casefold() logic and return behavior.

In `@tests/ui_and_conv/test_streaming_content_block.py`:
- Around line 338-353: Remove the monkeypatch of the module-global console
(monkeypatch.setattr(blocks_module, "console", output_console)) and drive
rendering through the public render path instead: keep creating a local
Console() (output_console) and call output_console.print(block.compose_final())
without altering blocks_module.console; then relax the assertion to check for
the preserved blank line and the report title via a public-visible substring or
regex (e.g. assert "\n\n" and "Deep Code Scan Results" or assert "\n\n  Deep
Code Scan Results" in output) instead of asserting the exact box-drawing prefix;
references: test_report_fence_continuation_keeps_gap_after_streamed_prose,
blocks_module, _ContentBlock, compose_final, and output_console.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c56a48e8-dfd5-4904-8ecc-01bbb428d7fe

📥 Commits

Reviewing files that changed from the base of the PR and between ccdcb0d and e968a78.

📒 Files selected for processing (89)
  • docs/superpowers/specs/2026-06-01-shimmer-traveling-waves-design.md
  • packages/pythinker-core/src/pythinker_core/chat_provider/__init__.py
  • packages/pythinker-core/src/pythinker_core/chat_provider/openai_common.py
  • packages/pythinker-core/src/pythinker_core/chat_provider/pythinker.py
  • packages/pythinker-core/src/pythinker_core/contrib/chat_provider/anthropic.py
  • packages/pythinker-core/src/pythinker_core/contrib/chat_provider/google_genai.py
  • packages/pythinker-core/tests/api_snapshot_tests/test_pythinker.py
  • packages/pythinker-core/tests/test_anthropic_thinking.py
  • packages/pythinker-core/tests/test_openai_common.py
  • src/pythinker_code/acp/server.py
  • src/pythinker_code/app.py
  • src/pythinker_code/auth/anthropic_direct.py
  • src/pythinker_code/auth/browser_login_page.py
  • src/pythinker_code/auth/deepseek.py
  • src/pythinker_code/auth/minimax.py
  • src/pythinker_code/auth/oauth.py
  • src/pythinker_code/auth/openai.py
  • src/pythinker_code/auth/opencode_go.py
  • src/pythinker_code/auth/openrouter.py
  • src/pythinker_code/cli/__init__.py
  • src/pythinker_code/cli/review.py
  • src/pythinker_code/config.py
  • src/pythinker_code/llm.py
  • src/pythinker_code/session_recap.py
  • src/pythinker_code/soul/__init__.py
  • src/pythinker_code/soul/agent.py
  • src/pythinker_code/soul/approval.py
  • src/pythinker_code/soul/deliberation.py
  • src/pythinker_code/soul/dynamic_injections/auto_mode.py
  • src/pythinker_code/soul/permission.py
  • src/pythinker_code/soul/pythinkersoul.py
  • src/pythinker_code/subagents/builder.py
  • src/pythinker_code/subagents/models.py
  • src/pythinker_code/subagents/runner.py
  • src/pythinker_code/subagents/store.py
  • src/pythinker_code/thinking.py
  • src/pythinker_code/tools/agent/__init__.py
  • src/pythinker_code/tools/ask_user/__init__.py
  • src/pythinker_code/ui/shell/__init__.py
  • src/pythinker_code/ui/shell/components/report.py
  • src/pythinker_code/ui/shell/keymap.py
  • src/pythinker_code/ui/shell/motion.py
  • src/pythinker_code/ui/shell/oauth.py
  • src/pythinker_code/ui/shell/prompt.py
  • src/pythinker_code/ui/shell/selectors/settings.py
  • src/pythinker_code/ui/shell/selectors/thinking.py
  • src/pythinker_code/ui/shell/setup.py
  • src/pythinker_code/ui/shell/slash.py
  • src/pythinker_code/ui/shell/spacing.py
  • src/pythinker_code/ui/shell/tips.py
  • src/pythinker_code/ui/shell/tool_renderers/ask_user.py
  • src/pythinker_code/ui/shell/visualize/_blocks.py
  • src/pythinker_code/ui/shell/visualize/_interactive.py
  • src/pythinker_code/ui/shell/visualize/_live_view.py
  • src/pythinker_code/ui/shell/visualize/_worklog.py
  • src/pythinker_code/ui/theme.py
  • src/pythinker_code/web/api/config.py
  • tests/auth/test_minimax_auth.py
  • tests/auth/test_openai_auth.py
  • tests/auth/test_opencode_go_auth.py
  • tests/conftest.py
  • tests/core/test_acp_thinking_effort.py
  • tests/core/test_approval_auto.py
  • tests/core/test_auto_injection.py
  • tests/core/test_config.py
  • tests/core/test_create_llm.py
  • tests/core/test_deliberation_advisor.py
  • tests/core/test_subagent_builder.py
  • tests/core/test_thinking.py
  • tests/test_session_recap.py
  • tests/tools/test_ask_user.py
  • tests/ui_and_conv/test_empty_think_part_indicator.py
  • tests/ui_and_conv/test_keymap_thinking.py
  • tests/ui_and_conv/test_live_view_notifications.py
  • tests/ui_and_conv/test_live_view_todos.py
  • tests/ui_and_conv/test_openai_shell_login.py
  • tests/ui_and_conv/test_plan_display_panel.py
  • tests/ui_and_conv/test_prompt_tips.py
  • tests/ui_and_conv/test_report.py
  • tests/ui_and_conv/test_report_fence_nesting.py
  • tests/ui_and_conv/test_settings_selector.py
  • tests/ui_and_conv/test_shell_design_system.py
  • tests/ui_and_conv/test_shell_motion.py
  • tests/ui_and_conv/test_shell_motion_shimmer.py
  • tests/ui_and_conv/test_streaming_content_block.py
  • tests/ui_and_conv/test_thinking_cycle.py
  • tests/ui_and_conv/test_tui_card_tool_renderers.py
  • tests/ui_and_conv/test_visualize_running_prompt.py
  • tests/web/test_config_api_thinking.py

Comment thread src/pythinker_code/ui/shell/visualize/_blocks.py Outdated
Comment thread tests/ui_and_conv/test_streaming_content_block.py Outdated
@elkaix elkaix changed the title Add thinking effort controls and auto-mode deliberation feat(shell): add thinking effort controls and auto-mode deliberation Jun 2, 2026
@elkaix
elkaix merged commit 1dd9ed2 into main Jun 2, 2026
29 checks passed
@elkaix
elkaix deleted the pr/auto-mode-deliberation-clean branch June 2, 2026 02:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant