trading_agent.backends.model_router
¶
Tries a desk's backends in order, so the desk keeps working when one model is unavailable.
A backend that fails is not tried again until its waiting period ends: 30 seconds after the first failure in a row, then 1 minute, then 5 minutes. A success resets it. Each backend keeps its own conversation, so when a backend takes over it is first told what was asked and answered on the turns it missed.
With a session store, every finished exchange is also written to disk, with what each backend needs to resume. After a restart, restore_session reads them back: a backend that can resume its own conversation, such as Claude, carries on, and the others are told what they missed exactly as after a switch.
Typical usage example:
router = ModelRouter('main', [claude_route, qwen_route, gemma_route], event_bus) result = await router.run_turn(trigger)
DEFAULT_WAITING_PERIODS_SECONDS
module-attribute
¶
BackendRoute
¶
One backend in a desk's order, with its failure record.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
The backend's name in trading_agent.toml. |
|
turn_runner |
What runs a turn on this backend. |
|
consecutive_failures |
How many turns in a row have failed on it. |
|
available_at |
The monotonic time from which it may be tried again. |
|
exchanges_seen |
How many of the desk's exchanges this backend already knows about. |
Creates a route with no failures.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The backend's name in trading_agent.toml. |
required |
runner
|
TurnRunner
|
What runs a turn on this backend. |
required |
Source code in src/trading_agent/backends/model_router.py
record_failure
¶
Counts a failure and starts the backend's waiting period.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
now
|
float
|
The current monotonic time. |
required |
waiting_periods_seconds
|
Sequence[float]
|
The waits after the first, second and later failures in a row. |
required |
retry_after_seconds
|
float | None
|
How long the backend itself said to wait, such as until a subscription limit resets; it replaces the usual period when given. |
None
|
Returns:
| Type | Description |
|---|---|
float
|
How long the backend now waits, in seconds. |
Source code in src/trading_agent/backends/model_router.py
ModelRouter
¶
ModelRouter(desk_name, routes, event_bus, waiting_periods_seconds=DEFAULT_WAITING_PERIODS_SECONDS, clock=monotonic, session_store=None, completed_calls=None)
Bases: TurnRunner
Runs each turn on the first backend in the desk's order that is available.
Attributes:
| Name | Type | Description |
|---|---|---|
session_id |
str | None
|
The current session's identifier, or None without a session store or before the session starts. |
trading_date |
date | None
|
The India date of the current session, or None likewise. |
Creates the router.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
desk_name
|
str
|
The desk the router belongs to. |
required |
routes
|
Sequence[BackendRoute]
|
The desk's backends, most preferred first. |
required |
event_bus
|
EventBus
|
Where failures and switches are published. |
required |
waiting_periods_seconds
|
Sequence[float]
|
The waits after the first, second and later failures in a row. |
DEFAULT_WAITING_PERIODS_SECONDS
|
clock
|
Callable[[], float]
|
The source of monotonic time, replaceable in tests. |
monotonic
|
session_store
|
SessionStore | None
|
Where exchanges are kept across restarts, or None to keep them in memory only. |
None
|
completed_calls
|
Callable[[str], Sequence[CompletedCall]] | None
|
Gives the tool calls already made for a trigger, so a backend that takes over halfway through a turn does not repeat them; None when unknown. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
No routes were given. |
Source code in src/trading_agent/backends/model_router.py
run_turn
async
¶
Runs the turn on the first available backend.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trigger
|
Trigger
|
The reason for the turn. |
required |
Returns:
| Type | Description |
|---|---|
TurnResult
|
The answer from the first backend that succeeded. |
Raises:
| Type | Description |
|---|---|
BackendUnavailableError
|
Every backend failed or is waiting. |
Source code in src/trading_agent/backends/model_router.py
side_question
async
¶
Answers a side question without changing any conversation or the session's history.
The backend that answered last is asked first, because its conversation holds the whole session; the others follow in the usual order. A failure here does not make a backend wait, because a side question must not change how turns are routed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
question
|
str
|
The user's question. |
required |
Returns:
| Type | Description |
|---|---|
tuple[str, str]
|
A tuple (backend_name, answer), where backend_name is the backend that answered. |
Raises:
| Type | Description |
|---|---|
BackendUnavailableError
|
Every backend failed or is waiting. |
Source code in src/trading_agent/backends/model_router.py
reset
async
¶
Forgets every backend's conversation and the hand-over history, and starts a new session.
It serves /new and the daily rollover.
Source code in src/trading_agent/backends/model_router.py
compact
async
¶
Compacts the conversation of the backend that answered last, for /compact.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trigger
|
Trigger
|
The command's trigger, used to tag events. |
required |
Returns:
| Type | Description |
|---|---|
str
|
What happened, naming the backend. |
Source code in src/trading_agent/backends/model_router.py
restore_session
async
¶
Picks up the session saved before a restart, or starts the first one.
Returns:
| Type | Description |
|---|---|
bool
|
True when a saved session was picked up, False when a new one started. |
Source code in src/trading_agent/backends/model_router.py
context_usage
¶
How full the context window is of the backend that answered last, or of the first one to be tried before any turn.
Returns:
| Type | Description |
|---|---|
ContextUsage | None
|
That backend's latest snapshot, or None when it has none. |
Source code in src/trading_agent/backends/model_router.py
close
async
¶
last_backend_name
property
¶
The backend that answered the last turn, or None before any turn.
preferred_backend_name
property
¶
The backend tried first because of /model, or None for the configured order.
choose
¶
Tries one backend first, optionally with another of its provider's models, or returns to the configured order and models.
The chosen model applies only to the chosen backend; every other backend goes back to its configured model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
backend_name
|
str | None
|
The backend to try first, or None for the configured order. |
required |
model
|
str | None
|
The model that backend should use, or None for its configured one. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
No backend of the desk has that name, or a model was given without a backend. |
Source code in src/trading_agent/backends/model_router.py
active_models
¶
The model each backend uses now.
Returns:
| Type | Description |
|---|---|
dict[str, str | None]
|
Each backend's model, keyed by backend name. |
Source code in src/trading_agent/backends/model_router.py
prefer
¶
Tries one backend first from now on, or returns to the configured order.
The other backends keep their order behind it, so they still take over when it fails.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
backend_name
|
str | None
|
The backend to try first, or None for the configured order. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
No backend of the desk has that name. |
Source code in src/trading_agent/backends/model_router.py
set_thinking
¶
Changes the thinking level of every backend that has one, from its next turn on.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
level
|
str | None
|
One of turn_runner.THINKING_LEVELS, or None for each backend's level in trading_agent.toml. |
required |
Source code in src/trading_agent/backends/model_router.py
thinking_lines
¶
Describes each backend's thinking level for /think.
Returns:
| Type | Description |
|---|---|
list[str]
|
One line per backend, in the order they will be tried. |
Source code in src/trading_agent/backends/model_router.py
status_lines
¶
Describes each backend's state for /status.
Returns:
| Type | Description |
|---|---|
list[str]
|
One line per backend, in the order they will be tried. |