dsh-context 0.11.1 → 0.12.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/README.md +12 -1
- package/lib/client.js +369 -40
- package/lib/index.js +1030 -74
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ A six-color stacked bar scaled against the model's full context window (the gray
|
|
|
53
53
|
|
|
54
54
|
### 📈 History — watch the window grow (and get compacted)
|
|
55
55
|
|
|
56
|
-
One stacked bar per model request, finer than per-message. Toggle between **Turn** and **Step** granularity, scroll sideways through the session, hover any bar for a quick tooltip, and click to pin the full breakdown — including provider-reported actual prompt/output tokens next to the estimate. **✂ marks where compaction or pruning happened** — watch the bars drop:
|
|
56
|
+
One stacked bar per model request, finer than per-message. Toggle between **Turn** and **Step** granularity, scroll sideways through the session, hover any bar for a quick tooltip, and click to pin the full breakdown — including provider-reported actual prompt/output tokens next to the estimate. **Hovering a bar also drives the Context browser beside it** — the browser previews that step's assembled context in real time as you scrub across the history. **✂ marks where compaction or pruning happened** — watch the bars drop:
|
|
57
57
|
|
|
58
58
|

|
|
59
59
|
|
|
@@ -73,6 +73,17 @@ Every compaction, tool-output prune, skill or plugin context injection, and mode
|
|
|
73
73
|
|
|
74
74
|
The exact message list the model sees right now, newest first, with a per-message token cost.
|
|
75
75
|
|
|
76
|
+
### 🧭 Context browser — open the box of any request
|
|
77
|
+
|
|
78
|
+
Pick **Live (next request)** or any retained step from the picker, and browse what that request was actually assembled from:
|
|
79
|
+
|
|
80
|
+

|
|
81
|
+
|
|
82
|
+
Six collapsible category sections (system prompt, tool schemas, user messages, injected context, assistant replies, tool results) expand into one row per element — each with its token price — and every element expands again into its **actual content**: the full system prompt, each tool's description and JSON schema, message text, reasoning, tool-call arguments, and tool outputs.
|
|
83
|
+
|
|
84
|
+
- **Linked with the history chart** — hover any bar in the History card and the browser previews that step instantly; leave the chart and it returns to your own pick. Keep a category open while scrubbing to compare one category across steps.
|
|
85
|
+
- **Honest about coverage** — steps before a compaction are reconstructed from the removed-message archive, and the card says so when a step's makeup is only approximate. Elements older than the loaded chat window page older history in automatically when you expand them, and live injections (AGENTS.md, session-start context, …) are always listed — never a token sum without its items.
|
|
86
|
+
|
|
76
87
|
## Like it?
|
|
77
88
|
|
|
78
89
|
If `dsh-context` helped you understand what your agent is carrying around, a ⭐ on [GitHub](https://github.com/bowenliang123/dsh-context) is much appreciated — and issues/PRs are welcome!
|
package/lib/client.js
CHANGED
|
@@ -82,7 +82,19 @@ var DICT_ZH = {
|
|
|
82
82
|
"node.nonText": "(\u975E\u6587\u672C\u6D88\u606F)",
|
|
83
83
|
"node.snapshot": "\u5FEB\u7167: ",
|
|
84
84
|
"cmd.desc": "\u67E5\u770B\u4E0A\u4E0B\u6587\u7684\u6784\u6210\u548C\u53D8\u5316",
|
|
85
|
-
"cmd.close": "\u5173\u95ED"
|
|
85
|
+
"cmd.close": "\u5173\u95ED",
|
|
86
|
+
"browser.title": "\u4E0A\u4E0B\u6587\u6D4F\u89C8",
|
|
87
|
+
"browser.hint": "\u67E5\u770B\u5F53\u524D\u6216\u6307\u5B9A\u6B65\u9AA4\u5B9E\u9645\u7EC4\u88C5\u7684\u4E0A\u4E0B\u6587\u5185\u5BB9",
|
|
88
|
+
"browser.live": "\u5F53\u524D\uFF08\u4E0B\u4E00\u6B21\u8BF7\u6C42\uFF09",
|
|
89
|
+
"browser.liveNow": "\u5F53\u524D \xB7 \u4E0B\u4E00\u6B21\u8BF7\u6C42",
|
|
90
|
+
"browser.items": "{n} \u9879",
|
|
91
|
+
"browser.missingLive": "\u2026 \u53E6\u6709 {n} \u6761\u66F4\u65E9\u7684\u6D88\u606F\u4E5F\u5728\u4E0A\u4E0B\u6587\u4E2D\uFF08\u8D85\u51FA\u5C55\u793A\u7A97\u53E3\uFF09",
|
|
92
|
+
"browser.approx": "\u8BE5\u6B65\u9AA4\u6D89\u53CA\u7684\u90E8\u5206\u5DF2\u79FB\u9664\u6D88\u606F\u8D85\u51FA\u4FDD\u7559\u8303\u56F4\uFF0C\u4EE5\u4E0B\u4E3A\u8FD1\u4F3C\u6784\u6210",
|
|
93
|
+
"browser.noHeader": "\u6B64\u6570\u636E\u6765\u81EA\u65E7\u7248\u63D2\u4EF6\uFF1A\u4EC5\u63D0\u4F9B token \u4F30\u7B97\uFF0C\u65E0\u5B9E\u9645\u5185\u5BB9",
|
|
94
|
+
"browser.noEpoch": "\u8BE5\u6B65\u9AA4\u7684\u5934\u90E8\u5185\u5BB9\uFF08\u7CFB\u7EDF\u63D0\u793A / \u5DE5\u5177\u5B9A\u4E49\uFF09\u4E0D\u5728\u4FDD\u7559\u8303\u56F4\u5185",
|
|
95
|
+
"browser.noContent": "\u5B8C\u6574\u5185\u5BB9\u4E0D\u5728\u5F53\u524D\u52A0\u8F7D\u7684\u6D88\u606F\u7A97\u53E3\u5185\uFF08\u5728\u804A\u5929\u9875\u52A0\u8F7D\u66F4\u65E9\u5386\u53F2\u540E\u53EF\u67E5\u770B\uFF09",
|
|
96
|
+
"browser.loading": "\u6B63\u5728\u4ECE\u66F4\u65E9\u7684\u4F1A\u8BDD\u5386\u53F2\u52A0\u8F7D\u5B8C\u6574\u5185\u5BB9\u2026",
|
|
97
|
+
"browser.preview": "\u9884\u89C8"
|
|
86
98
|
};
|
|
87
99
|
var DICT_EN = {
|
|
88
100
|
"tab": "Context",
|
|
@@ -159,7 +171,19 @@ var DICT_EN = {
|
|
|
159
171
|
"node.nonText": "(non-text message)",
|
|
160
172
|
"node.snapshot": "snapshot: ",
|
|
161
173
|
"cmd.desc": "View context makeup and how it evolves",
|
|
162
|
-
"cmd.close": "Close"
|
|
174
|
+
"cmd.close": "Close",
|
|
175
|
+
"browser.title": "Context browser",
|
|
176
|
+
"browser.hint": "browse what the live surface or a picked step was actually assembled from",
|
|
177
|
+
"browser.live": "Live (next request)",
|
|
178
|
+
"browser.liveNow": "Live \xB7 next request",
|
|
179
|
+
"browser.items": "{n} items",
|
|
180
|
+
"browser.missingLive": "\u2026 {n} earlier messages are also part of the context (outside the served window)",
|
|
181
|
+
"browser.approx": "Some removed messages of this step exceed retention \u2014 the makeup below is approximate",
|
|
182
|
+
"browser.noHeader": "Served by an older plugin build: token estimates only, no content",
|
|
183
|
+
"browser.noEpoch": "The header content (system prompt / tool schemas) of this step is outside retention",
|
|
184
|
+
"browser.noContent": "Full content is outside the loaded message window (load older history in Chat to view)",
|
|
185
|
+
"browser.loading": "Loading full content from older session history\u2026",
|
|
186
|
+
"browser.preview": "preview"
|
|
163
187
|
};
|
|
164
188
|
|
|
165
189
|
// src/client/modalStore.ts
|
|
@@ -276,6 +300,12 @@ function contextPressureOf(value) {
|
|
|
276
300
|
if (value === null || value === void 0 || typeof value !== "object") return null;
|
|
277
301
|
return value;
|
|
278
302
|
}
|
|
303
|
+
function headersOf(value) {
|
|
304
|
+
if (value === null || value === void 0 || typeof value !== "object") return null;
|
|
305
|
+
const headers = value.headers;
|
|
306
|
+
if (!Array.isArray(headers)) return null;
|
|
307
|
+
return value;
|
|
308
|
+
}
|
|
279
309
|
|
|
280
310
|
// src/client/react.ts
|
|
281
311
|
var React = require("react");
|
|
@@ -710,10 +740,6 @@ var STYLES = [
|
|
|
710
740
|
".lc-axis-mid { top: 69px; }",
|
|
711
741
|
".lc-axis-bot { top: 125px; }",
|
|
712
742
|
".lc-chart-scroll { position: relative; flex: 1; overflow-x: auto; overflow-y: hidden; min-width: 0; scrollbar-width: thin; }",
|
|
713
|
-
".lc-chart-scroll::-webkit-scrollbar { height: 8px; }",
|
|
714
|
-
".lc-chart-scroll::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--dsw-alias-label-secondary) 45%, transparent); border-radius: 4px; }",
|
|
715
|
-
".lc-chart-scroll::-webkit-scrollbar-thumb:hover { background: color-mix(in srgb, var(--dsw-alias-label-secondary) 70%, transparent); }",
|
|
716
|
-
".lc-chart-scroll::-webkit-scrollbar-track { background: transparent; }",
|
|
717
743
|
".lc-chart-fade { position: absolute; top: 0; bottom: 0; width: 26px; pointer-events: none; z-index: 2; }",
|
|
718
744
|
".lc-chart-fade-l { left: 0; background: linear-gradient(to right, var(--dsw-alias-bg-layer-1), transparent); }",
|
|
719
745
|
".lc-chart-fade-r { right: 0; background: linear-gradient(to left, var(--dsw-alias-bg-layer-1), transparent); }",
|
|
@@ -752,8 +778,16 @@ var STYLES = [
|
|
|
752
778
|
".lc-bar-fill { display: block; height: 100%; border-radius: 3px; }",
|
|
753
779
|
".lc-detail-num { width: 44px; text-align: right; }",
|
|
754
780
|
".lc-detail-pct { width: 34px; text-align: right; color: var(--dsw-alias-label-secondary); }",
|
|
755
|
-
|
|
781
|
+
// Section rows share one 14px vertical rhythm, owned by the ROW (flex gap
|
|
782
|
+
// covers the wrapped-row axis too), never by the cards inside: a card that
|
|
783
|
+
// IS a column (head, events/messages) drops its own bottom margin, and a
|
|
784
|
+
// card stacked inside a wrapper column (overview + trend) keeps its margin
|
|
785
|
+
// as the inner gap but the last one drops it — so every section boundary
|
|
786
|
+
// measures exactly one 14px, whichever way the flex wraps.
|
|
787
|
+
".lc-cols { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 14px; }",
|
|
756
788
|
".lc-col { flex: 1; min-width: 280px; }",
|
|
789
|
+
".lc-cols > .lc-card { margin-bottom: 0; }",
|
|
790
|
+
".lc-col > .lc-card:last-child { margin-bottom: 0; }",
|
|
757
791
|
// Head row: stats board + plugin info sit side by side under the shared
|
|
758
792
|
// `lc-cols` flex — stats takes ~7/10 of the row, plugin info ~3/10, both
|
|
759
793
|
// wrap onto their own line when the available width falls below each card's
|
|
@@ -761,7 +795,6 @@ var STYLES = [
|
|
|
761
795
|
// `.lc-card` themselves (rendered by StatsBoard / PluginInfo); the flex
|
|
762
796
|
// sizing lives on the head row's direct children so the existing card
|
|
763
797
|
// chrome doesn't change.
|
|
764
|
-
".lc-head > .lc-card { margin-bottom: 0; }",
|
|
765
798
|
".lc-head > .lc-card:first-child { flex: 7 1 0; min-width: 360px; }",
|
|
766
799
|
".lc-head > .lc-card:last-child { flex: 3 1 0; min-width: 220px; }",
|
|
767
800
|
// Plugin info: two full-width rows (Plugin / GitHub), each one horizontal
|
|
@@ -811,9 +844,308 @@ var STYLES = [
|
|
|
811
844
|
".lc-modal-title { font-weight: 600; font-size: 14px; }",
|
|
812
845
|
".lc-modal-close { margin-left: auto; border: 0; background: transparent; color: var(--dsw-alias-label-secondary); font-size: 18px; line-height: 1; padding: 2px 6px; border-radius: 6px; cursor: pointer; font-family: inherit; }",
|
|
813
846
|
".lc-modal-close:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-2); }",
|
|
814
|
-
".lc-modal-trend { margin-top: 14px; }"
|
|
847
|
+
".lc-modal-trend { margin-top: 14px; }",
|
|
848
|
+
// ---- Context browser card (progressive disclosure: category accordion ->
|
|
849
|
+
// element rows -> per-kind content) ----
|
|
850
|
+
".lc-br-pick { margin-left: auto; font: inherit; font-size: 12px; color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; padding: 3px 6px; max-width: 240px; }",
|
|
851
|
+
".lc-br-meta { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-bottom: 8px; color: var(--dsw-alias-label-secondary); }",
|
|
852
|
+
".lc-br-meta b { color: var(--dsw-alias-label-primary); }",
|
|
853
|
+
".lc-br-meta .lc-actual { color: var(--dsw-alias-state-success-primary); }",
|
|
854
|
+
".lc-br-note { margin-top: 8px; color: var(--dsw-alias-label-secondary); font-size: 12px; }",
|
|
855
|
+
".lc-br-cats { margin-top: 10px; display: flex; flex-direction: column; gap: 4px; }",
|
|
856
|
+
".lc-br-cat { border: 1px solid var(--dsw-alias-border-l1); border-radius: 8px; background: var(--dsw-alias-bg-layer-2); overflow: hidden; }",
|
|
857
|
+
".lc-br-cat-empty { opacity: 0.55; }",
|
|
858
|
+
".lc-br-cat-row { display: flex; align-items: center; gap: 8px; width: 100%; border: 0; background: transparent; color: var(--dsw-alias-label-primary); font: inherit; padding: 7px 10px; cursor: pointer; text-align: left; }",
|
|
859
|
+
".lc-br-cat-row:hover { background: var(--dsw-alias-bg-layer-1); }",
|
|
860
|
+
".lc-br-cat-row i { display: inline-block; width: 8px; height: 8px; border-radius: 2px; flex: none; }",
|
|
861
|
+
".lc-br-cat-label { font-weight: 600; }",
|
|
862
|
+
".lc-br-cat-count { color: var(--dsw-alias-label-secondary); font-size: 12px; flex: 1; }",
|
|
863
|
+
".lc-br-chev { flex: none; width: 12px; color: var(--dsw-alias-label-secondary); transition: transform 120ms ease; }",
|
|
864
|
+
".lc-br-chev-on { transform: rotate(90deg); }",
|
|
865
|
+
".lc-br-tokens { flex: none; color: var(--dsw-alias-label-secondary); font-size: 12px; }",
|
|
866
|
+
".lc-br-pct { flex: none; width: 36px; text-align: right; color: var(--dsw-alias-label-secondary); font-size: 12px; }",
|
|
867
|
+
".lc-br-body { border-top: 1px solid var(--dsw-alias-border-l1); padding: 4px 6px; display: flex; flex-direction: column; gap: 2px; }",
|
|
868
|
+
".lc-br-elem { border-radius: 6px; }",
|
|
869
|
+
".lc-br-elem-on { background: var(--dsw-alias-bg-layer-1); }",
|
|
870
|
+
".lc-br-elem-row { display: flex; align-items: center; gap: 8px; width: 100%; border: 0; background: transparent; color: var(--dsw-alias-label-primary); font: inherit; font-size: 12px; padding: 5px 6px; cursor: pointer; text-align: left; border-radius: 6px; }",
|
|
871
|
+
".lc-br-elem-row:hover { background: var(--dsw-alias-bg-layer-1); }",
|
|
872
|
+
".lc-br-tag { flex: none; font-size: 11px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-1); border: 1px solid var(--dsw-alias-border-l1); border-radius: 4px; padding: 0 6px; max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }",
|
|
873
|
+
".lc-br-preview { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }",
|
|
874
|
+
".lc-br-time { flex: none; color: var(--dsw-alias-label-secondary); font-size: 11px; }",
|
|
875
|
+
".lc-br-content { padding: 2px 6px 8px 26px; display: flex; flex-direction: column; gap: 6px; }",
|
|
876
|
+
".lc-br-pre { margin: 0; padding: 8px 10px; background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; color: var(--dsw-alias-label-primary); font-size: 12px; line-height: 1.55; white-space: pre-wrap; word-break: break-word; max-height: 320px; overflow-y: auto; scrollbar-width: thin; }",
|
|
877
|
+
".lc-br-dim { color: var(--dsw-alias-label-secondary); }",
|
|
878
|
+
".lc-br-call { display: flex; flex-direction: column; gap: 4px; align-items: flex-start; }"
|
|
815
879
|
].join("\n");
|
|
816
880
|
|
|
881
|
+
// src/client/assemble.ts
|
|
882
|
+
function headerAt(headers, seq) {
|
|
883
|
+
if (headers === null || headers.headers.length === 0) return null;
|
|
884
|
+
if (seq === null) return headers.headers[headers.headers.length - 1];
|
|
885
|
+
for (let i = headers.headers.length - 1; i >= 0; i--) {
|
|
886
|
+
if (headers.headers[i].seq < seq) return headers.headers[i];
|
|
887
|
+
}
|
|
888
|
+
return null;
|
|
889
|
+
}
|
|
890
|
+
function assemble(data, headers, seq) {
|
|
891
|
+
const live = seq === null;
|
|
892
|
+
let nodes;
|
|
893
|
+
if (live) {
|
|
894
|
+
nodes = data.nodes.slice();
|
|
895
|
+
} else {
|
|
896
|
+
const picked = [];
|
|
897
|
+
for (const n of data.nodes) {
|
|
898
|
+
if (n.seq < seq) picked.push(n);
|
|
899
|
+
}
|
|
900
|
+
for (const n of data.archive || []) {
|
|
901
|
+
if (n.seq < seq && n.gone !== void 0 && n.gone > seq) picked.push(n);
|
|
902
|
+
}
|
|
903
|
+
nodes = picked;
|
|
904
|
+
}
|
|
905
|
+
nodes.sort((a, b) => a.seq - b.seq);
|
|
906
|
+
let missingLive = 0;
|
|
907
|
+
if (data.droppedNodes > 0) {
|
|
908
|
+
if (live || data.surfaceFloor !== void 0 && seq > data.surfaceFloor) {
|
|
909
|
+
missingLive = data.droppedNodes;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
const approximate = !live && data.archiveFloor !== void 0 && seq < data.archiveFloor;
|
|
913
|
+
return { live, header: headerAt(headers, seq), nodes, missingLive, approximate };
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// src/client/components/nodes.tsx
|
|
917
|
+
function makeNodeText(kit) {
|
|
918
|
+
const { t } = kit;
|
|
919
|
+
return function nodeText(n) {
|
|
920
|
+
if (n.cat === "tool") {
|
|
921
|
+
return t("node.toolResult") + (n.tool ? " \u2190 " + n.tool : "") + (n.err ? " \u26A0" : "");
|
|
922
|
+
}
|
|
923
|
+
if (n.skill) return "Skill: " + n.skill;
|
|
924
|
+
if (n.calls) return t("node.calls") + n.calls.join(", ");
|
|
925
|
+
if (n.text) return n.form === "snapshot" ? t("node.snapshot") + n.text : n.text;
|
|
926
|
+
if (n.cat === "assistant") return t("node.empty");
|
|
927
|
+
if (n.cat === "inject") return t("form." + (n.form || "context"));
|
|
928
|
+
return t("node.nonText");
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
function makeNodeList(kit) {
|
|
932
|
+
const { t, tr, fmt: fmt3, fmtTime: fmtTime2 } = kit;
|
|
933
|
+
const nodeText = makeNodeText(kit);
|
|
934
|
+
return function NodeList(props) {
|
|
935
|
+
if (props.nodes.length === 0) {
|
|
936
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-empty" }, t("nodes.empty"));
|
|
937
|
+
}
|
|
938
|
+
const catColor = {};
|
|
939
|
+
for (const c of CATS) catColor[c.key] = c.color;
|
|
940
|
+
const rows = props.nodes.slice().reverse();
|
|
941
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-nodes" }, props.dropped > 0 ? /* @__PURE__ */ React.createElement("div", { className: "lc-nodes-more" }, tr("nodes.more", { n: props.dropped })) : null, rows.map((n) => {
|
|
942
|
+
const text = nodeText(n);
|
|
943
|
+
return /* @__PURE__ */ React.createElement("div", { key: n.seq, className: "lc-node" }, /* @__PURE__ */ React.createElement("i", { style: { background: catColor[n.cat] || "#999" } }), /* @__PURE__ */ React.createElement("span", { className: "lc-node-preview", title: text }, text), typeof n.time === "number" ? /* @__PURE__ */ React.createElement("span", { className: "lc-node-time" }, fmtTime2(n.time)) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-node-tokens" }, fmt3(n.tokens)));
|
|
944
|
+
}));
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// src/client/components/browser.tsx
|
|
949
|
+
function RawBlocks(props) {
|
|
950
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, props.blocks.map((b, i) => {
|
|
951
|
+
const blk = b;
|
|
952
|
+
if (blk !== null && typeof blk === "object" && (blk.type === "text" || blk.type === "reasoning") && typeof blk.text === "string") {
|
|
953
|
+
return /* @__PURE__ */ React.createElement("pre", { key: i, className: "lc-br-pre" + (blk.type === "reasoning" ? " lc-br-dim" : "") }, blk.text);
|
|
954
|
+
}
|
|
955
|
+
if (blk !== null && typeof blk === "object" && blk.type === "tool-result" && Array.isArray(blk.content)) {
|
|
956
|
+
return /* @__PURE__ */ React.createElement(RawBlocks, { key: i, blocks: blk.content });
|
|
957
|
+
}
|
|
958
|
+
return /* @__PURE__ */ React.createElement("pre", { key: i, className: "lc-br-pre lc-br-dim" }, JSON.stringify(b, null, 2));
|
|
959
|
+
}));
|
|
960
|
+
}
|
|
961
|
+
function NodeContent(props) {
|
|
962
|
+
const { node, conv } = props;
|
|
963
|
+
if (conv === void 0) {
|
|
964
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-br-content" }, node.text !== void 0 && node.text !== "" ? /* @__PURE__ */ React.createElement("pre", { className: "lc-br-pre" }, node.text) : null, /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, props.hint));
|
|
965
|
+
}
|
|
966
|
+
if (conv.kind === "assistant" && Array.isArray(conv.blocks)) {
|
|
967
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-br-content" }, conv.blocks.map((b, i) => {
|
|
968
|
+
const blk = b;
|
|
969
|
+
if (blk.kind === "text" && typeof blk.text === "string") {
|
|
970
|
+
return /* @__PURE__ */ React.createElement("pre", { key: i, className: "lc-br-pre" }, blk.text);
|
|
971
|
+
}
|
|
972
|
+
if (blk.kind === "reasoning" && typeof blk.text === "string") {
|
|
973
|
+
return /* @__PURE__ */ React.createElement("pre", { key: i, className: "lc-br-pre lc-br-dim" }, blk.text);
|
|
974
|
+
}
|
|
975
|
+
if (blk.kind === "tool-call") {
|
|
976
|
+
return /* @__PURE__ */ React.createElement("div", { key: i, className: "lc-br-call" }, /* @__PURE__ */ React.createElement("span", { className: "lc-br-tag" }, "\u2192 " + String(blk.name ?? "?")), typeof blk.argsRaw === "string" && blk.argsRaw !== "" ? /* @__PURE__ */ React.createElement("pre", { className: "lc-br-pre lc-br-dim" }, blk.argsRaw) : null);
|
|
977
|
+
}
|
|
978
|
+
return null;
|
|
979
|
+
}));
|
|
980
|
+
}
|
|
981
|
+
if (conv.kind === "tool-result") {
|
|
982
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-br-content" }, conv.call != null ? /* @__PURE__ */ React.createElement("div", { className: "lc-br-call" }, /* @__PURE__ */ React.createElement("span", { className: "lc-br-tag" }, "\u2190 " + conv.call.name), conv.call.argsRaw !== "" ? /* @__PURE__ */ React.createElement("pre", { className: "lc-br-pre lc-br-dim" }, conv.call.argsRaw) : null) : null, Array.isArray(conv.content) ? /* @__PURE__ */ React.createElement(RawBlocks, { blocks: conv.content }) : null);
|
|
983
|
+
}
|
|
984
|
+
if (conv.kind === "compaction") {
|
|
985
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-br-content" }, typeof conv.summary === "string" && conv.summary !== "" ? /* @__PURE__ */ React.createElement("pre", { className: "lc-br-pre" }, conv.summary) : null);
|
|
986
|
+
}
|
|
987
|
+
if (Array.isArray(conv.content)) {
|
|
988
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-br-content" }, /* @__PURE__ */ React.createElement(RawBlocks, { blocks: conv.content }));
|
|
989
|
+
}
|
|
990
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-br-content" }, /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, props.hint));
|
|
991
|
+
}
|
|
992
|
+
function makeContextBrowser(kit, StackedBar) {
|
|
993
|
+
const { t, tr, fmt: fmt3, fmtTime: fmtTime2, catLabel } = kit;
|
|
994
|
+
const nodeText = makeNodeText(kit);
|
|
995
|
+
const catColor = {};
|
|
996
|
+
for (const c of CATS) catColor[c.key] = c.color;
|
|
997
|
+
const MAX_AUTO_PAGES = 20;
|
|
998
|
+
return function ContextBrowser(props) {
|
|
999
|
+
var _a;
|
|
1000
|
+
const { data, headers } = props;
|
|
1001
|
+
const [sel, setSel] = React.useState("live");
|
|
1002
|
+
const [openCat, setOpenCat] = React.useState(null);
|
|
1003
|
+
const [openElem, setOpenElem] = React.useState(null);
|
|
1004
|
+
const convNodes = typeof props.useSession === "function" ? props.useSession((s) => s.nodes) : void 0;
|
|
1005
|
+
const bySeq = React.useMemo(() => {
|
|
1006
|
+
const m = /* @__PURE__ */ new Map();
|
|
1007
|
+
for (const n of convNodes ?? []) m.set(n.seq, n);
|
|
1008
|
+
return m;
|
|
1009
|
+
}, [convNodes]);
|
|
1010
|
+
const hasMore = typeof props.useSession === "function" ? props.useSession((s) => s.hasMore === true) : false;
|
|
1011
|
+
const loadingOlder = typeof props.useSession === "function" ? props.useSession((s) => s.loadingOlder === true) : false;
|
|
1012
|
+
const openSeq = openElem !== null && openElem.startsWith("n") ? Number(openElem.slice(1)) : null;
|
|
1013
|
+
const missingSeq = openSeq !== null && !bySeq.has(openSeq) ? openSeq : null;
|
|
1014
|
+
const [exhausted, setExhausted] = React.useState(false);
|
|
1015
|
+
const pagesRef = React.useRef(0);
|
|
1016
|
+
React.useEffect(() => {
|
|
1017
|
+
pagesRef.current = 0;
|
|
1018
|
+
setExhausted(false);
|
|
1019
|
+
}, [openElem]);
|
|
1020
|
+
const loadOlderHistory = props.loadOlderHistory;
|
|
1021
|
+
React.useEffect(() => {
|
|
1022
|
+
if (missingSeq === null || !hasMore || loadingOlder || exhausted) return;
|
|
1023
|
+
if (loadOlderHistory === void 0) return;
|
|
1024
|
+
if (pagesRef.current >= MAX_AUTO_PAGES) {
|
|
1025
|
+
setExhausted(true);
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
pagesRef.current += 1;
|
|
1029
|
+
void loadOlderHistory();
|
|
1030
|
+
}, [missingSeq, hasMore, loadingOlder, exhausted, bySeq, loadOlderHistory]);
|
|
1031
|
+
React.useEffect(() => {
|
|
1032
|
+
if (!hasMore && missingSeq !== null && !exhausted) setExhausted(true);
|
|
1033
|
+
}, [hasMore, missingSeq, exhausted]);
|
|
1034
|
+
const awaiting = missingSeq !== null && !exhausted && loadOlderHistory !== void 0 && hasMore;
|
|
1035
|
+
const requests = data.requests || [];
|
|
1036
|
+
const hoverReq = props.previewSeq !== null && props.previewSeq !== void 0 ? requests.find((r) => r.seq === props.previewSeq) ?? null : null;
|
|
1037
|
+
const req = hoverReq ?? (sel === "live" ? null : requests.find((r) => r.seq === sel) ?? null);
|
|
1038
|
+
const seq = req !== null ? req.seq : null;
|
|
1039
|
+
const view = assemble(data, headers, seq);
|
|
1040
|
+
const breakdown = req !== null ? req : data.current;
|
|
1041
|
+
const parts = partsOf(breakdown);
|
|
1042
|
+
const total = breakdown.total;
|
|
1043
|
+
const pick = (v) => {
|
|
1044
|
+
setSel(v === "live" ? "live" : Number(v));
|
|
1045
|
+
setOpenCat(null);
|
|
1046
|
+
setOpenElem(null);
|
|
1047
|
+
};
|
|
1048
|
+
const byCat = {};
|
|
1049
|
+
for (const n of view.nodes) (byCat[_a = n.cat] ?? (byCat[_a] = [])).push(n);
|
|
1050
|
+
const toolCount = (c) => {
|
|
1051
|
+
if (c === "system") return view.header !== null && view.header.system !== void 0 ? 1 : 0;
|
|
1052
|
+
if (c === "tools") return view.header !== null ? view.header.tools.length : 0;
|
|
1053
|
+
return byCat[c]?.length ?? 0;
|
|
1054
|
+
};
|
|
1055
|
+
const toggleCat = (c) => {
|
|
1056
|
+
const openable = toolCount(c) > 0 || (c === "system" || c === "tools") && view.header === null;
|
|
1057
|
+
if (!openable) return;
|
|
1058
|
+
setOpenCat(openCat === c ? null : c);
|
|
1059
|
+
setOpenElem(null);
|
|
1060
|
+
};
|
|
1061
|
+
const toggleElem = (key) => setOpenElem(openElem === key ? null : key);
|
|
1062
|
+
const elemRow = (key, tag, preview, tokens, time, body) => {
|
|
1063
|
+
const open = openElem === key;
|
|
1064
|
+
return /* @__PURE__ */ React.createElement("div", { key, className: "lc-br-elem" + (open ? " lc-br-elem-on" : "") }, /* @__PURE__ */ React.createElement("button", { type: "button", className: "lc-br-elem-row", onClick: () => {
|
|
1065
|
+
toggleElem(key);
|
|
1066
|
+
} }, /* @__PURE__ */ React.createElement("span", { className: "lc-br-chev" + (open ? " lc-br-chev-on" : "") }, "\u25B8"), tag !== null ? /* @__PURE__ */ React.createElement("span", { className: "lc-br-tag" }, tag) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-br-preview" }, preview), time !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-br-time" }, fmtTime2(time)) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-br-tokens" }, "\u2248" + fmt3(tokens))), open ? body : null);
|
|
1067
|
+
};
|
|
1068
|
+
const catBody = (c) => {
|
|
1069
|
+
if (c === "system") {
|
|
1070
|
+
if (view.header === null) return /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, t(headers === null ? "browser.noHeader" : "browser.noEpoch"));
|
|
1071
|
+
const system = view.header.system;
|
|
1072
|
+
if (system === void 0) return null;
|
|
1073
|
+
return elemRow(
|
|
1074
|
+
"sys",
|
|
1075
|
+
null,
|
|
1076
|
+
system.replace(/\s+/g, " ").trim().slice(0, 80),
|
|
1077
|
+
breakdown.system,
|
|
1078
|
+
void 0,
|
|
1079
|
+
/* @__PURE__ */ React.createElement("div", { className: "lc-br-content" }, /* @__PURE__ */ React.createElement("pre", { className: "lc-br-pre" }, system))
|
|
1080
|
+
);
|
|
1081
|
+
}
|
|
1082
|
+
if (c === "tools") {
|
|
1083
|
+
if (view.header === null) return /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, t(headers === null ? "browser.noHeader" : "browser.noEpoch"));
|
|
1084
|
+
return view.header.tools.map((tool) => {
|
|
1085
|
+
const schema = tool.schema !== void 0 ? JSON.stringify(tool.schema, null, 2) : "";
|
|
1086
|
+
return elemRow(
|
|
1087
|
+
"tool:" + tool.name,
|
|
1088
|
+
null,
|
|
1089
|
+
tool.name,
|
|
1090
|
+
tool.tokens,
|
|
1091
|
+
void 0,
|
|
1092
|
+
/* @__PURE__ */ React.createElement("div", { className: "lc-br-content" }, tool.description !== void 0 ? /* @__PURE__ */ React.createElement("pre", { className: "lc-br-pre" }, tool.description) : null, schema !== "" ? /* @__PURE__ */ React.createElement("pre", { className: "lc-br-pre lc-br-dim" }, schema) : null)
|
|
1093
|
+
);
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
const nodes = byCat[c] ?? [];
|
|
1097
|
+
return nodes.map((n) => {
|
|
1098
|
+
let tag = null;
|
|
1099
|
+
let preview = nodeText(n);
|
|
1100
|
+
if (n.cat === "tool") {
|
|
1101
|
+
tag = (n.tool ?? "?") + (n.err ? " \u26A0" : "");
|
|
1102
|
+
preview = t("node.toolResult") + (n.err ? " \u26A0" : "");
|
|
1103
|
+
} else if (n.cat === "inject" && !n.skill) {
|
|
1104
|
+
tag = t("form." + (n.form || "context"));
|
|
1105
|
+
if (n.text !== void 0 && n.text !== "") {
|
|
1106
|
+
preview = n.form === "snapshot" ? t("node.snapshot") + n.text : n.text;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
return elemRow(
|
|
1110
|
+
"n" + n.seq,
|
|
1111
|
+
tag,
|
|
1112
|
+
preview,
|
|
1113
|
+
n.tokens,
|
|
1114
|
+
n.time,
|
|
1115
|
+
/* @__PURE__ */ React.createElement(
|
|
1116
|
+
NodeContent,
|
|
1117
|
+
{
|
|
1118
|
+
node: n,
|
|
1119
|
+
conv: bySeq.get(n.seq),
|
|
1120
|
+
hint: bySeq.get(n.seq) === void 0 && awaiting ? t("browser.loading") : t("browser.noContent")
|
|
1121
|
+
}
|
|
1122
|
+
)
|
|
1123
|
+
);
|
|
1124
|
+
});
|
|
1125
|
+
};
|
|
1126
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("browser.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("browser.hint")), /* @__PURE__ */ React.createElement(
|
|
1127
|
+
"select",
|
|
1128
|
+
{
|
|
1129
|
+
className: "lc-br-pick",
|
|
1130
|
+
value: seq === null ? "live" : String(seq),
|
|
1131
|
+
onChange: (e) => {
|
|
1132
|
+
pick(e.target.value);
|
|
1133
|
+
}
|
|
1134
|
+
},
|
|
1135
|
+
/* @__PURE__ */ React.createElement("option", { value: "live" }, t("browser.live")),
|
|
1136
|
+
requests.slice().reverse().map((r) => /* @__PURE__ */ React.createElement("option", { key: r.seq, value: String(r.seq) }, tr("detail.step", { t: r.turn ?? 0, s: r.step ?? 0 }) + " \xB7 " + fmtTime2(r.time)))
|
|
1137
|
+
)), /* @__PURE__ */ React.createElement("div", { className: "lc-br-meta" }, /* @__PURE__ */ React.createElement("b", null, req !== null ? tr("detail.step", { t: req.turn ?? 0, s: req.step ?? 0 }) : t("browser.liveNow")), req !== null ? /* @__PURE__ */ React.createElement("span", null, fmtTime2(req.time)) : null, hoverReq !== null ? /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("browser.preview")) : null, /* @__PURE__ */ React.createElement("span", null, tr("detail.estTotal", { n: fmt3(total) })), req !== null && req.prompt !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-actual" }, tr("detail.actual", { n: fmt3(req.prompt) })) : null), /* @__PURE__ */ React.createElement(StackedBar, { parts, height: 10 }), view.missingLive > 0 ? /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, tr("browser.missingLive", { n: view.missingLive })) : null, view.approximate ? /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, t("browser.approx")) : null, /* @__PURE__ */ React.createElement("div", { className: "lc-br-cats" }, CATS.map((c) => {
|
|
1138
|
+
const count = toolCount(c.key);
|
|
1139
|
+
const v = breakdown[c.key] || 0;
|
|
1140
|
+
const openable = count > 0 || (c.key === "system" || c.key === "tools") && view.header === null;
|
|
1141
|
+
const open = openCat === c.key && openable;
|
|
1142
|
+
return /* @__PURE__ */ React.createElement("div", { key: c.key, className: "lc-br-cat" + (openable ? "" : " lc-br-cat-empty") }, /* @__PURE__ */ React.createElement("button", { type: "button", className: "lc-br-cat-row", onClick: () => {
|
|
1143
|
+
toggleCat(c.key);
|
|
1144
|
+
} }, /* @__PURE__ */ React.createElement("span", { className: "lc-br-chev" + (open ? " lc-br-chev-on" : "") }, "\u25B8"), /* @__PURE__ */ React.createElement("i", { style: { background: c.color } }), /* @__PURE__ */ React.createElement("span", { className: "lc-br-cat-label" }, catLabel(c.key)), /* @__PURE__ */ React.createElement("span", { className: "lc-br-cat-count" }, tr("browser.items", { n: count })), /* @__PURE__ */ React.createElement("span", { className: "lc-br-tokens" }, "\u2248" + fmt3(v)), /* @__PURE__ */ React.createElement("span", { className: "lc-br-pct" }, total > 0 ? Math.round(v / total * 100) + "%" : "")), open ? /* @__PURE__ */ React.createElement("div", { className: "lc-br-body" }, catBody(c.key)) : null);
|
|
1145
|
+
})));
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
|
|
817
1149
|
// src/client/components/events.tsx
|
|
818
1150
|
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
819
1151
|
|
|
@@ -893,37 +1225,9 @@ function makeEventList(kit) {
|
|
|
893
1225
|
};
|
|
894
1226
|
}
|
|
895
1227
|
|
|
896
|
-
// src/client/components/nodes.tsx
|
|
897
|
-
function makeNodeList(kit) {
|
|
898
|
-
const { t, tr, fmt: fmt3, fmtTime: fmtTime2 } = kit;
|
|
899
|
-
function nodeText(n) {
|
|
900
|
-
if (n.cat === "tool") {
|
|
901
|
-
return t("node.toolResult") + (n.tool ? " \u2190 " + n.tool : "") + (n.err ? " \u26A0" : "");
|
|
902
|
-
}
|
|
903
|
-
if (n.skill) return "Skill: " + n.skill;
|
|
904
|
-
if (n.calls) return t("node.calls") + n.calls.join(", ");
|
|
905
|
-
if (n.text) return n.form === "snapshot" ? t("node.snapshot") + n.text : n.text;
|
|
906
|
-
if (n.cat === "assistant") return t("node.empty");
|
|
907
|
-
if (n.cat === "inject") return t("form." + (n.form || "context"));
|
|
908
|
-
return t("node.nonText");
|
|
909
|
-
}
|
|
910
|
-
return function NodeList(props) {
|
|
911
|
-
if (props.nodes.length === 0) {
|
|
912
|
-
return /* @__PURE__ */ React.createElement("div", { className: "lc-empty" }, t("nodes.empty"));
|
|
913
|
-
}
|
|
914
|
-
const catColor = {};
|
|
915
|
-
for (const c of CATS) catColor[c.key] = c.color;
|
|
916
|
-
const rows = props.nodes.slice().reverse();
|
|
917
|
-
return /* @__PURE__ */ React.createElement("div", { className: "lc-nodes" }, props.dropped > 0 ? /* @__PURE__ */ React.createElement("div", { className: "lc-nodes-more" }, tr("nodes.more", { n: props.dropped })) : null, rows.map((n) => {
|
|
918
|
-
const text = nodeText(n);
|
|
919
|
-
return /* @__PURE__ */ React.createElement("div", { key: n.seq, className: "lc-node" }, /* @__PURE__ */ React.createElement("i", { style: { background: catColor[n.cat] || "#999" } }), /* @__PURE__ */ React.createElement("span", { className: "lc-node-preview", title: text }, text), typeof n.time === "number" ? /* @__PURE__ */ React.createElement("span", { className: "lc-node-time" }, fmtTime2(n.time)) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-node-tokens" }, fmt3(n.tokens)));
|
|
920
|
-
}));
|
|
921
|
-
};
|
|
922
|
-
}
|
|
923
|
-
|
|
924
1228
|
// src/client/meta.ts
|
|
925
1229
|
var PLUGIN_NAME = "dsh-context";
|
|
926
|
-
var PLUGIN_VERSION = true ? "0.
|
|
1230
|
+
var PLUGIN_VERSION = true ? "0.12.0" : "0.0.0-dev";
|
|
927
1231
|
var PLUGIN_REPO = true ? "https://github.com/bowenliang123/dsh-context" : "https://github.com/bowenliang123/dsh-context";
|
|
928
1232
|
var PLUGIN_REPO_SHORT = PLUGIN_REPO.replace(/^https?:\/\/github\.com\//, "");
|
|
929
1233
|
|
|
@@ -1008,10 +1312,12 @@ function makeContextView(ctx, kit) {
|
|
|
1008
1312
|
const NodeList = makeNodeList(kit);
|
|
1009
1313
|
const StatsBoard = makeStatsBoard(kit);
|
|
1010
1314
|
const PluginInfo = makePluginInfo(kit);
|
|
1315
|
+
const ContextBrowser = makeContextBrowser(kit, StackedBar);
|
|
1011
1316
|
return function ContextView(props) {
|
|
1012
1317
|
const sessionId = props.sessionId;
|
|
1013
1318
|
const data = typeof props.useProjection === "function" ? timelineOf(props.useProjection("contextTimeline")) : null;
|
|
1014
1319
|
const pressure = typeof props.useProjection === "function" ? contextPressureOf(props.useProjection("contextPressure")) : null;
|
|
1320
|
+
const headers = typeof props.useProjection === "function" ? headersOf(props.useProjection("contextHeaders")) : null;
|
|
1015
1321
|
const [selectedSeq, setSelectedSeq] = React.useState(null);
|
|
1016
1322
|
const [hoveredSeq, setHoveredSeq] = React.useState(null);
|
|
1017
1323
|
const [hoverTurn, setHoverTurn] = React.useState(null);
|
|
@@ -1081,7 +1387,7 @@ function makeContextView(ctx, kit) {
|
|
|
1081
1387
|
}
|
|
1082
1388
|
}
|
|
1083
1389
|
const head = headlineOf(data, pressure);
|
|
1084
|
-
return /* @__PURE__ */ React.createElement("div", { className: "lc-root", ref: rootRef }, /* @__PURE__ */ React.createElement("div", { className: "lc-cols lc-head" }, /* @__PURE__ */ React.createElement(StatsBoard, { requests, events }), /* @__PURE__ */ React.createElement(PluginInfo, null)), /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("overview.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, (data.model ? data.model : "") + (data.provider ? " \xB7 " + data.provider : ""))), /* @__PURE__ */ React.createElement("div", { className: "lc-overview-num" }, /* @__PURE__ */ React.createElement("b", null, fmt3(head.tokens)), /* @__PURE__ */ React.createElement("span", null, head.window ? " / " + fmt3(head.window) + " " + tr("overview.ofWindow", { p: head.pct ?? 0 }) : " " + t("overview.estimate")), !head.estimated ? /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("overview.splitEst")) : null), /* @__PURE__ */ React.createElement(StackedBar, { parts: head.parts, height: 16, max: head.window, hoverKey: hoverCat, onHoverKey: setHoverCat }), /* @__PURE__ */ React.createElement(Legend, { parts: head.parts, hoverKey: hoverCat, onHoverKey: setHoverCat }), data.toolList && data.toolList.length > 0 ? /* @__PURE__ */ React.createElement("div", { className: "lc-tools" }, t("tools.top"), data.toolList.slice().sort((a, b) => b.tokens - a.tokens).slice(0, 5).map((tool) => {
|
|
1390
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-root", ref: rootRef }, /* @__PURE__ */ React.createElement("div", { className: "lc-cols lc-head" }, /* @__PURE__ */ React.createElement(StatsBoard, { requests, events }), /* @__PURE__ */ React.createElement(PluginInfo, null)), /* @__PURE__ */ React.createElement("div", { className: "lc-cols" }, /* @__PURE__ */ React.createElement("div", { className: "lc-col" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("overview.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, (data.model ? data.model : "") + (data.provider ? " \xB7 " + data.provider : ""))), /* @__PURE__ */ React.createElement("div", { className: "lc-overview-num" }, /* @__PURE__ */ React.createElement("b", null, fmt3(head.tokens)), /* @__PURE__ */ React.createElement("span", null, head.window ? " / " + fmt3(head.window) + " " + tr("overview.ofWindow", { p: head.pct ?? 0 }) : " " + t("overview.estimate")), !head.estimated ? /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("overview.splitEst")) : null), /* @__PURE__ */ React.createElement(StackedBar, { parts: head.parts, height: 16, max: head.window, hoverKey: hoverCat, onHoverKey: setHoverCat }), /* @__PURE__ */ React.createElement(Legend, { parts: head.parts, hoverKey: hoverCat, onHoverKey: setHoverCat }), data.toolList && data.toolList.length > 0 ? /* @__PURE__ */ React.createElement("div", { className: "lc-tools" }, t("tools.top"), data.toolList.slice().sort((a, b) => b.tokens - a.tokens).slice(0, 5).map((tool) => {
|
|
1085
1391
|
return /* @__PURE__ */ React.createElement("span", { key: tool.name, className: "lc-tool-chip" }, tool.name + " " + fmt3(tool.tokens));
|
|
1086
1392
|
}), data.toolList.length > 5 ? /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, " " + tr("tools.more", { n: data.toolList.length })) : null) : null), /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("trend.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("trend.hint")), /* @__PURE__ */ React.createElement("div", { className: "lc-gran" }, /* @__PURE__ */ React.createElement(
|
|
1087
1393
|
"button",
|
|
@@ -1115,7 +1421,16 @@ function makeContextView(ctx, kit) {
|
|
|
1115
1421
|
onHover: setHoveredSeq,
|
|
1116
1422
|
onHoverTurn: setHoverTurn
|
|
1117
1423
|
}
|
|
1118
|
-
), /* @__PURE__ */ React.createElement(RequestDetail, { request: activeReq, marker: activeReq !== null ? markerOf(activeReq) : void 0 }))), /* @__PURE__ */ React.createElement("div", { className: "lc-
|
|
1424
|
+
), /* @__PURE__ */ React.createElement(RequestDetail, { request: activeReq, marker: activeReq !== null ? markerOf(activeReq) : void 0 })))), /* @__PURE__ */ React.createElement("div", { className: "lc-col" }, /* @__PURE__ */ React.createElement(
|
|
1425
|
+
ContextBrowser,
|
|
1426
|
+
{
|
|
1427
|
+
data,
|
|
1428
|
+
headers,
|
|
1429
|
+
useSession: props.useSession,
|
|
1430
|
+
loadOlderHistory: props.loadOlderHistory,
|
|
1431
|
+
previewSeq: hoveredSeq
|
|
1432
|
+
}
|
|
1433
|
+
))), /* @__PURE__ */ React.createElement("div", { className: "lc-cols" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("events.title"), /* @__PURE__ */ React.createElement("div", { className: "lc-kinds" }, EVENT_KINDS.map((k) => /* @__PURE__ */ React.createElement(
|
|
1119
1434
|
"button",
|
|
1120
1435
|
{
|
|
1121
1436
|
key: k,
|
|
@@ -1161,6 +1476,20 @@ function apply(ctx) {
|
|
|
1161
1476
|
}, "dsh-context: styles");
|
|
1162
1477
|
const kit = makeViewKit(t);
|
|
1163
1478
|
const ContextView = makeContextView(ctx, kit);
|
|
1479
|
+
ctx.effect(() => {
|
|
1480
|
+
const noop = () => {
|
|
1481
|
+
};
|
|
1482
|
+
const sessions = ctx.get("sessions");
|
|
1483
|
+
if (sessions === void 0 || typeof sessions.provide !== "function") return noop;
|
|
1484
|
+
try {
|
|
1485
|
+
return sessions.provide({
|
|
1486
|
+
props: ["loadOlderHistory"],
|
|
1487
|
+
resolve: (binding) => ({ props: { loadOlderHistory: () => binding.session.loadOlder() } })
|
|
1488
|
+
});
|
|
1489
|
+
} catch {
|
|
1490
|
+
return noop;
|
|
1491
|
+
}
|
|
1492
|
+
}, "dsh-context: loadOlderHistory prop");
|
|
1164
1493
|
ctx.slots.inject("conversation.view", () => {
|
|
1165
1494
|
return ctx.slots.register(
|
|
1166
1495
|
// order 20 renders right of Chat (0) and Trajectory (10); the locale
|