Skip to content

Live data

The elements draw what they are given; @contraagent/api gets it: a typed client, the live feeds and a store that folds a run’s feed into one state.

The store does the data work and the element draws it:

docs/examples/journal.ts
// A run's journal, live, with the store doing the data work: the store folds
// the run feed into one typed state, the element draws it.
import { MonitorStore, isBad } from '@contraagent/api';
import '@contraagent/ui/journal-table';
export function showJournal(host: HTMLElement, run: string, openTask: (key: string) => void): () => void {
const store = new MonitorStore({ baseUrl: 'http://127.0.0.1:8787' });
const table = document.createElement('ca-journal-table');
host.replaceChildren(table);
// Every change: the newest state, already typed (`RunState`).
const unsubscribe = store.subscribe((s) => {
table.rows = s.state.journal;
table.plan = s.state.plan;
table.fresh = s.fresh;
});
// Rows that arrive after the replay: tasks that just finished.
const unwatch = store.onNewRow((row) => {
if (isBad(row)) console.warn(`${row.key} ended ${row.stop}: ${row.reason ?? ''}`);
});
// The element asks; the page answers.
table.addEventListener('ca-filter', (e) => (table.stop = e.detail.stop ?? ''));
table.addEventListener('ca-open-task', (e) => openTask(e.detail.key));
void store.start();
store.selectRun(run);
return () => {
unsubscribe();
unwatch();
store.stop();
};
}

<ca-transcript> tails a task’s transcript itself when it is given run and stream; the page decides what a reader’s request means:

docs/examples/live-transcript.ts
// One task's transcript, tailed live, in a page of your own.
//
// The element renders; the page decides what a reader's request means. Here a
// round picked in the transcript is simply shown.
import { createMonitorClient } from '@contraagent/api';
import '@contraagent/ui/transcript';
/** Where `contraagent monitor` runs (start it with `--cors-origin <this page's origin>`). */
const MONITOR = 'http://127.0.0.1:8787';
export function showTranscript(host: HTMLElement, run: string, key: string): void {
const t = document.createElement('ca-transcript');
t.client = createMonitorClient({ baseUrl: MONITOR }); // for "load earlier"
t.baseUrl = MONITOR; // the live feed
t.run = run;
t.stream = key;
t.live = true;
t.addEventListener('ca-navigate', (e) => {
if (e.detail.round !== undefined) t.round = e.detail.round;
});
host.replaceChildren(t);
}