trader.chat.service module

The chat CLI’s core turn-handling logic (issues #13-#16).

ChatService.handle(message) is the single entry point: classify the message (trader.chat.intent), fetch whatever data that intent needs from the database, config/strategies.yaml, or the backtest engine, then — for every branch except a plain backtest result, which is already exact numbers — ask the local model to compose a conversational answer grounded in that data.

Every branch resolves to a plain string, never an exception and never a fabricated fact. That is the same discipline LlmStrategy.evaluate() uses for a trading decision (CLAUDE.md: “everything that can go wrong in the LLM path resolves to HOLD, never a trade”), carried over to a chat turn: nothing here can place an order or write a file, so the analogous “safe outcome” is a plain-text reply that says what went wrong instead of crashing the loop or inventing a number.

class trader.chat.service.ChatService(*, llm, decisions, trades, snapshots, outcomes, strategy_entries, strategies_path, bar_cache, backtest_repository=None)[source]

Bases: object

Answers one chat turn at a time. Holds no conversation state.

Statelessness is deliberate for v1: each handle() call re-fetches its own grounding data fresh from the database, so there is no session cache that could go stale between turns or leak one user’s context into another’s. Multi-turn memory is future work, not a requirement any of issues #13-#16 asks for.

Parameters:
__init__(*, llm, decisions, trades, snapshots, outcomes, strategy_entries, strategies_path, bar_cache, backtest_repository=None)[source]
Parameters:
Return type:

None

handle(message)[source]

Answer one message. Never raises — every failure becomes a reply.

Parameters:

message (str)

Return type:

str