Context Replay
Debug and analyse agent execution by replaying context changes step-by-step
from praisonaiagents import Agent
agent = Agent(name="replay-agent", instructions="Replay recorded agent sessions for debugging.")
agent.start("Replay the session from yesterday to reproduce the bug.")The user saves a trace during a run, then steps through recorded context events to debug handoffs and tools.
Record agent context events during a run, then step through them interactively to debug handoffs, tool calls, and token growth.
praisonai recipe run my-recipe --save
praisonai replay list
praisonai replay context <session_id>Quick Start
- Simple Usage
Save a trace during a recipe or workflow run:
bash # Recipe run with trace saving praisonai recipe run my-recipe --save # agents.yaml or workflow praisonai agents.yaml --save praisonai workflow run my-workflow --save # List and replay praisonai replay list praisonai replay context <session_id> - With Configuration
Emit traces from Python and persist to disk:
python from praisonai.replay import ContextTraceWriter from praisonaiagents import ContextTraceEmitter writer = ContextTraceWriter(session_id="my-session") emitter = ContextTraceEmitter(sink=writer, session_id="my-session", redact=True) emitter.session_start() emitter.agent_start("researcher") emitter.message_added("researcher", "user", "Find info about AI", 1, 100) emitter.agent_end("researcher") emitter.session_end() writer.close()
How It Works
| Event type | Description |
|---|---|
SESSION_START / SESSION_END | Session boundaries |
AGENT_START / AGENT_END | Agent lifecycle |
AGENT_HANDOFF | Handoff to another agent |
MESSAGE_ADDED | Context message appended |
TOOL_CALL_START / TOOL_CALL_END | Tool execution |
LLM_REQUEST / LLM_RESPONSE | LLM API calls |
CONTEXT_SNAPSHOT | Full context state captured |
AGENT_END carries data["status"]: "completed", "failed" (the agent raised), or "cancelled". An unnamed agent (Agent(instructions=...)) uses node_id="agent:Agent", matching its id in to_graph(agent). Both sync (start/chat) and async (astart/achat) runs record LLM_REQUEST / LLM_RESPONSE.
Traces are stored as JSONL in ~/.praisonai/traces/.
Node IDs & Reused Steps
Every step gets a stable node_id built from its name and position, so one handler reused at two positions shows up as two separate nodes.
from praisonaiagents import AgentFlow
def review(ctx):
return "ok"
def draft(ctx):
return "drafted"
flow = AgentFlow(steps=[review, draft, review])
flow.run("go")
# step_start / step_end node_ids:
# step:review step:draft step:review#2| Scenario | node_id behaviour |
|---|---|
| Same handler at two sequential positions | Each position gets its own id (step:review, step:review#2) |
Same handler in both then and else of If | Each branch gets its own id |
Same handler in two slots of a Loop body | Each slot gets its own id |
| Same handler across loop iterations | Same id on every pass — the #N suffix is positional, not a run counter |
Same pattern object (If, Loop, Parallel) at two positions | Each occurrence gets its own id (step:if, step:if#2) |
Repeat members | Keep one id per object across repeats |
CLI Commands
| Command | Purpose |
|---|---|
praisonai replay list | List available traces |
praisonai replay context <id> | Interactive step-through |
praisonai replay flow <id> | Agent flow visualisation |
praisonai replay show <id> | Dump events (non-interactive) |
praisonai replay delete <id> | Delete a trace |
praisonai replay cleanup | Remove old traces |
Interactive navigation
In replay context: Enter/n next, p previous, `g
go to event, q` quit.
Filters
praisonai replay show my-session --agent researcher
praisonai replay show my-session --type agent_start
praisonai replay show my-session --jsonCommon Patterns
In-memory trace during tests
from praisonaiagents import ContextTraceEmitter, ContextListSink
sink = ContextListSink()
emitter = ContextTraceEmitter(sink=sink, session_id="test-session")
emitter.session_start()
# ... agent execution ...
emitter.session_end()
for event in sink.get_events():
print(f"{event.event_type}: {event.agent_name}")Read traces programmatically
from praisonai.replay import ContextTraceReader, ReplayPlayer
reader = ContextTraceReader("my-session")
if reader.exists:
player = ReplayPlayer(reader, use_rich=True)
player.run()Cleanup old traces
praisonai replay cleanup --max-age 7
praisonai replay cleanup --max-size 200 --dry-runBest Practices
Use meaningful session IDs
Include a timestamp or task identifier so traces are easy to find in replay list.
Keep redaction enabled
redact=True (default) strips sensitive data from persisted traces.
Use snapshots sparingly
Full CONTEXT_SNAPSHOT events can be large — prefer message and tool events for routine debugging.
Run cleanup periodically
Use replay cleanup --max-age 7 so trace storage does not grow unbounded on developer machines.