footprint-explainable-ui 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +203 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +108 -2
- package/dist/index.d.ts +108 -2
- package/dist/index.js +192 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -39,6 +49,7 @@ __export(src_exports, {
|
|
|
39
49
|
StoryNarrative: () => StoryNarrative,
|
|
40
50
|
SubflowTree: () => SubflowTree,
|
|
41
51
|
TimeTravelControls: () => TimeTravelControls,
|
|
52
|
+
TraceViewer: () => TraceViewer,
|
|
42
53
|
buildEntryRangeIndex: () => buildEntryRangeIndex,
|
|
43
54
|
computeRevealedEntryCount: () => computeRevealedEntryCount,
|
|
44
55
|
coolDark: () => coolDark,
|
|
@@ -2350,13 +2361,20 @@ function extractStageTimings(recorders) {
|
|
|
2350
2361
|
const timings = /* @__PURE__ */ new Map();
|
|
2351
2362
|
if (!recorders) return timings;
|
|
2352
2363
|
for (const rec of recorders) {
|
|
2353
|
-
if (rec.name
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2364
|
+
if (rec.name !== "Metrics" || !rec.data || typeof rec.data !== "object") continue;
|
|
2365
|
+
const data = rec.data;
|
|
2366
|
+
if (data.steps) {
|
|
2367
|
+
for (const step of Object.values(data.steps)) {
|
|
2368
|
+
const name = step?.stageName;
|
|
2369
|
+
const d = step?.duration;
|
|
2370
|
+
if (!name || typeof d !== "number" || d <= 0) continue;
|
|
2371
|
+
timings.set(name, Math.round((timings.get(name) ?? 0) + d));
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
if (data.stages) {
|
|
2375
|
+
for (const [stageName, metrics] of Object.entries(data.stages)) {
|
|
2376
|
+
if (typeof metrics.totalDuration === "number" && metrics.totalDuration > 0) {
|
|
2377
|
+
timings.set(stageName, Math.round(metrics.totalDuration));
|
|
2360
2378
|
}
|
|
2361
2379
|
}
|
|
2362
2380
|
}
|
|
@@ -2728,11 +2746,37 @@ function StoryNarrative({
|
|
|
2728
2746
|
|
|
2729
2747
|
// src/components/NarrativePanel/NarrativePanel.tsx
|
|
2730
2748
|
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2749
|
+
function safeJsonStringify(value) {
|
|
2750
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
2751
|
+
const MAX_CHARS = 5e5;
|
|
2752
|
+
try {
|
|
2753
|
+
let text = JSON.stringify(
|
|
2754
|
+
value,
|
|
2755
|
+
(_key, v2) => {
|
|
2756
|
+
if (typeof v2 === "object" && v2 !== null) {
|
|
2757
|
+
if (seen.has(v2)) return "[Circular]";
|
|
2758
|
+
seen.add(v2);
|
|
2759
|
+
}
|
|
2760
|
+
return v2;
|
|
2761
|
+
},
|
|
2762
|
+
2
|
|
2763
|
+
);
|
|
2764
|
+
if (text && text.length > MAX_CHARS) {
|
|
2765
|
+
text = text.slice(0, MAX_CHARS) + `
|
|
2766
|
+
... [truncated at ${MAX_CHARS} chars]`;
|
|
2767
|
+
}
|
|
2768
|
+
return text ?? "undefined";
|
|
2769
|
+
} catch (err) {
|
|
2770
|
+
return `[stringify error: ${err instanceof Error ? err.message : String(err)}]`;
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2731
2773
|
function NarrativePanel({
|
|
2732
2774
|
snapshots,
|
|
2733
2775
|
selectedIndex,
|
|
2734
2776
|
narrativeEntries,
|
|
2735
2777
|
narrative: narrativeProp,
|
|
2778
|
+
runtimeSnapshot,
|
|
2779
|
+
spec,
|
|
2736
2780
|
size = "default",
|
|
2737
2781
|
unstyled = false,
|
|
2738
2782
|
className,
|
|
@@ -2841,8 +2885,53 @@ function NarrativePanel({
|
|
|
2841
2885
|
sections.push("");
|
|
2842
2886
|
}
|
|
2843
2887
|
}
|
|
2888
|
+
if (runtimeSnapshot) {
|
|
2889
|
+
const snap = runtimeSnapshot;
|
|
2890
|
+
if (snap.sharedState !== void 0) {
|
|
2891
|
+
sections.push("\n\n## Final Shared State");
|
|
2892
|
+
sections.push("```json");
|
|
2893
|
+
sections.push(safeJsonStringify(snap.sharedState));
|
|
2894
|
+
sections.push("```");
|
|
2895
|
+
}
|
|
2896
|
+
if (Array.isArray(snap.commitLog) && snap.commitLog.length > 0) {
|
|
2897
|
+
sections.push("\n\n## Commit Log");
|
|
2898
|
+
sections.push(
|
|
2899
|
+
"Each entry = one stage execution's writes to shared state. `rsid` is the runtimeStageId (use it to correlate with narrative + executionTree).\n"
|
|
2900
|
+
);
|
|
2901
|
+
sections.push("```json");
|
|
2902
|
+
sections.push(safeJsonStringify(snap.commitLog));
|
|
2903
|
+
sections.push("```");
|
|
2904
|
+
}
|
|
2905
|
+
if (snap.recorders && typeof snap.recorders === "object") {
|
|
2906
|
+
sections.push("\n\n## Recorder Snapshots");
|
|
2907
|
+
sections.push(
|
|
2908
|
+
"Per-recorder data captured DURING the run (metrics, tokens, instructions, emit events).\n"
|
|
2909
|
+
);
|
|
2910
|
+
sections.push("```json");
|
|
2911
|
+
sections.push(safeJsonStringify(snap.recorders));
|
|
2912
|
+
sections.push("```");
|
|
2913
|
+
}
|
|
2914
|
+
if (snap.subflowResults && typeof snap.subflowResults === "object") {
|
|
2915
|
+
const keys = Object.keys(snap.subflowResults);
|
|
2916
|
+
if (keys.length > 0) {
|
|
2917
|
+
sections.push("\n\n## Subflow Results");
|
|
2918
|
+
sections.push("```json");
|
|
2919
|
+
sections.push(safeJsonStringify(snap.subflowResults));
|
|
2920
|
+
sections.push("```");
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
if (spec) {
|
|
2925
|
+
sections.push("\n\n## Flowchart Spec (topology)");
|
|
2926
|
+
sections.push(
|
|
2927
|
+
"Node + edge metadata for the chart that ran. Useful for 'where in the graph did step N happen?' questions.\n"
|
|
2928
|
+
);
|
|
2929
|
+
sections.push("```json");
|
|
2930
|
+
sections.push(safeJsonStringify(spec));
|
|
2931
|
+
sections.push("```");
|
|
2932
|
+
}
|
|
2844
2933
|
return sections.join("\n");
|
|
2845
|
-
}, [narrativeEntries, narrative]);
|
|
2934
|
+
}, [narrativeEntries, narrative, runtimeSnapshot, spec]);
|
|
2846
2935
|
const handleCopy = (0, import_react12.useCallback)(async () => {
|
|
2847
2936
|
const text = buildLLMNarrative();
|
|
2848
2937
|
await navigator.clipboard.writeText(text);
|
|
@@ -4878,6 +4967,7 @@ var RightPanel = (0, import_react24.memo)(function RightPanel2({
|
|
|
4878
4967
|
snapshots,
|
|
4879
4968
|
selectedIndex,
|
|
4880
4969
|
runtimeSnapshot,
|
|
4970
|
+
spec,
|
|
4881
4971
|
activeTab,
|
|
4882
4972
|
allTabs,
|
|
4883
4973
|
activeNarrativeEntries,
|
|
@@ -4924,7 +5014,7 @@ var RightPanel = (0, import_react24.memo)(function RightPanel2({
|
|
|
4924
5014
|
id: tab.id,
|
|
4925
5015
|
name: insightName(tab.name),
|
|
4926
5016
|
render: () => {
|
|
4927
|
-
if (tab.id === "narrative") return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(NarrativePanel, { snapshots, selectedIndex, narrativeEntries: activeNarrativeEntries, narrative: activeNarrative, size, style: { height: "100%" } });
|
|
5017
|
+
if (tab.id === "narrative") return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(NarrativePanel, { snapshots, selectedIndex, narrativeEntries: activeNarrativeEntries, narrative: activeNarrative, runtimeSnapshot, spec, size, style: { height: "100%" } });
|
|
4928
5018
|
const customView = recorderViews?.find((v2) => v2.id === tab.id);
|
|
4929
5019
|
if (customView?.render) return customView.render({ snapshots, selectedIndex });
|
|
4930
5020
|
const autoView = autoRecorderViews.find((v2) => v2.id === tab.id);
|
|
@@ -5339,6 +5429,7 @@ function ExplainableShell({
|
|
|
5339
5429
|
snapshots: activeSnapshots,
|
|
5340
5430
|
selectedIndex: safeIdx,
|
|
5341
5431
|
runtimeSnapshot,
|
|
5432
|
+
spec,
|
|
5342
5433
|
activeTab,
|
|
5343
5434
|
allTabs,
|
|
5344
5435
|
activeNarrativeEntries,
|
|
@@ -5367,6 +5458,108 @@ function ExplainableShell({
|
|
|
5367
5458
|
}
|
|
5368
5459
|
);
|
|
5369
5460
|
}
|
|
5461
|
+
|
|
5462
|
+
// src/components/TraceViewer/TraceViewer.tsx
|
|
5463
|
+
var React = __toESM(require("react"), 1);
|
|
5464
|
+
var import_react25 = require("react");
|
|
5465
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
5466
|
+
function parseTrace(input) {
|
|
5467
|
+
if (input == null) {
|
|
5468
|
+
return {
|
|
5469
|
+
ok: false,
|
|
5470
|
+
error: { kind: "invalid-json", message: "No trace provided." }
|
|
5471
|
+
};
|
|
5472
|
+
}
|
|
5473
|
+
let candidate = input;
|
|
5474
|
+
if (typeof input === "string") {
|
|
5475
|
+
if (!input.trim()) {
|
|
5476
|
+
return { ok: false, error: { kind: "invalid-json", message: "Empty input." } };
|
|
5477
|
+
}
|
|
5478
|
+
try {
|
|
5479
|
+
candidate = JSON.parse(input);
|
|
5480
|
+
} catch (err) {
|
|
5481
|
+
return {
|
|
5482
|
+
ok: false,
|
|
5483
|
+
error: { kind: "invalid-json", message: err.message }
|
|
5484
|
+
};
|
|
5485
|
+
}
|
|
5486
|
+
}
|
|
5487
|
+
if (!candidate || typeof candidate !== "object") {
|
|
5488
|
+
return {
|
|
5489
|
+
ok: false,
|
|
5490
|
+
error: { kind: "not-object", message: "Trace must be a JSON object." }
|
|
5491
|
+
};
|
|
5492
|
+
}
|
|
5493
|
+
const t = candidate;
|
|
5494
|
+
if (typeof t.schemaVersion !== "number") {
|
|
5495
|
+
return {
|
|
5496
|
+
ok: false,
|
|
5497
|
+
error: {
|
|
5498
|
+
kind: "missing-version",
|
|
5499
|
+
message: "Trace is missing required field `schemaVersion`. Did you pass an exportTrace() output?"
|
|
5500
|
+
}
|
|
5501
|
+
};
|
|
5502
|
+
}
|
|
5503
|
+
if (t.schemaVersion !== 1) {
|
|
5504
|
+
return {
|
|
5505
|
+
ok: false,
|
|
5506
|
+
error: {
|
|
5507
|
+
kind: "unsupported-version",
|
|
5508
|
+
message: `Unsupported schemaVersion ${t.schemaVersion}. This TraceViewer renders schemaVersion 1.`,
|
|
5509
|
+
version: t.schemaVersion
|
|
5510
|
+
}
|
|
5511
|
+
};
|
|
5512
|
+
}
|
|
5513
|
+
return { ok: true, trace: t };
|
|
5514
|
+
}
|
|
5515
|
+
var DEFAULT_TABS = ["explainable"];
|
|
5516
|
+
function TraceViewer({
|
|
5517
|
+
trace,
|
|
5518
|
+
onError,
|
|
5519
|
+
fallback,
|
|
5520
|
+
tabs = DEFAULT_TABS,
|
|
5521
|
+
defaultTab = "narrative",
|
|
5522
|
+
hideTabs,
|
|
5523
|
+
size,
|
|
5524
|
+
panelLabels,
|
|
5525
|
+
recorderViews,
|
|
5526
|
+
renderFlowchart
|
|
5527
|
+
}) {
|
|
5528
|
+
const parsed = (0, import_react25.useMemo)(() => parseTrace(trace), [trace]);
|
|
5529
|
+
React.useEffect(() => {
|
|
5530
|
+
if (!parsed.ok && onError) onError(parsed.error);
|
|
5531
|
+
}, [parsed, onError]);
|
|
5532
|
+
const snapshots = (0, import_react25.useMemo)(() => {
|
|
5533
|
+
if (!parsed.ok || !parsed.trace.snapshot) return [];
|
|
5534
|
+
try {
|
|
5535
|
+
return toVisualizationSnapshots(
|
|
5536
|
+
parsed.trace.snapshot,
|
|
5537
|
+
parsed.trace.narrativeEntries ?? void 0
|
|
5538
|
+
);
|
|
5539
|
+
} catch {
|
|
5540
|
+
return [];
|
|
5541
|
+
}
|
|
5542
|
+
}, [parsed]);
|
|
5543
|
+
if (!parsed.ok || snapshots.length === 0) {
|
|
5544
|
+
return fallback ?? null;
|
|
5545
|
+
}
|
|
5546
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
5547
|
+
ExplainableShell,
|
|
5548
|
+
{
|
|
5549
|
+
snapshots,
|
|
5550
|
+
spec: parsed.trace.spec,
|
|
5551
|
+
narrative: parsed.trace.narrative,
|
|
5552
|
+
narrativeEntries: parsed.trace.narrativeEntries,
|
|
5553
|
+
tabs,
|
|
5554
|
+
defaultTab,
|
|
5555
|
+
hideTabs,
|
|
5556
|
+
size,
|
|
5557
|
+
panelLabels,
|
|
5558
|
+
recorderViews,
|
|
5559
|
+
renderFlowchart
|
|
5560
|
+
}
|
|
5561
|
+
);
|
|
5562
|
+
}
|
|
5370
5563
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5371
5564
|
0 && (module.exports = {
|
|
5372
5565
|
CompactTimeline,
|
|
@@ -5388,6 +5581,7 @@ function ExplainableShell({
|
|
|
5388
5581
|
StoryNarrative,
|
|
5389
5582
|
SubflowTree,
|
|
5390
5583
|
TimeTravelControls,
|
|
5584
|
+
TraceViewer,
|
|
5391
5585
|
buildEntryRangeIndex,
|
|
5392
5586
|
computeRevealedEntryCount,
|
|
5393
5587
|
coolDark,
|