footprint-explainable-ui 0.13.3 → 0.14.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 +119 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -2
- package/dist/index.d.ts +73 -2
- package/dist/index.js +116 -59
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -35,10 +35,13 @@ __export(src_exports, {
|
|
|
35
35
|
StoryNarrative: () => StoryNarrative,
|
|
36
36
|
SubflowTree: () => SubflowTree,
|
|
37
37
|
TimeTravelControls: () => TimeTravelControls,
|
|
38
|
+
buildEntryRangeIndex: () => buildEntryRangeIndex,
|
|
39
|
+
computeRevealedEntryCount: () => computeRevealedEntryCount,
|
|
38
40
|
coolDark: () => coolDark,
|
|
39
41
|
coolLight: () => coolLight,
|
|
40
42
|
createSnapshots: () => createSnapshots,
|
|
41
43
|
defaultTokens: () => defaultTokens,
|
|
44
|
+
extractSubflowNarrative: () => extractSubflowNarrative,
|
|
42
45
|
rawDefaults: () => rawDefaults,
|
|
43
46
|
subflowResultToSnapshots: () => subflowResultToSnapshots,
|
|
44
47
|
themePresets: () => themePresets,
|
|
@@ -2256,6 +2259,81 @@ function TimeTravelControls({
|
|
|
2256
2259
|
// src/components/ExplainableShell/ExplainableShell.tsx
|
|
2257
2260
|
var import_react19 = require("react");
|
|
2258
2261
|
|
|
2262
|
+
// src/utils/narrativeSync.ts
|
|
2263
|
+
function buildEntryRangeIndex(entries) {
|
|
2264
|
+
const ranges = /* @__PURE__ */ new Map();
|
|
2265
|
+
let lastId;
|
|
2266
|
+
for (let i = 0; i < entries.length; i++) {
|
|
2267
|
+
const id = entries[i].runtimeStageId;
|
|
2268
|
+
if (id) {
|
|
2269
|
+
const existing = ranges.get(id);
|
|
2270
|
+
if (!existing) {
|
|
2271
|
+
ranges.set(id, { firstIdx: i, endIdx: i + 1 });
|
|
2272
|
+
} else {
|
|
2273
|
+
existing.endIdx = i + 1;
|
|
2274
|
+
}
|
|
2275
|
+
lastId = id;
|
|
2276
|
+
} else if (lastId) {
|
|
2277
|
+
ranges.get(lastId).endIdx = i + 1;
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
return ranges;
|
|
2281
|
+
}
|
|
2282
|
+
function computeRevealedEntryCount(narrativeEntries, snapshots, selectedIndex, rangeIndex) {
|
|
2283
|
+
if (!narrativeEntries.length || snapshots.length === 0) return 0;
|
|
2284
|
+
if (rangeIndex) {
|
|
2285
|
+
let maxEndIdx = 0;
|
|
2286
|
+
for (let si = 0; si <= selectedIndex && si < snapshots.length; si++) {
|
|
2287
|
+
const targetId = snapshots[si].runtimeStageId;
|
|
2288
|
+
if (!targetId) continue;
|
|
2289
|
+
const range = rangeIndex.get(targetId);
|
|
2290
|
+
if (range && range.endIdx > maxEndIdx) {
|
|
2291
|
+
maxEndIdx = range.endIdx;
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
return maxEndIdx;
|
|
2295
|
+
}
|
|
2296
|
+
let entryIdx = 0;
|
|
2297
|
+
for (let si = 0; si <= selectedIndex && si < snapshots.length; si++) {
|
|
2298
|
+
const targetId = snapshots[si].runtimeStageId;
|
|
2299
|
+
if (!targetId) continue;
|
|
2300
|
+
let found = false;
|
|
2301
|
+
for (let j = entryIdx; j < narrativeEntries.length; j++) {
|
|
2302
|
+
if (narrativeEntries[j].runtimeStageId === targetId) {
|
|
2303
|
+
found = true;
|
|
2304
|
+
entryIdx = j;
|
|
2305
|
+
break;
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
if (!found) continue;
|
|
2309
|
+
while (entryIdx < narrativeEntries.length) {
|
|
2310
|
+
const eId = narrativeEntries[entryIdx].runtimeStageId;
|
|
2311
|
+
if (eId && eId !== targetId) break;
|
|
2312
|
+
entryIdx++;
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
return entryIdx;
|
|
2316
|
+
}
|
|
2317
|
+
function extractSubflowNarrative(entries, subflowId, subflowName) {
|
|
2318
|
+
const prefix = subflowId + "/";
|
|
2319
|
+
const byPrefix = entries.filter((e) => e.stageName?.startsWith(prefix));
|
|
2320
|
+
if (byPrefix.length > 0) return byPrefix;
|
|
2321
|
+
const byId = entries.filter((e) => e.subflowId === subflowId);
|
|
2322
|
+
if (byId.length > 0) return byId;
|
|
2323
|
+
const result = [];
|
|
2324
|
+
const searchName = subflowName ?? subflowId;
|
|
2325
|
+
let inside = false;
|
|
2326
|
+
for (const entry of entries) {
|
|
2327
|
+
if (entry.type === "subflow" && entry.direction === "entry" && entry.stageName === searchName) {
|
|
2328
|
+
inside = true;
|
|
2329
|
+
continue;
|
|
2330
|
+
}
|
|
2331
|
+
if (inside && entry.type === "subflow" && entry.direction === "exit" && entry.stageName === searchName) break;
|
|
2332
|
+
if (inside) result.push(entry);
|
|
2333
|
+
}
|
|
2334
|
+
return result;
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2259
2337
|
// src/adapters/fromRuntimeSnapshot.ts
|
|
2260
2338
|
function toVisualizationSnapshots(runtime, narrativeEntries) {
|
|
2261
2339
|
const stageNarrativeMap = narrativeEntries?.length ? buildStageNarrativeMap(narrativeEntries) : /* @__PURE__ */ new Map();
|
|
@@ -2684,37 +2762,14 @@ function NarrativePanel({
|
|
|
2684
2762
|
const endIdx = groupsToShow < stageBoundaries.length ? stageBoundaries[groupsToShow] : narrative.length;
|
|
2685
2763
|
return Math.max(1, endIdx);
|
|
2686
2764
|
}, [snapshots.length, selectedIndex, narrative]);
|
|
2687
|
-
const
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
if (snap.subflowId) keys.add(snap.subflowId);
|
|
2696
|
-
let found = false;
|
|
2697
|
-
for (let j = entryIdx; j < narrativeEntries.length; j++) {
|
|
2698
|
-
const e = narrativeEntries[j];
|
|
2699
|
-
const eKey = e.stageId ?? e.subflowId ?? e.stageName;
|
|
2700
|
-
if (eKey && keys.has(eKey)) {
|
|
2701
|
-
found = true;
|
|
2702
|
-
entryIdx = j;
|
|
2703
|
-
break;
|
|
2704
|
-
}
|
|
2705
|
-
if (!eKey && !found) {
|
|
2706
|
-
}
|
|
2707
|
-
}
|
|
2708
|
-
if (!found) continue;
|
|
2709
|
-
while (entryIdx < narrativeEntries.length) {
|
|
2710
|
-
const e = narrativeEntries[entryIdx];
|
|
2711
|
-
const eKey = e.stageId ?? e.subflowId ?? e.stageName;
|
|
2712
|
-
if (eKey && !keys.has(eKey)) break;
|
|
2713
|
-
entryIdx++;
|
|
2714
|
-
}
|
|
2715
|
-
}
|
|
2716
|
-
return entryIdx;
|
|
2717
|
-
}, [narrativeEntries, snapshots, selectedIndex]);
|
|
2765
|
+
const rangeIndex = (0, import_react12.useMemo)(
|
|
2766
|
+
() => narrativeEntries?.length ? buildEntryRangeIndex(narrativeEntries) : void 0,
|
|
2767
|
+
[narrativeEntries]
|
|
2768
|
+
);
|
|
2769
|
+
const revealedEntryCount = (0, import_react12.useMemo)(
|
|
2770
|
+
() => narrativeEntries?.length ? computeRevealedEntryCount(narrativeEntries, snapshots, selectedIndex, rangeIndex) : 0,
|
|
2771
|
+
[narrativeEntries, snapshots, selectedIndex, rangeIndex]
|
|
2772
|
+
);
|
|
2718
2773
|
const hasStructured = narrativeEntries && narrativeEntries.length > 0;
|
|
2719
2774
|
const [copied, setCopied] = (0, import_react12.useState)(false);
|
|
2720
2775
|
const buildLLMNarrative = (0, import_react12.useCallback)(() => {
|
|
@@ -2730,7 +2785,7 @@ function NarrativePanel({
|
|
|
2730
2785
|
root.push(entry);
|
|
2731
2786
|
} else {
|
|
2732
2787
|
if (entry.type === "subflow") {
|
|
2733
|
-
const isExit = entry.
|
|
2788
|
+
const isExit = entry.direction === "exit";
|
|
2734
2789
|
if (!isExit) {
|
|
2735
2790
|
root.push(entry);
|
|
2736
2791
|
}
|
|
@@ -2750,7 +2805,11 @@ function NarrativePanel({
|
|
|
2750
2805
|
if (opts?.inSubflow && e.type === "subflow") continue;
|
|
2751
2806
|
let text = e.text;
|
|
2752
2807
|
if (opts?.inSubflow) {
|
|
2753
|
-
|
|
2808
|
+
const prefix = `[${opts.inSubflow}/`;
|
|
2809
|
+
const idx = text.indexOf(prefix);
|
|
2810
|
+
if (idx !== -1) {
|
|
2811
|
+
text = text.slice(0, idx) + "[" + text.slice(idx + prefix.length);
|
|
2812
|
+
}
|
|
2754
2813
|
}
|
|
2755
2814
|
const isHeading = e.type === "stage" || e.type === "subflow" || e.type === "fork" || e.type === "selector";
|
|
2756
2815
|
if (isHeading) {
|
|
@@ -4050,6 +4109,12 @@ var DetailsContent = (0, import_react19.memo)(function DetailsContent2({
|
|
|
4050
4109
|
];
|
|
4051
4110
|
const allViews = [...builtInViews, ...extraViews ?? []];
|
|
4052
4111
|
const [activeViewId, setActiveViewId] = (0, import_react19.useState)(allViews[0]?.id ?? "memory");
|
|
4112
|
+
const viewIds = allViews.map((v2) => v2.id).join(",");
|
|
4113
|
+
(0, import_react19.useEffect)(() => {
|
|
4114
|
+
if (!allViews.find((v2) => v2.id === activeViewId)) {
|
|
4115
|
+
setActiveViewId(allViews[0]?.id ?? "memory");
|
|
4116
|
+
}
|
|
4117
|
+
}, [viewIds]);
|
|
4053
4118
|
const activeView = allViews.find((v2) => v2.id === activeViewId) ?? allViews[0];
|
|
4054
4119
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
|
|
4055
4120
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { display: "flex", borderBottom: `1px solid ${theme.border}`, flexShrink: 0, overflowX: "auto" }, children: allViews.map((view) => {
|
|
@@ -4100,25 +4165,6 @@ function resolveSubflowLevel(parentSpec, parentSnapshots, subflowNodeName, narra
|
|
|
4100
4165
|
snapshots: sfSnapshots
|
|
4101
4166
|
};
|
|
4102
4167
|
}
|
|
4103
|
-
function extractSubflowNarrative(entries, subflowId, subflowName) {
|
|
4104
|
-
const prefix = subflowId + "/";
|
|
4105
|
-
const byPrefix = entries.filter((e) => e.stageName?.startsWith(prefix));
|
|
4106
|
-
if (byPrefix.length > 0) return byPrefix;
|
|
4107
|
-
const byId = entries.filter((e) => e.subflowId === subflowId);
|
|
4108
|
-
if (byId.length > 0) return byId;
|
|
4109
|
-
const result = [];
|
|
4110
|
-
const searchName = subflowName ?? subflowId;
|
|
4111
|
-
let inside = false;
|
|
4112
|
-
for (const entry of entries) {
|
|
4113
|
-
if (entry.type === "subflow" && entry.text.includes(searchName) && entry.text.startsWith("Entering")) {
|
|
4114
|
-
inside = true;
|
|
4115
|
-
continue;
|
|
4116
|
-
}
|
|
4117
|
-
if (inside && entry.type === "subflow" && entry.text.includes(searchName) && entry.text.startsWith("Exiting")) break;
|
|
4118
|
-
if (inside) result.push(entry);
|
|
4119
|
-
}
|
|
4120
|
-
return result;
|
|
4121
|
-
}
|
|
4122
4168
|
function findSubflowSpecNode(node, name) {
|
|
4123
4169
|
if ((node.name === name || node.id === name) && node.isSubflowRoot) return node;
|
|
4124
4170
|
if (node.children) {
|
|
@@ -4207,22 +4253,22 @@ function ExplainableShell({
|
|
|
4207
4253
|
const recorders = runtimeSnapshot?.recorders;
|
|
4208
4254
|
if (!recorders?.length) return [];
|
|
4209
4255
|
const explicitIds = new Set((recorderViews ?? []).map((v2) => v2.id));
|
|
4210
|
-
return recorders.filter((r) => !explicitIds.has(r.id)).map((r) => ({ id: r.id, name: r.name, data: r.data }));
|
|
4256
|
+
return recorders.filter((r) => !explicitIds.has(r.id)).map((r) => ({ id: r.id, name: r.name, description: r.description, data: r.data }));
|
|
4211
4257
|
}, [runtimeSnapshot, recorderViews]);
|
|
4212
4258
|
const hasNarrative = !!(narrative?.length || narrativeEntries?.length);
|
|
4213
4259
|
const allTabs = (0, import_react19.useMemo)(() => {
|
|
4214
4260
|
const tabs2 = [
|
|
4215
|
-
{ id: "result", name: "Result" },
|
|
4216
|
-
{ id: "memory", name: "Memory" }
|
|
4261
|
+
{ id: "result", name: "Result", description: "Final output and console logs" },
|
|
4262
|
+
{ id: "memory", name: "Memory", description: "Accumulated shared state at each stage" }
|
|
4217
4263
|
];
|
|
4218
4264
|
if (hasNarrative) {
|
|
4219
|
-
tabs2.push({ id: "narrative", name: "Narrative" });
|
|
4265
|
+
tabs2.push({ id: "narrative", name: "Narrative", description: "What happened, what data flowed, what decisions were made" });
|
|
4220
4266
|
}
|
|
4221
4267
|
for (const v2 of recorderViews ?? []) {
|
|
4222
|
-
tabs2.push({ id: v2.id, name: v2.name });
|
|
4268
|
+
tabs2.push({ id: v2.id, name: v2.name, description: v2.description });
|
|
4223
4269
|
}
|
|
4224
4270
|
for (const v2 of autoRecorderViews) {
|
|
4225
|
-
tabs2.push({ id: v2.id, name: v2.name });
|
|
4271
|
+
tabs2.push({ id: v2.id, name: v2.name, description: v2.description });
|
|
4226
4272
|
}
|
|
4227
4273
|
const hideSet = new Set(hideTabsProp ?? []);
|
|
4228
4274
|
return hideSet.size > 0 ? tabs2.filter((t) => !hideSet.has(t.id)) : tabs2;
|
|
@@ -4384,7 +4430,17 @@ function ExplainableShell({
|
|
|
4384
4430
|
}
|
|
4385
4431
|
const autoView = autoRecorderViews.find((v2) => v2.id === activeTab);
|
|
4386
4432
|
if (autoView) {
|
|
4387
|
-
return /* @__PURE__ */ (0, import_jsx_runtime18.
|
|
4433
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { overflow: "auto", height: "100%", display: "flex", flexDirection: "column" }, children: [
|
|
4434
|
+
autoView.description && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: {
|
|
4435
|
+
padding: "6px 12px",
|
|
4436
|
+
fontSize: 11,
|
|
4437
|
+
color: theme.textMuted,
|
|
4438
|
+
fontStyle: "italic",
|
|
4439
|
+
borderBottom: `1px solid ${theme.border}`,
|
|
4440
|
+
flexShrink: 0
|
|
4441
|
+
}, children: autoView.description }),
|
|
4442
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { padding: 12, fontFamily: theme.fontMono, fontSize: 11, whiteSpace: "pre-wrap", overflow: "auto", flex: 1 }, children: typeof autoView.data === "string" ? autoView.data : JSON.stringify(autoView.data, null, 2) })
|
|
4443
|
+
] });
|
|
4388
4444
|
}
|
|
4389
4445
|
return null;
|
|
4390
4446
|
}, [activeTab, resultData, logs, hideConsole, size, activeSnapshots, safeIdx, activeNarrativeEntries, activeNarrative, recorderViews, autoRecorderViews]);
|
|
@@ -4401,6 +4457,7 @@ function ExplainableShell({
|
|
|
4401
4457
|
"button",
|
|
4402
4458
|
{
|
|
4403
4459
|
onClick: () => handleTabChange(tab.id),
|
|
4460
|
+
title: tab.description,
|
|
4404
4461
|
style: {
|
|
4405
4462
|
padding: "6px 14px",
|
|
4406
4463
|
fontSize: 11,
|
|
@@ -4535,10 +4592,13 @@ function ExplainableShell({
|
|
|
4535
4592
|
StoryNarrative,
|
|
4536
4593
|
SubflowTree,
|
|
4537
4594
|
TimeTravelControls,
|
|
4595
|
+
buildEntryRangeIndex,
|
|
4596
|
+
computeRevealedEntryCount,
|
|
4538
4597
|
coolDark,
|
|
4539
4598
|
coolLight,
|
|
4540
4599
|
createSnapshots,
|
|
4541
4600
|
defaultTokens,
|
|
4601
|
+
extractSubflowNarrative,
|
|
4542
4602
|
rawDefaults,
|
|
4543
4603
|
subflowResultToSnapshots,
|
|
4544
4604
|
themePresets,
|