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 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 === "Metrics" && rec.data && typeof rec.data === "object") {
2354
- const data = rec.data;
2355
- if (data.stages) {
2356
- for (const [stageName, metrics] of Object.entries(data.stages)) {
2357
- if (typeof metrics.totalDuration === "number" && metrics.totalDuration > 0) {
2358
- timings.set(stageName, Math.round(metrics.totalDuration));
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,