Message Flow

Follow one message from the dashboard to the reply, through every step and every hook point, in the order the code runs them.

This trace follows one message to a client’s agent. The agent saves a preference to memory, hands two tasks to helper agents, and emails the result after you approve it. Each row is one step. Diamonds are hook points, squares are database writes, and a ringed dot is where two paths meet. Select a row to see what happens, where in the code it happens, and what a hook there can do.

AcmeManagerclient:acme53 steps · 23 at hook points

The message: Remember that Acme prefers Tuesday calls. Find what we know about their competitors, draft a kickoff agenda, and email it to Dana.

Hooks in this trace

In order, for the parent turn:

  1. pre_gateway_dispatch, post_gateway_admission: the Dispatcher, before a turn exists.
  2. on_session_start, pre_llm_call: once, before the loop.
  3. Per model call: pre_api_request, then post_api_request. Three calls here.
  4. Per tool call: pre_tool_call, then post_tool_call and transform_tool_result. A write tool adds pre_approval_request and post_approval_response between them.
  5. Per child agent: subagent_start and subagent_stop, from inside delegate_task.
  6. transform_llm_output, post_llm_call, on_session_end: once, at the end.

Each child runs a full turn of its own at depth 1, so it fires its own on_session_start, pre_llm_call, model-call, tool-call and on_session_end hooks. The trace folds those into the child lanes. The dashboard shows them all as live events, with turn.depth telling parent and child apart.

What the dashboard sees

The live feed sends twelve of these hook points to every open dashboard as {"type": "event"} messages: on_session_start, pre_api_request, post_api_request, api_request_error, post_tool_call, pre_approval_request, post_approval_response, subagent_start, subagent_stop, post_llm_call, agent_loop_stopped and on_session_end. The Dispatcher adds one more, reply, when a turn finishes.

This is what a real cos serve --mock session sent for delegate: plan dinners in a new session, recorded over the WebSocket. Each line shows turn.depth and the event’s kind; (reply) marks the {"type": "reply"} message.

Live events from a real session
0 on_session_start
0 pre_api_request
0 post_api_request
1 subagent_start
1 on_session_start
1 pre_api_request
1 post_api_request
1 post_llm_call
1 on_session_end
1 subagent_stop
0 post_tool_call
0 pre_api_request
0 post_api_request
0 post_llm_call
(reply)
0 on_session_end
0 reply

The reply travels on its own channel, so here it arrived before the turn’s last two events. Don’t rely on on_session_end coming first.

Where to go next

Edit this page on GitHub

Esc