ExAthena.Web.Live.ChatLive (ExAthena v0.19.0)

Copy Markdown View Source

Summary

Functions

What the currently-running worker is doing, for the main streaming line.

Populate the sidebar's session list for the current working directory.

Reopen an assistant turn whose run never finished.

The map persisted for a session.

Cheap fingerprint of everything save_session/1 persists that can change mid-run. Compared against the last saved value so the tick only writes when the session actually moved.

The orchestrator snapshot stored with a session, if any.

Split a run's token use between the orchestrator and its workers.

Append msg, or replace the existing message with the same id.

Functions

active_worker_action(_)

@spec active_worker_action(map() | nil) :: String.t() | nil

What the currently-running worker is doing, for the main streaming line.

While a worker runs — often many minutes — the orchestrator's own action is just "running spawn_agent…", which says nothing. The useful detail lives on AgentInfo but was only rendered in the Overview tab, so following a run meant switching tabs or reading the log.

The DEEPEST running agent is the informative one: a parent that spawned a child is only waiting on it.

apply_event(socket, arg2)

assign_session_list(socket, lister, visibility \\ :auto)

@spec assign_session_list(
  Phoenix.LiveView.Socket.t(),
  (String.t() | nil -> [map()]),
  :auto | :keep
) :: Phoenix.LiveView.Socket.t()

Populate the sidebar's session list for the current working directory.

The list used to be built ONLY by open_cwd and toggle_sessions, so opening a session by URL (or reloading the page on one) left sessions at its mount default of [] — an empty sidebar that had simply never been asked to build itself.

visibility is :auto on a first load (open the panel when there is something to show) or :keep on a refresh, which must never open a panel the user closed nor close one they opened. lister takes the cwd and returns the headers (injected so this is testable without the filesystem).

restore_open_turn(data)

@spec restore_open_turn(map()) :: map()

Reopen an assistant turn whose run never finished.

Details are stamped with the assistant message's id from the first event onward, but the message itself was only appended when the run COMPLETED. A run that was killed, crashed, or is still in flight therefore leaves its details parented to a message that does not exist — and message_items/2 matches on message_id, so every one of them renders nowhere. A session holding 118 saved entries opened as a blank screen.

This synthesises the missing message from the details themselves, so an interrupted run shows the work it did instead of nothing.

session_payload(a)

@spec session_payload(map()) :: map()

The map persisted for a session.

Includes the orchestrator snapshot: the Overview tab is fed by the Coordinator, which lives only in memory and is only re-subscribed while a run is still attachable. Without this, reloading the page after a run ended (or after a server restart) showed a blank Overview even though the whole run was on disk.

session_signature(assigns)

@spec session_signature(map()) :: integer()

Cheap fingerprint of everything save_session/1 persists that can change mid-run. Compared against the last saved value so the tick only writes when the session actually moved.

Hashes the whole structure rather than counting entries: content and thinking deltas EXTEND an existing details_stream entry instead of prepending a new one, so a length check would miss a streaming answer.

stored_orchestrator(data)

@spec stored_orchestrator(map()) :: map() | nil

The orchestrator snapshot stored with a session, if any.

token_summary(_)

@spec token_summary(map() | nil) :: map() | nil

Split a run's token use between the orchestrator and its workers.

Per-agent totals are already tracked on AgentInfo and shown per row, but nothing aggregated them. The split is the interesting number: the orchestrator's context stays small by design (workers return summaries, not transcripts), so a large worker total against a small orchestrator total is the architecture behaving, not a leak.

Nested subagents are counted with the workers — the agent list is flat and every depth carries its own usage.

upsert_message(messages, msg)

@spec upsert_message([map()], map()) :: [map()]

Append msg, or replace the existing message with the same id.

restore_open_turn/1 may already have put a placeholder for the in-flight turn into the list (a reload mid-run), and a blind append would then leave two messages sharing an id — a duplicate DOM id, which LiveView raises on.