dsh-context 0.11.2 → 0.12.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/README.md +12 -1
- package/lib/client.js +376 -46
- package/lib/index.js +1030 -74
- package/package.json +7 -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
|
@@ -37,7 +37,7 @@ var DICT_ZH = {
|
|
|
37
37
|
"trend.title": "\u5386\u53F2\u8D8B\u52BF",
|
|
38
38
|
"gran.step": "\u6B65\u9AA4",
|
|
39
39
|
"gran.turn": "\u8F6E\u6B21",
|
|
40
|
-
"trend.hint": "\u60AC\u505C\
|
|
40
|
+
"trend.hint": "\u60AC\u505C\u67E5\u770B\u8BE6\u60C5\uFF0C\u2702 \u8868\u793A\u538B\u7F29/\u526A\u679D\uFF0CStep/Turn \u5207\u6362\u7C92\u5EA6",
|
|
41
41
|
"trend.empty": "\u53D1\u8D77\u4E00\u8F6E\u5BF9\u8BDD\u540E\uFF0C\u8FD9\u91CC\u4F1A\u5C55\u793A\u6BCF\u6B21\u6A21\u578B\u8BF7\u6C42\u7684\u4E0A\u4E0B\u6587\u6784\u6210",
|
|
42
42
|
"detail.step": "\u7B2C {t} \u8F6E \xB7 \u7B2C {s} \u6B65",
|
|
43
43
|
"detail.turn": "\u7B2C {t} \u8F6E \xB7 \u5171 {n} \u6B65",
|
|
@@ -82,7 +82,18 @@ 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\u5668",
|
|
87
|
+
"browser.live": "\u5F53\u524D\uFF08\u4E0B\u4E00\u6B21\u8BF7\u6C42\uFF09",
|
|
88
|
+
"browser.liveNow": "\u5F53\u524D \xB7 \u4E0B\u4E00\u6B21\u8BF7\u6C42",
|
|
89
|
+
"browser.items": "{n} \u9879",
|
|
90
|
+
"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",
|
|
91
|
+
"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",
|
|
92
|
+
"browser.noHeader": "\u6B64\u6570\u636E\u6765\u81EA\u65E7\u7248\u63D2\u4EF6\uFF1A\u4EC5\u63D0\u4F9B token \u4F30\u7B97\uFF0C\u65E0\u5B9E\u9645\u5185\u5BB9",
|
|
93
|
+
"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",
|
|
94
|
+
"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",
|
|
95
|
+
"browser.loading": "\u6B63\u5728\u4ECE\u66F4\u65E9\u7684\u4F1A\u8BDD\u5386\u53F2\u52A0\u8F7D\u5B8C\u6574\u5185\u5BB9\u2026",
|
|
96
|
+
"browser.preview": "\u9884\u89C8"
|
|
86
97
|
};
|
|
87
98
|
var DICT_EN = {
|
|
88
99
|
"tab": "Context",
|
|
@@ -159,7 +170,18 @@ var DICT_EN = {
|
|
|
159
170
|
"node.nonText": "(non-text message)",
|
|
160
171
|
"node.snapshot": "snapshot: ",
|
|
161
172
|
"cmd.desc": "View context makeup and how it evolves",
|
|
162
|
-
"cmd.close": "Close"
|
|
173
|
+
"cmd.close": "Close",
|
|
174
|
+
"browser.title": "Context browser",
|
|
175
|
+
"browser.live": "Live (next request)",
|
|
176
|
+
"browser.liveNow": "Live \xB7 next request",
|
|
177
|
+
"browser.items": "{n} items",
|
|
178
|
+
"browser.missingLive": "\u2026 {n} earlier messages are also part of the context (outside the served window)",
|
|
179
|
+
"browser.approx": "Some removed messages of this step exceed retention \u2014 the makeup below is approximate",
|
|
180
|
+
"browser.noHeader": "Served by an older plugin build: token estimates only, no content",
|
|
181
|
+
"browser.noEpoch": "The header content (system prompt / tool schemas) of this step is outside retention",
|
|
182
|
+
"browser.noContent": "Full content is outside the loaded message window (load older history in Chat to view)",
|
|
183
|
+
"browser.loading": "Loading full content from older session history\u2026",
|
|
184
|
+
"browser.preview": "preview"
|
|
163
185
|
};
|
|
164
186
|
|
|
165
187
|
// src/client/modalStore.ts
|
|
@@ -276,6 +298,12 @@ function contextPressureOf(value) {
|
|
|
276
298
|
if (value === null || value === void 0 || typeof value !== "object") return null;
|
|
277
299
|
return value;
|
|
278
300
|
}
|
|
301
|
+
function headersOf(value) {
|
|
302
|
+
if (value === null || value === void 0 || typeof value !== "object") return null;
|
|
303
|
+
const headers = value.headers;
|
|
304
|
+
if (!Array.isArray(headers)) return null;
|
|
305
|
+
return value;
|
|
306
|
+
}
|
|
279
307
|
|
|
280
308
|
// src/client/react.ts
|
|
281
309
|
var React = require("react");
|
|
@@ -435,7 +463,7 @@ function makeTrendChart(kit) {
|
|
|
435
463
|
const CHART_H = 112;
|
|
436
464
|
const BAR_W = 14;
|
|
437
465
|
const BAR_GAP = 2;
|
|
438
|
-
const
|
|
466
|
+
const TURN_FILLS = ["rgba(128,128,128,0.12)", "rgba(128,128,128,0.26)"];
|
|
439
467
|
return function TrendChart(props) {
|
|
440
468
|
const requests = props.requests;
|
|
441
469
|
const markers = props.markers;
|
|
@@ -565,7 +593,7 @@ function makeTrendChart(kit) {
|
|
|
565
593
|
className: "lc-turn" + (on ? " lc-turn-on" : ""),
|
|
566
594
|
style: {
|
|
567
595
|
width: blockW + "px",
|
|
568
|
-
background:
|
|
596
|
+
background: TURN_FILLS[gi % TURN_FILLS.length]
|
|
569
597
|
},
|
|
570
598
|
title: "T" + grp.turn,
|
|
571
599
|
onMouseEnter: () => {
|
|
@@ -710,10 +738,6 @@ var STYLES = [
|
|
|
710
738
|
".lc-axis-mid { top: 69px; }",
|
|
711
739
|
".lc-axis-bot { top: 125px; }",
|
|
712
740
|
".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
741
|
".lc-chart-fade { position: absolute; top: 0; bottom: 0; width: 26px; pointer-events: none; z-index: 2; }",
|
|
718
742
|
".lc-chart-fade-l { left: 0; background: linear-gradient(to right, var(--dsw-alias-bg-layer-1), transparent); }",
|
|
719
743
|
".lc-chart-fade-r { right: 0; background: linear-gradient(to left, var(--dsw-alias-bg-layer-1), transparent); }",
|
|
@@ -732,13 +756,16 @@ var STYLES = [
|
|
|
732
756
|
".lc-bar:hover { background: var(--dsw-alias-bg-layer-2); }",
|
|
733
757
|
".lc-bar-selected { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 1px; }",
|
|
734
758
|
".lc-bar-hovered { outline: 1px dashed var(--dsw-alias-brand-primary); outline-offset: 1px; }",
|
|
735
|
-
".lc-bar-in-turn { background: rgba(
|
|
759
|
+
".lc-bar-in-turn { background: rgba(128,128,128,0.14); }",
|
|
736
760
|
".lc-bar-stack { display: flex; flex-direction: column-reverse; width: 100%; }",
|
|
737
761
|
".lc-bar-stack > div { width: 100%; }",
|
|
738
762
|
".lc-bar-marker { position: absolute; top: -16px; left: 50%; transform: translateX(-50%); font-size: 11px; color: var(--dsw-alias-state-warn-primary); }",
|
|
763
|
+
// Turn strip: NEUTRAL zebra fills (inline, see TURN_FILLS) with secondary
|
|
764
|
+
// text — never the category palette, or the strip reads as a detached
|
|
765
|
+
// bottom segment of the bars above it.
|
|
739
766
|
".lc-turns { display: flex; gap: 2px; width: max-content; min-width: 100%; margin-top: 4px; }",
|
|
740
|
-
".lc-turn { flex: none; box-sizing: border-box; text-align: center; font-size: 10px; line-height: 14px; font-weight: 600; color:
|
|
741
|
-
".lc-turn-on { filter: brightness(1.35);
|
|
767
|
+
".lc-turn { flex: none; box-sizing: border-box; text-align: center; font-size: 10px; line-height: 14px; font-weight: 600; color: var(--dsw-alias-label-secondary); border-radius: 3px; height: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: default; transition: filter 120ms, opacity 120ms; }",
|
|
768
|
+
".lc-turn-on { filter: brightness(1.35); color: var(--dsw-alias-label-primary); }",
|
|
742
769
|
".lc-detail { margin-top: 12px; border-top: 1px solid var(--dsw-alias-border-l1); padding-top: 12px; }",
|
|
743
770
|
".lc-detail-head { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-bottom: 8px; color: var(--dsw-alias-label-secondary); }",
|
|
744
771
|
".lc-detail-head b { color: var(--dsw-alias-label-primary); }",
|
|
@@ -752,8 +779,16 @@ var STYLES = [
|
|
|
752
779
|
".lc-bar-fill { display: block; height: 100%; border-radius: 3px; }",
|
|
753
780
|
".lc-detail-num { width: 44px; text-align: right; }",
|
|
754
781
|
".lc-detail-pct { width: 34px; text-align: right; color: var(--dsw-alias-label-secondary); }",
|
|
755
|
-
|
|
782
|
+
// Section rows share one 14px vertical rhythm, owned by the ROW (flex gap
|
|
783
|
+
// covers the wrapped-row axis too), never by the cards inside: a card that
|
|
784
|
+
// IS a column (head, events/messages) drops its own bottom margin, and a
|
|
785
|
+
// card stacked inside a wrapper column (overview + trend) keeps its margin
|
|
786
|
+
// as the inner gap but the last one drops it — so every section boundary
|
|
787
|
+
// measures exactly one 14px, whichever way the flex wraps.
|
|
788
|
+
".lc-cols { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 14px; }",
|
|
756
789
|
".lc-col { flex: 1; min-width: 280px; }",
|
|
790
|
+
".lc-cols > .lc-card { margin-bottom: 0; }",
|
|
791
|
+
".lc-col > .lc-card:last-child { margin-bottom: 0; }",
|
|
757
792
|
// Head row: stats board + plugin info sit side by side under the shared
|
|
758
793
|
// `lc-cols` flex — stats takes ~7/10 of the row, plugin info ~3/10, both
|
|
759
794
|
// wrap onto their own line when the available width falls below each card's
|
|
@@ -761,7 +796,6 @@ var STYLES = [
|
|
|
761
796
|
// `.lc-card` themselves (rendered by StatsBoard / PluginInfo); the flex
|
|
762
797
|
// sizing lives on the head row's direct children so the existing card
|
|
763
798
|
// chrome doesn't change.
|
|
764
|
-
".lc-head > .lc-card { margin-bottom: 0; }",
|
|
765
799
|
".lc-head > .lc-card:first-child { flex: 7 1 0; min-width: 360px; }",
|
|
766
800
|
".lc-head > .lc-card:last-child { flex: 3 1 0; min-width: 220px; }",
|
|
767
801
|
// Plugin info: two full-width rows (Plugin / GitHub), each one horizontal
|
|
@@ -811,9 +845,308 @@ var STYLES = [
|
|
|
811
845
|
".lc-modal-title { font-weight: 600; font-size: 14px; }",
|
|
812
846
|
".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
847
|
".lc-modal-close:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-2); }",
|
|
814
|
-
".lc-modal-trend { margin-top: 14px; }"
|
|
848
|
+
".lc-modal-trend { margin-top: 14px; }",
|
|
849
|
+
// ---- Context browser card (progressive disclosure: category accordion ->
|
|
850
|
+
// element rows -> per-kind content) ----
|
|
851
|
+
".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; }",
|
|
852
|
+
".lc-br-meta { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-bottom: 8px; color: var(--dsw-alias-label-secondary); }",
|
|
853
|
+
".lc-br-meta b { color: var(--dsw-alias-label-primary); }",
|
|
854
|
+
".lc-br-meta .lc-actual { color: var(--dsw-alias-state-success-primary); }",
|
|
855
|
+
".lc-br-note { margin-top: 8px; color: var(--dsw-alias-label-secondary); font-size: 12px; }",
|
|
856
|
+
".lc-br-cats { margin-top: 10px; display: flex; flex-direction: column; gap: 4px; }",
|
|
857
|
+
".lc-br-cat { border: 1px solid var(--dsw-alias-border-l1); border-radius: 8px; background: var(--dsw-alias-bg-layer-2); overflow: hidden; }",
|
|
858
|
+
".lc-br-cat-empty { opacity: 0.55; }",
|
|
859
|
+
".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; }",
|
|
860
|
+
".lc-br-cat-row:hover { background: var(--dsw-alias-bg-layer-1); }",
|
|
861
|
+
".lc-br-cat-row i { display: inline-block; width: 8px; height: 8px; border-radius: 2px; flex: none; }",
|
|
862
|
+
".lc-br-cat-label { font-weight: 600; }",
|
|
863
|
+
".lc-br-cat-count { color: var(--dsw-alias-label-secondary); font-size: 12px; flex: 1; }",
|
|
864
|
+
".lc-br-chev { flex: none; width: 12px; color: var(--dsw-alias-label-secondary); transition: transform 120ms ease; }",
|
|
865
|
+
".lc-br-chev-on { transform: rotate(90deg); }",
|
|
866
|
+
".lc-br-tokens { flex: none; color: var(--dsw-alias-label-secondary); font-size: 12px; }",
|
|
867
|
+
".lc-br-pct { flex: none; width: 36px; text-align: right; color: var(--dsw-alias-label-secondary); font-size: 12px; }",
|
|
868
|
+
".lc-br-body { border-top: 1px solid var(--dsw-alias-border-l1); padding: 4px 6px; display: flex; flex-direction: column; gap: 2px; }",
|
|
869
|
+
".lc-br-elem { border-radius: 6px; }",
|
|
870
|
+
".lc-br-elem-on { background: var(--dsw-alias-bg-layer-1); }",
|
|
871
|
+
".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; }",
|
|
872
|
+
".lc-br-elem-row:hover { background: var(--dsw-alias-bg-layer-1); }",
|
|
873
|
+
".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; }",
|
|
874
|
+
".lc-br-preview { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }",
|
|
875
|
+
".lc-br-time { flex: none; color: var(--dsw-alias-label-secondary); font-size: 11px; }",
|
|
876
|
+
".lc-br-content { padding: 2px 6px 8px 26px; display: flex; flex-direction: column; gap: 6px; }",
|
|
877
|
+
".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; }",
|
|
878
|
+
".lc-br-dim { color: var(--dsw-alias-label-secondary); }",
|
|
879
|
+
".lc-br-call { display: flex; flex-direction: column; gap: 4px; align-items: flex-start; }"
|
|
815
880
|
].join("\n");
|
|
816
881
|
|
|
882
|
+
// src/client/assemble.ts
|
|
883
|
+
function headerAt(headers, seq) {
|
|
884
|
+
if (headers === null || headers.headers.length === 0) return null;
|
|
885
|
+
if (seq === null) return headers.headers[headers.headers.length - 1];
|
|
886
|
+
for (let i = headers.headers.length - 1; i >= 0; i--) {
|
|
887
|
+
if (headers.headers[i].seq < seq) return headers.headers[i];
|
|
888
|
+
}
|
|
889
|
+
return null;
|
|
890
|
+
}
|
|
891
|
+
function assemble(data, headers, seq) {
|
|
892
|
+
const live = seq === null;
|
|
893
|
+
let nodes;
|
|
894
|
+
if (live) {
|
|
895
|
+
nodes = data.nodes.slice();
|
|
896
|
+
} else {
|
|
897
|
+
const picked = [];
|
|
898
|
+
for (const n of data.nodes) {
|
|
899
|
+
if (n.seq < seq) picked.push(n);
|
|
900
|
+
}
|
|
901
|
+
for (const n of data.archive || []) {
|
|
902
|
+
if (n.seq < seq && n.gone !== void 0 && n.gone > seq) picked.push(n);
|
|
903
|
+
}
|
|
904
|
+
nodes = picked;
|
|
905
|
+
}
|
|
906
|
+
nodes.sort((a, b) => a.seq - b.seq);
|
|
907
|
+
let missingLive = 0;
|
|
908
|
+
if (data.droppedNodes > 0) {
|
|
909
|
+
if (live || data.surfaceFloor !== void 0 && seq > data.surfaceFloor) {
|
|
910
|
+
missingLive = data.droppedNodes;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
const approximate = !live && data.archiveFloor !== void 0 && seq < data.archiveFloor;
|
|
914
|
+
return { live, header: headerAt(headers, seq), nodes, missingLive, approximate };
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
// src/client/components/nodes.tsx
|
|
918
|
+
function makeNodeText(kit) {
|
|
919
|
+
const { t } = kit;
|
|
920
|
+
return function nodeText(n) {
|
|
921
|
+
if (n.cat === "tool") {
|
|
922
|
+
return t("node.toolResult") + (n.tool ? " \u2190 " + n.tool : "") + (n.err ? " \u26A0" : "");
|
|
923
|
+
}
|
|
924
|
+
if (n.skill) return "Skill: " + n.skill;
|
|
925
|
+
if (n.calls) return t("node.calls") + n.calls.join(", ");
|
|
926
|
+
if (n.text) return n.form === "snapshot" ? t("node.snapshot") + n.text : n.text;
|
|
927
|
+
if (n.cat === "assistant") return t("node.empty");
|
|
928
|
+
if (n.cat === "inject") return t("form." + (n.form || "context"));
|
|
929
|
+
return t("node.nonText");
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
function makeNodeList(kit) {
|
|
933
|
+
const { t, tr, fmt: fmt3, fmtTime: fmtTime2 } = kit;
|
|
934
|
+
const nodeText = makeNodeText(kit);
|
|
935
|
+
return function NodeList(props) {
|
|
936
|
+
if (props.nodes.length === 0) {
|
|
937
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-empty" }, t("nodes.empty"));
|
|
938
|
+
}
|
|
939
|
+
const catColor = {};
|
|
940
|
+
for (const c of CATS) catColor[c.key] = c.color;
|
|
941
|
+
const rows = props.nodes.slice().reverse();
|
|
942
|
+
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) => {
|
|
943
|
+
const text = nodeText(n);
|
|
944
|
+
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)));
|
|
945
|
+
}));
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
// src/client/components/browser.tsx
|
|
950
|
+
function RawBlocks(props) {
|
|
951
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, props.blocks.map((b, i) => {
|
|
952
|
+
const blk = b;
|
|
953
|
+
if (blk !== null && typeof blk === "object" && (blk.type === "text" || blk.type === "reasoning") && typeof blk.text === "string") {
|
|
954
|
+
return /* @__PURE__ */ React.createElement("pre", { key: i, className: "lc-br-pre" + (blk.type === "reasoning" ? " lc-br-dim" : "") }, blk.text);
|
|
955
|
+
}
|
|
956
|
+
if (blk !== null && typeof blk === "object" && blk.type === "tool-result" && Array.isArray(blk.content)) {
|
|
957
|
+
return /* @__PURE__ */ React.createElement(RawBlocks, { key: i, blocks: blk.content });
|
|
958
|
+
}
|
|
959
|
+
return /* @__PURE__ */ React.createElement("pre", { key: i, className: "lc-br-pre lc-br-dim" }, JSON.stringify(b, null, 2));
|
|
960
|
+
}));
|
|
961
|
+
}
|
|
962
|
+
function NodeContent(props) {
|
|
963
|
+
const { node, conv } = props;
|
|
964
|
+
if (conv === void 0) {
|
|
965
|
+
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));
|
|
966
|
+
}
|
|
967
|
+
if (conv.kind === "assistant" && Array.isArray(conv.blocks)) {
|
|
968
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-br-content" }, conv.blocks.map((b, i) => {
|
|
969
|
+
const blk = b;
|
|
970
|
+
if (blk.kind === "text" && typeof blk.text === "string") {
|
|
971
|
+
return /* @__PURE__ */ React.createElement("pre", { key: i, className: "lc-br-pre" }, blk.text);
|
|
972
|
+
}
|
|
973
|
+
if (blk.kind === "reasoning" && typeof blk.text === "string") {
|
|
974
|
+
return /* @__PURE__ */ React.createElement("pre", { key: i, className: "lc-br-pre lc-br-dim" }, blk.text);
|
|
975
|
+
}
|
|
976
|
+
if (blk.kind === "tool-call") {
|
|
977
|
+
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);
|
|
978
|
+
}
|
|
979
|
+
return null;
|
|
980
|
+
}));
|
|
981
|
+
}
|
|
982
|
+
if (conv.kind === "tool-result") {
|
|
983
|
+
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);
|
|
984
|
+
}
|
|
985
|
+
if (conv.kind === "compaction") {
|
|
986
|
+
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);
|
|
987
|
+
}
|
|
988
|
+
if (Array.isArray(conv.content)) {
|
|
989
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-br-content" }, /* @__PURE__ */ React.createElement(RawBlocks, { blocks: conv.content }));
|
|
990
|
+
}
|
|
991
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-br-content" }, /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, props.hint));
|
|
992
|
+
}
|
|
993
|
+
function makeContextBrowser(kit, StackedBar) {
|
|
994
|
+
const { t, tr, fmt: fmt3, fmtTime: fmtTime2, catLabel } = kit;
|
|
995
|
+
const nodeText = makeNodeText(kit);
|
|
996
|
+
const catColor = {};
|
|
997
|
+
for (const c of CATS) catColor[c.key] = c.color;
|
|
998
|
+
const MAX_AUTO_PAGES = 20;
|
|
999
|
+
return function ContextBrowser(props) {
|
|
1000
|
+
var _a;
|
|
1001
|
+
const { data, headers } = props;
|
|
1002
|
+
const [sel, setSel] = React.useState("live");
|
|
1003
|
+
const [openCat, setOpenCat] = React.useState(null);
|
|
1004
|
+
const [openElem, setOpenElem] = React.useState(null);
|
|
1005
|
+
const convNodes = typeof props.useSession === "function" ? props.useSession((s) => s.nodes) : void 0;
|
|
1006
|
+
const bySeq = React.useMemo(() => {
|
|
1007
|
+
const m = /* @__PURE__ */ new Map();
|
|
1008
|
+
for (const n of convNodes ?? []) m.set(n.seq, n);
|
|
1009
|
+
return m;
|
|
1010
|
+
}, [convNodes]);
|
|
1011
|
+
const hasMore = typeof props.useSession === "function" ? props.useSession((s) => s.hasMore === true) : false;
|
|
1012
|
+
const loadingOlder = typeof props.useSession === "function" ? props.useSession((s) => s.loadingOlder === true) : false;
|
|
1013
|
+
const openSeq = openElem !== null && openElem.startsWith("n") ? Number(openElem.slice(1)) : null;
|
|
1014
|
+
const missingSeq = openSeq !== null && !bySeq.has(openSeq) ? openSeq : null;
|
|
1015
|
+
const [exhausted, setExhausted] = React.useState(false);
|
|
1016
|
+
const pagesRef = React.useRef(0);
|
|
1017
|
+
React.useEffect(() => {
|
|
1018
|
+
pagesRef.current = 0;
|
|
1019
|
+
setExhausted(false);
|
|
1020
|
+
}, [openElem]);
|
|
1021
|
+
const loadOlderHistory = props.loadOlderHistory;
|
|
1022
|
+
React.useEffect(() => {
|
|
1023
|
+
if (missingSeq === null || !hasMore || loadingOlder || exhausted) return;
|
|
1024
|
+
if (loadOlderHistory === void 0) return;
|
|
1025
|
+
if (pagesRef.current >= MAX_AUTO_PAGES) {
|
|
1026
|
+
setExhausted(true);
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
pagesRef.current += 1;
|
|
1030
|
+
void loadOlderHistory();
|
|
1031
|
+
}, [missingSeq, hasMore, loadingOlder, exhausted, bySeq, loadOlderHistory]);
|
|
1032
|
+
React.useEffect(() => {
|
|
1033
|
+
if (!hasMore && missingSeq !== null && !exhausted) setExhausted(true);
|
|
1034
|
+
}, [hasMore, missingSeq, exhausted]);
|
|
1035
|
+
const awaiting = missingSeq !== null && !exhausted && loadOlderHistory !== void 0 && hasMore;
|
|
1036
|
+
const requests = data.requests || [];
|
|
1037
|
+
const hoverReq = props.previewSeq !== null && props.previewSeq !== void 0 ? requests.find((r) => r.seq === props.previewSeq) ?? null : null;
|
|
1038
|
+
const req = hoverReq ?? (sel === "live" ? null : requests.find((r) => r.seq === sel) ?? null);
|
|
1039
|
+
const seq = req !== null ? req.seq : null;
|
|
1040
|
+
const view = assemble(data, headers, seq);
|
|
1041
|
+
const breakdown = req !== null ? req : data.current;
|
|
1042
|
+
const parts = partsOf(breakdown);
|
|
1043
|
+
const total = breakdown.total;
|
|
1044
|
+
const pick = (v) => {
|
|
1045
|
+
setSel(v === "live" ? "live" : Number(v));
|
|
1046
|
+
setOpenCat(null);
|
|
1047
|
+
setOpenElem(null);
|
|
1048
|
+
};
|
|
1049
|
+
const byCat = {};
|
|
1050
|
+
for (const n of view.nodes) (byCat[_a = n.cat] ?? (byCat[_a] = [])).push(n);
|
|
1051
|
+
const toolCount = (c) => {
|
|
1052
|
+
if (c === "system") return view.header !== null && view.header.system !== void 0 ? 1 : 0;
|
|
1053
|
+
if (c === "tools") return view.header !== null ? view.header.tools.length : 0;
|
|
1054
|
+
return byCat[c]?.length ?? 0;
|
|
1055
|
+
};
|
|
1056
|
+
const toggleCat = (c) => {
|
|
1057
|
+
const openable = toolCount(c) > 0 || (c === "system" || c === "tools") && view.header === null;
|
|
1058
|
+
if (!openable) return;
|
|
1059
|
+
setOpenCat(openCat === c ? null : c);
|
|
1060
|
+
setOpenElem(null);
|
|
1061
|
+
};
|
|
1062
|
+
const toggleElem = (key) => setOpenElem(openElem === key ? null : key);
|
|
1063
|
+
const elemRow = (key, tag, preview, tokens, time, body) => {
|
|
1064
|
+
const open = openElem === key;
|
|
1065
|
+
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: () => {
|
|
1066
|
+
toggleElem(key);
|
|
1067
|
+
} }, /* @__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);
|
|
1068
|
+
};
|
|
1069
|
+
const catBody = (c) => {
|
|
1070
|
+
if (c === "system") {
|
|
1071
|
+
if (view.header === null) return /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, t(headers === null ? "browser.noHeader" : "browser.noEpoch"));
|
|
1072
|
+
const system = view.header.system;
|
|
1073
|
+
if (system === void 0) return null;
|
|
1074
|
+
return elemRow(
|
|
1075
|
+
"sys",
|
|
1076
|
+
null,
|
|
1077
|
+
system.replace(/\s+/g, " ").trim().slice(0, 80),
|
|
1078
|
+
breakdown.system,
|
|
1079
|
+
void 0,
|
|
1080
|
+
/* @__PURE__ */ React.createElement("div", { className: "lc-br-content" }, /* @__PURE__ */ React.createElement("pre", { className: "lc-br-pre" }, system))
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1083
|
+
if (c === "tools") {
|
|
1084
|
+
if (view.header === null) return /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, t(headers === null ? "browser.noHeader" : "browser.noEpoch"));
|
|
1085
|
+
return view.header.tools.map((tool) => {
|
|
1086
|
+
const schema = tool.schema !== void 0 ? JSON.stringify(tool.schema, null, 2) : "";
|
|
1087
|
+
return elemRow(
|
|
1088
|
+
"tool:" + tool.name,
|
|
1089
|
+
null,
|
|
1090
|
+
tool.name,
|
|
1091
|
+
tool.tokens,
|
|
1092
|
+
void 0,
|
|
1093
|
+
/* @__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)
|
|
1094
|
+
);
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
const nodes = byCat[c] ?? [];
|
|
1098
|
+
return nodes.map((n) => {
|
|
1099
|
+
let tag = null;
|
|
1100
|
+
let preview = nodeText(n);
|
|
1101
|
+
if (n.cat === "tool") {
|
|
1102
|
+
tag = (n.tool ?? "?") + (n.err ? " \u26A0" : "");
|
|
1103
|
+
preview = t("node.toolResult") + (n.err ? " \u26A0" : "");
|
|
1104
|
+
} else if (n.cat === "inject" && !n.skill) {
|
|
1105
|
+
tag = t("form." + (n.form || "context"));
|
|
1106
|
+
if (n.text !== void 0 && n.text !== "") {
|
|
1107
|
+
preview = n.form === "snapshot" ? t("node.snapshot") + n.text : n.text;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
return elemRow(
|
|
1111
|
+
"n" + n.seq,
|
|
1112
|
+
tag,
|
|
1113
|
+
preview,
|
|
1114
|
+
n.tokens,
|
|
1115
|
+
n.time,
|
|
1116
|
+
/* @__PURE__ */ React.createElement(
|
|
1117
|
+
NodeContent,
|
|
1118
|
+
{
|
|
1119
|
+
node: n,
|
|
1120
|
+
conv: bySeq.get(n.seq),
|
|
1121
|
+
hint: bySeq.get(n.seq) === void 0 && awaiting ? t("browser.loading") : t("browser.noContent")
|
|
1122
|
+
}
|
|
1123
|
+
)
|
|
1124
|
+
);
|
|
1125
|
+
});
|
|
1126
|
+
};
|
|
1127
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("browser.title"), /* @__PURE__ */ React.createElement(
|
|
1128
|
+
"select",
|
|
1129
|
+
{
|
|
1130
|
+
className: "lc-br-pick",
|
|
1131
|
+
value: seq === null ? "live" : String(seq),
|
|
1132
|
+
onChange: (e) => {
|
|
1133
|
+
pick(e.target.value);
|
|
1134
|
+
}
|
|
1135
|
+
},
|
|
1136
|
+
/* @__PURE__ */ React.createElement("option", { value: "live" }, t("browser.live")),
|
|
1137
|
+
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)))
|
|
1138
|
+
)), /* @__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) => {
|
|
1139
|
+
const count = toolCount(c.key);
|
|
1140
|
+
const v = breakdown[c.key] || 0;
|
|
1141
|
+
const openable = count > 0 || (c.key === "system" || c.key === "tools") && view.header === null;
|
|
1142
|
+
const open = openCat === c.key && openable;
|
|
1143
|
+
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: () => {
|
|
1144
|
+
toggleCat(c.key);
|
|
1145
|
+
} }, /* @__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);
|
|
1146
|
+
})));
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
|
|
817
1150
|
// src/client/components/events.tsx
|
|
818
1151
|
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
819
1152
|
|
|
@@ -893,37 +1226,9 @@ function makeEventList(kit) {
|
|
|
893
1226
|
};
|
|
894
1227
|
}
|
|
895
1228
|
|
|
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
1229
|
// src/client/meta.ts
|
|
925
1230
|
var PLUGIN_NAME = "dsh-context";
|
|
926
|
-
var PLUGIN_VERSION = true ? "0.
|
|
1231
|
+
var PLUGIN_VERSION = true ? "0.12.1" : "0.0.0-dev";
|
|
927
1232
|
var PLUGIN_REPO = true ? "https://github.com/bowenliang123/dsh-context" : "https://github.com/bowenliang123/dsh-context";
|
|
928
1233
|
var PLUGIN_REPO_SHORT = PLUGIN_REPO.replace(/^https?:\/\/github\.com\//, "");
|
|
929
1234
|
|
|
@@ -1008,10 +1313,12 @@ function makeContextView(ctx, kit) {
|
|
|
1008
1313
|
const NodeList = makeNodeList(kit);
|
|
1009
1314
|
const StatsBoard = makeStatsBoard(kit);
|
|
1010
1315
|
const PluginInfo = makePluginInfo(kit);
|
|
1316
|
+
const ContextBrowser = makeContextBrowser(kit, StackedBar);
|
|
1011
1317
|
return function ContextView(props) {
|
|
1012
1318
|
const sessionId = props.sessionId;
|
|
1013
1319
|
const data = typeof props.useProjection === "function" ? timelineOf(props.useProjection("contextTimeline")) : null;
|
|
1014
1320
|
const pressure = typeof props.useProjection === "function" ? contextPressureOf(props.useProjection("contextPressure")) : null;
|
|
1321
|
+
const headers = typeof props.useProjection === "function" ? headersOf(props.useProjection("contextHeaders")) : null;
|
|
1015
1322
|
const [selectedSeq, setSelectedSeq] = React.useState(null);
|
|
1016
1323
|
const [hoveredSeq, setHoveredSeq] = React.useState(null);
|
|
1017
1324
|
const [hoverTurn, setHoverTurn] = React.useState(null);
|
|
@@ -1081,7 +1388,7 @@ function makeContextView(ctx, kit) {
|
|
|
1081
1388
|
}
|
|
1082
1389
|
}
|
|
1083
1390
|
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) => {
|
|
1391
|
+
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
1392
|
return /* @__PURE__ */ React.createElement("span", { key: tool.name, className: "lc-tool-chip" }, tool.name + " " + fmt3(tool.tokens));
|
|
1086
1393
|
}), 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
1394
|
"button",
|
|
@@ -1115,7 +1422,16 @@ function makeContextView(ctx, kit) {
|
|
|
1115
1422
|
onHover: setHoveredSeq,
|
|
1116
1423
|
onHoverTurn: setHoverTurn
|
|
1117
1424
|
}
|
|
1118
|
-
), /* @__PURE__ */ React.createElement(RequestDetail, { request: activeReq, marker: activeReq !== null ? markerOf(activeReq) : void 0 }))), /* @__PURE__ */ React.createElement("div", { className: "lc-
|
|
1425
|
+
), /* @__PURE__ */ React.createElement(RequestDetail, { request: activeReq, marker: activeReq !== null ? markerOf(activeReq) : void 0 })))), /* @__PURE__ */ React.createElement("div", { className: "lc-col" }, /* @__PURE__ */ React.createElement(
|
|
1426
|
+
ContextBrowser,
|
|
1427
|
+
{
|
|
1428
|
+
data,
|
|
1429
|
+
headers,
|
|
1430
|
+
useSession: props.useSession,
|
|
1431
|
+
loadOlderHistory: props.loadOlderHistory,
|
|
1432
|
+
previewSeq: hoveredSeq
|
|
1433
|
+
}
|
|
1434
|
+
))), /* @__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
1435
|
"button",
|
|
1120
1436
|
{
|
|
1121
1437
|
key: k,
|
|
@@ -1161,6 +1477,20 @@ function apply(ctx) {
|
|
|
1161
1477
|
}, "dsh-context: styles");
|
|
1162
1478
|
const kit = makeViewKit(t);
|
|
1163
1479
|
const ContextView = makeContextView(ctx, kit);
|
|
1480
|
+
ctx.effect(() => {
|
|
1481
|
+
const noop = () => {
|
|
1482
|
+
};
|
|
1483
|
+
const sessions = ctx.get("sessions");
|
|
1484
|
+
if (sessions === void 0 || typeof sessions.provide !== "function") return noop;
|
|
1485
|
+
try {
|
|
1486
|
+
return sessions.provide({
|
|
1487
|
+
props: ["loadOlderHistory"],
|
|
1488
|
+
resolve: (binding) => ({ props: { loadOlderHistory: () => binding.session.loadOlder() } })
|
|
1489
|
+
});
|
|
1490
|
+
} catch {
|
|
1491
|
+
return noop;
|
|
1492
|
+
}
|
|
1493
|
+
}, "dsh-context: loadOlderHistory prop");
|
|
1164
1494
|
ctx.slots.inject("conversation.view", () => {
|
|
1165
1495
|
return ctx.slots.register(
|
|
1166
1496
|
// order 20 renders right of Chat (0) and Trajectory (10); the locale
|