dsh-context 0.21.0 → 0.21.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/lib/client.js +107 -9
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -67,6 +67,7 @@ var DICT_ZH = {
|
|
|
67
67
|
"nodes.empty": "\u5F53\u524D\u6CA1\u6709\u6A21\u578B\u53EF\u89C1\u7684\u6D88\u606F",
|
|
68
68
|
"loading": "\u6B63\u5728\u8BFB\u53D6\u4F1A\u8BDD\u65E5\u5FD7\u2026",
|
|
69
69
|
"error": "\u4E0A\u4E0B\u6587\u6570\u636E\u8BFB\u53D6\u5931\u8D25\uFF1A",
|
|
70
|
+
"error.retry": "\u91CD\u8BD5",
|
|
70
71
|
"footer": "\u4F30\u7B97\u53E3\u5F84\uFF1A\u4E0E dsh \u5185\u7F6E tokenMeter \u76F8\u540C\u7684\u56FA\u5B9A\u5BC6\u5EA6\u542F\u53D1\u5F0F\uFF08\u7EA6 4 \u5B57\u7B26 \u2248 1 token\uFF09\uFF1B\u300C\u5B9E\u9645\u300D\u4E3A\u4F9B\u5E94\u5546\u4E0A\u62A5\u7528\u91CF\u3002",
|
|
71
72
|
"tip.step": "\u7B2C {t} \u8F6E \xB7 \u7B2C{s}\u6B65",
|
|
72
73
|
"tip.turn": "\u7B2C {t} \u8F6E \xB7 \u5171 {n} \u6B65",
|
|
@@ -177,6 +178,7 @@ var DICT_EN = {
|
|
|
177
178
|
"nodes.empty": "No model-visible messages right now",
|
|
178
179
|
"loading": "Reading the session log\u2026",
|
|
179
180
|
"error": "Failed to read context data: ",
|
|
181
|
+
"error.retry": "Retry",
|
|
180
182
|
"footer": "Estimate: same fixed-density heuristic as dsh\u2019s built-in tokenMeter (~4 chars \u2248 1 token); \u201Cactual\u201D is provider-reported usage.",
|
|
181
183
|
"tip.step": "Turn {t} \xB7 Step {s}",
|
|
182
184
|
"tip.turn": "Turn {t} \xB7 {n} steps",
|
|
@@ -338,12 +340,60 @@ function asRecord(value) {
|
|
|
338
340
|
if (value === null || value === void 0 || typeof value !== "object") return null;
|
|
339
341
|
return value;
|
|
340
342
|
}
|
|
341
|
-
|
|
343
|
+
function numOf(value) {
|
|
344
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
345
|
+
}
|
|
346
|
+
function objectsOf(value) {
|
|
347
|
+
if (!Array.isArray(value)) return [];
|
|
348
|
+
return value.filter((v) => v !== null && typeof v === "object");
|
|
349
|
+
}
|
|
350
|
+
function timelineOf(value) {
|
|
351
|
+
const data = asRecord(value);
|
|
352
|
+
if (data === null) return null;
|
|
353
|
+
const current = data.current;
|
|
354
|
+
const numericBreakdown = current !== null && typeof current === "object" && ["system", "tools", "user", "inject", "assistant", "tool", "total"].every((k) => typeof current[k] === "number");
|
|
355
|
+
if (numericBreakdown && Array.isArray(data.requests) && Array.isArray(data.events) && Array.isArray(data.nodes) && Array.isArray(data.archive) && Array.isArray(data.toolList)) {
|
|
356
|
+
return data;
|
|
357
|
+
}
|
|
358
|
+
const safeCurrent = current !== null && typeof current === "object" ? current : {};
|
|
359
|
+
const cost = typeof data.cost === "object" && data.cost !== null && !Array.isArray(data.cost) ? data.cost : void 0;
|
|
360
|
+
return {
|
|
361
|
+
ok: true,
|
|
362
|
+
...typeof data.model === "string" ? { model: data.model } : {},
|
|
363
|
+
...typeof data.provider === "string" ? { provider: data.provider } : {},
|
|
364
|
+
...typeof data.contextWindow === "number" ? { contextWindow: data.contextWindow } : {},
|
|
365
|
+
current: {
|
|
366
|
+
system: numOf(safeCurrent.system),
|
|
367
|
+
tools: numOf(safeCurrent.tools),
|
|
368
|
+
user: numOf(safeCurrent.user),
|
|
369
|
+
inject: numOf(safeCurrent.inject),
|
|
370
|
+
assistant: numOf(safeCurrent.assistant),
|
|
371
|
+
tool: numOf(safeCurrent.tool),
|
|
372
|
+
total: numOf(safeCurrent.total)
|
|
373
|
+
},
|
|
374
|
+
toolList: objectsOf(data.toolList),
|
|
375
|
+
requests: objectsOf(data.requests),
|
|
376
|
+
events: objectsOf(data.events),
|
|
377
|
+
nodes: objectsOf(data.nodes),
|
|
378
|
+
droppedNodes: numOf(data.droppedNodes),
|
|
379
|
+
archive: objectsOf(data.archive),
|
|
380
|
+
...cost !== void 0 ? { cost } : {},
|
|
381
|
+
...typeof data.surfaceFloor === "number" ? { surfaceFloor: data.surfaceFloor } : {},
|
|
382
|
+
...typeof data.archiveFloor === "number" ? { archiveFloor: data.archiveFloor } : {}
|
|
383
|
+
};
|
|
384
|
+
}
|
|
342
385
|
var contextPressureOf = (value) => asRecord(value);
|
|
343
386
|
var tokenUsageOf = (value) => asRecord(value);
|
|
344
387
|
function headersOf(value) {
|
|
345
388
|
const headers = asRecord(value);
|
|
346
|
-
|
|
389
|
+
if (headers === null || !Array.isArray(headers.headers)) return null;
|
|
390
|
+
for (const h2 of headers.headers) {
|
|
391
|
+
if (h2 === null || typeof h2 !== "object") return null;
|
|
392
|
+
const entry = h2;
|
|
393
|
+
if (!Array.isArray(entry.tools)) return null;
|
|
394
|
+
if (entry.system !== void 0 && typeof entry.system !== "string") return null;
|
|
395
|
+
}
|
|
396
|
+
return headers;
|
|
347
397
|
}
|
|
348
398
|
|
|
349
399
|
// src/client/assemble.ts
|
|
@@ -982,6 +1032,34 @@ function makeCurrentComposition(kit, StackedBar, Legend) {
|
|
|
982
1032
|
};
|
|
983
1033
|
}
|
|
984
1034
|
|
|
1035
|
+
// src/client/components/errorBoundary.tsx
|
|
1036
|
+
function makeErrorBoundary(t) {
|
|
1037
|
+
return class ErrorBoundary extends React.Component {
|
|
1038
|
+
constructor(props) {
|
|
1039
|
+
super(props);
|
|
1040
|
+
this.state = { error: null };
|
|
1041
|
+
}
|
|
1042
|
+
static getDerivedStateFromError(error) {
|
|
1043
|
+
return { error: error instanceof Error ? error : new Error(String(error)) };
|
|
1044
|
+
}
|
|
1045
|
+
render() {
|
|
1046
|
+
const error = this.state.error;
|
|
1047
|
+
if (error === null) return this.props.children;
|
|
1048
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-root" }, /* @__PURE__ */ React.createElement("div", { className: "lc-empty lc-error" }, /* @__PURE__ */ React.createElement("span", null, t("error")), /* @__PURE__ */ React.createElement("code", { className: "lc-error-msg" }, error.message), /* @__PURE__ */ React.createElement(
|
|
1049
|
+
"button",
|
|
1050
|
+
{
|
|
1051
|
+
type: "button",
|
|
1052
|
+
className: "lc-error-retry",
|
|
1053
|
+
onClick: () => {
|
|
1054
|
+
this.setState({ error: null });
|
|
1055
|
+
}
|
|
1056
|
+
},
|
|
1057
|
+
t("error.retry")
|
|
1058
|
+
)));
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
|
|
985
1063
|
// src/client/components/contextModal.tsx
|
|
986
1064
|
function makeContextModal(ctx, kit) {
|
|
987
1065
|
const { t } = kit;
|
|
@@ -990,7 +1068,8 @@ function makeContextModal(ctx, kit) {
|
|
|
990
1068
|
const Legend = makeLegend(kit);
|
|
991
1069
|
const CurrentComposition = makeCurrentComposition(kit, StackedBar, Legend);
|
|
992
1070
|
const ContextBrowser = makeContextBrowser(kit, StackedBar);
|
|
993
|
-
|
|
1071
|
+
const ErrorBoundary = makeErrorBoundary(t);
|
|
1072
|
+
function ContextModalBody(props) {
|
|
994
1073
|
const sessionId = typeof props.sessionId === "string" ? props.sessionId : "";
|
|
995
1074
|
const open = typeof props.useContextModal === "function" ? props.useContextModal((s) => s) : false;
|
|
996
1075
|
const data = typeof props.useProjection === "function" ? timelineOf(props.useProjection("contextTimeline")) : null;
|
|
@@ -1051,6 +1130,9 @@ function makeContextModal(ctx, kit) {
|
|
|
1051
1130
|
}
|
|
1052
1131
|
}
|
|
1053
1132
|
))));
|
|
1133
|
+
}
|
|
1134
|
+
return function ContextModal(props) {
|
|
1135
|
+
return h(ErrorBoundary, null, h(ContextModalBody, props));
|
|
1054
1136
|
};
|
|
1055
1137
|
}
|
|
1056
1138
|
|
|
@@ -1273,6 +1355,13 @@ var STYLES = [
|
|
|
1273
1355
|
".lc-node-tokens { color: var(--dsw-alias-label-secondary); }",
|
|
1274
1356
|
".lc-nodes-more { color: var(--dsw-alias-label-secondary); padding: 3px 0; }",
|
|
1275
1357
|
".lc-empty { color: var(--dsw-alias-label-secondary); padding: 18px 0; text-align: center; }",
|
|
1358
|
+
// Error-boundary fallback card: the tab degrades to this instead of
|
|
1359
|
+
// white-screening; the message runs in mono on a padded chip, and Retry
|
|
1360
|
+
// re-mounts the subtree once a healthy value arrives.
|
|
1361
|
+
".lc-error { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 40px 16px; }",
|
|
1362
|
+
".lc-error-msg { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; color: var(--dsw-alias-state-error-primary); background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; padding: 4px 8px; max-width: 100%; overflow-wrap: anywhere; }",
|
|
1363
|
+
".lc-error-retry { border: 1px solid var(--dsw-alias-border-l1); background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-primary); font: inherit; font-size: 12px; padding: 4px 14px; border-radius: 6px; cursor: pointer; }",
|
|
1364
|
+
".lc-error-retry:hover { border-color: var(--dsw-alias-label-primary); }",
|
|
1276
1365
|
".lc-foot { color: var(--dsw-alias-label-secondary); font-size: 12px; margin-top: 4px; }",
|
|
1277
1366
|
// ---- /context modal (centered dialog; escapes the composer anchor via fixed positioning) ----
|
|
1278
1367
|
".lc-modal-backdrop { position: fixed; inset: 0; z-index: 200; background: rgba(0, 0, 0, 0.45); display: flex; align-items: center; justify-content: center; }",
|
|
@@ -1406,7 +1495,9 @@ function fmt(n) {
|
|
|
1406
1495
|
return String(Math.round(n));
|
|
1407
1496
|
}
|
|
1408
1497
|
function fmtTime(t) {
|
|
1409
|
-
|
|
1498
|
+
const d = new Date(t);
|
|
1499
|
+
if (isNaN(d.getTime())) return "\u2014";
|
|
1500
|
+
return d.toLocaleTimeString("en-GB", { hour12: false });
|
|
1410
1501
|
}
|
|
1411
1502
|
|
|
1412
1503
|
// src/client/components/events.tsx
|
|
@@ -1472,7 +1563,7 @@ function makeEventList(kit) {
|
|
|
1472
1563
|
|
|
1473
1564
|
// src/client/meta.ts
|
|
1474
1565
|
var PLUGIN_NAME = "dsh-context";
|
|
1475
|
-
var PLUGIN_VERSION = true ? "0.21.
|
|
1566
|
+
var PLUGIN_VERSION = true ? "0.21.1" : "0.0.0-dev";
|
|
1476
1567
|
var PLUGIN_REPO = true ? "https://github.com/bowenliang123/dsh-context" : "https://github.com/bowenliang123/dsh-context";
|
|
1477
1568
|
var PLUGIN_REPO_SHORT = PLUGIN_REPO.replace(/^https?:\/\/github\.com\//, "");
|
|
1478
1569
|
|
|
@@ -1563,7 +1654,7 @@ function estimateSessionCost(usage, currency) {
|
|
|
1563
1654
|
const b = fam[period];
|
|
1564
1655
|
if (b === void 0) continue;
|
|
1565
1656
|
const p = PRICES[currency][family][period];
|
|
1566
|
-
total += (b.cacheRead * p.hit + (b.uncached + b.cacheWrite) * p.miss + b.output * p.out) / 1e6;
|
|
1657
|
+
total += (numOf(b.cacheRead) * p.hit + (numOf(b.uncached) + numOf(b.cacheWrite)) * p.miss + numOf(b.output) * p.out) / 1e6;
|
|
1567
1658
|
any = true;
|
|
1568
1659
|
}
|
|
1569
1660
|
}
|
|
@@ -1586,9 +1677,12 @@ function formatPriceRate(amount, currency) {
|
|
|
1586
1677
|
|
|
1587
1678
|
// src/client/components/statsBoard.tsx
|
|
1588
1679
|
function cacheHitPercent(usage) {
|
|
1589
|
-
const
|
|
1680
|
+
const uncached = numOf(usage.uncachedInputTokens);
|
|
1681
|
+
const reads = numOf(usage.cacheReadTokens);
|
|
1682
|
+
const writes = numOf(usage.cacheWriteTokens);
|
|
1683
|
+
const billed = uncached + reads + writes;
|
|
1590
1684
|
if (billed === 0) return null;
|
|
1591
|
-
const hundredths = Math.trunc(
|
|
1685
|
+
const hundredths = Math.trunc(reads / billed * 1e4 + 1e-9);
|
|
1592
1686
|
return `${Math.floor(hundredths / 100)}.${String(hundredths % 100).padStart(2, "0")}`;
|
|
1593
1687
|
}
|
|
1594
1688
|
function makeStatsBoard(kit) {
|
|
@@ -1811,7 +1905,8 @@ function makeContextView(ctx, kit) {
|
|
|
1811
1905
|
const StatsBoard = makeStatsBoard(kit);
|
|
1812
1906
|
const PluginInfo = makePluginInfo(kit);
|
|
1813
1907
|
const ContextBrowser = makeContextBrowser(kit, StackedBar);
|
|
1814
|
-
|
|
1908
|
+
const ErrorBoundary = makeErrorBoundary(t);
|
|
1909
|
+
function ContextViewBody(props) {
|
|
1815
1910
|
const sessionId = props.sessionId;
|
|
1816
1911
|
const data = typeof props.useProjection === "function" ? timelineOf(props.useProjection("contextTimeline")) : null;
|
|
1817
1912
|
const pressure = typeof props.useProjection === "function" ? contextPressureOf(props.useProjection("contextPressure")) : null;
|
|
@@ -1959,6 +2054,9 @@ function makeContextView(ctx, kit) {
|
|
|
1959
2054
|
},
|
|
1960
2055
|
t("kind." + k)
|
|
1961
2056
|
)))), /* @__PURE__ */ React.createElement(EventList, { events: shownEvents })), /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, /* @__PURE__ */ React.createElement("span", { className: "lc-card-title-text" }, t("nodes.title")), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("nodes.hint"))), /* @__PURE__ */ React.createElement(NodeList, { nodes, dropped: data.droppedNodes || 0 }))), /* @__PURE__ */ React.createElement("div", { className: "lc-foot" }, t("footer")));
|
|
2057
|
+
}
|
|
2058
|
+
return function ContextView(props) {
|
|
2059
|
+
return h(ErrorBoundary, null, h(ContextViewBody, props));
|
|
1962
2060
|
};
|
|
1963
2061
|
}
|
|
1964
2062
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-context",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.1",
|
|
4
4
|
"description": "A DeepSeek Harness plugin for context insight and management, with context dashboard and context command, for understanding how the context is made of, and how it evolves.",
|
|
5
5
|
"author": "bowenliang123",
|
|
6
6
|
"repository": {
|