Skip to content

trading_agent.runtime.slash_commands

Commands a user types to a desk, such as /status, answered by code with no model.

Typical usage example:

commands = SlashCommands(desk, 'dry_run') reply = await commands.handle('/status')

CommandHelp dataclass

CommandHelp(usage, description)

One line of /help: how a command is typed and what it does.

Attributes:

Name Type Description
usage str

How the command is typed, such as "/think ".

description str

What it does.

name

name()

The command word, such as "/think".

Returns:

Type Description
str

The first word of the usage.

Source code in src/trading_agent/runtime/slash_commands.py
def name(self) -> str:
    """The command word, such as "/think".

    Returns:
        str: The first word of the usage.
    """
    return self.usage.split()[0]

line

line()

The line /help prints for this command.

Returns:

Type Description
str

The usage padded to 20 characters, a space, then the description.

Source code in src/trading_agent/runtime/slash_commands.py
def line(self) -> str:
    """The line /help prints for this command.

    Returns:
        str: The usage padded to 20 characters, a space, then the description.
    """
    return f'{self.usage:<20} {self.description}'

CommandParts dataclass

CommandParts(tool_registry=None, subagent_library=None, journal_reader=None, subagent_runner=None)

The parts of the gateway some commands read, beyond the desk itself.

Attributes:

Name Type Description
tool_registry ToolRegistry | None

The desk's tools, listed by /tools, or None.

subagent_library SubagentLibrary | None

The subagents the desk can delegate to, listed by /subagents, or None.

journal_reader JournalReader | None

The desk's journal, read by /subagents and /review, or None.

subagent_runner SubagentRunner | None

Runs the trade reviewer for /review, or None.

SlashCommands

SlashCommands(desk, mode, skill_library=None, parts=None)

The commands of one desk.

Creates the commands for a desk.

Parameters:

Name Type Description Default
desk DeskRuntime

The desk the commands act on.

required
mode str

"dry_run" or "live", reported by /status.

required
skill_library SkillLibrary | None

The desk's skills, each of which can be invoked as /, or None.

None
parts CommandParts | None

The tools, subagents and journal some commands read, or None when none are available.

None
Source code in src/trading_agent/runtime/slash_commands.py
def __init__(
    self,
    desk: desk_runtime.DeskRuntime,
    mode: str,
    skill_library: skill_library_module.SkillLibrary | None = None,
    parts: CommandParts | None = None,
):
    """Creates the commands for a desk.

    Args:
        desk (desk_runtime.DeskRuntime): The desk the commands act on.
        mode (str): "dry_run" or "live", reported by /status.
        skill_library (skill_library_module.SkillLibrary | None): The desk's skills, each of which can be invoked as /<skill-name>, or None.
        parts (CommandParts | None): The tools, subagents and journal some commands read, or None when none are available.
    """
    self._desk = desk
    self._mode = mode
    self._skill_library = skill_library
    self._parts = parts or CommandParts()
    self._background_command: str | None = None
    self._commands: dict[str, Callable[[str], Awaitable[str]]] = {
        '/help': self._help,
        '/status': self._status,
        '/new': self._new,
        '/compact': self._compact,
        '/rollover': self._rollover,
        '/usage': self._usage,
        '/model': self._model,
        '/pause': self._pause,
        '/resume': self._resume,
        '/think': self._think,
        '/btw': self._btw,
        '/review': self._review,
        '/context': self._context,
        '/tools': self._tools,
        '/skills': self._skills,
        '/subagents': self._subagents,
    }

is_command

is_command(text)

Says whether a message is a command rather than something for the model.

Parameters:

Name Type Description Default
text str

The message.

required

Returns:

Type Description
bool

True when it starts with a slash.

Source code in src/trading_agent/runtime/slash_commands.py
def is_command(self, text: str) -> bool:
    """Says whether a message is a command rather than something for the model.

    Args:
        text (str): The message.

    Returns:
        bool: True when it starts with a slash.
    """
    return text.strip().startswith('/')

command_name

command_name(text)

The command word of a message, lowercased and without the @botname suffix Telegram adds in groups.

Parameters:

Name Type Description Default
text str

The message, such as "/usage@my_bot today".

required

Returns:

Type Description
str

The command word, such as "/usage", or an empty string for an empty message.

Source code in src/trading_agent/runtime/slash_commands.py
def command_name(self, text: str) -> str:
    """The command word of a message, lowercased and without the @botname suffix Telegram adds in groups.

    Args:
        text (str): The message, such as "/usage@my_bot today".

    Returns:
        str: The command word, such as "/usage", or an empty string for an empty message.
    """
    words = text.strip().split()
    if not words:
        return ''
    return words[0].split('@')[0].lower()

is_instant

is_instant(text)

Says whether a command only reads the desk, so it can be answered at once instead of waiting for the running turn.

Parameters:

Name Type Description Default
text str

The message.

required

Returns:

Type Description
bool

True for the read-only commands, such as /status.

Source code in src/trading_agent/runtime/slash_commands.py
def is_instant(self, text: str) -> bool:
    """Says whether a command only reads the desk, so it can be answered at once instead of waiting for the running turn.

    Args:
        text (str): The message.

    Returns:
        bool: True for the read-only commands, such as /status.
    """
    return self.command_name(text) in _INSTANT_COMMANDS

is_background

is_background(text)

Says whether a command asks a model and runs beside the desk's turn, one at a time.

Parameters:

Name Type Description Default
text str

The message.

required

Returns:

Type Description
bool

True for /btw and /review.

Source code in src/trading_agent/runtime/slash_commands.py
def is_background(self, text: str) -> bool:
    """Says whether a command asks a model and runs beside the desk's turn, one at a time.

    Args:
        text (str): The message.

    Returns:
        bool: True for /btw and /review.
    """
    return self.command_name(text) in _BACKGROUND_COMMANDS

skill_request

skill_request(text)

Turns / into a request for the model to follow that skill.

Built-in commands take precedence over skills of the same name.

Parameters:

Name Type Description Default
text str

The message, such as "/opening-range-breakout NIFTY".

required

Returns:

Type Description
str | None

The text to send to the model, or None when the message does not name a usable skill.

Source code in src/trading_agent/runtime/slash_commands.py
def skill_request(self, text: str) -> str | None:
    """Turns /<skill-name> into a request for the model to follow that skill.

    Built-in commands take precedence over skills of the same name.

    Args:
        text (str): The message, such as "/opening-range-breakout NIFTY".

    Returns:
        str | None: The text to send to the model, or None when the message does not name a usable skill.
    """
    if self._skill_library is None:
        return None
    name = self.command_name(text)
    argument = self._argument(text)
    if name in self._commands:
        return None
    skill = self._skill_library.find(name[1:])
    if skill is None:
        return None
    lines = [
        f'[The user invoked your skill {skill.name} with /{skill.name}. Load it with load_skill and follow it.]',
    ]
    if argument:
        lines.append(argument)
    return '\n'.join(lines)

catalogue

catalogue()

Every command and usable skill, for a client's command menu.

Returns:

Type Description
list[dict[str, str]]

One entry per /help line, then one per usable skill, each with name, usage, description, kind ("command" or "skill") and runs ("at_once", "beside" or "queued"; /stop is "at_once" because it skips the queue).

Source code in src/trading_agent/runtime/slash_commands.py
def catalogue(self) -> list[dict[str, str]]:
    """Every command and usable skill, for a client's command menu.

    Returns:
        list[dict[str, str]]: One entry per /help line, then one per usable skill, each with name, usage, description, kind ("command" or "skill") and runs ("at_once", "beside" or "queued"; /stop is "at_once" because it skips the queue).
    """
    entries = []
    for entry in _COMMAND_HELP:
        name = entry.name()
        if name == '/<skill-name>':
            continue
        runs = 'queued'
        if name in _INSTANT_COMMANDS or name == '/stop':
            runs = 'at_once'
        elif name in _BACKGROUND_COMMANDS:
            runs = 'beside'
        entries.append(
            {
                'name': name,
                'usage': entry.usage,
                'description': entry.description,
                'kind': 'command',
                'runs': runs,
            }
        )
    if self._skill_library is None:
        return entries
    for skill in self._skill_library.available():
        if f'/{skill.name}' in self._commands:
            continue
        entries.append(
            {
                'name': f'/{skill.name}',
                'usage': f'/{skill.name}',
                'description': skill.description,
                'kind': 'skill',
                'runs': 'queued',
            }
        )
    return entries

handle async

handle(text)

Runs one command.

Parameters:

Name Type Description Default
text str

The message, such as "/model qwen".

required

Returns:

Type Description
str

The reply to show the user.

Source code in src/trading_agent/runtime/slash_commands.py
async def handle(self, text: str) -> str:
    """Runs one command.

    Args:
        text (str): The message, such as "/model qwen".

    Returns:
        str: The reply to show the user.
    """
    name = self.command_name(text)
    command = self._commands.get(name)
    if command is not None:
        return await command(self._argument(text))
    return f'Unknown command {name}. Type /help for the list.'