footprint-explainable-ui 0.13.3 → 0.14.1
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 +234 -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 +231 -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) {
|
|
@@ -4027,6 +4086,123 @@ var VLinePill = (0, import_react19.memo)(function VLinePill2({
|
|
|
4027
4086
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } })
|
|
4028
4087
|
] });
|
|
4029
4088
|
});
|
|
4089
|
+
function detectKeyedSteps(data) {
|
|
4090
|
+
if (!data || typeof data !== "object") return null;
|
|
4091
|
+
const obj = data;
|
|
4092
|
+
for (const val of Object.values(obj)) {
|
|
4093
|
+
if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
4094
|
+
const keys = Object.keys(val);
|
|
4095
|
+
if (keys.length > 0 && keys.every((k) => k.includes("#"))) {
|
|
4096
|
+
return val;
|
|
4097
|
+
}
|
|
4098
|
+
}
|
|
4099
|
+
}
|
|
4100
|
+
return null;
|
|
4101
|
+
}
|
|
4102
|
+
function findNumericField(entry) {
|
|
4103
|
+
for (const [k, v2] of Object.entries(entry)) {
|
|
4104
|
+
if (typeof v2 === "number") return { key: k, value: v2 };
|
|
4105
|
+
}
|
|
4106
|
+
return null;
|
|
4107
|
+
}
|
|
4108
|
+
function KeyedRecorderView({
|
|
4109
|
+
data,
|
|
4110
|
+
description,
|
|
4111
|
+
snapshots,
|
|
4112
|
+
selectedIndex
|
|
4113
|
+
}) {
|
|
4114
|
+
const [showAggregate, setShowAggregate] = (0, import_react19.useState)(false);
|
|
4115
|
+
const steps = (0, import_react19.useMemo)(() => detectKeyedSteps(data), [data]);
|
|
4116
|
+
const visibleIds = (0, import_react19.useMemo)(() => {
|
|
4117
|
+
const ids = /* @__PURE__ */ new Set();
|
|
4118
|
+
for (let i = 0; i <= selectedIndex && i < snapshots.length; i++) {
|
|
4119
|
+
const id = snapshots[i].runtimeStageId;
|
|
4120
|
+
if (id) ids.add(id);
|
|
4121
|
+
}
|
|
4122
|
+
return ids;
|
|
4123
|
+
}, [snapshots, selectedIndex]);
|
|
4124
|
+
const isAtEnd = selectedIndex >= snapshots.length - 1;
|
|
4125
|
+
if (!steps) {
|
|
4126
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { padding: 12, fontFamily: theme.fontMono, fontSize: 11, whiteSpace: "pre-wrap", overflow: "auto", height: "100%" }, children: typeof data === "string" ? data : JSON.stringify(data, null, 2) });
|
|
4127
|
+
}
|
|
4128
|
+
const allKeys = Object.keys(steps);
|
|
4129
|
+
const visibleEntries = allKeys.filter((k) => visibleIds.has(k));
|
|
4130
|
+
const numField = allKeys.length > 0 ? findNumericField(steps[allKeys[0]]) : null;
|
|
4131
|
+
const numFieldKey = numField?.key ?? "";
|
|
4132
|
+
let runningTotal = 0;
|
|
4133
|
+
if (numFieldKey) {
|
|
4134
|
+
for (const k of visibleEntries) {
|
|
4135
|
+
runningTotal += steps[k][numFieldKey] ?? 0;
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
let grandTotal = 0;
|
|
4139
|
+
if (numFieldKey) {
|
|
4140
|
+
for (const entry of Object.values(steps)) {
|
|
4141
|
+
grandTotal += entry[numFieldKey] ?? 0;
|
|
4142
|
+
}
|
|
4143
|
+
}
|
|
4144
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { overflow: "auto", height: "100%", display: "flex", flexDirection: "column" }, children: [
|
|
4145
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { padding: "6px 12px", fontSize: 11, color: theme.textMuted, fontStyle: "italic", borderBottom: `1px solid ${theme.border}`, flexShrink: 0 }, children: description }),
|
|
4146
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { padding: 12, flex: 1, overflow: "auto" }, children: [
|
|
4147
|
+
visibleEntries.map((key) => {
|
|
4148
|
+
const entry = steps[key];
|
|
4149
|
+
const label = entry.stageName ?? key;
|
|
4150
|
+
const numVal = numFieldKey ? entry[numFieldKey] : void 0;
|
|
4151
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", alignItems: "center", padding: "4px 0", fontSize: 12, fontFamily: theme.fontMono, borderBottom: `1px solid ${theme.border}22` }, children: [
|
|
4152
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { color: theme.textMuted, width: 140, flexShrink: 0, fontSize: 10 }, children: key }),
|
|
4153
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontWeight: 600, flex: 1 }, children: label }),
|
|
4154
|
+
numVal !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { color: theme.primary, fontWeight: 700, marginLeft: 8 }, children: numVal < 1 ? numVal.toFixed(3) : numVal.toFixed(1) })
|
|
4155
|
+
] }, key);
|
|
4156
|
+
}),
|
|
4157
|
+
visibleEntries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { color: theme.textMuted, fontSize: 11, fontStyle: "italic", padding: "8px 0" }, children: "Scrub the slider to reveal entries..." }),
|
|
4158
|
+
numFieldKey && visibleEntries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { marginTop: 12, padding: "8px 12px", background: `color-mix(in srgb, ${theme.primary} 8%, transparent)`, borderRadius: 6, fontSize: 12 }, children: [
|
|
4159
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: { color: theme.textMuted }, children: [
|
|
4160
|
+
"Running total (",
|
|
4161
|
+
numFieldKey,
|
|
4162
|
+
"):"
|
|
4163
|
+
] }),
|
|
4164
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontWeight: 700, marginLeft: 8, color: theme.primary }, children: runningTotal < 1 ? runningTotal.toFixed(3) : runningTotal.toFixed(1) }),
|
|
4165
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: { color: theme.textMuted, marginLeft: 8, fontSize: 10 }, children: [
|
|
4166
|
+
"(",
|
|
4167
|
+
visibleEntries.length,
|
|
4168
|
+
" of ",
|
|
4169
|
+
allKeys.length,
|
|
4170
|
+
" steps)"
|
|
4171
|
+
] })
|
|
4172
|
+
] }),
|
|
4173
|
+
isAtEnd && numFieldKey && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { marginTop: 12 }, children: !showAggregate ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
4174
|
+
"button",
|
|
4175
|
+
{
|
|
4176
|
+
onClick: () => setShowAggregate(true),
|
|
4177
|
+
style: {
|
|
4178
|
+
background: theme.primary,
|
|
4179
|
+
color: "#fff",
|
|
4180
|
+
border: "none",
|
|
4181
|
+
borderRadius: 6,
|
|
4182
|
+
padding: "8px 16px",
|
|
4183
|
+
fontSize: 12,
|
|
4184
|
+
fontWeight: 600,
|
|
4185
|
+
cursor: "pointer",
|
|
4186
|
+
fontFamily: "inherit"
|
|
4187
|
+
},
|
|
4188
|
+
children: [
|
|
4189
|
+
"Aggregate (",
|
|
4190
|
+
numFieldKey,
|
|
4191
|
+
")"
|
|
4192
|
+
]
|
|
4193
|
+
}
|
|
4194
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.success} 12%, transparent)`, borderRadius: 6, border: `1px solid ${theme.success}44` }, children: [
|
|
4195
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 4 }, children: "Aggregate \u2014 Grand Total" }),
|
|
4196
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { fontSize: 20, fontWeight: 700, color: theme.success }, children: grandTotal < 1 ? grandTotal.toFixed(3) : grandTotal.toFixed(1) }),
|
|
4197
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { fontSize: 10, color: theme.textMuted, marginTop: 2 }, children: [
|
|
4198
|
+
allKeys.length,
|
|
4199
|
+
" steps \xB7 ",
|
|
4200
|
+
numFieldKey
|
|
4201
|
+
] })
|
|
4202
|
+
] }) })
|
|
4203
|
+
] })
|
|
4204
|
+
] });
|
|
4205
|
+
}
|
|
4030
4206
|
var DetailsContent = (0, import_react19.memo)(function DetailsContent2({
|
|
4031
4207
|
snapshots,
|
|
4032
4208
|
selectedIndex,
|
|
@@ -4050,6 +4226,12 @@ var DetailsContent = (0, import_react19.memo)(function DetailsContent2({
|
|
|
4050
4226
|
];
|
|
4051
4227
|
const allViews = [...builtInViews, ...extraViews ?? []];
|
|
4052
4228
|
const [activeViewId, setActiveViewId] = (0, import_react19.useState)(allViews[0]?.id ?? "memory");
|
|
4229
|
+
const viewIds = allViews.map((v2) => v2.id).join(",");
|
|
4230
|
+
(0, import_react19.useEffect)(() => {
|
|
4231
|
+
if (!allViews.find((v2) => v2.id === activeViewId)) {
|
|
4232
|
+
setActiveViewId(allViews[0]?.id ?? "memory");
|
|
4233
|
+
}
|
|
4234
|
+
}, [viewIds]);
|
|
4053
4235
|
const activeView = allViews.find((v2) => v2.id === activeViewId) ?? allViews[0];
|
|
4054
4236
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
|
|
4055
4237
|
/* @__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 +4282,6 @@ function resolveSubflowLevel(parentSpec, parentSnapshots, subflowNodeName, narra
|
|
|
4100
4282
|
snapshots: sfSnapshots
|
|
4101
4283
|
};
|
|
4102
4284
|
}
|
|
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
4285
|
function findSubflowSpecNode(node, name) {
|
|
4123
4286
|
if ((node.name === name || node.id === name) && node.isSubflowRoot) return node;
|
|
4124
4287
|
if (node.children) {
|
|
@@ -4207,22 +4370,22 @@ function ExplainableShell({
|
|
|
4207
4370
|
const recorders = runtimeSnapshot?.recorders;
|
|
4208
4371
|
if (!recorders?.length) return [];
|
|
4209
4372
|
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 }));
|
|
4373
|
+
return recorders.filter((r) => !explicitIds.has(r.id)).map((r) => ({ id: r.id, name: r.name, description: r.description, data: r.data }));
|
|
4211
4374
|
}, [runtimeSnapshot, recorderViews]);
|
|
4212
4375
|
const hasNarrative = !!(narrative?.length || narrativeEntries?.length);
|
|
4213
4376
|
const allTabs = (0, import_react19.useMemo)(() => {
|
|
4214
4377
|
const tabs2 = [
|
|
4215
|
-
{ id: "result", name: "Result" },
|
|
4216
|
-
{ id: "memory", name: "Memory" }
|
|
4378
|
+
{ id: "result", name: "Result", description: "Final output and console logs" },
|
|
4379
|
+
{ id: "memory", name: "Memory", description: "Accumulator \u2014 progressive shared state at each stage" }
|
|
4217
4380
|
];
|
|
4218
4381
|
if (hasNarrative) {
|
|
4219
|
-
tabs2.push({ id: "narrative", name: "Narrative" });
|
|
4382
|
+
tabs2.push({ id: "narrative", name: "Narrative", description: "Translator (SequenceRecorder) \u2014 interleaved flow + data narrative per execution step" });
|
|
4220
4383
|
}
|
|
4221
4384
|
for (const v2 of recorderViews ?? []) {
|
|
4222
|
-
tabs2.push({ id: v2.id, name: v2.name });
|
|
4385
|
+
tabs2.push({ id: v2.id, name: v2.name, description: v2.description });
|
|
4223
4386
|
}
|
|
4224
4387
|
for (const v2 of autoRecorderViews) {
|
|
4225
|
-
tabs2.push({ id: v2.id, name: v2.name });
|
|
4388
|
+
tabs2.push({ id: v2.id, name: v2.name, description: v2.description });
|
|
4226
4389
|
}
|
|
4227
4390
|
const hideSet = new Set(hideTabsProp ?? []);
|
|
4228
4391
|
return hideSet.size > 0 ? tabs2.filter((t) => !hideSet.has(t.id)) : tabs2;
|
|
@@ -4384,7 +4547,15 @@ function ExplainableShell({
|
|
|
4384
4547
|
}
|
|
4385
4548
|
const autoView = autoRecorderViews.find((v2) => v2.id === activeTab);
|
|
4386
4549
|
if (autoView) {
|
|
4387
|
-
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4550
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4551
|
+
KeyedRecorderView,
|
|
4552
|
+
{
|
|
4553
|
+
data: autoView.data,
|
|
4554
|
+
description: autoView.description,
|
|
4555
|
+
snapshots: activeSnapshots,
|
|
4556
|
+
selectedIndex: safeIdx
|
|
4557
|
+
}
|
|
4558
|
+
);
|
|
4388
4559
|
}
|
|
4389
4560
|
return null;
|
|
4390
4561
|
}, [activeTab, resultData, logs, hideConsole, size, activeSnapshots, safeIdx, activeNarrativeEntries, activeNarrative, recorderViews, autoRecorderViews]);
|
|
@@ -4401,6 +4572,7 @@ function ExplainableShell({
|
|
|
4401
4572
|
"button",
|
|
4402
4573
|
{
|
|
4403
4574
|
onClick: () => handleTabChange(tab.id),
|
|
4575
|
+
title: tab.description,
|
|
4404
4576
|
style: {
|
|
4405
4577
|
padding: "6px 14px",
|
|
4406
4578
|
fontSize: 11,
|
|
@@ -4535,10 +4707,13 @@ function ExplainableShell({
|
|
|
4535
4707
|
StoryNarrative,
|
|
4536
4708
|
SubflowTree,
|
|
4537
4709
|
TimeTravelControls,
|
|
4710
|
+
buildEntryRangeIndex,
|
|
4711
|
+
computeRevealedEntryCount,
|
|
4538
4712
|
coolDark,
|
|
4539
4713
|
coolLight,
|
|
4540
4714
|
createSnapshots,
|
|
4541
4715
|
defaultTokens,
|
|
4716
|
+
extractSubflowNarrative,
|
|
4542
4717
|
rawDefaults,
|
|
4543
4718
|
subflowResultToSnapshots,
|
|
4544
4719
|
themePresets,
|