Class AgentTrace

java.lang.Object
ai.redouble.demo.AgentTrace
All Implemented Interfaces:
JobObserver<JobEvent>

public final class AgentTrace extends Object implements JobObserver<JobEvent>
One agent run, streamed to the browser as it happens: an observer on the runtime's message bus, scoped to the run's workflow, that writes every event of the run and of every job under it - the model turns, the tool calls, the sub-agents - as one line of newline-delimited JSON, so a page draws the run as a timeline while it is on. Every line names its job (id, parent, type, display name, the turn it belongs to), so the page rebuilds the tree and shows the calls of one turn side by side. A model turn's completion carries what the model decided - its reasoning, the tool calls it asked for, whether it answered - and what the call cost; a tool's first line carries the arguments the model gave it, paired from the turn's decision by order and name, and its completion carries the result as the tool returned it. The run's totals ride on every terminal line, summed the way the benchmark's rows are. The last line is the answer with the totals, or the failure, written when the run's own terminal event comes through the bus - after every line before it, since the bus delivers in order and the dispatcher publishes the terminal event before it settles the handle. A browser that leaves stops the lines and nothing else: the run goes on to its end on the runtime.

The logic is the demo's, shared by every host: a host supplies how a line reaches the client (sink), how the stream is closed (onEnd), and its own JSON serializer (toJson), so the wire is the framework's while the trace is one. The serializer is the host's rather than the runtime's because the page reads the answer's fields as the host's mapper names them (skillsUsed, not the runtime's snake case).

Since:
0.1 (2026-09-25)
Author:
Andrey Santrosyan
  • Constructor Details

    • AgentTrace

      public AgentTrace(Function<Object,String> toJson, String workflowId, String agentJobId, Consumer<String> sink, Runnable onEnd)
      Parameters:
      toJson - the host's JSON serializer, so the answer's fields are named as the page reads them
      sink - where a rendered line goes, one call per line
      onEnd - closes the stream, called once when the last line is written
  • Method Details

    • getPredicate

      public Predicate<JobEvent> getPredicate()
      Description copied from interface: JobObserver
      Returns a predicate for filtering events at the MessageBus level. Called once during subscription.
      Specified by:
      getPredicate in interface JobObserver<JobEvent>
      Returns:
      predicate to filter events, or null to accept all events of type T
    • observe

      public void observe(JobEvent event)
      Description copied from interface: JobObserver
      Process a job event. Runs in a separate virtual thread. Must handle its own resources and exceptions.
      Specified by:
      observe in interface JobObserver<JobEvent>
      Parameters:
      event - the job event to process
    • fail

      public void fail(Throwable failure)
      The last line when the run itself failed, then the stream closes. The run's own failed event brings it here; a holder of the handle calls it only when no terminal event reached the stream (awaitEnd(Duration)), so a stream never hangs open on a run that ended without one.
    • awaitEnd

      public boolean awaitEnd(Duration wait) throws InterruptedException
      Whether the stream ended within the wait: the run's own terminal event came through and wrote the last line.
      Throws:
      InterruptedException