feat(shell): add thinking effort controls and auto-mode deliberation - #50
Conversation
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.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughAdds 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. ChangesUnified Thinking Effort, Shimmer, and Auto-Deliberation
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
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested labels
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
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
📒 Files selected for processing (89)
docs/superpowers/specs/2026-06-01-shimmer-traveling-waves-design.mdpackages/pythinker-core/src/pythinker_core/chat_provider/__init__.pypackages/pythinker-core/src/pythinker_core/chat_provider/openai_common.pypackages/pythinker-core/src/pythinker_core/chat_provider/pythinker.pypackages/pythinker-core/src/pythinker_core/contrib/chat_provider/anthropic.pypackages/pythinker-core/src/pythinker_core/contrib/chat_provider/google_genai.pypackages/pythinker-core/tests/api_snapshot_tests/test_pythinker.pypackages/pythinker-core/tests/test_anthropic_thinking.pypackages/pythinker-core/tests/test_openai_common.pysrc/pythinker_code/acp/server.pysrc/pythinker_code/app.pysrc/pythinker_code/auth/anthropic_direct.pysrc/pythinker_code/auth/browser_login_page.pysrc/pythinker_code/auth/deepseek.pysrc/pythinker_code/auth/minimax.pysrc/pythinker_code/auth/oauth.pysrc/pythinker_code/auth/openai.pysrc/pythinker_code/auth/opencode_go.pysrc/pythinker_code/auth/openrouter.pysrc/pythinker_code/cli/__init__.pysrc/pythinker_code/cli/review.pysrc/pythinker_code/config.pysrc/pythinker_code/llm.pysrc/pythinker_code/session_recap.pysrc/pythinker_code/soul/__init__.pysrc/pythinker_code/soul/agent.pysrc/pythinker_code/soul/approval.pysrc/pythinker_code/soul/deliberation.pysrc/pythinker_code/soul/dynamic_injections/auto_mode.pysrc/pythinker_code/soul/permission.pysrc/pythinker_code/soul/pythinkersoul.pysrc/pythinker_code/subagents/builder.pysrc/pythinker_code/subagents/models.pysrc/pythinker_code/subagents/runner.pysrc/pythinker_code/subagents/store.pysrc/pythinker_code/thinking.pysrc/pythinker_code/tools/agent/__init__.pysrc/pythinker_code/tools/ask_user/__init__.pysrc/pythinker_code/ui/shell/__init__.pysrc/pythinker_code/ui/shell/components/report.pysrc/pythinker_code/ui/shell/keymap.pysrc/pythinker_code/ui/shell/motion.pysrc/pythinker_code/ui/shell/oauth.pysrc/pythinker_code/ui/shell/prompt.pysrc/pythinker_code/ui/shell/selectors/settings.pysrc/pythinker_code/ui/shell/selectors/thinking.pysrc/pythinker_code/ui/shell/setup.pysrc/pythinker_code/ui/shell/slash.pysrc/pythinker_code/ui/shell/spacing.pysrc/pythinker_code/ui/shell/tips.pysrc/pythinker_code/ui/shell/tool_renderers/ask_user.pysrc/pythinker_code/ui/shell/visualize/_blocks.pysrc/pythinker_code/ui/shell/visualize/_interactive.pysrc/pythinker_code/ui/shell/visualize/_live_view.pysrc/pythinker_code/ui/shell/visualize/_worklog.pysrc/pythinker_code/ui/theme.pysrc/pythinker_code/web/api/config.pytests/auth/test_minimax_auth.pytests/auth/test_openai_auth.pytests/auth/test_opencode_go_auth.pytests/conftest.pytests/core/test_acp_thinking_effort.pytests/core/test_approval_auto.pytests/core/test_auto_injection.pytests/core/test_config.pytests/core/test_create_llm.pytests/core/test_deliberation_advisor.pytests/core/test_subagent_builder.pytests/core/test_thinking.pytests/test_session_recap.pytests/tools/test_ask_user.pytests/ui_and_conv/test_empty_think_part_indicator.pytests/ui_and_conv/test_keymap_thinking.pytests/ui_and_conv/test_live_view_notifications.pytests/ui_and_conv/test_live_view_todos.pytests/ui_and_conv/test_openai_shell_login.pytests/ui_and_conv/test_plan_display_panel.pytests/ui_and_conv/test_prompt_tips.pytests/ui_and_conv/test_report.pytests/ui_and_conv/test_report_fence_nesting.pytests/ui_and_conv/test_settings_selector.pytests/ui_and_conv/test_shell_design_system.pytests/ui_and_conv/test_shell_motion.pytests/ui_and_conv/test_shell_motion_shimmer.pytests/ui_and_conv/test_streaming_content_block.pytests/ui_and_conv/test_thinking_cycle.pytests/ui_and_conv/test_tui_card_tool_renderers.pytests/ui_and_conv/test_visualize_running_prompt.pytests/web/test_config_api_thinking.py
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:
Verification
CI is pending. I will monitor all checks, CodeRabbit, and PR comments and address root causes until the PR is green.
Checklist
make gen-changelogto update the changelog.make gen-docsto update the user documentation.Summary by CodeRabbit
New Features
UI/Visual Improvements
Documentation