Corail includes an in-process event bus for runtime observability. Components emit events as they execute; subscribers react asynchronously. This is a lightweight pub/sub for a single agent Pod, not a distributed message broker.
Emitted around each round of the agent loop. Useful for observability,
stream UX, and MLflow child spans.
Event
Emitted when
turn.started
A new reasoning round begins (includes round index)
turn.ended
The round ends. Only emitted at the terminal exit of the loop, and carries the real stop_reason (one of StopReason: end_turn, max_rounds, token_budget, tool_error, guard_blocked, user_aborted).
TURN_ENDED -- one final event carrying the StopReason
MESSAGE_RESPONSE -- final response ready
The MLflow tracing listener (corail/tracing/mlflow_listener.py)
subscribes to TOOL_CALLED / TOOL_RESULT / TOOL_ERROR and collects
them into contextvar storage. The channel layer then turns each
collected event into a tool:<name> child span inside the
@mlflow.trace-decorated chat handler, so every request produces a
full trace tree without requiring strategies to know about MLflow
directly.