Files
portal/docs/observer/dashboard-core.js
T
2026-05-19 16:23:46 +03:00

63 lines
2.1 KiB
JavaScript

// Pure logic for the Brain Dashboard. Browser-safe ES module (no node: APIs)
// so it loads both in the browser and under Vitest's node environment.
export function normalizeEpisode(raw) {
const v2 = raw.schema_version === 2;
const pr = raw.primary_rationale || {};
const events = Array.isArray(raw.events) ? raw.events : [];
const tools = {};
for (const ev of events) {
if (ev.kind === 'tool_summary' && ev.counts) {
for (const [k, n] of Object.entries(ev.counts)) tools[k] = (tools[k] || 0) + n;
}
}
const started = raw.timestamps?.started_at || null;
const ended = raw.timestamps?.ended_at || null;
return {
schemaVersion: v2 ? 2 : 1,
taskId: raw.task_id || null,
taskRef: raw.task_ref || raw.task_id || null,
startedAt: started,
endedAt: ended,
durationMs: started && ended ? Date.parse(ended) - Date.parse(started) : null,
pathType: raw.path_type || null,
outcome: raw.outcome || 'unknown',
promptSignal: v2 ? raw.prompt_signal || null : null,
decisionProvenance: v2 ? raw.decision_provenance || null : null,
environment: v2 ? raw.environment || null : null,
taskSize: v2 ? raw.task_size || null : null,
taskClassification: pr.task_classification || null,
nodeChosen: pr.node_chosen || null,
hardFloor: pr.hard_floor || { invoked: false, rules: [] },
skills: events.filter((e) => e.kind === 'skill_invoked').map((e) => e.skill),
tools,
errorCount: events.filter((e) => e.kind === 'error').length,
retryCount: events.filter((e) => e.kind === 'retry').length,
interruptCount: events.filter((e) => e.kind === 'interrupt').length,
events,
raw,
};
}
export function parseEpisodes(text) {
const episodes = [];
let skipped = 0;
for (const line of String(text).split('\n')) {
const trimmed = line.trim();
if (!trimmed) continue;
let raw;
try {
raw = JSON.parse(trimmed);
} catch {
skipped++;
continue;
}
if (!raw || typeof raw !== 'object' || raw.observer_error) {
skipped++;
continue;
}
episodes.push(normalizeEpisode(raw));
}
return { episodes, skipped };
}