Skip to content

fix(tui-v2): repair NameError on exit-boundary replay in _on_stream - #757

Open
Kailigithub wants to merge 1 commit into
lsdefine:mainfrom
Kailigithub:fix/issue-6594-tui-v2-stale-replay-nameerror
Open

fix(tui-v2): repair NameError on exit-boundary replay in _on_stream#757
Kailigithub wants to merge 1 commit into
lsdefine:mainfrom
Kailigithub:fix/issue-6594-tui-v2-stale-replay-nameerror

Conversation

@Kailigithub

Copy link
Copy Markdown
Contributor

Problem

frontends/tuiapp_v2.py:6594 references a local refresh_chrome that the surrounding function _on_stream never receives:

def _on_stream(self, agent_id, task_id, text, done):   # no `refresh_chrome`
    ...
    if s.current_task_id != task_id:
        ...
        if found and agent_id == self.current_id:
            ...
            if refresh_chrome:                            # NameError here
                self._refresh_sidebar()
                self._refresh_topbar()
            self._ensure_spinner()

The function only takes (agent_id, task_id, text, done); refresh_chrome is a parameter of _update_assistant and is not in scope here.

The branch fires whenever exit-boundary replay starts a follow-up task before the original display queue emits its final done — exactly the spinner-forever scenario the comment block warns about. The original if refresh_chrome: guard would always evaluate False (or NameError), so the sidebar/topbar refresh is silently lost in the replay path.

The regular done=True path a few lines below (line ~6603) calls _update_assistant(..., refresh_chrome=True), so the fix mirrors that.

Repro

The included test_issue_6594_tui_v2_stale_replay_nameerror.py exercises the replay path without needing a live Textual app:

$ python3 -m unittest -v test_issue_6594_tui_v2_stale_replay_nameerror
test_done_false_is_a_noop ... ok
test_replay_path_runs_without_name_error ... ok
Ran 2 tests in 1.286s
OK

The test fails on the parent commit with the exact NameError: name refresh_chrome is not defined and passes with this fix.

Verification

  • python3 -m ruff check frontends/tuiapp_v2.py --select E9,F63,F7,F82 is clean (8 prior F821 warnings reduced to 0; the 7 List-under-from __future__ import annotations F821s were false positives that pyflakes also flagged — fixed by adding List to the existing from typing import line so typing.get_type_hints on the affected @dataclass and helper functions resolves cleanly).
  • python3 -m compileall is clean across the whole repo.
  • git diff --check is clean.

Scope

One behaviour change: the replay branch now always refreshes the sidebar and topbar (matching the regular done path), instead of the if refresh_chrome: guard which always evaluated False or raised NameError.

The same fix incidentally resolves a closely-related F821 noise class in this file: from __future__ import annotations is in effect, so the 7 List[...] annotations are stored as strings and do not fail at runtime. @dataclass RenderRow, however, introspects annotations via typing.get_type_hints at class creation, and render_tree return annotation needs List to be in scope if any caller does the same. Adding the import is a 1-line change that matches the codebase other typing-aware modules.

Files

  • frontends/tuiapp_v2.py — 1 logic line + 1 import line (8 insertions, 4 deletions)
  • test_issue_6594_tui_v2_stale_replay_nameerror.py — new regression test (127 lines)

# Problem

The stale-replay branch in `_on_stream` (frontends/tuiapp_v2.py:6594)
referenced a local `refresh_chrome` that the function never receives:

  def _on_stream(self, agent_id, task_id, text, done):
      ...
      if s.current_task_id != task_id:
          ...
          if found and agent_id == self.current_id:
              if found._segment_widgets:
                  try: self._stream_update_assistant(found)
                  except Exception: self._refresh_messages()
              else:
                  self._refresh_messages()
              if refresh_chrome:                       # <-- NameError here
                  self._refresh_sidebar()
                  self._refresh_topbar()
              self._ensure_spinner()

The function only takes (agent_id, task_id, text, done); `refresh_chrome`
is a parameter of `_update_assistant` and is not in scope. The regular
`done=True` path a few lines below (line ~6603) calls
`_update_assistant(..., refresh_chrome=True)`, so the fix mirrors that.

# Repro

This branch fires whenever exit-boundary replay starts a follow-up task
before the original display queue emits its final `done` — i.e. the
spinner-forever scenario the comment block warns about. Reached via the
agent's exit-boundary replay path; the test in
`test_issue_6594_tui_v2_stale_replay_nameerror.py` reproduces it
without needing a live Textual app.

# Verification

- `python -m ruff check frontends/tuiapp_v2.py --select E9,F63,F7,F82`
  is clean (8 prior F821 warnings reduced to 0; the 7 `List`-under-future-
  annotations F821s were false positives that pyflakes also flagged — fixed
  by adding `List` to the existing `from typing import` line).
- The new test fails on the parent commit with the exact
  `NameError: name 'refresh_chrome' is not defined` and passes with this
  fix.
- `python -m compileall` is clean across the whole repo.

# Scope

One behaviour change: the replay branch now always refreshes the sidebar
and topbar (matching the regular done path), instead of the
`if refresh_chrome:` guard which always evaluated `False` *or* raised
NameError.
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