Skip to content

Run screen

PhaseRow

PhaseRow(phase: Phase)

Bases: Static


              flowchart TD
              src.tradingagents.interface.tui.run_screen.PhaseRow[PhaseRow]

              

              click src.tradingagents.interface.tui.run_screen.PhaseRow href "" "src.tradingagents.interface.tui.run_screen.PhaseRow"
            

One row in the phase sidebar.

Rendered as a compact icon | label | progress line whose CSS class encodes the current status (-pending / -running / -done) so :file:styles.tcss can colour them appropriately.

Parameters:

Name Type Description Default

phase

Phase

Initial phase data; the widget id is taken from phase.id so later updates can target it via query_one.

required

Methods:

Name Description
render

Compose the row content as a Rich Text line.

update_phase

Replace the row's contents and CSS class with phase.

Source code in src/tradingagents/interface/tui/run_screen.py
def __init__(self, phase: Phase) -> None:
    """Create a row matching ``phase``.

    Args:
        phase (Phase): Initial phase data; the widget id is taken
            from ``phase.id`` so later updates can target it via
            ``query_one``.
    """
    super().__init__(id=phase.id, classes=f"phase-row -{phase.status}")
    self._phase = phase

render

render() -> Text

Compose the row content as a Rich Text line.

Returns:

Name Type Description
Text Text

An icon, the phase label, and an optional progress

Text

counter, separated by a space.

Source code in src/tradingagents/interface/tui/run_screen.py
def render(self) -> Text:
    """Compose the row content as a Rich Text line.

    Returns:
        Text: An icon, the phase label, and an optional progress
        counter, separated by a space.
    """
    icon = _PHASE_ICONS.get(self._phase.status, "?")
    suffix = f"  {self._phase.progress}" if self._phase.progress else ""
    return Text.from_markup(f"{icon}  {self._phase.label}{suffix}")

update_phase

update_phase(phase: Phase) -> None

Replace the row's contents and CSS class with phase.

Parameters:

Name Type Description Default

phase

Phase

The new phase data; only fields whose values differ from the previous render trigger a refresh.

required
Source code in src/tradingagents/interface/tui/run_screen.py
def update_phase(self, phase: Phase) -> None:
    """Replace the row's contents and CSS class with ``phase``.

    Args:
        phase (Phase): The new phase data; only fields whose values
            differ from the previous render trigger a refresh.
    """
    if phase == self._phase:
        return
    self._phase = phase
    self.remove_class("-pending", "-running", "-done")
    self.add_class(f"-{phase.status}")
    self.refresh()

RunScreen

RunScreen(params: SetupParams)

Bases: Screen[None]


              flowchart TD
              src.tradingagents.interface.tui.run_screen.RunScreen[RunScreen]

              

              click src.tradingagents.interface.tui.run_screen.RunScreen href "" "src.tradingagents.interface.tui.run_screen.RunScreen"
            

Drive a single :meth:TradingAgentsGraph.propagate run.

The screen composes the static layout up-front, then kicks off a worker thread on mount. The worker streams panel renderables back via :meth:App.call_from_thread, which is the only thread-safe way to mutate Textual widgets from outside the event loop.

Parameters:

Name Type Description Default

params

SetupParams

The validated parameter bundle from :class:SetupScreen.

required

Methods:

Name Description
compose

Build the screen layout.

on_mount

Cache widget references and kick off the pipeline worker.

action_quit_screen

Exit the app, returning the final decision (or None) to run_tui.

run_pipeline

Run :meth:TradingAgentsGraph.propagate on a worker thread.

Source code in src/tradingagents/interface/tui/run_screen.py
def __init__(self, params: SetupParams) -> None:
    """Store the run parameters; widgets are built in :meth:`compose`.

    Args:
        params (SetupParams): The validated parameter bundle from
            :class:`SetupScreen`.
    """
    super().__init__()
    self.params = params
    self._log: RichLog | None = None
    self._status: Static | None = None
    self._final_decision: str | None = None
    self._config = TradingAgentsConfig(
        llm_provider=params.llm_provider,
        deep_think_llm=params.deep_think_llm,
        quick_think_llm=params.quick_think_llm,
        max_debate_rounds=params.max_debate_rounds,
        max_risk_discuss_rounds=params.max_risk_discuss_rounds,
        max_recur_limit=params.max_recur_limit,
        reasoning_effort=params.reasoning_effort,
        response_language=params.response_language,
    )

BINDINGS

BINDINGS: list[Binding] = [
    Binding("q", "quit_screen", "Quit"),
    Binding("ctrl+c", "quit_screen", "Quit"),
]

params

params = params

compose

compose() -> ComposeResult

Build the screen layout.

Yields:

Name Type Description
ComposeResult ComposeResult

Header panel, sidebar with one

ComposeResult

class:PhaseRow per pipeline phase, the messages

ComposeResult

class:RichLog, and a status footer.

Source code in src/tradingagents/interface/tui/run_screen.py
def compose(self) -> ComposeResult:
    """Build the screen layout.

    Yields:
        ComposeResult: Header panel, sidebar with one
        :class:`PhaseRow` per pipeline phase, the messages
        :class:`RichLog`, and a status footer.
    """
    yield Static(
        make_run_header_panel(
            ticker=self.params.ticker, trade_date=self.params.date, config=self._config
        ),
        id="run-header",
    )
    with Horizontal(id="run-body"):
        with Vertical(id="phase-sidebar"):
            yield Static("Phases", id="phase-sidebar-title")
            for phase in self._initial_phases():
                yield PhaseRow(phase)
        yield RichLog(
            id="messages", wrap=True, markup=False, highlight=False, auto_scroll=True
        )
    yield Static("Initialising...", id="run-status")

on_mount

on_mount() -> None

Cache widget references and kick off the pipeline worker.

Source code in src/tradingagents/interface/tui/run_screen.py
def on_mount(self) -> None:
    """Cache widget references and kick off the pipeline worker."""
    self._log = self.query_one("#messages", RichLog)
    self._status = self.query_one("#run-status", Static)
    self.run_pipeline()

action_quit_screen

action_quit_screen() -> None

Exit the app, returning the final decision (or None) to run_tui.

Source code in src/tradingagents/interface/tui/run_screen.py
def action_quit_screen(self) -> None:
    """Exit the app, returning the final decision (or None) to ``run_tui``."""
    self.app.exit(self._final_decision)

run_pipeline

run_pipeline() -> None

Run :meth:TradingAgentsGraph.propagate on a worker thread.

Constructs a :class:MessageRenderer whose emit defers each Rich renderable to the Textual event loop, and an on_state hook that recomputes the sidebar phase list from the latest :class:AgentState snapshot. All UI mutations are routed through :meth:App.call_from_thread via :meth:_safe_call so the worker unwinds quietly when the user quits mid-run; a broken hook can never abort a paid LLM call once it has started.

Source code in src/tradingagents/interface/tui/run_screen.py
@work(thread=True, exclusive=True)
def run_pipeline(self) -> None:
    """Run :meth:`TradingAgentsGraph.propagate` on a worker thread.

    Constructs a :class:`MessageRenderer` whose ``emit`` defers each
    Rich renderable to the Textual event loop, and an ``on_state``
    hook that recomputes the sidebar phase list from the latest
    :class:`AgentState` snapshot. All UI mutations are routed
    through :meth:`App.call_from_thread` via :meth:`_safe_call` so
    the worker unwinds quietly when the user quits mid-run; a
    broken hook can never abort a paid LLM call once it has
    started.
    """
    log = self._log
    if log is None:
        raise RuntimeError("run_pipeline invoked before on_mount cached the RichLog")

    def emit(renderable: object) -> None:
        self._safe_call(log.write, renderable)

    renderer = MessageRenderer(emit=emit)

    def on_state(state: AgentState) -> None:
        self._safe_call(self._update_phases_from_state, state)

    self._safe_call(self._set_status, "Running pipeline...")

    try:
        ta = TradingAgentsGraph(
            debug=self.params.debug,
            config=self._config,
            selected_analysts=self.params.selected_analysts,
        )
        _, decision = ta.propagate(
            self.params.ticker, self.params.date, on_message=renderer, on_state=on_state
        )
    except Exception as exc:
        logger.exception("TUI pipeline run failed")
        self._safe_call(self._on_error, exc)
        return

    self._safe_call(self._on_done, decision)