dsh-context 0.10.1 → 0.10.3
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 +1 -1
- package/lib/client.js +93 -43
- package/lib/index.js +116 -126
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ Type `/context` (or pick it from the `/` menu) and press Enter: a centered dialo
|
|
|
40
40
|
|
|
41
41
|
### 📊 Context stats — the session at a glance
|
|
42
42
|
|
|
43
|
-
Turns, steps, how
|
|
43
|
+
Turns, steps, how many injections, compactions, and prunes have happened.
|
|
44
44
|
|
|
45
45
|
### 🧱 Current composition — what's in the window right now
|
|
46
46
|
|
package/lib/client.js
CHANGED
|
@@ -25,13 +25,15 @@ var DICT_ZH = {
|
|
|
25
25
|
"stats.hint": "\u7EDF\u8BA1\u5F53\u524D\u4FDD\u7559\u7684\u5386\u53F2\u7A97\u53E3\uFF08\u4E0E\u8D8B\u52BF\u56FE\u4E00\u81F4\uFF09",
|
|
26
26
|
"stats.turns": "\u8F6E\u6B21",
|
|
27
27
|
"stats.steps": "\u6B65\u6570",
|
|
28
|
-
"stats.
|
|
29
|
-
"stats.
|
|
30
|
-
"stats.
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
28
|
+
"stats.injects": "\u6CE8\u5165",
|
|
29
|
+
"stats.compactions": "\u538B\u7F29",
|
|
30
|
+
"stats.prunes": "\u526A\u679D",
|
|
31
|
+
"plugin.title": "\u63D2\u4EF6\u4FE1\u606F",
|
|
32
|
+
"plugin.hint": "\u611F\u8C22\u4F7F\u7528 \xB7 \u6B22\u8FCE Star \u4E0E\u53CD\u9988 \u2B50",
|
|
33
|
+
"plugin.name": "\u63D2\u4EF6",
|
|
34
|
+
"plugin.version": "\u7248\u672C",
|
|
35
|
+
"plugin.updateBadge": "Update!",
|
|
36
|
+
"plugin.updateTip": "\u65B0\u7248\u672C v{v} \u53EF\u7528 \xB7 \u6267\u884C dsh plugin --profile web add dsh-context \u66F4\u65B0\uFF08\u70B9\u51FB\u524D\u5F80 npm\uFF09",
|
|
35
37
|
"tools.top": "\u5DE5\u5177\u5B9A\u4E49 Top\uFF1A",
|
|
36
38
|
"tools.more": "\u7B49 {n} \u4E2A",
|
|
37
39
|
"trend.title": "\u5386\u53F2\u8D8B\u52BF",
|
|
@@ -98,13 +100,15 @@ var DICT_EN = {
|
|
|
98
100
|
"stats.hint": "Over the retained history window (same as the History chart)",
|
|
99
101
|
"stats.turns": "Turns",
|
|
100
102
|
"stats.steps": "Steps",
|
|
101
|
-
"stats.
|
|
102
|
-
"stats.
|
|
103
|
-
"stats.
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
103
|
+
"stats.injects": "Injections",
|
|
104
|
+
"stats.compactions": "Compactions",
|
|
105
|
+
"stats.prunes": "Prunes",
|
|
106
|
+
"plugin.title": "Plugin info",
|
|
107
|
+
"plugin.hint": "Thanks for using \u2014 stars & feedback welcome \u2B50",
|
|
108
|
+
"plugin.name": "Plugin",
|
|
109
|
+
"plugin.version": "Version",
|
|
110
|
+
"plugin.updateBadge": "Update!",
|
|
111
|
+
"plugin.updateTip": "v{v} available \u2014 run `dsh plugin --profile web add dsh-context` to update (click for npm)",
|
|
108
112
|
"tools.top": "Top tool schemas:",
|
|
109
113
|
"tools.more": "of {n}",
|
|
110
114
|
"trend.title": "History",
|
|
@@ -245,15 +249,14 @@ function anchoredParts(parts, target) {
|
|
|
245
249
|
}
|
|
246
250
|
|
|
247
251
|
// src/client/headline.ts
|
|
248
|
-
function headlineOf(data) {
|
|
252
|
+
function headlineOf(data, pressure = null) {
|
|
249
253
|
const current = data.current;
|
|
250
|
-
const
|
|
251
|
-
const projected = occ !== void 0 && typeof occ.projectedTokens === "number" ? occ.projectedTokens : void 0;
|
|
254
|
+
const projected = pressure !== null && typeof pressure.projectedTokens === "number" ? pressure.projectedTokens : void 0;
|
|
252
255
|
const requests = data.requests || [];
|
|
253
256
|
const lastReq = requests.length > 0 ? requests[requests.length - 1] : null;
|
|
254
257
|
const derived = lastReq !== null && typeof lastReq.prompt === "number" ? lastReq.prompt + (current.total - lastReq.total) : void 0;
|
|
255
258
|
const occupancyTokens = projected ?? derived ?? null;
|
|
256
|
-
const window2 =
|
|
259
|
+
const window2 = pressure !== null && typeof pressure.contextWindow === "number" ? pressure.contextWindow : data.contextWindow;
|
|
257
260
|
const tokens = occupancyTokens ?? current.total;
|
|
258
261
|
const pct = window2 !== void 0 && window2 > 0 ? Math.min(100, Math.round(tokens / window2 * 100)) : null;
|
|
259
262
|
const parts = anchoredParts(partsOf(current), occupancyTokens !== null && tokens > 0 ? tokens : null);
|
|
@@ -265,6 +268,10 @@ function timelineOf(value) {
|
|
|
265
268
|
if (value === null || value === void 0 || typeof value !== "object") return null;
|
|
266
269
|
return value;
|
|
267
270
|
}
|
|
271
|
+
function contextPressureOf(value) {
|
|
272
|
+
if (value === null || value === void 0 || typeof value !== "object") return null;
|
|
273
|
+
return value;
|
|
274
|
+
}
|
|
268
275
|
|
|
269
276
|
// src/client/react.ts
|
|
270
277
|
var React = require("react");
|
|
@@ -581,6 +588,7 @@ function makeContextModal(ctx, kit) {
|
|
|
581
588
|
const sessionId = typeof props.sessionId === "string" ? props.sessionId : "";
|
|
582
589
|
const open = typeof props.useContextModal === "function" ? props.useContextModal((s) => s) : false;
|
|
583
590
|
const data = typeof props.useProjection === "function" ? timelineOf(props.useProjection("contextTimeline")) : null;
|
|
591
|
+
const pressure = typeof props.useProjection === "function" ? contextPressureOf(props.useProjection("contextPressure")) : null;
|
|
584
592
|
const [selectedSeq, setSelectedSeq] = React.useState(null);
|
|
585
593
|
const [hoveredSeq, setHoveredSeq] = React.useState(null);
|
|
586
594
|
const [hoverCat, setHoverCat] = React.useState(null);
|
|
@@ -624,7 +632,7 @@ function makeContextModal(ctx, kit) {
|
|
|
624
632
|
const i = turns.indexOf(req);
|
|
625
633
|
return i >= 0 ? markers[i] : void 0;
|
|
626
634
|
};
|
|
627
|
-
const head = data !== null ? headlineOf(data) : null;
|
|
635
|
+
const head = data !== null ? headlineOf(data, pressure) : null;
|
|
628
636
|
return /* @__PURE__ */ React.createElement("div", { className: "lc-modal-backdrop", onClick: close }, /* @__PURE__ */ React.createElement("div", { className: "lc-modal-card", onClick: (ev) => {
|
|
629
637
|
ev.stopPropagation();
|
|
630
638
|
} }, /* @__PURE__ */ React.createElement("div", { className: "lc-modal-head" }, /* @__PURE__ */ React.createElement("span", { className: "lc-modal-title" }, t("tab")), data !== null && (data.model || data.provider) ? /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, (data.model ? data.model : "") + (data.provider ? " \xB7 " + data.provider : "")) : null, /* @__PURE__ */ React.createElement("button", { className: "lc-modal-close", "aria-label": t("cmd.close"), onClick: close }, "\xD7")), data === null || head === null ? /* @__PURE__ */ React.createElement("div", { className: "lc-empty" }, t("loading")) : /* @__PURE__ */ React.createElement("div", null, /* @__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 }), /* @__PURE__ */ React.createElement("div", { className: "lc-card-title lc-modal-trend" }, t("trend.title")), turns.length === 0 ? /* @__PURE__ */ React.createElement("div", { className: "lc-empty" }, t("trend.empty")) : /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
|
|
@@ -652,8 +660,8 @@ var STYLES = [
|
|
|
652
660
|
".lc-card-title { font-weight: 600; margin-bottom: 10px; display: flex; align-items: baseline; gap: 8px; }",
|
|
653
661
|
".lc-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); gap: 8px; }",
|
|
654
662
|
".lc-stat { background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l1); border-radius: 8px; padding: 8px 10px; display: flex; flex-direction: column; gap: 2px; min-width: 0; }",
|
|
655
|
-
".lc-stat-label { color: var(--dsw-alias-label-secondary); font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }",
|
|
656
|
-
".lc-stat-value { color: var(--dsw-alias-label-primary); font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }",
|
|
663
|
+
".lc-stat-label { color: var(--dsw-alias-label-secondary); font-size: 11px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }",
|
|
664
|
+
".lc-stat-value { color: var(--dsw-alias-label-primary); font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: center; }",
|
|
657
665
|
".lc-stat-sub { color: var(--dsw-alias-label-secondary); font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }",
|
|
658
666
|
".lc-card-sub { font-weight: 400; color: var(--dsw-alias-label-secondary); font-size: 12px; }",
|
|
659
667
|
".lc-gran { margin-left: auto; display: flex; gap: 2px; background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; padding: 1px; }",
|
|
@@ -742,6 +750,19 @@ var STYLES = [
|
|
|
742
750
|
".lc-detail-pct { width: 34px; text-align: right; color: var(--dsw-alias-label-secondary); }",
|
|
743
751
|
".lc-cols { display: flex; gap: 14px; flex-wrap: wrap; }",
|
|
744
752
|
".lc-col { flex: 1; min-width: 280px; }",
|
|
753
|
+
// Head row: the stats board (five cells) takes the wider share, the plugin
|
|
754
|
+
// card (three cells) the narrower — both wrap onto their own line when tight.
|
|
755
|
+
".lc-col-stats { flex: 3; min-width: 380px; }",
|
|
756
|
+
".lc-col-plugin { flex: 2; min-width: 260px; }",
|
|
757
|
+
".lc-stat-link { color: var(--dsw-alias-brand-primary); text-decoration: none; font-weight: 600; }",
|
|
758
|
+
// Whole-cell link (Plugin info): the anchor carries the stat-cell chrome,
|
|
759
|
+
// so the entire padded box is one hit target; hovering anywhere on it
|
|
760
|
+
// underlines the value and tints the border for affordance.
|
|
761
|
+
".lc-stat-cell { text-decoration: none; cursor: pointer; transition: border-color 120ms ease; }",
|
|
762
|
+
".lc-stat-cell:hover { border-color: var(--dsw-alias-brand-primary); }",
|
|
763
|
+
".lc-stat:hover .lc-stat-link { text-decoration: underline; }",
|
|
764
|
+
// "Update!" pill inside the version cell (update = good news -> brand fill).
|
|
765
|
+
".lc-update-badge { margin-left: 6px; font-size: 10px; font-weight: 600; background: var(--dsw-alias-button-primary-fill); color: var(--dsw-alias-label-primary-foreground); border-radius: 4px; padding: 1px 6px; }",
|
|
745
766
|
".lc-events, .lc-nodes { display: flex; flex-direction: column; gap: 2px; max-height: 320px; overflow-y: auto; }",
|
|
746
767
|
".lc-event { display: flex; align-items: center; gap: 8px; padding: 3px 0; }",
|
|
747
768
|
".lc-event-icon { width: 18px; text-align: center; color: var(--dsw-alias-state-warn-primary); }",
|
|
@@ -863,36 +884,63 @@ function makeNodeList(kit) {
|
|
|
863
884
|
};
|
|
864
885
|
}
|
|
865
886
|
|
|
887
|
+
// src/client/meta.ts
|
|
888
|
+
var PLUGIN_NAME = "dsh-context";
|
|
889
|
+
var PLUGIN_VERSION = true ? "0.10.3" : "0.0.0-dev";
|
|
890
|
+
var PLUGIN_REPO = true ? "https://github.com/bowenliang123/dsh-context" : "https://github.com/bowenliang123/dsh-context";
|
|
891
|
+
var PLUGIN_NPM = "https://www.npmjs.com/package/" + PLUGIN_NAME;
|
|
892
|
+
var PLUGIN_REPO_SHORT = PLUGIN_REPO.replace(/^https?:\/\/github\.com\//, "");
|
|
893
|
+
|
|
894
|
+
// src/client/components/pluginInfo.tsx
|
|
895
|
+
var latestCache;
|
|
896
|
+
function makePluginInfo(kit) {
|
|
897
|
+
const { t, tr } = kit;
|
|
898
|
+
return function PluginInfo() {
|
|
899
|
+
const [latest, setLatest] = React.useState(latestCache);
|
|
900
|
+
React.useEffect(() => {
|
|
901
|
+
if (latestCache !== void 0) return void 0;
|
|
902
|
+
let alive = true;
|
|
903
|
+
fetch("https://registry.npmjs.org/" + PLUGIN_NAME + "/latest").then((res) => res.ok ? res.json() : null).then((body) => {
|
|
904
|
+
if (!alive) return;
|
|
905
|
+
latestCache = body && typeof body.version === "string" ? body.version : null;
|
|
906
|
+
setLatest(latestCache);
|
|
907
|
+
}).catch(() => {
|
|
908
|
+
if (!alive) return;
|
|
909
|
+
latestCache = null;
|
|
910
|
+
setLatest(null);
|
|
911
|
+
});
|
|
912
|
+
return () => {
|
|
913
|
+
alive = false;
|
|
914
|
+
};
|
|
915
|
+
}, []);
|
|
916
|
+
const update = typeof latest === "string" && latest !== PLUGIN_VERSION;
|
|
917
|
+
const cell = (label, value, href, title) => /* @__PURE__ */ React.createElement("a", { className: "lc-stat lc-stat-cell", href, target: "_blank", rel: "noreferrer", title }, /* @__PURE__ */ React.createElement("span", { className: "lc-stat-label" }, label), /* @__PURE__ */ React.createElement("b", { className: "lc-stat-value lc-stat-link" }, value));
|
|
918
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col lc-col-plugin" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("plugin.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("plugin.hint"))), /* @__PURE__ */ React.createElement("div", { className: "lc-stats" }, cell(t("plugin.name"), PLUGIN_NAME, PLUGIN_REPO), cell(
|
|
919
|
+
t("plugin.version"),
|
|
920
|
+
/* @__PURE__ */ React.createElement(React.Fragment, null, "v" + PLUGIN_VERSION, update ? /* @__PURE__ */ React.createElement("span", { className: "lc-update-badge" }, t("plugin.updateBadge")) : null),
|
|
921
|
+
PLUGIN_NPM,
|
|
922
|
+
update ? tr("plugin.updateTip", { v: latest ?? "" }) : void 0
|
|
923
|
+
), cell("GitHub", PLUGIN_REPO_SHORT + " \u2197", PLUGIN_REPO)));
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
|
|
866
927
|
// src/client/components/statsBoard.tsx
|
|
867
928
|
function makeStatsBoard(kit) {
|
|
868
|
-
const { t,
|
|
929
|
+
const { t, fmt: fmt3 } = kit;
|
|
869
930
|
return function StatsBoard(props) {
|
|
870
931
|
const turns = /* @__PURE__ */ new Set();
|
|
871
|
-
let steps = 0, compactions = 0, prunes = 0, injects = 0
|
|
872
|
-
let recycled = 0, est = 0, prompt = 0, output = 0;
|
|
932
|
+
let steps = 0, compactions = 0, prunes = 0, injects = 0;
|
|
873
933
|
for (const req of props.requests) {
|
|
874
934
|
turns.add(req.turn ?? 0);
|
|
875
935
|
steps++;
|
|
876
|
-
est += req.total;
|
|
877
|
-
if (typeof req.prompt === "number") prompt += req.prompt;
|
|
878
|
-
if (typeof req.output === "number") output += req.output;
|
|
879
936
|
}
|
|
880
937
|
for (const ev of props.events) {
|
|
881
|
-
if (ev.kind === "compaction")
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
} else if (ev.kind === "prune") {
|
|
885
|
-
prunes++;
|
|
886
|
-
recycled += ev.tokens || 0;
|
|
887
|
-
} else if (ev.kind === "inject") injects++;
|
|
888
|
-
else if (ev.kind === "model") switches++;
|
|
938
|
+
if (ev.kind === "compaction") compactions++;
|
|
939
|
+
else if (ev.kind === "prune") prunes++;
|
|
940
|
+
else if (ev.kind === "inject") injects++;
|
|
889
941
|
}
|
|
890
|
-
const cell = (label, value
|
|
891
|
-
return /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("stats.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("stats.hint"))), /* @__PURE__ */ React.createElement("div", { className: "lc-stats" }, cell(t("stats.turns"), fmt3(turns.size)), cell(t("stats.steps"), fmt3(steps)), cell(
|
|
892
|
-
t("stats.recycled"),
|
|
893
|
-
recycled > 0 ? "\u2212" + fmt3(recycled) : "0",
|
|
894
|
-
tr("stats.recycleSub", { c: compactions, p: prunes })
|
|
895
|
-
), cell(t("stats.injects"), fmt3(injects)), cell(t("stats.switches"), fmt3(switches)), cell(t("stats.est"), "\u2248 " + fmt3(est)), cell(t("stats.actualPrompt"), fmt3(prompt)), cell(t("stats.output"), fmt3(output))));
|
|
942
|
+
const cell = (label, value) => /* @__PURE__ */ React.createElement("div", { className: "lc-stat" }, /* @__PURE__ */ React.createElement("span", { className: "lc-stat-label" }, label), /* @__PURE__ */ React.createElement("b", { className: "lc-stat-value" }, value));
|
|
943
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col lc-col-stats" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("stats.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("stats.hint"))), /* @__PURE__ */ React.createElement("div", { className: "lc-stats" }, cell(t("stats.turns"), fmt3(turns.size)), cell(t("stats.steps"), fmt3(steps)), cell(t("stats.injects"), fmt3(injects)), cell(t("stats.compactions"), fmt3(compactions)), cell(t("stats.prunes"), fmt3(prunes))));
|
|
896
944
|
};
|
|
897
945
|
}
|
|
898
946
|
|
|
@@ -907,9 +955,11 @@ function makeContextView(ctx, kit) {
|
|
|
907
955
|
const EventList = makeEventList(kit);
|
|
908
956
|
const NodeList = makeNodeList(kit);
|
|
909
957
|
const StatsBoard = makeStatsBoard(kit);
|
|
958
|
+
const PluginInfo = makePluginInfo(kit);
|
|
910
959
|
return function ContextView(props) {
|
|
911
960
|
const sessionId = props.sessionId;
|
|
912
961
|
const data = typeof props.useProjection === "function" ? timelineOf(props.useProjection("contextTimeline")) : null;
|
|
962
|
+
const pressure = typeof props.useProjection === "function" ? contextPressureOf(props.useProjection("contextPressure")) : null;
|
|
913
963
|
const [selectedSeq, setSelectedSeq] = React.useState(null);
|
|
914
964
|
const [hoveredSeq, setHoveredSeq] = React.useState(null);
|
|
915
965
|
const [hoverTurn, setHoverTurn] = React.useState(null);
|
|
@@ -969,8 +1019,8 @@ function makeContextView(ctx, kit) {
|
|
|
969
1019
|
break;
|
|
970
1020
|
}
|
|
971
1021
|
}
|
|
972
|
-
const head = headlineOf(data);
|
|
973
|
-
return /* @__PURE__ */ React.createElement("div", { className: "lc-root", ref: rootRef }, /* @__PURE__ */ React.createElement(StatsBoard, { requests, events }), /* @__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) => {
|
|
1022
|
+
const head = headlineOf(data, pressure);
|
|
1023
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-root", ref: rootRef }, /* @__PURE__ */ React.createElement("div", { className: "lc-cols" }, /* @__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) => {
|
|
974
1024
|
return /* @__PURE__ */ React.createElement("span", { key: tool.name, className: "lc-tool-chip" }, tool.name + " " + fmt3(tool.tokens));
|
|
975
1025
|
}), 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(
|
|
976
1026
|
"button",
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
|
-
// src/host/
|
|
1
|
+
// src/host/config.ts
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
var DEFAULT_BOUNDS = {
|
|
4
|
+
maxRequestSteps: 1500,
|
|
5
|
+
maxKeptTurns: 300,
|
|
6
|
+
maxEvents: 400,
|
|
7
|
+
maxNodes: 200
|
|
8
|
+
};
|
|
9
|
+
var Config = z.preprocess(
|
|
10
|
+
(v) => v ?? {},
|
|
11
|
+
z.object({
|
|
12
|
+
maxRequestSteps: z.number().int().min(1).default(DEFAULT_BOUNDS.maxRequestSteps),
|
|
13
|
+
maxKeptTurns: z.number().int().min(1).default(DEFAULT_BOUNDS.maxKeptTurns),
|
|
14
|
+
maxEvents: z.number().int().min(1).default(DEFAULT_BOUNDS.maxEvents),
|
|
15
|
+
maxNodes: z.number().int().min(1).default(DEFAULT_BOUNDS.maxNodes)
|
|
16
|
+
}).strict()
|
|
17
|
+
);
|
|
18
|
+
function resolveBounds(config) {
|
|
19
|
+
const parsed = Config.parse(config ?? {});
|
|
20
|
+
return {
|
|
21
|
+
maxRequestSteps: parsed.maxRequestSteps,
|
|
22
|
+
maxKeptTurns: parsed.maxKeptTurns,
|
|
23
|
+
maxEvents: parsed.maxEvents,
|
|
24
|
+
maxNodes: parsed.maxNodes
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/host/timeline.ts
|
|
29
|
+
import { z as z2 } from "zod";
|
|
3
30
|
|
|
4
31
|
// src/host/pricing.ts
|
|
5
32
|
var CHARS_PER_TOKEN = 4;
|
|
@@ -65,10 +92,6 @@ function isInjection(source) {
|
|
|
65
92
|
}
|
|
66
93
|
|
|
67
94
|
// src/host/fold.ts
|
|
68
|
-
var MAX_REQUEST_STEPS = 1500;
|
|
69
|
-
var MAX_KEPT_TURNS = 300;
|
|
70
|
-
var MAX_EVENTS = 400;
|
|
71
|
-
var MAX_NODES = 200;
|
|
72
95
|
function trimToLastTurns(requests, maxTurns) {
|
|
73
96
|
let runs = 0;
|
|
74
97
|
let start = requests.length;
|
|
@@ -95,14 +118,14 @@ function countTurnRuns(requests) {
|
|
|
95
118
|
}
|
|
96
119
|
return runs;
|
|
97
120
|
}
|
|
98
|
-
function trimState(st) {
|
|
99
|
-
if (countTurnRuns(st.requests) >
|
|
100
|
-
st.requests = trimToLastTurns(st.requests,
|
|
121
|
+
function trimState(st, bounds) {
|
|
122
|
+
if (countTurnRuns(st.requests) > bounds.maxKeptTurns) {
|
|
123
|
+
st.requests = trimToLastTurns(st.requests, bounds.maxKeptTurns);
|
|
101
124
|
}
|
|
102
|
-
if (st.requests.length >
|
|
103
|
-
st.requests = st.requests.slice(-
|
|
125
|
+
if (st.requests.length > bounds.maxRequestSteps) {
|
|
126
|
+
st.requests = st.requests.slice(-bounds.maxRequestSteps);
|
|
104
127
|
}
|
|
105
|
-
if (st.events.length >
|
|
128
|
+
if (st.events.length > bounds.maxEvents) st.events = st.events.slice(-bounds.maxEvents);
|
|
106
129
|
}
|
|
107
130
|
function createTimelineState() {
|
|
108
131
|
return {
|
|
@@ -115,9 +138,6 @@ function createTimelineState() {
|
|
|
115
138
|
provider: void 0,
|
|
116
139
|
lastModel: void 0,
|
|
117
140
|
contextWindow: void 0,
|
|
118
|
-
pressureTokens: void 0,
|
|
119
|
-
sampledSurfaceTokens: void 0,
|
|
120
|
-
occupancyWindow: void 0,
|
|
121
141
|
requests: [],
|
|
122
142
|
events: [],
|
|
123
143
|
callNames: {}
|
|
@@ -207,17 +227,7 @@ function applySurface(st, ev, type, data, message) {
|
|
|
207
227
|
st.sums[cat] += node.tokens;
|
|
208
228
|
return node;
|
|
209
229
|
}
|
|
210
|
-
function
|
|
211
|
-
if (usage === void 0 || typeof usage.inputTokens !== "number") return void 0;
|
|
212
|
-
return usage.inputTokens + (usage.cacheReadTokens || 0) + (usage.cacheWriteTokens || 0);
|
|
213
|
-
}
|
|
214
|
-
function sampleUsage(st, usage) {
|
|
215
|
-
const pressureTokens = pressureOf(usage);
|
|
216
|
-
if (pressureTokens === void 0) return;
|
|
217
|
-
st.pressureTokens = pressureTokens;
|
|
218
|
-
st.sampledSurfaceTokens = st.sums.user + st.sums.inject + st.sums.assistant + st.sums.tool;
|
|
219
|
-
}
|
|
220
|
-
function applyTimeline(state, event) {
|
|
230
|
+
function applyTimeline(state, event, bounds) {
|
|
221
231
|
let st;
|
|
222
232
|
const ensure = () => st ??= {
|
|
223
233
|
...state,
|
|
@@ -253,7 +263,6 @@ function applyTimeline(state, event) {
|
|
|
253
263
|
if (data && typeof data.contextWindow === "number") s.contextWindow = data.contextWindow;
|
|
254
264
|
if (data && typeof data.model === "string") s.model = data.model;
|
|
255
265
|
if (data && typeof data.provider === "string") s.provider = data.provider;
|
|
256
|
-
s.occupancyWindow = data && typeof data.contextWindow === "number" ? data.contextWindow : void 0;
|
|
257
266
|
break;
|
|
258
267
|
}
|
|
259
268
|
case "tool/call": {
|
|
@@ -292,18 +301,9 @@ function applyTimeline(state, event) {
|
|
|
292
301
|
applySurface(s, event, event.type, data, toolMsg);
|
|
293
302
|
break;
|
|
294
303
|
}
|
|
295
|
-
case "assistant/chunk": {
|
|
296
|
-
const chunk = data?.chunk;
|
|
297
|
-
if (chunk !== void 0 && chunk.type === "usage") {
|
|
298
|
-
const s = ensure();
|
|
299
|
-
sampleUsage(s, chunk.usage);
|
|
300
|
-
}
|
|
301
|
-
break;
|
|
302
|
-
}
|
|
303
304
|
case "assistant/message": {
|
|
304
305
|
const usage = data?.usage;
|
|
305
306
|
const s = ensure();
|
|
306
|
-
sampleUsage(s, usage);
|
|
307
307
|
const total = s.systemTokens + s.toolsTokens + s.sums.user + s.sums.inject + s.sums.assistant + s.sums.tool;
|
|
308
308
|
const record = {
|
|
309
309
|
turn: data && typeof data.turn === "number" ? data.turn : void 0,
|
|
@@ -346,14 +346,13 @@ function applyTimeline(state, event) {
|
|
|
346
346
|
return state;
|
|
347
347
|
}
|
|
348
348
|
if (st !== void 0) {
|
|
349
|
-
trimState(st);
|
|
349
|
+
trimState(st, bounds);
|
|
350
350
|
return st;
|
|
351
351
|
}
|
|
352
352
|
return state;
|
|
353
353
|
}
|
|
354
|
-
function buildTimelineView(state) {
|
|
354
|
+
function buildTimelineView(state, bounds) {
|
|
355
355
|
const surfaceTotal = state.sums.user + state.sums.inject + state.sums.assistant + state.sums.tool;
|
|
356
|
-
const projectedTokens = state.pressureTokens !== void 0 && state.sampledSurfaceTokens !== void 0 ? Math.max(0, state.pressureTokens + surfaceTotal - state.sampledSurfaceTokens) : void 0;
|
|
357
356
|
const result = {
|
|
358
357
|
ok: true,
|
|
359
358
|
model: state.model,
|
|
@@ -368,21 +367,14 @@ function buildTimelineView(state) {
|
|
|
368
367
|
tool: state.sums.tool,
|
|
369
368
|
total: surfaceTotal + state.systemTokens + state.toolsTokens
|
|
370
369
|
},
|
|
371
|
-
occupancy: {
|
|
372
|
-
...state.pressureTokens === void 0 ? {} : { pressureTokens: state.pressureTokens },
|
|
373
|
-
surfaceTokens: surfaceTotal,
|
|
374
|
-
...state.sampledSurfaceTokens === void 0 ? {} : { sampledSurfaceTokens: state.sampledSurfaceTokens },
|
|
375
|
-
...projectedTokens === void 0 ? {} : { projectedTokens },
|
|
376
|
-
...state.occupancyWindow === void 0 ? {} : { contextWindow: state.occupancyWindow }
|
|
377
|
-
},
|
|
378
370
|
toolList: state.toolList,
|
|
379
371
|
requests: state.requests.map((r) => ({ ...r })),
|
|
380
372
|
events: state.events.map((e) => ({ ...e })),
|
|
381
373
|
nodes: [],
|
|
382
374
|
droppedNodes: 0
|
|
383
375
|
};
|
|
384
|
-
result.droppedNodes = Math.max(0, state.surface.length -
|
|
385
|
-
result.nodes = state.surface.slice(-
|
|
376
|
+
result.droppedNodes = Math.max(0, state.surface.length - bounds.maxNodes);
|
|
377
|
+
result.nodes = state.surface.slice(-bounds.maxNodes);
|
|
386
378
|
const requests = result.requests;
|
|
387
379
|
const events = result.events;
|
|
388
380
|
let ri = 0;
|
|
@@ -403,97 +395,95 @@ function buildTimelineView(state) {
|
|
|
403
395
|
}
|
|
404
396
|
|
|
405
397
|
// src/host/timeline.ts
|
|
406
|
-
var surfaceNodeSchema =
|
|
407
|
-
seq:
|
|
408
|
-
time:
|
|
409
|
-
cat:
|
|
410
|
-
tokens:
|
|
411
|
-
form:
|
|
412
|
-
text:
|
|
413
|
-
tool:
|
|
414
|
-
err:
|
|
415
|
-
skill:
|
|
416
|
-
calls:
|
|
417
|
-
}).strict();
|
|
418
|
-
var requestRecordSchema = z.object({
|
|
419
|
-
turn: z.number().optional(),
|
|
420
|
-
step: z.number().optional(),
|
|
421
|
-
time: z.number(),
|
|
422
|
-
seq: z.number(),
|
|
423
|
-
system: z.number().int().nonnegative(),
|
|
424
|
-
tools: z.number().int().nonnegative(),
|
|
425
|
-
user: z.number().int().nonnegative(),
|
|
426
|
-
inject: z.number().int().nonnegative(),
|
|
427
|
-
assistant: z.number().int().nonnegative(),
|
|
428
|
-
tool: z.number().int().nonnegative(),
|
|
429
|
-
total: z.number().int().nonnegative(),
|
|
430
|
-
prompt: z.number().int().nonnegative().optional(),
|
|
431
|
-
output: z.number().int().nonnegative().optional(),
|
|
432
|
-
stepCount: z.number().int().positive().optional()
|
|
398
|
+
var surfaceNodeSchema = z2.object({
|
|
399
|
+
seq: z2.number().int().nonnegative(),
|
|
400
|
+
time: z2.number().optional(),
|
|
401
|
+
cat: z2.enum(["user", "inject", "assistant", "tool"]),
|
|
402
|
+
tokens: z2.number().int().nonnegative(),
|
|
403
|
+
form: z2.string().optional(),
|
|
404
|
+
text: z2.string().optional(),
|
|
405
|
+
tool: z2.string().optional(),
|
|
406
|
+
err: z2.boolean().optional(),
|
|
407
|
+
skill: z2.string().optional(),
|
|
408
|
+
calls: z2.array(z2.string()).optional()
|
|
433
409
|
}).strict();
|
|
434
|
-
var
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
410
|
+
var requestRecordSchema = z2.object({
|
|
411
|
+
turn: z2.number().optional(),
|
|
412
|
+
step: z2.number().optional(),
|
|
413
|
+
time: z2.number(),
|
|
414
|
+
seq: z2.number(),
|
|
415
|
+
system: z2.number().int().nonnegative(),
|
|
416
|
+
tools: z2.number().int().nonnegative(),
|
|
417
|
+
user: z2.number().int().nonnegative(),
|
|
418
|
+
inject: z2.number().int().nonnegative(),
|
|
419
|
+
assistant: z2.number().int().nonnegative(),
|
|
420
|
+
tool: z2.number().int().nonnegative(),
|
|
421
|
+
total: z2.number().int().nonnegative(),
|
|
422
|
+
prompt: z2.number().int().nonnegative().optional(),
|
|
423
|
+
output: z2.number().int().nonnegative().optional(),
|
|
424
|
+
stepCount: z2.number().int().positive().optional()
|
|
449
425
|
}).strict();
|
|
450
|
-
var
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
426
|
+
var contextEventSchema = z2.object({
|
|
427
|
+
seq: z2.number(),
|
|
428
|
+
time: z2.number(),
|
|
429
|
+
kind: z2.enum(["compaction", "prune", "inject", "model"]),
|
|
430
|
+
form: z2.string().optional(),
|
|
431
|
+
tokens: z2.number().optional(),
|
|
432
|
+
count: z2.number().optional(),
|
|
433
|
+
sub: z2.string().optional(),
|
|
434
|
+
name: z2.string().optional(),
|
|
435
|
+
from: z2.string().optional(),
|
|
436
|
+
to: z2.string().optional(),
|
|
437
|
+
fromTurn: z2.number().optional(),
|
|
438
|
+
fromStep: z2.number().optional(),
|
|
439
|
+
turn: z2.number().optional(),
|
|
440
|
+
step: z2.number().optional()
|
|
458
441
|
}).strict();
|
|
459
|
-
var
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
442
|
+
var currentSchema = z2.object({
|
|
443
|
+
system: z2.number().int().nonnegative(),
|
|
444
|
+
tools: z2.number().int().nonnegative(),
|
|
445
|
+
user: z2.number().int().nonnegative(),
|
|
446
|
+
inject: z2.number().int().nonnegative(),
|
|
447
|
+
assistant: z2.number().int().nonnegative(),
|
|
448
|
+
tool: z2.number().int().nonnegative(),
|
|
449
|
+
total: z2.number().int().nonnegative()
|
|
465
450
|
}).strict();
|
|
466
|
-
var contextTimelineSchema =
|
|
467
|
-
ok:
|
|
468
|
-
model:
|
|
469
|
-
provider:
|
|
470
|
-
contextWindow:
|
|
451
|
+
var contextTimelineSchema = z2.object({
|
|
452
|
+
ok: z2.literal(true),
|
|
453
|
+
model: z2.string().optional(),
|
|
454
|
+
provider: z2.string().optional(),
|
|
455
|
+
contextWindow: z2.number().optional(),
|
|
471
456
|
current: currentSchema,
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
droppedNodes: z.number().int().nonnegative()
|
|
457
|
+
toolList: z2.array(z2.object({ name: z2.string(), tokens: z2.number().int().nonnegative() }).strict()),
|
|
458
|
+
requests: z2.array(requestRecordSchema),
|
|
459
|
+
events: z2.array(contextEventSchema),
|
|
460
|
+
nodes: z2.array(surfaceNodeSchema),
|
|
461
|
+
droppedNodes: z2.number().int().nonnegative()
|
|
478
462
|
}).strict();
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
463
|
+
function createContextTimelineDefinition(config) {
|
|
464
|
+
const bounds = resolveBounds(config);
|
|
465
|
+
return {
|
|
466
|
+
key: "contextTimeline",
|
|
467
|
+
schema: contextTimelineSchema,
|
|
468
|
+
init: () => createTimelineState(),
|
|
469
|
+
apply: (state, event) => applyTimeline(state, event, bounds),
|
|
470
|
+
view: (state) => buildTimelineView(state, bounds),
|
|
471
|
+
// 2 since 0.11: the occupancy mirror (pressureTokens/sampledSurfaceTokens/
|
|
472
|
+
// occupancyWindow) left the persisted state — the client now reads the
|
|
473
|
+
// official token-meter `contextPressure` projection instead. Old cached
|
|
474
|
+
// rows are discarded and refolded.
|
|
475
|
+
stateVersion: 2
|
|
476
|
+
};
|
|
477
|
+
}
|
|
487
478
|
|
|
488
479
|
// src/host/index.ts
|
|
489
480
|
var name = "dsh-context";
|
|
490
481
|
var inject = ["sessionProjections"];
|
|
491
|
-
function apply(ctx) {
|
|
492
|
-
ctx.
|
|
493
|
-
projectionCtx.sessionProjections.register(contextTimelineDefinition);
|
|
494
|
-
});
|
|
482
|
+
function apply(ctx, config) {
|
|
483
|
+
ctx.sessionProjections.register(createContextTimelineDefinition(config));
|
|
495
484
|
}
|
|
496
485
|
export {
|
|
486
|
+
Config,
|
|
497
487
|
apply,
|
|
498
488
|
inject,
|
|
499
489
|
name
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-context",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.3",
|
|
4
4
|
"description": "A DeepSeek Harness plugin for context dashboard and context command, for understanding how the context is made of, and how it evolves.",
|
|
5
5
|
"author": "bowenliang123",
|
|
6
6
|
"repository": {
|