fix(cli): clear flow header's current method when a method ends

Review follow-up: the flow header keys off _current_method, which was set on
MethodExecutionStarted but never cleared on Finished/Failed. Between steps (or
after a failed method before kickoff exits) the header kept spinning the old
method name while the STEPS sidebar already showed it done/failed.

_clear_current_method now drops the header's active method when it ends,
falling back to another still-active step (methods can overlap) or none. The
header's idle fallback shows "Working…" once a step has run and "Starting
flow…" only before the first method.

Tests: test_current_method_clears_and_falls_back_across_overlap, plus a
_current_method assertion in test_flow_method_events_build_steps.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh
This commit is contained in:
Joao Moura
2026-07-08 07:47:07 -07:00
parent 6b7529f2d9
commit ec55c31fed
2 changed files with 55 additions and 1 deletions

View File

@@ -1550,6 +1550,40 @@ def test_flow_method_events_build_steps() -> None:
{"name": "research", "call_type": "crew", "status": "done"},
{"name": "summarize", "call_type": "agent", "status": "failed"},
]
# The header must not keep spinning a method that already ended.
assert app._current_method is None
def test_current_method_clears_and_falls_back_across_overlap() -> None:
app = CrewRunApp(crew_name="Demo")
app._flow = SimpleNamespace()
app._subscribe()
try:
_emit_event(
MethodExecutionStartedEvent(flow_name="Demo", method_name="a", state={})
)
_emit_event(
MethodExecutionStartedEvent(flow_name="Demo", method_name="b", state={})
)
assert app._current_method == "b"
# 'a' finishes while 'b' is still active → header stays on 'b'.
_emit_event(
MethodExecutionFinishedEvent(
flow_name="Demo", method_name="a", result=None, state={}
)
)
assert app._current_method == "b"
# 'b' finishes → nothing active left → header clears.
_emit_event(
MethodExecutionFinishedEvent(
flow_name="Demo", method_name="b", result=None, state={}
)
)
assert app._current_method is None
finally:
app._unsubscribe()
@pytest.mark.asyncio