Skip to content

Display & logging

caw can stream a live, human-readable view of what the agent is doing, and/or emit a one-line summary of every event to a logger of your choice.

Console display

The Display class renders agent events (user messages, thinking, text, tool calls and results, end-of-turn stats) to the terminal with Rich. It has four DisplayModes:

Mode Shows
FULL Everything, untruncated
SHORT Truncated previews (the default)
RESULT Only the final result, in a panel
OFF Nothing

The simplest way to control it is the CAW_LOG environment variable, which the global display reads on first use:

import os
os.environ["CAW_LOG"] = "full"   # or "short", "result", "off"

from caw import Agent
Agent().completion("Hello")      # streams output per CAW_LOG

Programmatically:

from caw import Display, DisplayMode, set_global_display

set_global_display(Display(mode=DisplayMode.RESULT))

get_global_display() returns the current instance (creating one from CAW_LOG on first call); set_global_display(None) silences it.

Structured logging

Separately from the pretty console output, you can route a one-line summary per event to any logger via AgentLogger. Any object with info / warn / error string methods satisfies the protocol — including the stdlib logging.Logger (after a tiny warnwarning adapter) and your own sinks (e.g. a Redis logger).

import logging
from caw import Agent

logging.basicConfig(level=logging.INFO)
log = logging.getLogger("agent")
log.warn = log.warning  # satisfy the AgentLogger protocol

agent = Agent(logger=log)         # or agent.start_session(logger=log)
agent.completion("List the files here")

Every major event — user message, tool call, tool result, assistant text, thinking, turn-end stats — is emitted as a compact line, in addition to the console Display.

FastStats

FastStats extracts the frequently-needed header/footer fields (cost, model, timestamps, token totals) from a trajectory file by reading only its head and tail — roughly 3× faster than a full parse on small files and 25×+ on multi-MB ones, with a full-parse fallback when the fast path doesn't apply.

from caw import FastStats

stats = FastStats.from_path("caw_data/sessions/<id>/trajectory.json")
print(stats.model, stats.cost_usd, stats.total_tokens)

# Aggregate across a directory:
total = FastStats.directory_total_cost("caw_data")

See the Display & logging API reference for the full surface.