Skip to content

trading_agent.terminal.widgets.side_panel

The right-hand panel of the chat: eight cards about the desk, as on the web page.

The panel reads the gateway on the web page's timings: the context window every 20 seconds and after a turn, a compression, a new session or a model switch; the account and the desks' open orders every 15 seconds and after an order, a fill, a halt or the kill switch; the MCP servers every minute. The counts of orders and the outputs come from the desk's events of today, which the chat screen passes on. Which cards are folded is remembered between runs.

Typical usage example:

panel = SidePanel(gateway, settings, opener) panel.set_desk('general') panel.take_events(events)

SidePanel

SidePanel(gateway, settings, opener)

Bases: VerticalScroll

The side panel.

Creates the panel and its cards.

Parameters:

Name Type Description Default
gateway GatewayClient

The gateway's routes.

required
settings TerminalSettings

The remembered choices, holding the folded cards.

required
opener AttachmentOpener

Downloads and opens the desk's files.

required
Source code in src/trading_agent/terminal/widgets/side_panel.py
def __init__(
    self,
    gateway: gateway_client.GatewayClient,
    settings: terminal_settings.TerminalSettings,
    opener: attachment_opener.AttachmentOpener,
):
    """Creates the panel and its cards.

    Args:
        gateway (gateway_client.GatewayClient): The gateway's routes.
        settings (terminal_settings.TerminalSettings): The remembered choices, holding the folded cards.
        opener (attachment_opener.AttachmentOpener): Downloads and opens the desk's files.
    """
    super().__init__(id='side-panel')
    self._gateway = gateway
    self._settings = settings
    folded = set(settings.collapsed_cards)
    self._desk_card = desk_card.DeskCard('desk' in folded)
    self._model_card = model_card.ModelCard('model' in folded)
    self._context_card = context_card.ContextCard('context' in folded)
    self._funds_card = funds_card.FundsCard('funds' in folded)
    self._profit_card = profit_card.ProfitCard('pnl' in folded)
    self._orders_card = orders_card.OrdersCard('orders' in folded)
    self._tools_card = tools_card.ToolsCard('tools' in folded)
    self._outputs_card = outputs_card.OutputsCard(
        opener, 'outputs' in folded
    )
    self._desk_name = ''
    self._mode = ''
    self._desk: dict[str, Any] | None = None
    self._events: list[dict[str, Any]] = []
    self._context_document: dict[str, Any] | None = None
    self._account: dict[str, Any] | None = None
    self._desk_orders: dict[str, Any] | None = None
    self._servers: list[dict[str, Any]] | None = None

compose

compose()

Builds the panel.

Yields:

Type Description
Widget

The eight cards.

Source code in src/trading_agent/terminal/widgets/side_panel.py
def compose(self):
    """Builds the panel.

    Yields:
        Widget: The eight cards.
    """
    yield self._desk_card
    yield self._model_card
    yield self._context_card
    yield self._funds_card
    yield self._profit_card
    yield self._orders_card
    yield self._tools_card
    yield self._outputs_card

on_mount

on_mount()

Starts the timers that read the gateway.

Source code in src/trading_agent/terminal/widgets/side_panel.py
def on_mount(self) -> None:
    """Starts the timers that read the gateway."""
    self.set_interval(_CONTEXT_REFRESH_SECONDS, self.refresh_context)
    self.set_interval(_ACCOUNT_REFRESH_SECONDS, self.refresh_account)
    self.set_interval(_SERVERS_REFRESH_SECONDS, self.refresh_servers)
    self.refresh_account()
    self.refresh_servers()

set_desk

set_desk(desk_name)

Shows another desk, forgetting the previous desk's events.

Parameters:

Name Type Description Default
desk_name str

The desk.

required
Source code in src/trading_agent/terminal/widgets/side_panel.py
def set_desk(self, desk_name: str) -> None:
    """Shows another desk, forgetting the previous desk's events.

    Args:
        desk_name (str): The desk.
    """
    self._desk_name = desk_name
    self._events = []
    self._context_document = None
    self._show_all()
    self.refresh_context()

take_events

take_events(events)

Takes the desk's new events and reads the gateway again when they change something.

Parameters:

Name Type Description Default
events list[dict[str, Any]]

The events, oldest first.

required
Source code in src/trading_agent/terminal/widgets/side_panel.py
def take_events(self, events: list[dict[str, Any]]) -> None:
    """Takes the desk's new events and reads the gateway again when they change something.

    Args:
        events (list[dict[str, Any]]): The events, oldest first.
    """
    context_changed = False
    account_changed = False
    for event in events:
        kind = event.get('kind')
        if kind == 'text_delta':
            continue
        self._events.append(event)
        if kind in _CONTEXT_CHANGING_KINDS:
            context_changed = True
        if kind in _ACCOUNT_CHANGING_KINDS:
            account_changed = True
    if context_changed:
        self.refresh_context()
    if account_changed:
        self.refresh_account()
    self._show_events()

take_desk

take_desk(desk, mode)

Shows the desk's state and models.

Parameters:

Name Type Description Default
desk dict[str, Any] | None

The desk summary, or None while loading.

required
mode str

"dry_run" or "live".

required
Source code in src/trading_agent/terminal/widgets/side_panel.py
def take_desk(self, desk: dict[str, Any] | None, mode: str) -> None:
    """Shows the desk's state and models.

    Args:
        desk (dict[str, Any] | None): The desk summary, or None while loading.
        mode (str): "dry_run" or "live".
    """
    self._desk = desk
    self._mode = mode
    self._desk_card.show(desk, mode)
    self._show_model()

on_collapsible_collapsed

on_collapsible_collapsed(event)

Remembers that a card was folded.

Parameters:

Name Type Description Default
event Collapsed

The fold.

required
Source code in src/trading_agent/terminal/widgets/side_panel.py
def on_collapsible_collapsed(
    self, event: widgets.Collapsible.Collapsed
) -> None:
    """Remembers that a card was folded.

    Args:
        event (widgets.Collapsible.Collapsed): The fold.
    """
    self._remember(event.collapsible, True)

on_collapsible_expanded

on_collapsible_expanded(event)

Remembers that a card was opened.

Parameters:

Name Type Description Default
event Expanded

The opening.

required
Source code in src/trading_agent/terminal/widgets/side_panel.py
def on_collapsible_expanded(
    self, event: widgets.Collapsible.Expanded
) -> None:
    """Remembers that a card was opened.

    Args:
        event (widgets.Collapsible.Expanded): The opening.
    """
    self._remember(event.collapsible, False)

refresh_context async

refresh_context()

Reads the desk's context window and tools.

Source code in src/trading_agent/terminal/widgets/side_panel.py
@work(exclusive=True, group='side-context')
async def refresh_context(self) -> None:
    """Reads the desk's context window and tools."""
    if not self._desk_name:
        return
    desk_name = self._desk_name
    try:
        document = await self._gateway.desk_context(desk_name)
    except gateway_client.GatewayError as error:
        self._context_card.show(None, error.message)
        return
    if desk_name != self._desk_name:
        return
    self._context_document = document
    self._context_card.show(document.get('usage'), None)
    self._show_model()
    self._show_tools()

refresh_account async

refresh_account()

Reads the account and the desks' open orders.

Source code in src/trading_agent/terminal/widgets/side_panel.py
@work(exclusive=True, group='side-account')
async def refresh_account(self) -> None:
    """Reads the account and the desks' open orders."""
    try:
        self._account = await self._gateway.account()
    except gateway_client.GatewayError as error:
        self._funds_card.show(None, error.message)
        return
    try:
        self._desk_orders = await self._gateway.desk_orders()
    except gateway_client.GatewayError:
        self._desk_orders = None
    self._funds_card.show(self._account, None)
    self._profit_card.show(self._desk_name, self._account)
    self._show_events()

refresh_servers async

refresh_servers()

Reads the MCP servers.

Source code in src/trading_agent/terminal/widgets/side_panel.py
@work(exclusive=True, group='side-servers')
async def refresh_servers(self) -> None:
    """Reads the MCP servers."""
    try:
        answer = await self._gateway.mcp_servers()
    except gateway_client.GatewayError:
        return
    self._servers = answer.get('servers') or []
    self._show_tools()