Skip to content

Run viewer

Record runs to a folder and browse them on 127.0.0.1 (agent-adapter ui), or chat with an agent there. Guides: See your runs, Chat with your agent, See your evals.

agent_adapter.viewer

Run viewer: record runs to JSONL files, browse them and chat locally (agent-adapter ui).

DEFAULT_FOLDER = '.agent_adapter/runs' module-attribute

LOOPBACK = '127.0.0.1' module-attribute

ApprovalDesk

Decides tool approvals in a SQLiteApprovalStore file; it never runs a tool.

The app's own executor.resume(approval_id) later runs the call with this decision.

Raises:

Type Description
ConfigError

no database at path, or an empty or too long reviewer.

decide(approval_id, *, approved, reason='')

Record approve or deny as this desk's reviewer; only a pending tool record.

Raises:

Type Description
ApprovalNotFound

unknown id.

ApprovalAlreadyDecided

the record is no longer pending (here or by a race).

ToolUsageError

a flow-node record, or one the HTTP tool server parked.

pending()

Pending records, newest first, masked, each with similar past decisions (advice).

Recorder

Writes events under folder, one segment file per run and process (append-only).

emit only queues: a background thread writes, in batches, so the event loop never waits on the disk. A full queue drops events (counted, logged). Queued events are written at flush, close and interpreter exit. Tool and LLM content keys are left out unless capture_content; secret-named values are always masked. Past keep_runs the oldest ended runs are deleted; a run stops recording after max_events_per_run events.

Raises:

Type Description
ConfigError

a bad limit, or a folder that cannot be made.

wants_confirm_content property

Also asks for confirm tools' results (opt-in on top of capture_content).

wants_content property

Asks native calls for their content (arguments, results, messages, flow state).

close(timeout=5.0)

Write what is queued and stop the writer; later events start a new one.

flush(timeout=5.0)

Wait until every queued event is written; False on timeout.

registry()

The registry whose catalogue each run file starts with.

stop(timeout=5.0)

Detach from every executor record() attached it to, write what is queued, and stop.

Later events are ignored. False when the queue was not written within timeout.

take_flow_graph(run_id, flow, graph)

Write a flow's graph once into its run's file (FlowRunner calls this).

RunFolder

A runs folder, or a single run file, read again on each refresh from where it stopped.

Raises:

Type Description
ConfigError

target is a file that is not a run segment.

tags_folder property

Where the run tag sidecars live: the runs folder, or the run file's folder.

detail(key, since=0, *, paged=True)

One run: summary, graphs, tools, spans with lanes, and events since (paged).

None for an unknown run.

refresh()

Pick up new runs and new lines; deleted (rotated) runs are dropped.

Raises:

Type Description
OSError

the folder cannot be listed.

search_folds()

Copies of the search folds of each run's segments, by run key (safe to read later).

summaries()

One summary per run, newest first.

ViewerServer

Bases: ThreadingHTTPServer

A ThreadingHTTPServer holding the runs folder, the approval desk and its secrets.

token travels in the URL fragment of url (never sent to a server, a log or a Referer); the page keeps it in sessionStorage and sends it as X-AA-Token on every /api/ call. csrf guards decisions on top. Both are new on every start. The HTML shell and its static files hold no secret and are public.

url property

The address to open: it carries the access token, so keep it private.

server_close()

Close the socket; with chat on, stop running turns and the chat loop first.

trusted_hosts()

Host header values that name this server (DNS-rebinding guard).

assign_lanes(spans)

Give each span the lowest free lane at its start (greedy interval colouring).

build_spans(events)

One span per call (tool, LLM, node, flow, compression), in start order, with lanes.

check_host(host)

Refuse any bind address but the IPv4 loopback.

Raises:

Type Description
ConfigError

host is not 127.0.0.1.

import_otlp(source, folder)

Write one run file per trace of the OTLP JSON file source into folder; run keys back.

Importing the same file again rewrites the same run files.

Raises:

Type Description
ConfigError

source is too big, not JSON, not an OTLP trace export, or holds too many spans or traces.

OSError

source cannot be read or folder cannot be written.

make_server(target, *, host=LOOPBACK, port=DEFAULT_PORT, approvals=None, reviewer='', chat=None, evals=DEFAULT_EVALS_FOLDER, cases_dir=DEFAULT_CHAT_DIR)

A bound, not yet serving, viewer server (port=0 picks a free port); chat turns chat on.

evals is the folder of saved eval reports the Evals view lists; runs saved as eval cases go to the chat's eval_cases.jsonl, or without chat to the one in cases_dir.

Raises:

Type Description
ConfigError

a non-loopback host, a bad target, or a bad approvals database/reviewer.

OSError

the port is taken.

record(executor=None, *, folder=DEFAULT_FOLDER, capture_content=False, keep_runs=200, source='', capture_confirm_content=False)

Record every run of executor under folder.

With no executor it follows the default executor, also after aa.configure replaces it. Calling it again for the same target and folder returns the recorder already attached; recorder.stop() detaches it again.

Raises:

Type Description
ConfigError

a bad keep_runs, a folder that cannot be made, or a second call for the same target and folder with other options.

serve(agent=None, *, model=None, registry=None, executor=None, folder=DEFAULT_FOLDER, port=DEFAULT_PORT, open_browser=True, system='', max_steps=8, turn_timeout=300.0, approval_timeout=600.0, reviewer='local', chat_dir=DEFAULT_CHAT_DIR, stream=True, evals=DEFAULT_EVALS_FOLDER, user_id='', memory=None, memory_save='none', memory_every=1, recall_k=5, out=None)

Chat with agent (or the built-in loop over model and registry) in the viewer.

Blocks until Ctrl+C. Turns are recorded into folder, so the Runs view shows them. open_browser opens a one-use launch link (valid 60 s); stream=False makes the built-in loop call generate (so an LLM response cache applies). The Evals view lists the reports saved in evals. user_id owns the chats; with memory, turns recall that user's records across chats and memory_save ("summary", "facts" or the default "none") saves new ones every memory_every turns.

Raises:

Type Description
ConfigError

neither or both of agent and model, or a bad option.

OSError

the port is taken.

Also exported here, documented under the canonical path: Attachment, ChatAgent, ChatMessage, ChatSession.

agent_adapter.viewer.chat

Chat with an agent in the viewer: the contract types an agent receives and returns.

chat_agent_task(agent, executor)

fn(task, ctx) that runs agent(message, session) in the calling run; chunks are joined.

Also exported here, documented under the canonical path: Attachment, ChatAgent, ChatMessage, ChatReply, ChatSession.