trading_agent.backends.claude_code_turn_runner
¶
Runs a desk's turns on Claude through Claude Code and the Max subscription.
Claude Code runs the agent loop itself, so this is a turn runner rather than a ModelBackend. It keeps one Claude Code session per desk, so Claude remembers earlier turns. It is set up so that it never stops for a human:
- permission_mode is bypassPermissions and setting_sources is empty, so no "ask" rule from any settings file applies;
- the subscription token from
claude setup-tokenis passed as CLAUDE_CODE_OAUTH_TOKEN; - every built-in Claude Code tool is switched off, and a PreToolUse hook allows only trading-agent's tools.
Before each turn the runner asks Claude Code how full the session's context is. At 70% of the window it gives Claude a memory-flush turn and then sends /compact, so Claude saves what matters before the older turns are summarised. Claude Code's own automatic compaction stays on as a safety net for one very long turn, set to fire at about 82% by limiting the window it measures against.
Typical usage example:
runner = ClaudeCodeTurnRunner('main', 'claude', backend_configuration, bridge, event_bus, settings) result = await runner.run_turn(trigger)
ClaudeCodeSettings
dataclass
¶
ClaudeCodeSettings(prompt_builder, oauth_token, working_directory, maximum_rounds, sessions_directory, compression_threshold, emergency_compression_threshold)
The settings of one Claude Code session that do not come from the backend's table.
Attributes:
| Name | Type | Description |
|---|---|---|
prompt_builder |
PromptBuilder
|
Builds the desk's instructions before every turn. |
oauth_token |
str
|
The subscription token from |
working_directory |
Path
|
The folder Claude Code runs in. |
maximum_rounds |
int
|
The most model calls one turn may make. |
sessions_directory |
Path
|
Where Claude Code keeps its sessions, normally ~/.claude/projects, checked before a saved session is resumed. |
compression_threshold |
float
|
The share of the context window at which the session is flushed and compacted before a turn. |
emergency_compression_threshold |
float
|
The share of the window given to Claude Code as its own compaction window, the safety net for one long turn. |
ClaudeCodeTurnRunner
¶
ClaudeCodeTurnRunner(desk_name, backend_name, backend_configuration, bridge, event_bus, settings, steering_inbox=None)
Bases: TurnRunner
One desk's Claude Code session.
Attributes:
| Name | Type | Description |
|---|---|---|
session_id |
str | None
|
Claude Code's session identifier, known after the first turn. |
Creates the runner without starting Claude Code.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
desk_name
|
str
|
The desk the session belongs to. |
required |
backend_name
|
str
|
The backend's name in trading_agent.toml. |
required |
backend_configuration
|
BackendConfiguration
|
Its settings, of kind "claude_code". |
required |
bridge
|
ClaudeToolBridge
|
The desk's tools, as Claude Code sees them. |
required |
event_bus
|
EventBus
|
Where every step is published. |
required |
settings
|
ClaudeCodeSettings
|
The prompt, token, folder and round limit. |
required |
steering_inbox
|
SteeringInbox | None
|
The desk's mid-turn messages, handed to Claude after each tool call, or None. |
None
|
Source code in src/trading_agent/backends/claude_code_turn_runner.py
run_turn
async
¶
Sends the trigger to Claude and waits for its final answer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trigger
|
Trigger
|
The reason for the turn. |
required |
Returns:
| Type | Description |
|---|---|
TurnResult
|
Claude's final text. |
Raises:
| Type | Description |
|---|---|
BackendUnavailableError
|
Claude cannot be used now: no token, an API key is set, the subscription limit is reached, or Claude Code failed. |
Source code in src/trading_agent/backends/claude_code_turn_runner.py
side_question
async
¶
Answers a question in a throwaway fork of the session, so the desk's own session is not changed.
The fork runs in its own short-lived Claude Code process, beside any turn the desk is running. Its session file is deleted afterwards.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
question
|
str
|
The user's question. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Claude's answer. |
Raises:
| Type | Description |
|---|---|
BackendUnavailableError
|
Claude cannot be used now, or answered with an error. |
Source code in src/trading_agent/backends/claude_code_turn_runner.py
compact
async
¶
Flushes and compacts the session now, for the /compact command.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trigger
|
Trigger
|
The command's trigger, used to tag events. |
required |
Returns:
| Type | Description |
|---|---|
str
|
What happened, for the user. |
Raises:
| Type | Description |
|---|---|
BackendUnavailableError
|
Claude cannot be used now. |
Source code in src/trading_agent/backends/claude_code_turn_runner.py
active_model
¶
The Claude model the session uses now: the user's choice from the model menu, or the configured one.
Returns:
| Type | Description |
|---|---|
str | None
|
The model's name or alias. |
Source code in src/trading_agent/backends/claude_code_turn_runner.py
use_model
¶
Switches the session to another Claude model at its next turn, keeping the conversation, as /model does in Claude Code.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str | None
|
The model's name, or None for the configured model. |
required |
Source code in src/trading_agent/backends/claude_code_turn_runner.py
thinking
¶
Claude's effort level now, or "off" when thinking is switched off.
Returns:
| Type | Description |
|---|---|
str | None
|
The level, or "default" when trading_agent.toml sets no effort. |
Source code in src/trading_agent/backends/claude_code_turn_runner.py
set_thinking
¶
Sets Claude's effort, or switches thinking off, from the next turn on.
Claude Code takes these settings only when its process starts, so the next turn restarts the process and resumes the same session, keeping the conversation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
level
|
str | None
|
One of turn_runner.THINKING_LEVELS, or None for the effort in trading_agent.toml with thinking on. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
Always True. |
Source code in src/trading_agent/backends/claude_code_turn_runner.py
context_usage
¶
How full Claude's context window was at the end of the last turn, as Claude Code measured it.
Returns:
| Type | Description |
|---|---|
ContextUsage | None
|
The snapshot, or None before the first turn of the session. |
Source code in src/trading_agent/backends/claude_code_turn_runner.py
note_compaction
¶
Remembers that the session was compacted, so the next turn sends the instruction files again.
Updated instructions delivered inside earlier messages may not survive a compaction, so the next turn's message carries the complete current version.
Source code in src/trading_agent/backends/claude_code_turn_runner.py
saved_state
¶
Claude Code's session id and the prompt it last saw, so a restart can resume the session.
Returns:
| Type | Description |
|---|---|
dict[str, Any] | None
|
The session id and prompt fingerprint, or None before the first turn. |
Source code in src/trading_agent/backends/claude_code_turn_runner.py
restore_state
async
¶
Resumes a session saved before a restart, if Claude Code still has it.
Claude Code keeps each session as a file named after its id. When that file is gone, resuming would fail, so the runner starts a new session instead and the router tells it what it missed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
dict[str, Any]
|
What saved_state returned before the restart. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True when the next turn will resume the saved session. |
Source code in src/trading_agent/backends/claude_code_turn_runner.py
reset
async
¶
Stops Claude Code and forgets the session, so the next turn starts afresh.