Skip to content

trading_agent.agent.prompt_builder

Builds a desk's system prompt from the workspace files.

The prompt is read fresh before every turn, so an edit to a file reaches the desk on its next turn. It holds only slow-changing text, so that it stays identical between turns and the model's prompt cache keeps working; the time and the trigger go in the user message instead.

Typical usage example:

builder = PromptBuilder(layout, 'main', 'dry_run') prompt = builder.build() prompt.text, prompt.fingerprint

MAXIMUM_FILE_CHARACTERS module-attribute

MAXIMUM_FILE_CHARACTERS = 20000

MAXIMUM_TOTAL_CHARACTERS module-attribute

MAXIMUM_TOTAL_CHARACTERS = 60000

SystemPrompt dataclass

SystemPrompt(text, fingerprint)

One built prompt.

Attributes:

Name Type Description
text str

The prompt.

fingerprint str

A short hash of the text, which changes whenever the text does.

PromptBuilder

PromptBuilder(layout, desk_name, mode, skill_library=None, mcp_manager=None, subagent_library=None, other_desks=())

Assembles one desk's prompt.

Creates the builder.

Parameters:

Name Type Description Default
layout WorkspaceLayout

Where the files are.

required
desk_name str

The desk the prompt is for.

required
mode str

"dry_run" or "live", stated in the prompt.

required
skill_library SkillLibrary | None

The desk's skills, listed as an index at the end, or None for no index.

None
mcp_manager McpClientManager | None

The MCP connections, whose tool names are listed last, or None.

None
subagent_library SubagentLibrary | None

The subagents the desk can delegate to, listed after the skills, or None.

None
other_desks Sequence[str]

The other desks sharing the account, named in the header.

()
Source code in src/trading_agent/agent/prompt_builder.py
def __init__(
    self,
    layout: workspace_layout.WorkspaceLayout,
    desk_name: str,
    mode: str,
    skill_library: skill_library_module.SkillLibrary | None = None,
    mcp_manager: mcp_client_manager.McpClientManager | None = None,
    subagent_library: subagent_library_module.SubagentLibrary | None = None,
    other_desks: Sequence[str] = (),
):
    """Creates the builder.

    Args:
        layout (workspace_layout.WorkspaceLayout): Where the files are.
        desk_name (str): The desk the prompt is for.
        mode (str): "dry_run" or "live", stated in the prompt.
        skill_library (skill_library_module.SkillLibrary | None): The desk's skills, listed as an index at the end, or None for no index.
        mcp_manager (mcp_client_manager.McpClientManager | None): The MCP connections, whose tool names are listed last, or None.
        subagent_library (subagent_library_module.SubagentLibrary | None): The subagents the desk can delegate to, listed after the skills, or None.
        other_desks (Sequence[str]): The other desks sharing the account, named in the header.
    """
    self._layout = layout
    self._desk_name = desk_name
    self._mode = mode
    self._skill_library = skill_library
    self._mcp_manager = mcp_manager
    self._subagent_library = subagent_library
    self._other_desks = list(other_desks)

build

build()

Reads the files and assembles the prompt.

Returns:

Type Description
SystemPrompt

The prompt and its fingerprint.

Source code in src/trading_agent/agent/prompt_builder.py
def build(self) -> SystemPrompt:
    """Reads the files and assembles the prompt.

    Returns:
        SystemPrompt: The prompt and its fingerprint.
    """
    sections = [
        self._header(),
        self._memory_guide(),
        self._section('Agents.md', self._layout.agents_file),
        self._section(
            'Persona.md', self._layout.persona_file(self._desk_name)
        ),
        self._section('User.md', self._layout.user_file),
        self._section('TradingRules.md', self._layout.trading_rules_file),
        self._section(
            'Memory.md', self._layout.memory_file(self._desk_name)
        ),
    ]
    if self._skill_library is not None:
        sections.append(self._skill_library.index_text())
    if self._subagent_library is not None:
        subagent_index = self._subagent_library.index_text()
        if subagent_index:
            sections.append(subagent_index)
    if self._mcp_manager is not None:
        mcp_index = self._mcp_manager.index_text()
        if mcp_index:
            sections.append(mcp_index)
    if self._layout.is_template(self._layout.user_file):
        sections.append(self._layout.template_text('FirstRunInterview.md'))
    text = '\n\n'.join(sections)
    if len(text) > MAXIMUM_TOTAL_CHARACTERS:
        text = (
            text[:MAXIMUM_TOTAL_CHARACTERS]
            + '\n\n[The workspace files were cut here because together they exceed 60,000 characters.]'
        )
    fingerprint = hashlib.sha256(text.encode('utf-8')).hexdigest()[:16]
    return SystemPrompt(text=text, fingerprint=fingerprint)