Skip to content

trading_agent.agent.context_usage

How full a desk's context window is, broken down by what fills it.

Claude Code measures its own window and names the categories itself, such as "Messages", "System tools" and "Free space". The Ollama and OpenAI backends have no such report, so their runner estimates the same kind of breakdown from the conversation it keeps: the system prompt, the tool definitions, the messages and the space left.

Typical usage example:

usage = ContextUsage.estimate('qwen', 'qwen3.8:27b', 32768, conversation, definitions) usage.to_payload()

SYSTEM_PROMPT module-attribute

SYSTEM_PROMPT = 'System prompt'

TOOLS module-attribute

TOOLS = 'Tools'

MESSAGES module-attribute

MESSAGES = 'Messages'

FREE_SPACE module-attribute

FREE_SPACE = 'Free space'

ContextCategory dataclass

ContextCategory(name, tokens, deferred=False)

One part of the context window.

Attributes:

Name Type Description
name str

What fills this part, such as "Messages".

tokens int

How many tokens it holds.

deferred bool

True for something listed but not loaded into the window, such as a deferred tool.

ContextUsage dataclass

ContextUsage(backend, model, total_tokens, context_window, categories, measured, recorded_at)

A snapshot of one backend's context window.

Attributes:

Name Type Description
backend str

The backend's name in trading_agent.toml.

model str

The model's name on its server.

total_tokens int

How many tokens the window holds.

context_window int

How many tokens it can hold.

categories tuple[ContextCategory, ...]

What fills it, in the order to show them.

measured bool

True when the model's own tool counted the tokens, False for an estimate.

recorded_at str

When the snapshot was taken, as ISO text.

from_claude classmethod

from_claude(backend, report)

Builds a snapshot from Claude Code's get_context_usage report.

Parameters:

Name Type Description Default
backend str

The backend's name in trading_agent.toml.

required
report Mapping[str, Any]

The report, with categories, totalTokens, rawMaxTokens and model.

required

Returns:

Type Description
ContextUsage

The snapshot.

Source code in src/trading_agent/agent/context_usage.py
@classmethod
def from_claude(
    cls,
    backend: str,
    report: Mapping[str, Any],
) -> 'ContextUsage':
    """Builds a snapshot from Claude Code's get_context_usage report.

    Args:
        backend (str): The backend's name in trading_agent.toml.
        report (Mapping[str, Any]): The report, with categories, totalTokens, rawMaxTokens and model.

    Returns:
        ContextUsage: The snapshot.
    """
    categories = []
    for category in report.get('categories') or []:
        categories.append(
            ContextCategory(
                name=str(category.get('name', '')),
                tokens=int(category.get('tokens', 0)),
                deferred=bool(category.get('isDeferred', False)),
            )
        )
    window = report.get('rawMaxTokens') or report.get('maxTokens') or 0
    return cls(
        backend=backend,
        model=str(report.get('model', '')),
        total_tokens=int(report.get('totalTokens', 0)),
        context_window=int(window),
        categories=tuple(categories),
        measured=True,
        recorded_at=cls._now_text(),
    )

estimate classmethod

estimate(backend, model, context_window, conversation, tool_definitions)

Estimates a snapshot from a conversation the agent loop keeps.

The system prompt, the tool definitions and the messages are first counted roughly, at three characters per token and 1500 tokens per picture. Once the model has reported how many tokens it read, the three rough counts are scaled so that they add up to that total, because the rough rate is far off for some text, such as the JSON of tool definitions.

Parameters:

Name Type Description Default
backend str

The backend's name in trading_agent.toml.

required
model str

The model's name on its server.

required
context_window int

How many tokens the model is given.

required
conversation Conversation

The conversation so far.

required
tool_definitions Sequence[Mapping[str, Any]]

The tools the model is offered.

required

Returns:

Type Description
ContextUsage

The estimated snapshot.

Source code in src/trading_agent/agent/context_usage.py
@classmethod
def estimate(
    cls,
    backend: str,
    model: str,
    context_window: int,
    conversation: conversation_module.Conversation,
    tool_definitions: Sequence[Mapping[str, Any]],
) -> 'ContextUsage':
    """Estimates a snapshot from a conversation the agent loop keeps.

    The system prompt, the tool definitions and the messages are first counted roughly, at three characters per token and 1500 tokens per picture. Once the model has reported how many tokens it read, the three rough counts are scaled so that they add up to that total, because the rough rate is far off for some text, such as the JSON of tool definitions.

    Args:
        backend (str): The backend's name in trading_agent.toml.
        model (str): The model's name on its server.
        context_window (int): How many tokens the model is given.
        conversation (conversation_module.Conversation): The conversation so far.
        tool_definitions (Sequence[Mapping[str, Any]]): The tools the model is offered.

    Returns:
        ContextUsage: The estimated snapshot.
    """
    system_tokens = len(conversation.system_prompt) // _CHARACTERS_PER_TOKEN
    tool_tokens = (
        len(json.dumps(list(tool_definitions))) // _CHARACTERS_PER_TOKEN
    )
    message_tokens = cls._message_tokens(conversation)
    rough_total = system_tokens + tool_tokens + message_tokens
    total = rough_total
    if conversation.measured_tokens > 0 and rough_total > 0:
        total = conversation.estimated_tokens()
        system_tokens = round(system_tokens * total / rough_total)
        tool_tokens = round(tool_tokens * total / rough_total)
        message_tokens = max(0, total - system_tokens - tool_tokens)
    free = max(0, context_window - total)
    categories = (
        ContextCategory(SYSTEM_PROMPT, system_tokens),
        ContextCategory(TOOLS, tool_tokens),
        ContextCategory(MESSAGES, message_tokens),
        ContextCategory(FREE_SPACE, free),
    )
    return cls(
        backend=backend,
        model=model,
        total_tokens=total,
        context_window=context_window,
        categories=categories,
        measured=False,
        recorded_at=cls._now_text(),
    )

to_payload

to_payload()

Describes the snapshot for the gateway's API.

Returns:

Type Description
dict[str, Any]

The snapshot as plain JSON-ready values.

Source code in src/trading_agent/agent/context_usage.py
def to_payload(self) -> dict[str, Any]:
    """Describes the snapshot for the gateway's API.

    Returns:
        dict[str, Any]: The snapshot as plain JSON-ready values.
    """
    categories = []
    for category in self.categories:
        categories.append(
            {
                'name': category.name,
                'tokens': category.tokens,
                'deferred': category.deferred,
            }
        )
    return {
        'backend': self.backend,
        'model': self.model,
        'total_tokens': self.total_tokens,
        'context_window': self.context_window,
        'categories': categories,
        'measured': self.measured,
        'recorded_at': self.recorded_at,
    }