const state = { manifest: null, graph: null, trace: null, report: null, filter: "all", }; const ids = { manifestUrl: document.getElementById("manifest-url"), manifestUrlLoad: document.getElementById("manifest-url-load"), manifestFile: document.getElementById("manifest-file"), graphFile: document.getElementById("graph-file"), traceFile: document.getElementById("trace-file"), reportFile: document.getElementById("report-file"), summaryStatus: document.getElementById("summary-status"), graphStatus: document.getElementById("graph-status"), traceStatus: document.getElementById("trace-status"), stats: document.getElementById("stats"), analysisMetrics: document.getElementById("analysis-metrics"), nodeChips: document.getElementById("node-chips"), edgeList: document.getElementById("edge-list"), traceList: document.getElementById("trace-list"), traceTemplate: document.getElementById("trace-card-template"), filterButtons: Array.from(document.querySelectorAll(".filter")), }; ids.manifestUrlLoad.addEventListener("click", () => loadManifestFromUrl()); ids.manifestUrl.addEventListener("keydown", (event) => { if (event.key === "Enter") { event.preventDefault(); loadManifestFromUrl(); } }); ids.manifestFile.addEventListener("change", (event) => loadJsonFile(event, "manifest")); ids.graphFile.addEventListener("change", (event) => loadJsonFile(event, "graph")); ids.traceFile.addEventListener("change", (event) => loadJsonFile(event, "trace")); ids.reportFile.addEventListener("change", (event) => loadJsonFile(event, "report")); for (const button of ids.filterButtons) { button.addEventListener("click", () => { state.filter = button.dataset.filter ?? "all"; syncFilterButtons(); renderTrace(); }); } syncFilterButtons(); renderSummary(); renderGraph(); renderTrace(); async function loadJsonFile(event, kind) { const input = event.currentTarget; const file = input.files?.[0]; if (!file) { return; } try { const text = await file.text(); const parsed = JSON.parse(text); if (kind === "manifest") { validateManifest(parsed); state.manifest = parsed; ids.summaryStatus.textContent = `Manifest loaded: schema ${parsed.schema_version}. ` + "For full auto-load, use the manifest URL field while serving the artifacts over HTTP."; return; } const envelope = validateEnvelope(parsed, expectedArtifactType(kind)); state[kind] = envelope.payload; if (kind === "graph") { renderGraph(); } else if (kind === "trace") { renderTrace(); } else if (kind === "report") { renderSummary(); } } catch (error) { const message = error instanceof Error ? error.message : String(error); window.alert(`Failed to load ${kind} JSON: ${message}`); } finally { input.value = ""; } } async function loadManifestFromUrl() { const manifestUrl = ids.manifestUrl.value.trim(); if (!manifestUrl) { window.alert("Enter a manifest URL first."); return; } try { const manifestResponse = await fetch(manifestUrl); if (!manifestResponse.ok) { throw new Error(`Manifest request failed with status ${manifestResponse.status}`); } const manifest = await manifestResponse.json(); validateManifest(manifest); state.manifest = manifest; const baseUrl = new URL(manifestUrl, window.location.href); const parent = new URL("./", baseUrl); const artifactMap = Object.fromEntries( manifest.artifacts.map((artifact) => [artifact.artifact_type, artifact.file_name]) ); const graph = await fetchArtifactJson(parent, artifactMap.graph_schema, "graph_schema"); const trace = await fetchArtifactJson( parent, artifactMap.execution_trace, "execution_trace" ); const report = await fetchArtifactJson(parent, artifactMap.run_report, "run_report"); state.graph = graph.payload; state.trace = trace.payload; state.report = report.payload; ids.summaryStatus.textContent = `Loaded manifest and artifacts from ${baseUrl.origin}.`; renderGraph(); renderTrace(); renderSummary(); } catch (error) { const message = error instanceof Error ? error.message : String(error); window.alert(`Failed to load manifest URL: ${message}`); } } async function fetchArtifactJson(baseUrl, fileName, expectedType) { if (!fileName) { throw new Error(`Manifest does not include ${expectedType}`); } const artifactUrl = new URL(fileName, baseUrl); const response = await fetch(artifactUrl); if (!response.ok) { throw new Error( `${expectedType} request failed with status ${response.status}` ); } const json = await response.json(); return validateEnvelope(json, expectedType); } function expectedArtifactType(kind) { if (kind === "graph") return "graph_schema"; if (kind === "trace") return "execution_trace"; if (kind === "report") return "run_report"; return kind; } function validateEnvelope(value, expectedType) { if ( !value || typeof value !== "object" || typeof value.artifact_type !== "string" || typeof value.schema_version !== "string" || !("payload" in value) || typeof value.metadata !== "object" ) { throw new Error("Invalid artifact envelope"); } if (value.artifact_type !== expectedType) { throw new Error( `Unexpected artifact type: expected ${expectedType}, got ${value.artifact_type}` ); } return value; } function validateManifest(value) { if ( !value || typeof value !== "object" || typeof value.schema_version !== "string" || !Array.isArray(value.artifacts) ) { throw new Error("Invalid artifact manifest"); } } function syncFilterButtons() { for (const button of ids.filterButtons) { const active = button.dataset.filter === state.filter; button.classList.toggle("is-active", active); } } function renderSummary() { ids.stats.replaceChildren(); ids.analysisMetrics.replaceChildren(); if (!state.report) { ids.summaryStatus.textContent = "Load a report to populate metrics."; return; } ids.summaryStatus.textContent = "Report loaded."; appendStat("Accepted", state.report.accepted_count, ids.stats); appendStat("Attempts", state.report.attempt_count, ids.stats); appendStat( "Avg / Accept", formatNumber(state.report.average_attempts_per_accept), ids.stats ); appendStat("Seconds", formatNumber(state.report.total_seconds), ids.stats); const analysis = state.report.sequence_analysis ?? {}; if (Object.keys(analysis).length === 0) { const empty = document.createElement("div"); empty.className = "empty-note"; empty.textContent = "No sequence analysis in this report."; ids.analysisMetrics.append(empty); return; } for (const [key, value] of Object.entries(analysis)) { appendMetric(key, value, ids.analysisMetrics); } } function renderGraph() { ids.nodeChips.replaceChildren(); ids.edgeList.replaceChildren(); if (!state.graph) { ids.graphStatus.textContent = "Load a graph schema to inspect node wiring."; return; } ids.graphStatus.textContent = `${state.graph.nodes.length} nodes, ${state.graph.edges.length} edges.`; for (const node of state.graph.nodes) { const chip = document.createElement("article"); chip.className = "chip"; chip.innerHTML = `

${escapeHtml(node.node_type)}

${escapeHtml(node.node_id)}

${escapeHtml(node.input_names.join(", ") || "no inputs")} -> ${escapeHtml( node.output_names.join(", ") || "no outputs" )}

`; ids.nodeChips.append(chip); } for (const edge of state.graph.edges) { const item = document.createElement("li"); item.innerHTML = `${escapeHtml(edge.source_node_id)}.${escapeHtml( edge.source_output )} -> ${escapeHtml(edge.target_node_id)}.${escapeHtml( edge.target_input )}`; ids.edgeList.append(item); } } function renderTrace() { ids.traceList.replaceChildren(); if (!state.trace) { ids.traceStatus.textContent = "Load a trace to inspect candidate-by-candidate behavior."; return; } const attempts = state.trace.attempts ?? []; const filtered = attempts.filter((attempt) => { if (state.filter === "accepted") { return attempt.accepted; } if (state.filter === "rejected") { return !attempt.accepted; } return true; }); ids.traceStatus.textContent = `${filtered.length} shown of ${attempts.length} attempts.`; filtered.forEach((trace, index) => { const fragment = ids.traceTemplate.content.cloneNode(true); const card = fragment.querySelector(".trace-card"); const traceLabel = fragment.querySelector(".trace-label"); const traceTitle = fragment.querySelector(".trace-title"); const badge = fragment.querySelector(".badge"); const metrics = fragment.querySelector(".metric-list"); const metadata = fragment.querySelector(".json-block"); const transition = fragment.querySelector(".transition-block"); card.dataset.accepted = String(trace.accepted); traceLabel.textContent = `Attempt ${index + 1}`; traceTitle.textContent = `Candidate ${JSON.stringify(trace.candidate)}`; badge.textContent = trace.accepted ? "Accepted" : "Rejected"; badge.classList.toggle("accepted", trace.accepted); badge.classList.toggle("rejected", !trace.accepted); appendMetric("elapsed_seconds", trace.elapsed_seconds, metrics); const score = trace.metadata?.critique?.outputs?.[0] ?? trace.metadata?.decision?.accepted; if (score !== undefined) { appendMetric("signal", score, metrics); } metadata.textContent = JSON.stringify(trace.metadata, null, 2); transition.textContent = JSON.stringify( { previous_state: trace.previous_state, next_state: trace.next_state, }, null, 2 ); ids.traceList.append(fragment); }); } function appendStat(label, value, container) { const article = document.createElement("article"); article.className = "stat-card"; article.innerHTML = `

${escapeHtml(label)}

${escapeHtml(String(value))}

`; container.append(article); } function appendMetric(label, value, container) { const dt = document.createElement("dt"); dt.textContent = label; const dd = document.createElement("dd"); dd.textContent = typeof value === "number" ? formatNumber(value) : JSON.stringify(value); container.append(dt, dd); } function formatNumber(value) { if (typeof value !== "number") { return String(value); } if (Number.isInteger(value)) { return String(value); } return value.toFixed(6).replace(/0+$/, "").replace(/\.$/, ""); } function escapeHtml(value) { return value .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">"); }