Skip to content

System Context Construction

This page documents how the discretionary agent constructs the live trading environment and injects it into the LLM on every turn.

Discretionary turns enter through the shared websocket endpoint:

  • /ws/agent
  • handled in backend/services/agent/ws/handler.ts

The transport layer dispatches discretionary events to:

  • backend/services/autodiscretionary/turn-runner.ts

For a user message, the path is:

  1. disc_message
  2. handleDiscMessage(...)
  3. runDiscTurnAndDrain(...)

If the thread is already running, the new message is queued into Redis instead of starting another concurrent turn.

runDiscTurnAndDrain(...) first resolves:

  • the thread
  • the owning discretionary session
  • the runtime scope

The runtime scope is:

getDiscRuntimeScope(session.id) -> `session:${sessionId}`

This is the core isolation boundary for multi-agent-per-user support.

The runner then resolves:

  • the configured discretionary provider/model from the session
  • the user’s active LLM key from llm_api_keys
  • fallback key/provider if needed

The discretionary system prompt is assembled in:

  • backend/services/autodiscretionary/system-prompt.ts

The final prompt is:

  1. base system prompt
  2. thread-type prompt
  3. formatted live trading context from formatContextForPrompt(...)
  4. optional portfolio strategy prompt
  5. alert-specific suffix for alert threads
  6. persistent prompt notes

The live trading context is built in:

  • backend/services/autodiscretionary/context-builder.ts

Main entry point:

buildTradingContext(userId, runtimeScope, sessionId)

This function consumes the canonical runtime snapshot:

  • buildDiscretionaryRuntimeSnapshot(...)

It then enriches that snapshot with prompt-specific material such as:

  • recent closed-trade performance
  • market metadata / funding / open interest
  • execution config
  • risk config
  • prompt notes
  • formatted market hours

The canonical runtime snapshot lives in:

  • backend/services/autodiscretionary/runtime-snapshot.ts

This is the shared backend source for both:

  • the UI live-state API
  • the prompt context builder

It loads and normalizes:

  • account state from Redis
  • trade risk state from Redis
  • time alerts from Redis
  • merged persisted + runtime alerts
  • trading notes from Postgres
  • active trades from the trade ledger
  • market conditions from Redis
  • drawdown lockout from Redis
  • market hours
  • live prices
  • runtime health

Discretionary tools are built in:

  • backend/services/autodiscretionary/tools/index.ts

Main entry:

buildDiscretionaryTools(ctx, threadType, alertData, creds)

Tool surface differs by thread type:

  • chat threads: full discretionary toolset
  • alert threads: scoped by alert type

After prompt and tools are ready, discretionary still uses the shared agent core:

  • runAgentTurn(...)

So the discretionary runtime owns environment orchestration, but not a duplicate turn engine.