Skip to content

refactor(tui): prompt deep-module PR 2 — awaited lifecycle + state reducer - #219

Merged
elkaix merged 4 commits into
mainfrom
refactor/tui-prompt-deep-module-pr2
Jul 20, 2026
Merged

refactor(tui): prompt deep-module PR 2 — awaited lifecycle + state reducer#219
elkaix merged 4 commits into
mainfrom
refactor/tui-prompt-deep-module-pr2

Conversation

@elkaix

@elkaix elkaix commented Jul 20, 2026

Copy link
Copy Markdown
Member

PR 2 of the TUI prompt deep-module refactor plan, covering Tasks 4–5. Stacked on #218 (base is the PR 1 branch); review/merge after #218.

What

  • Task 4 — awaited lifecycle (bebee17d): new prompting/lifecycle.py (PromptLifecycle: owned tasks, reverse-order async closers, idempotent awaited aclose). CustomPromptSession gains async context management (__aenter__/__aexit__/aclose); Shell.run shuts the session down via async with. Replaces the private prompt_toolkit exception-filter hack with the public set_exception_handler=False option.
  • Task 5 — state reducer (6d842fb2): new prompting/state.py with a pure transition(state, event) -> PromptTransition over PromptState (mode, phase, running delegate, modal stack, suspended document, shortcut help). CustomPromptSession routes turn/delegate/modal/mode/shortcut/buffer mutations through one _dispatch that applies effects and invalidates once; the distributed flags become reducer-owned mirrors. PromptMode and RunningPromptDelegate move to the new module and are re-exported for compatibility.

Verification

  • make check-pythinker-code and make test-pythinker-code green (8265 + 65 passed).
  • Frozen behavior suites (test_visualize_running_prompt, test_prompt_tips, test_prompt_public_contract) pass unmodified.
  • New test_prompt_lifecycle.py (cancellation/reaping) and test_prompt_state.py (full transition table incl. idempotent stale events).
  • PTY layout + modal e2e suites pass locally (20 tests).

Changelog

Unreleased bullet added covering height budgets + awaited lifecycle.

Summary by CodeRabbit

  • Bug Fixes
    • Improved interactive prompt lifecycle so background tasks and related processes shut down reliably, including height-constrained prompt rendering.
    • Updated prompt input/visibility and modal handling for more consistent mode switching and shortcut behavior.
    • Ensured status-refresh and status-line runner start/stop are safe to call repeatedly without duplicating work.
  • Tests
    • Added async regression coverage for prompt lifecycle shutdown/cancellation behavior, reducer/state transitions, modal/suspension ordering, and status-line idempotency.

@coderabbitai

coderabbitai Bot commented Jul 20, 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

Run ID: a3c958bf-8793-4621-8f17-3a2c2ef6098a

📥 Commits

Reviewing files that changed from the base of the PR and between b8d8ec1 and 9738bc3.

📒 Files selected for processing (3)
  • src/pythinker_code/ui/shell/prompting/lifecycle.py
  • src/pythinker_code/ui/shell/prompting/state.py
  • tests/ui_and_conv/test_prompt_lifecycle.py

📝 Walkthrough

Walkthrough

The prompt session now uses immutable reducer state and a session-scoped async lifecycle. Modal visibility, mode changes, delegates, document suspension, task cancellation, and resource cleanup are centralized and covered by regression tests.

Changes

Interactive prompt lifecycle

Layer / File(s) Summary
Prompt state reducer
src/pythinker_code/ui/shell/prompting/state.py, tests/ui_and_conv/test_prompt_state.py
Prompt modes, phases, delegates, modals, events, effects, and document suspension are modeled through pure immutable transitions with invariant and ordering tests.
Session shutdown lifecycle
src/pythinker_code/ui/shell/prompting/lifecycle.py, src/pythinker_code/ui/shell/prompt.py, tests/ui_and_conv/test_prompt_lifecycle.py, tests/ui_and_conv/test_statusline.py
PromptLifecycle cancels and awaits owned tasks, runs closers in reverse order, and supports idempotent shutdown; session and statusline shutdown paths use it.
Reducer-backed prompt session
src/pythinker_code/ui/shell/prompt.py, src/pythinker_code/ui/shell/__init__.py, tests/ui_and_conv/test_shell_run_placeholders.py
CustomPromptSession dispatches prompt events, applies effects, toggles mode through Ctrl-X, observes buffer changes, and is used through an asynchronous context manager.
Prompt integration validation
tests/ui_and_conv/test_prompt_tips.py, tests/ui_and_conv/test_prompt_lifecycle.py, CHANGELOG.md
Prompt exception-handler tests are removed, async lifecycle and prompt configuration behavior are tested, and the unreleased changelog describes bounded prompt scenes and awaited cleanup.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested labels: enhancement

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 70.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows conventional commits and accurately summarizes the TUI prompt lifecycle and state-reducer refactor.
Description check ✅ Passed The description is detailed and covers the change, verification, and changelog, so it is mostly aligned with the template.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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 refactor/tui-prompt-deep-module-pr2

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.94139% with 22 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/pythinker_code/ui/shell/prompt.py 83.52% 11 Missing and 3 partials ⚠️
src/pythinker_code/ui/shell/prompting/lifecycle.py 84.44% 4 Missing and 3 partials ⚠️
src/pythinker_code/ui/shell/prompting/state.py 99.30% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

elkaix added 3 commits July 20, 2026 13:25
Add prompting/lifecycle.py (PromptLifecycle: owned tasks, reverse-order
async closers, idempotent awaited aclose) and async context management
on CustomPromptSession; Shell.run now shuts the session down via
async with. Replace the private prompt_toolkit exception-filter hack
with the public set_exception_handler=False option.
Add prompting/state.py with a pure transition(state, event) reducer over
PromptState/PromptTransition (mode, phase, running delegate, modal stack,
suspended document, shortcut help). CustomPromptSession routes turn,
delegate, modal, mode, shortcut, and buffer mutations through one
_dispatch that applies effects and invalidates once; the distributed
flags become reducer-owned mirrors. PromptMode and RunningPromptDelegate
move to the new module and are re-exported for compatibility.
@elkaix
elkaix force-pushed the refactor/tui-prompt-deep-module-pr2 branch from 6d842fb to b8d8ec1 Compare July 20, 2026 17:50
@elkaix
elkaix changed the base branch from refactor/tui-prompt-deep-module-pr1 to main July 20, 2026 17:51
@elkaix elkaix closed this Jul 20, 2026
@elkaix elkaix reopened this Jul 20, 2026
@elkaix

elkaix commented Jul 20, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@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: 3

🤖 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/prompting/lifecycle.py`:
- Around line 59-69: Update the CancelledError handler in aclose so cancellation
escaping a closer is logged and re-raised instead of continuing to the next
resource. Preserve the existing warning handling for ordinary exceptions and
allow individual closers to manage their own internal cancellations.

In `@src/pythinker_code/ui/shell/prompting/state.py`:
- Around line 225-273: Extract the duplicated suspend/restore transition logic
from the ModalAttached and ModalDetached branches into a shared helper, such as
_suspend_restore_effects, accepting the old/new active modal states, suspended
document, and current document and returning the updated suspended document plus
effects. Replace both inline computations with calls to the helper, preserving
each branch’s existing stack construction and state updates.

In `@tests/ui_and_conv/test_prompt_state.py`:
- Around line 372-398: Refactor
test_session_dispatch_keeps_reducer_modal_snapshot_authoritative to construct
CustomPromptSession through its public setup path, using attach_modal() and
related session APIs instead of object.__new__ and direct assignments to private
attributes. Preserve the test’s assertions about the modal snapshot, suspended
document, visibility_queries, and invalidations, and configure the fixture so
attach_modal() produces the same modal_stack.
🪄 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

Run ID: dd5495d1-f4a0-40d4-9aee-c91eff557128

📥 Commits

Reviewing files that changed from the base of the PR and between 2c7a94c and b8d8ec1.

📒 Files selected for processing (10)
  • CHANGELOG.md
  • src/pythinker_code/ui/shell/__init__.py
  • src/pythinker_code/ui/shell/prompt.py
  • src/pythinker_code/ui/shell/prompting/lifecycle.py
  • src/pythinker_code/ui/shell/prompting/state.py
  • tests/ui_and_conv/test_prompt_lifecycle.py
  • tests/ui_and_conv/test_prompt_state.py
  • tests/ui_and_conv/test_prompt_tips.py
  • tests/ui_and_conv/test_shell_run_placeholders.py
  • tests/ui_and_conv/test_statusline.py
💤 Files with no reviewable changes (1)
  • tests/ui_and_conv/test_prompt_tips.py

Comment thread src/pythinker_code/ui/shell/prompting/lifecycle.py
Comment thread src/pythinker_code/ui/shell/prompting/state.py
Comment thread tests/ui_and_conv/test_prompt_state.py
Address CodeRabbit review on #219:
- PromptLifecycle.aclose no longer swallows CancelledError of aclose()
  itself: a wait_for-timed-out shutdown now propagates cancellation
  instead of continuing to close remaining resources past the deadline.
  Individual closers still own their internal cancellation.
- Extract the duplicated modal suspend/restore transition shared by
  ModalAttached/ModalDetached into _suspend_restore_effects (behavior
  preserving).
Comment thread src/pythinker_code/ui/shell/prompting/state.py
Comment thread src/pythinker_code/ui/shell/prompting/state.py
Comment thread src/pythinker_code/ui/shell/prompting/state.py
Comment thread src/pythinker_code/ui/shell/prompting/state.py
Comment thread src/pythinker_code/ui/shell/prompting/state.py
Comment thread src/pythinker_code/ui/shell/prompting/state.py
Comment thread src/pythinker_code/ui/shell/prompting/state.py
@elkaix
elkaix merged commit 30f7b17 into main Jul 20, 2026
59 checks passed
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