footprint-explainable-ui 0.14.0 → 0.14.2
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 +140 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +140 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4086,6 +4086,135 @@ var VLinePill = (0, import_react19.memo)(function VLinePill2({
|
|
|
4086
4086
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } })
|
|
4087
4087
|
] });
|
|
4088
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 entries = Object.entries(val);
|
|
4095
|
+
if (entries.length === 0) continue;
|
|
4096
|
+
const allObjectsWithNumbers = entries.every(([, v2]) => {
|
|
4097
|
+
if (!v2 || typeof v2 !== "object" || Array.isArray(v2)) return false;
|
|
4098
|
+
return Object.values(v2).some((f) => typeof f === "number");
|
|
4099
|
+
});
|
|
4100
|
+
if (allObjectsWithNumbers) {
|
|
4101
|
+
const keyType = entries.some(([k]) => k.includes("#")) ? "runtimeStageId" : "stageName";
|
|
4102
|
+
return { steps: val, keyType };
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
}
|
|
4106
|
+
return null;
|
|
4107
|
+
}
|
|
4108
|
+
function findNumericField(entry) {
|
|
4109
|
+
for (const [k, v2] of Object.entries(entry)) {
|
|
4110
|
+
if (typeof v2 === "number") return { key: k, value: v2 };
|
|
4111
|
+
}
|
|
4112
|
+
return null;
|
|
4113
|
+
}
|
|
4114
|
+
function KeyedRecorderView({
|
|
4115
|
+
data,
|
|
4116
|
+
description,
|
|
4117
|
+
snapshots,
|
|
4118
|
+
selectedIndex
|
|
4119
|
+
}) {
|
|
4120
|
+
const [showAggregate, setShowAggregate] = (0, import_react19.useState)(false);
|
|
4121
|
+
const detected = (0, import_react19.useMemo)(() => detectKeyedSteps(data), [data]);
|
|
4122
|
+
const visibleKeys = (0, import_react19.useMemo)(() => {
|
|
4123
|
+
const keys = /* @__PURE__ */ new Set();
|
|
4124
|
+
for (let i = 0; i <= selectedIndex && i < snapshots.length; i++) {
|
|
4125
|
+
const snap = snapshots[i];
|
|
4126
|
+
if (detected?.keyType === "runtimeStageId") {
|
|
4127
|
+
if (snap.runtimeStageId) keys.add(snap.runtimeStageId);
|
|
4128
|
+
} else {
|
|
4129
|
+
if (snap.stageName) keys.add(snap.stageName);
|
|
4130
|
+
if (snap.stageLabel) keys.add(snap.stageLabel);
|
|
4131
|
+
}
|
|
4132
|
+
}
|
|
4133
|
+
return keys;
|
|
4134
|
+
}, [snapshots, selectedIndex, detected?.keyType]);
|
|
4135
|
+
const isAtEnd = selectedIndex >= snapshots.length - 1;
|
|
4136
|
+
if (!detected) {
|
|
4137
|
+
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) });
|
|
4138
|
+
}
|
|
4139
|
+
const steps = detected.steps;
|
|
4140
|
+
const allKeys = Object.keys(steps);
|
|
4141
|
+
const visibleEntries = allKeys.filter((k) => visibleKeys.has(k));
|
|
4142
|
+
const numField = allKeys.length > 0 ? findNumericField(steps[allKeys[0]]) : null;
|
|
4143
|
+
const numFieldKey = numField?.key ?? "";
|
|
4144
|
+
let runningTotal = 0;
|
|
4145
|
+
if (numFieldKey) {
|
|
4146
|
+
for (const k of visibleEntries) {
|
|
4147
|
+
runningTotal += steps[k][numFieldKey] ?? 0;
|
|
4148
|
+
}
|
|
4149
|
+
}
|
|
4150
|
+
let grandTotal = 0;
|
|
4151
|
+
if (numFieldKey) {
|
|
4152
|
+
for (const entry of Object.values(steps)) {
|
|
4153
|
+
grandTotal += entry[numFieldKey] ?? 0;
|
|
4154
|
+
}
|
|
4155
|
+
}
|
|
4156
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { overflow: "auto", height: "100%", display: "flex", flexDirection: "column" }, children: [
|
|
4157
|
+
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 }),
|
|
4158
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { padding: 12, flex: 1, overflow: "auto" }, children: [
|
|
4159
|
+
visibleEntries.map((key) => {
|
|
4160
|
+
const entry = steps[key];
|
|
4161
|
+
const label = entry.stageName ?? key;
|
|
4162
|
+
const numVal = numFieldKey ? entry[numFieldKey] : void 0;
|
|
4163
|
+
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: [
|
|
4164
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { color: theme.textMuted, width: 140, flexShrink: 0, fontSize: 10 }, children: key }),
|
|
4165
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontWeight: 600, flex: 1 }, children: label }),
|
|
4166
|
+
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) })
|
|
4167
|
+
] }, key);
|
|
4168
|
+
}),
|
|
4169
|
+
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..." }),
|
|
4170
|
+
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: [
|
|
4171
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: { color: theme.textMuted }, children: [
|
|
4172
|
+
"Running total (",
|
|
4173
|
+
numFieldKey,
|
|
4174
|
+
"):"
|
|
4175
|
+
] }),
|
|
4176
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontWeight: 700, marginLeft: 8, color: theme.primary }, children: runningTotal < 1 ? runningTotal.toFixed(3) : runningTotal.toFixed(1) }),
|
|
4177
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: { color: theme.textMuted, marginLeft: 8, fontSize: 10 }, children: [
|
|
4178
|
+
"(",
|
|
4179
|
+
visibleEntries.length,
|
|
4180
|
+
" of ",
|
|
4181
|
+
allKeys.length,
|
|
4182
|
+
" steps)"
|
|
4183
|
+
] })
|
|
4184
|
+
] }),
|
|
4185
|
+
isAtEnd && numFieldKey && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { marginTop: 12 }, children: !showAggregate ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
4186
|
+
"button",
|
|
4187
|
+
{
|
|
4188
|
+
onClick: () => setShowAggregate(true),
|
|
4189
|
+
style: {
|
|
4190
|
+
background: theme.primary,
|
|
4191
|
+
color: "#fff",
|
|
4192
|
+
border: "none",
|
|
4193
|
+
borderRadius: 6,
|
|
4194
|
+
padding: "8px 16px",
|
|
4195
|
+
fontSize: 12,
|
|
4196
|
+
fontWeight: 600,
|
|
4197
|
+
cursor: "pointer",
|
|
4198
|
+
fontFamily: "inherit"
|
|
4199
|
+
},
|
|
4200
|
+
children: [
|
|
4201
|
+
"Aggregate (",
|
|
4202
|
+
numFieldKey,
|
|
4203
|
+
")"
|
|
4204
|
+
]
|
|
4205
|
+
}
|
|
4206
|
+
) : /* @__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: [
|
|
4207
|
+
/* @__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" }),
|
|
4208
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { fontSize: 20, fontWeight: 700, color: theme.success }, children: grandTotal < 1 ? grandTotal.toFixed(3) : grandTotal.toFixed(1) }),
|
|
4209
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { fontSize: 10, color: theme.textMuted, marginTop: 2 }, children: [
|
|
4210
|
+
allKeys.length,
|
|
4211
|
+
" steps \xB7 ",
|
|
4212
|
+
numFieldKey
|
|
4213
|
+
] })
|
|
4214
|
+
] }) })
|
|
4215
|
+
] })
|
|
4216
|
+
] });
|
|
4217
|
+
}
|
|
4089
4218
|
var DetailsContent = (0, import_react19.memo)(function DetailsContent2({
|
|
4090
4219
|
snapshots,
|
|
4091
4220
|
selectedIndex,
|
|
@@ -4259,10 +4388,10 @@ function ExplainableShell({
|
|
|
4259
4388
|
const allTabs = (0, import_react19.useMemo)(() => {
|
|
4260
4389
|
const tabs2 = [
|
|
4261
4390
|
{ id: "result", name: "Result", description: "Final output and console logs" },
|
|
4262
|
-
{ id: "memory", name: "Memory", description: "
|
|
4391
|
+
{ id: "memory", name: "Memory", description: "Accumulator \u2014 progressive shared state at each stage" }
|
|
4263
4392
|
];
|
|
4264
4393
|
if (hasNarrative) {
|
|
4265
|
-
tabs2.push({ id: "narrative", name: "Narrative", description: "
|
|
4394
|
+
tabs2.push({ id: "narrative", name: "Narrative", description: "Translator (SequenceRecorder) \u2014 interleaved flow + data narrative per execution step" });
|
|
4266
4395
|
}
|
|
4267
4396
|
for (const v2 of recorderViews ?? []) {
|
|
4268
4397
|
tabs2.push({ id: v2.id, name: v2.name, description: v2.description });
|
|
@@ -4430,17 +4559,15 @@ function ExplainableShell({
|
|
|
4430
4559
|
}
|
|
4431
4560
|
const autoView = autoRecorderViews.find((v2) => v2.id === activeTab);
|
|
4432
4561
|
if (autoView) {
|
|
4433
|
-
return /* @__PURE__ */ (0, import_jsx_runtime18.
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
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
|
-
] });
|
|
4562
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4563
|
+
KeyedRecorderView,
|
|
4564
|
+
{
|
|
4565
|
+
data: autoView.data,
|
|
4566
|
+
description: autoView.description,
|
|
4567
|
+
snapshots: activeSnapshots,
|
|
4568
|
+
selectedIndex: safeIdx
|
|
4569
|
+
}
|
|
4570
|
+
);
|
|
4444
4571
|
}
|
|
4445
4572
|
return null;
|
|
4446
4573
|
}, [activeTab, resultData, logs, hideConsole, size, activeSnapshots, safeIdx, activeNarrativeEntries, activeNarrative, recorderViews, autoRecorderViews]);
|