dsh-context 0.38.5 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/client.js +264 -82
- package/lib/index.d.ts +30 -8
- package/lib/index.js +78 -48
- package/package.json +10 -11
package/README.md
CHANGED
|
@@ -140,7 +140,7 @@ In **Settings → Plugins → Plugin configuration**, the **Context** card holds
|
|
|
140
140
|
## Good to know
|
|
141
141
|
|
|
142
142
|
- **Estimates vs actuals** — category figures use dsh's own fixed-density heuristic (the same one as its built-in token meter); the pinned trend details and Token/Timing rings show provider-reported actuals next to them.
|
|
143
|
-
- **Compatibility** — works on `@deepseek-ai/dsh` **0.1.
|
|
143
|
+
- **Compatibility** — works on `@deepseek-ai/dsh` **0.1.1-rc2+** and **0.1.2-alpha2+**.
|
|
144
144
|
- **I18n** — UI in English and 简体中文.
|
|
145
145
|
|
|
146
146
|
## Like it?
|
package/lib/client.js
CHANGED
|
@@ -40,15 +40,17 @@ window.__ModuleLoader__.load({
|
|
|
40
40
|
"timing.lm": "模型调用",
|
|
41
41
|
"timing.tools": "工具执行",
|
|
42
42
|
"timing.other": "其他开销",
|
|
43
|
-
"timing.
|
|
43
|
+
"timing.lmTimes": "{n}次",
|
|
44
|
+
"timing.toolTimes": "{n}次",
|
|
44
45
|
"timing.empty": "暂无耗时数据 · 对话开始后这里会显示时长分布",
|
|
45
46
|
"tokens.title": "Token 统计",
|
|
46
47
|
"tokens.hint": "供应商上报的累计计费用量",
|
|
47
48
|
"tokens.cacheHit": "缓存命中",
|
|
48
|
-
"tokens.cacheRead": "
|
|
49
|
+
"tokens.cacheRead": "缓存输入",
|
|
49
50
|
"tokens.cacheWrite": "缓存写入",
|
|
50
|
-
"tokens.uncached": "
|
|
51
|
-
"tokens.output": "
|
|
51
|
+
"tokens.uncached": "未缓存输入",
|
|
52
|
+
"tokens.output": "输出",
|
|
53
|
+
"tokens.outputNote": "含思考",
|
|
52
54
|
"plugin.title": "插件信息",
|
|
53
55
|
"plugin.hint": "The best DSH context plugin ⭐",
|
|
54
56
|
"plugin.name": "插件",
|
|
@@ -60,9 +62,9 @@ window.__ModuleLoader__.load({
|
|
|
60
62
|
"gran.turn": "轮次",
|
|
61
63
|
"settings.title": "上下文",
|
|
62
64
|
"settings.desc": "dsh-context 插件中上下文面板的偏好设置",
|
|
63
|
-
"settings.gran": "
|
|
64
|
-
"settings.mode": "
|
|
65
|
-
"settings.fileSort": "
|
|
65
|
+
"settings.gran": "趋势图 · 默认粒度",
|
|
66
|
+
"settings.mode": "趋势图 · 默认展示方式",
|
|
67
|
+
"settings.fileSort": "文件活动 · 默认排序",
|
|
66
68
|
"settings.expand": "展开",
|
|
67
69
|
"settings.collapse": "收起",
|
|
68
70
|
"settings.readOnly": "当前环境的设置为只读",
|
|
@@ -222,6 +224,8 @@ window.__ModuleLoader__.load({
|
|
|
222
224
|
"browser.deltaHint": "对比上轮末步的变动",
|
|
223
225
|
"browser.noHeader": "此数据来自旧版插件:仅提供 token 估算,无实际内容",
|
|
224
226
|
"browser.noEpoch": "该步骤的头部内容(系统提示词 / 工具定义)不在保留范围内",
|
|
227
|
+
"browser.headerMetaOnly": "此环境不支持按需读取头部内容,仅显示 token 估算",
|
|
228
|
+
"browser.noSystem": "该请求头部未包含系统提示词",
|
|
225
229
|
"browser.noContent": "完整内容不在当前加载的消息窗口内(在聊天页加载更早历史后可查看)",
|
|
226
230
|
"browser.search.user": "按消息内容过滤…",
|
|
227
231
|
"browser.search.inject": "按注入内容过滤…",
|
|
@@ -311,15 +315,17 @@ window.__ModuleLoader__.load({
|
|
|
311
315
|
"timing.lm": "Model calls",
|
|
312
316
|
"timing.tools": "Tool runs",
|
|
313
317
|
"timing.other": "Overhead",
|
|
314
|
-
"timing.
|
|
318
|
+
"timing.lmTimes": "{n} calls",
|
|
319
|
+
"timing.toolTimes": "{n} runs",
|
|
315
320
|
"timing.empty": "No timing data yet — durations appear as the conversation runs",
|
|
316
321
|
"tokens.title": "Token Stats",
|
|
317
322
|
"tokens.hint": "Cumulative provider-reported usage",
|
|
318
|
-
"tokens.cacheHit": "Cache
|
|
319
|
-
"tokens.cacheRead": "
|
|
320
|
-
"tokens.cacheWrite": "Cache
|
|
321
|
-
"tokens.uncached": "Uncached
|
|
322
|
-
"tokens.output": "Output
|
|
323
|
+
"tokens.cacheHit": "Cache Hit",
|
|
324
|
+
"tokens.cacheRead": "Cached Input",
|
|
325
|
+
"tokens.cacheWrite": "Cache Write",
|
|
326
|
+
"tokens.uncached": "Uncached Input",
|
|
327
|
+
"tokens.output": "Output",
|
|
328
|
+
"tokens.outputNote": "incl. reasoning",
|
|
323
329
|
"plugin.title": "Plugin Info",
|
|
324
330
|
"plugin.hint": "The best DSH context plugin ⭐",
|
|
325
331
|
"plugin.name": "Plugin",
|
|
@@ -331,9 +337,9 @@ window.__ModuleLoader__.load({
|
|
|
331
337
|
"gran.turn": "Turn",
|
|
332
338
|
"settings.title": "Context",
|
|
333
339
|
"settings.desc": "Preferences for Context panel in dsh-context plugin",
|
|
334
|
-
"settings.gran": "Default
|
|
335
|
-
"settings.mode": "Default
|
|
336
|
-
"settings.fileSort": "File Activity
|
|
340
|
+
"settings.gran": "Trend Chart · Default granularity",
|
|
341
|
+
"settings.mode": "Trend Chart · Default display",
|
|
342
|
+
"settings.fileSort": "File Activity · Default sort",
|
|
337
343
|
"settings.expand": "Expand",
|
|
338
344
|
"settings.collapse": "Collapse",
|
|
339
345
|
"settings.readOnly": "Settings are read-only in this environment",
|
|
@@ -493,6 +499,8 @@ window.__ModuleLoader__.load({
|
|
|
493
499
|
"browser.deltaHint": "vs previous turn",
|
|
494
500
|
"browser.noHeader": "Served by an older plugin build: token estimates only, no content",
|
|
495
501
|
"browser.noEpoch": "The header content (System Prompt / Tool Schemas) of this step is outside retention",
|
|
502
|
+
"browser.headerMetaOnly": "This environment cannot fetch header content on demand; token estimates only",
|
|
503
|
+
"browser.noSystem": "This request header carried no system prompt",
|
|
496
504
|
"browser.noContent": "Full content is outside the loaded message window (load older history in Chat to view)",
|
|
497
505
|
"browser.search.user": "Filter by message text…",
|
|
498
506
|
"browser.search.inject": "Filter injected context…",
|
|
@@ -998,14 +1006,15 @@ window.__ModuleLoader__.load({
|
|
|
998
1006
|
}
|
|
999
1007
|
/**
|
|
1000
1008
|
* Narrow a delivered projection value to the plugin's `contextHeaders`
|
|
1001
|
-
* (request-header
|
|
1002
|
-
* the companion unit — the Context
|
|
1003
|
-
* sections to
|
|
1009
|
+
* (request-header epoch METADATA — boundaries, token prices, attribution).
|
|
1010
|
+
* Absent key = an older Host half without the companion unit — the Context
|
|
1011
|
+
* browser degrades its system/tools sections to a metadata-only note.
|
|
1004
1012
|
*
|
|
1005
1013
|
* Entry-level shape is checked too: a malformed epoch (corrupt payload with
|
|
1006
|
-
* a missing tools list or wrong-typed
|
|
1014
|
+
* a missing tools list or wrong-typed systemTokens) would crash the
|
|
1007
1015
|
* browser's tools/sections reads, so the WHOLE projection degrades to null
|
|
1008
|
-
* and the card falls back to its
|
|
1016
|
+
* and the card falls back to its metadata-only note. The epoch CONTENT is
|
|
1017
|
+
* not part of this value — the browser fetches it per epoch on demand.
|
|
1009
1018
|
*/
|
|
1010
1019
|
function headersOf(value) {
|
|
1011
1020
|
const headers = asRecord$1(value);
|
|
@@ -1014,7 +1023,7 @@ window.__ModuleLoader__.load({
|
|
|
1014
1023
|
if (h === null || typeof h !== "object") return null;
|
|
1015
1024
|
const entry = h;
|
|
1016
1025
|
if (!Array.isArray(entry.tools)) return null;
|
|
1017
|
-
if (entry.
|
|
1026
|
+
if (entry.systemTokens !== void 0 && (typeof entry.systemTokens !== "number" || !Number.isFinite(entry.systemTokens))) return null;
|
|
1018
1027
|
}
|
|
1019
1028
|
return headers;
|
|
1020
1029
|
}
|
|
@@ -1217,6 +1226,37 @@ window.__ModuleLoader__.load({
|
|
|
1217
1226
|
return rows;
|
|
1218
1227
|
}
|
|
1219
1228
|
/**
|
|
1229
|
+
* The session's history readers over whichever face the running harness
|
|
1230
|
+
* serves — the 0.1.2+ gateway remotes (`remote.session.page`) first, the
|
|
1231
|
+
* pre-0.1.2 api client verb (`connection.api.sessions.history`) beneath it.
|
|
1232
|
+
* Both cut message-aligned pages, so the returned read covers `seq` whenever
|
|
1233
|
+
* the durable log still holds it: the newer face pins the inclusive cut to
|
|
1234
|
+
* the seq itself, the legacy reader uses the exclusive bound one past it.
|
|
1235
|
+
* Undefined when no face exists (older hosts) — callers keep their static
|
|
1236
|
+
* degradation.
|
|
1237
|
+
*/
|
|
1238
|
+
function pageReadersOf(ctx, sessionId) {
|
|
1239
|
+
const pageFace = serviceOf(ctx, "remote.session");
|
|
1240
|
+
const page = pageFace !== void 0 && typeof pageFace.page === "function" ? pageFace.page.bind(pageFace) : void 0;
|
|
1241
|
+
const historyFace = serviceOf(ctx, "connection")?.api?.sessions;
|
|
1242
|
+
const history = historyFace !== void 0 && typeof historyFace.history === "function" ? historyFace.history.bind(historyFace) : void 0;
|
|
1243
|
+
if (page === void 0 && history === void 0) return void 0;
|
|
1244
|
+
return (seq) => {
|
|
1245
|
+
if (page !== void 0) return page({
|
|
1246
|
+
address: {
|
|
1247
|
+
kind: "session",
|
|
1248
|
+
sessionId
|
|
1249
|
+
},
|
|
1250
|
+
throughSeq: seq,
|
|
1251
|
+
beforeSeq: seq + 1
|
|
1252
|
+
}, new AbortController().signal);
|
|
1253
|
+
return history({
|
|
1254
|
+
sessionId,
|
|
1255
|
+
beforeSeq: seq + 1
|
|
1256
|
+
});
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
/**
|
|
1220
1260
|
* Build the browser's per-session fetcher over whichever history face the
|
|
1221
1261
|
* running harness serves — the 0.1.2+ gateway remotes (`remote.session.page`)
|
|
1222
1262
|
* first, the pre-0.1.2 api client verb (`connection.api.sessions.history`)
|
|
@@ -1227,32 +1267,73 @@ window.__ModuleLoader__.load({
|
|
|
1227
1267
|
* nodes cache in the closure: one mount re-reading a row never re-fetches.
|
|
1228
1268
|
*/
|
|
1229
1269
|
function makeContentFetcher(ctx, sessionId) {
|
|
1230
|
-
const
|
|
1231
|
-
|
|
1232
|
-
const historyFace = serviceOf(ctx, "connection")?.api?.sessions;
|
|
1233
|
-
const history = historyFace !== void 0 && typeof historyFace.history === "function" ? historyFace.history.bind(historyFace) : void 0;
|
|
1234
|
-
if (page === void 0 && history === void 0) return void 0;
|
|
1235
|
-
const pageRequest = (seq) => ({
|
|
1236
|
-
address: {
|
|
1237
|
-
kind: "session",
|
|
1238
|
-
sessionId
|
|
1239
|
-
},
|
|
1240
|
-
throughSeq: seq,
|
|
1241
|
-
beforeSeq: seq + 1
|
|
1242
|
-
});
|
|
1243
|
-
const historyCall = (seq) => history({
|
|
1244
|
-
sessionId,
|
|
1245
|
-
beforeSeq: seq + 1
|
|
1246
|
-
});
|
|
1270
|
+
const read = pageReadersOf(ctx, sessionId);
|
|
1271
|
+
if (read === void 0) return void 0;
|
|
1247
1272
|
const cache = /* @__PURE__ */ new Map();
|
|
1248
1273
|
return async (seq) => {
|
|
1249
1274
|
const hit = cache.get(seq);
|
|
1250
1275
|
if (hit !== void 0) return hit;
|
|
1251
|
-
const node = pageNodesOf(rowsOf(
|
|
1276
|
+
const node = pageNodesOf(rowsOf(await read(seq))).get(seq) ?? null;
|
|
1252
1277
|
if (node !== null) cache.set(seq, node);
|
|
1253
1278
|
return node;
|
|
1254
1279
|
};
|
|
1255
1280
|
}
|
|
1281
|
+
/**
|
|
1282
|
+
* Map one raw `request/header` event into the epoch content the browser
|
|
1283
|
+
* renders — the full system prompt text plus each tool's producer
|
|
1284
|
+
* description and raw schema, mirroring the host fold's per-entry guards
|
|
1285
|
+
* (a null or primitive tool entry degrades to an unnamed row instead of
|
|
1286
|
+
* throwing the read). Null when the envelope carries no usable header.
|
|
1287
|
+
*/
|
|
1288
|
+
function headerContentOf(data) {
|
|
1289
|
+
const rawHeader = data.header !== null && typeof data.header === "object" ? data.header : null;
|
|
1290
|
+
if (rawHeader === null) return null;
|
|
1291
|
+
const toolsRaw = Array.isArray(rawHeader.tools) ? rawHeader.tools : [];
|
|
1292
|
+
const tools = [];
|
|
1293
|
+
for (const t of toolsRaw) {
|
|
1294
|
+
const tool = t !== null && typeof t === "object" ? t : null;
|
|
1295
|
+
tools.push({
|
|
1296
|
+
name: tool !== null && typeof tool.name === "string" ? tool.name : "?",
|
|
1297
|
+
...tool !== null && typeof tool.description === "string" && tool.description !== "" ? { description: tool.description } : {},
|
|
1298
|
+
schema: t
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
return {
|
|
1302
|
+
...typeof rawHeader.system === "string" && rawHeader.system !== "" ? { system: rawHeader.system } : {},
|
|
1303
|
+
tools
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* The on-demand CONTENT fetch for `contextHeaders` epochs — the lazy
|
|
1308
|
+
* counterpart of the node fetcher above. One seq-anchored history read off
|
|
1309
|
+
* the epoch's `seq` returns the page holding that epoch's `request/header`
|
|
1310
|
+
* event (non-message events ride the page verbatim); the raw header is
|
|
1311
|
+
* mapped client-side into the renderable content. Epochs cache per session
|
|
1312
|
+
* (history is immutable), and OLDER epochs sharing the page cache for free —
|
|
1313
|
+
* stepping back through epochs walks the same pages. Undefined when no
|
|
1314
|
+
* history face exists (older hosts) — the browser keeps a metadata-only
|
|
1315
|
+
* degradation instead.
|
|
1316
|
+
*/
|
|
1317
|
+
function makeHeaderFetcher(ctx, sessionId) {
|
|
1318
|
+
const read = pageReadersOf(ctx, sessionId);
|
|
1319
|
+
if (read === void 0) return void 0;
|
|
1320
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1321
|
+
return async (seq) => {
|
|
1322
|
+
const hit = cache.get(seq);
|
|
1323
|
+
if (hit !== void 0) return hit;
|
|
1324
|
+
const rows = rowsOf(await read(seq));
|
|
1325
|
+
let picked = null;
|
|
1326
|
+
for (const entry of rows) {
|
|
1327
|
+
const ev = eventOf(entry);
|
|
1328
|
+
if (ev === null || ev.type !== "request/header") continue;
|
|
1329
|
+
const content = headerContentOf(ev.data);
|
|
1330
|
+
if (content === null) continue;
|
|
1331
|
+
cache.set(ev.seq, content);
|
|
1332
|
+
if (ev.seq === seq) picked = content;
|
|
1333
|
+
}
|
|
1334
|
+
return picked;
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1256
1337
|
//#endregion
|
|
1257
1338
|
//#region src/client/assemble.ts
|
|
1258
1339
|
/** The header epoch in force at `seq` (last logged before it), or the newest. */
|
|
@@ -1898,7 +1979,7 @@ window.__ModuleLoader__.load({
|
|
|
1898
1979
|
}
|
|
1899
1980
|
return out;
|
|
1900
1981
|
}, [params]);
|
|
1901
|
-
const schemaJson = React.useMemo(() =>
|
|
1982
|
+
const schemaJson = React.useMemo(() => jsonOpen ? JSON.stringify(props.schema, null, 2) : "", [props.schema, jsonOpen]);
|
|
1902
1983
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, props.description !== void 0 ? /* @__PURE__ */ React.createElement(TextSection, {
|
|
1903
1984
|
label: props.labels.desc,
|
|
1904
1985
|
text: props.description,
|
|
@@ -1912,13 +1993,13 @@ window.__ModuleLoader__.load({
|
|
|
1912
1993
|
name: r.name,
|
|
1913
1994
|
schema: r.schema,
|
|
1914
1995
|
required: r.required
|
|
1915
|
-
}))) : params !== null ? /* @__PURE__ */ React.createElement("div", { className: "lc-ts-params-empty" }, props.labels.empty) : null,
|
|
1996
|
+
}))) : params !== null ? /* @__PURE__ */ React.createElement("div", { className: "lc-ts-params-empty" }, props.labels.empty) : null, /* @__PURE__ */ React.createElement("div", { className: "lc-ts-json" }, /* @__PURE__ */ React.createElement("button", {
|
|
1916
1997
|
type: "button",
|
|
1917
1998
|
className: "lc-ts-json-toggle",
|
|
1918
1999
|
onClick: () => {
|
|
1919
2000
|
setJsonOpen((o) => !o);
|
|
1920
2001
|
}
|
|
1921
|
-
}, (jsonOpen ? "▾ " : "▸ ") + (jsonOpen ? props.labels.hide : props.labels.show)), jsonOpen ? /* @__PURE__ */ React.createElement("pre", { className: "lc-ts-desc-body lc-br-dim" }, schemaJson) : null)
|
|
2002
|
+
}, (jsonOpen ? "▾ " : "▸ ") + (jsonOpen ? props.labels.hide : props.labels.show)), jsonOpen ? /* @__PURE__ */ React.createElement("pre", { className: "lc-ts-desc-body lc-br-dim" }, schemaJson) : null));
|
|
1922
2003
|
}
|
|
1923
2004
|
/**
|
|
1924
2005
|
* Both block vocabularies normalize here — raw durable blocks (`type`: text/reasoning/tool-call/tool-result/image) and snapshot assistant
|
|
@@ -2139,7 +2220,7 @@ window.__ModuleLoader__.load({
|
|
|
2139
2220
|
return m;
|
|
2140
2221
|
}
|
|
2141
2222
|
function countOf(asm, byCat, c) {
|
|
2142
|
-
if (c === "system") return asm.header !== null && asm.header.
|
|
2223
|
+
if (c === "system") return asm.header !== null && asm.header.systemTokens !== void 0 ? 1 : 0;
|
|
2143
2224
|
if (c === "tools") return asm.header !== null ? asm.header.tools.length : 0;
|
|
2144
2225
|
return byCat[c]?.length ?? 0;
|
|
2145
2226
|
}
|
|
@@ -2237,6 +2318,48 @@ window.__ModuleLoader__.load({
|
|
|
2237
2318
|
const linked = req === null && props.onHoverKey !== void 0;
|
|
2238
2319
|
const linkKey = linked && props.hoverKey !== null && props.hoverKey !== "free" ? props.hoverKey : null;
|
|
2239
2320
|
const view = assemble(data, headers, seq);
|
|
2321
|
+
const [headerContent, setHeaderContent] = React.useState(() => /* @__PURE__ */ new Map());
|
|
2322
|
+
const [headerState, setHeaderState] = React.useState("idle");
|
|
2323
|
+
const [headerRetry, setHeaderRetry] = React.useState(0);
|
|
2324
|
+
const fetchHeader = props.fetchHeader;
|
|
2325
|
+
const headerSeq = view.header !== null ? view.header.seq : null;
|
|
2326
|
+
const headerNeeded = view.header !== null && headerSeq !== null && !headerContent.has(headerSeq) && (openCat === "system" || openCat === "tools");
|
|
2327
|
+
React.useEffect(() => {
|
|
2328
|
+
if (!headerNeeded || fetchHeader === void 0) return;
|
|
2329
|
+
let live = true;
|
|
2330
|
+
setHeaderState("loading");
|
|
2331
|
+
fetchHeader(headerSeq).then((content) => {
|
|
2332
|
+
if (!live) return;
|
|
2333
|
+
if (content === null) {
|
|
2334
|
+
setHeaderState("absent");
|
|
2335
|
+
return;
|
|
2336
|
+
}
|
|
2337
|
+
setHeaderContent((prev) => {
|
|
2338
|
+
const next = new Map(prev);
|
|
2339
|
+
next.set(headerSeq, content);
|
|
2340
|
+
return next;
|
|
2341
|
+
});
|
|
2342
|
+
setHeaderState("idle");
|
|
2343
|
+
}, (error) => {
|
|
2344
|
+
console.warn("dsh-context: header content fetch failed", error);
|
|
2345
|
+
if (live) setHeaderState("failed");
|
|
2346
|
+
});
|
|
2347
|
+
return () => {
|
|
2348
|
+
live = false;
|
|
2349
|
+
};
|
|
2350
|
+
}, [
|
|
2351
|
+
headerNeeded,
|
|
2352
|
+
headerSeq,
|
|
2353
|
+
fetchHeader,
|
|
2354
|
+
headerRetry
|
|
2355
|
+
]);
|
|
2356
|
+
const headerNote = fetchHeader === void 0 ? t("browser.headerMetaOnly") : headerState === "loading" || headerState === "idle" ? t("browser.loading") : headerState === "absent" ? t("browser.notInLog") : /* @__PURE__ */ React.createElement("button", {
|
|
2357
|
+
type: "button",
|
|
2358
|
+
className: "lc-br-retry",
|
|
2359
|
+
onClick: () => {
|
|
2360
|
+
setHeaderRetry((r) => r + 1);
|
|
2361
|
+
}
|
|
2362
|
+
}, t("browser.loadFailed"));
|
|
2240
2363
|
const breakdown = req !== null ? req : data.current;
|
|
2241
2364
|
const parts = partsOf(breakdown);
|
|
2242
2365
|
const total = breakdown.total;
|
|
@@ -2251,7 +2374,7 @@ window.__ModuleLoader__.load({
|
|
|
2251
2374
|
const byCat = byCatOf(view);
|
|
2252
2375
|
const toolCount = (c) => countOf(view, byCat, c);
|
|
2253
2376
|
const singleKeyOf = (c) => {
|
|
2254
|
-
if (c === "system") return view.header?.
|
|
2377
|
+
if (c === "system") return view.header?.systemTokens !== void 0 ? "sys" : null;
|
|
2255
2378
|
if (c === "tools") {
|
|
2256
2379
|
const tools = view.header?.tools;
|
|
2257
2380
|
return tools !== void 0 && tools.length === 1 ? "tool:" + tools[0].name : null;
|
|
@@ -2298,13 +2421,12 @@ window.__ModuleLoader__.load({
|
|
|
2298
2421
|
const catBody = (c) => {
|
|
2299
2422
|
if (c === "system") {
|
|
2300
2423
|
if (view.header === null) return /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, t(headers === null ? "browser.noHeader" : "browser.noEpoch"));
|
|
2301
|
-
const
|
|
2302
|
-
|
|
2303
|
-
(
|
|
2304
|
-
|
|
2305
|
-
return elemRow("sys", null, system.replace(/\s+/g, " ").trim().slice(0, 80), breakdown.system, void 0, /* @__PURE__ */ React.createElement(TextSection, {
|
|
2424
|
+
const content = headerContent.get(view.header.seq);
|
|
2425
|
+
if (content === void 0) return /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, headerNote);
|
|
2426
|
+
if (content.system === void 0) return /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, t("browser.noSystem"));
|
|
2427
|
+
return elemRow("sys", null, content.system.replace(/\s+/g, " ").trim().slice(0, 80), breakdown.system, void 0, /* @__PURE__ */ React.createElement(TextSection, {
|
|
2306
2428
|
label: catLabel("system"),
|
|
2307
|
-
text: system,
|
|
2429
|
+
text: content.system,
|
|
2308
2430
|
rich,
|
|
2309
2431
|
lines: lineLabel
|
|
2310
2432
|
}));
|
|
@@ -2318,8 +2440,17 @@ window.__ModuleLoader__.load({
|
|
|
2318
2440
|
show: t("tool.jsonToggle"),
|
|
2319
2441
|
hide: t("tool.jsonHide")
|
|
2320
2442
|
};
|
|
2443
|
+
const content = headerContent.get(view.header.seq);
|
|
2444
|
+
const contentByName = new Map(content?.tools.map((t) => [t.name, t]) ?? []);
|
|
2321
2445
|
const q = rowQuery.trim().toLowerCase();
|
|
2322
|
-
const shown = view.header.tools.filter((tool) =>
|
|
2446
|
+
const shown = view.header.tools.filter((tool) => {
|
|
2447
|
+
if (q === "") return true;
|
|
2448
|
+
if (tool.name.toLowerCase().includes(q)) return true;
|
|
2449
|
+
if ((tool.plugin ?? "").toLowerCase().includes(q)) return true;
|
|
2450
|
+
const row = contentByName.get(tool.name);
|
|
2451
|
+
if (row === void 0) return false;
|
|
2452
|
+
return (row.description ?? "").toLowerCase().includes(q) || schemaTextOf(row.schema).toLowerCase().includes(q);
|
|
2453
|
+
}).sort((a, b) => toolSort === "size" ? b.tokens - a.tokens : a.name < b.name ? -1 : 1);
|
|
2323
2454
|
const toolctl = /* @__PURE__ */ React.createElement(RowToolbar, {
|
|
2324
2455
|
value: rowQuery,
|
|
2325
2456
|
placeholder: t("tool.search"),
|
|
@@ -2334,18 +2465,23 @@ window.__ModuleLoader__.load({
|
|
|
2334
2465
|
}
|
|
2335
2466
|
}, t("tool.sort." + k))));
|
|
2336
2467
|
if (shown.length === 0) return /* @__PURE__ */ React.createElement("div", null, toolctl, /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, t("tool.noMatch")));
|
|
2468
|
+
const toolBody = (tool) => {
|
|
2469
|
+
if (content === void 0) return /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, headerNote);
|
|
2470
|
+
const row = contentByName.get(tool.name);
|
|
2471
|
+
return row === void 0 ? /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, t("browser.notInLog")) : /* @__PURE__ */ React.createElement(ToolSchema, {
|
|
2472
|
+
description: row.description,
|
|
2473
|
+
schema: row.schema,
|
|
2474
|
+
rich,
|
|
2475
|
+
lines: lineLabel,
|
|
2476
|
+
labels
|
|
2477
|
+
});
|
|
2478
|
+
};
|
|
2337
2479
|
return /* @__PURE__ */ React.createElement("div", null, toolctl, shown.map((tool) => {
|
|
2338
2480
|
const trailing = tool.plugin !== void 0 ? /* @__PURE__ */ React.createElement("span", {
|
|
2339
2481
|
className: "lc-br-tag lc-br-tool-plugin",
|
|
2340
2482
|
title: tool.plugin === "<unknown-plugin>" ? t("tool.unknownTitle") : t("tool.plugin")
|
|
2341
2483
|
}, tool.plugin === "<unknown-plugin>" ? t("tool.unknown") : tool.plugin) : null;
|
|
2342
|
-
return elemRow("tool:" + tool.name, null, tool.name, tool.tokens, void 0,
|
|
2343
|
-
description: tool.description,
|
|
2344
|
-
schema: tool.schema,
|
|
2345
|
-
rich,
|
|
2346
|
-
lines: lineLabel,
|
|
2347
|
-
labels
|
|
2348
|
-
}), false, trailing);
|
|
2484
|
+
return elemRow("tool:" + tool.name, null, tool.name, tool.tokens, void 0, toolBody(tool), false, trailing);
|
|
2349
2485
|
}));
|
|
2350
2486
|
}
|
|
2351
2487
|
const rows = (byCat[c] ?? []).slice().reverse().map((n) => {
|
|
@@ -2653,6 +2789,7 @@ window.__ModuleLoader__.load({
|
|
|
2653
2789
|
const convNodes = conversationNodesOf(props);
|
|
2654
2790
|
const [hoverCat, setHoverCat] = React.useState(null);
|
|
2655
2791
|
const fetchContent = React.useMemo(() => sessionId !== "" ? makeContentFetcher(ctx, sessionId) : void 0, [ctx, sessionId]);
|
|
2792
|
+
const fetchHeader = React.useMemo(() => sessionId !== "" ? makeHeaderFetcher(ctx, sessionId) : void 0, [ctx, sessionId]);
|
|
2656
2793
|
const close = React.useCallback(() => {
|
|
2657
2794
|
if (sessionId === "") return;
|
|
2658
2795
|
modalStoreOf(sessionId).set(false);
|
|
@@ -2702,6 +2839,7 @@ window.__ModuleLoader__.load({
|
|
|
2702
2839
|
headers,
|
|
2703
2840
|
convNodes,
|
|
2704
2841
|
fetchContent,
|
|
2842
|
+
fetchHeader,
|
|
2705
2843
|
hoverKey: hoverCat,
|
|
2706
2844
|
onHoverKey: setHoverCat
|
|
2707
2845
|
}))));
|
|
@@ -4462,11 +4600,15 @@ window.__ModuleLoader__.load({
|
|
|
4462
4600
|
});
|
|
4463
4601
|
acc += pct;
|
|
4464
4602
|
}
|
|
4603
|
+
const hovering = props.hoverKey !== null && props.hoverKey !== void 0 && arcs.some((a) => a.key === props.hoverKey);
|
|
4465
4604
|
return /* @__PURE__ */ React.createElement("div", {
|
|
4466
|
-
className: "lc-donut",
|
|
4605
|
+
className: "lc-donut" + (hovering ? " lc-donut-dim" : ""),
|
|
4467
4606
|
style: {
|
|
4468
4607
|
width: size,
|
|
4469
4608
|
height: size
|
|
4609
|
+
},
|
|
4610
|
+
onMouseLeave: () => {
|
|
4611
|
+
if (props.onHoverKey !== void 0) props.onHoverKey(null);
|
|
4470
4612
|
}
|
|
4471
4613
|
}, /* @__PURE__ */ React.createElement("svg", {
|
|
4472
4614
|
viewBox: "0 0 42 42",
|
|
@@ -4482,6 +4624,7 @@ window.__ModuleLoader__.load({
|
|
|
4482
4624
|
strokeWidth: "4"
|
|
4483
4625
|
}) : arcs.map((a) => /* @__PURE__ */ React.createElement("circle", {
|
|
4484
4626
|
key: a.key,
|
|
4627
|
+
className: "lc-donut-seg" + (props.hoverKey === a.key ? " lc-donut-seg-on" : ""),
|
|
4485
4628
|
cx: "21",
|
|
4486
4629
|
cy: "21",
|
|
4487
4630
|
r: "15.9155",
|
|
@@ -4489,7 +4632,10 @@ window.__ModuleLoader__.load({
|
|
|
4489
4632
|
stroke: a.color,
|
|
4490
4633
|
strokeWidth: "4",
|
|
4491
4634
|
strokeDasharray: `${a.pct} ${100 - a.pct}`,
|
|
4492
|
-
strokeDashoffset: a.offset
|
|
4635
|
+
strokeDashoffset: a.offset,
|
|
4636
|
+
onMouseEnter: () => {
|
|
4637
|
+
if (props.onHoverKey !== void 0) props.onHoverKey(a.key);
|
|
4638
|
+
}
|
|
4493
4639
|
}))), /* @__PURE__ */ React.createElement("div", { className: "lc-donut-center" }, /* @__PURE__ */ React.createElement("b", { style: { fontSize: Math.max(11, Math.round(size * .13)) } }, props.centerTop), props.centerSub !== void 0 ? /* @__PURE__ */ React.createElement("span", { style: { fontSize: Math.max(9, Math.round(size * .105)) } }, props.centerSub) : null));
|
|
4494
4640
|
};
|
|
4495
4641
|
}
|
|
@@ -4833,7 +4979,7 @@ window.__ModuleLoader__.load({
|
|
|
4833
4979
|
return function PluginInfo() {
|
|
4834
4980
|
const [latest, setLatest] = React.useState(null);
|
|
4835
4981
|
React.useEffect(() => {
|
|
4836
|
-
if ("0.
|
|
4982
|
+
if ("0.40.0".includes("-dev")) return;
|
|
4837
4983
|
let on = true;
|
|
4838
4984
|
fetchLatestVersion().then((v) => {
|
|
4839
4985
|
if (on && v) setLatest(v);
|
|
@@ -4842,8 +4988,8 @@ window.__ModuleLoader__.load({
|
|
|
4842
4988
|
on = false;
|
|
4843
4989
|
};
|
|
4844
4990
|
}, []);
|
|
4845
|
-
const update = latest !== null && isNewerVersion(latest, "0.
|
|
4846
|
-
const nameText = "dsh-context (v0.
|
|
4991
|
+
const update = latest !== null && isNewerVersion(latest, "0.40.0") ? latest : null;
|
|
4992
|
+
const nameText = "dsh-context (v0.40.0)";
|
|
4847
4993
|
const nameValue = [nameText];
|
|
4848
4994
|
if (update) nameValue.push(/* @__PURE__ */ React.createElement("span", {
|
|
4849
4995
|
key: "update",
|
|
@@ -5215,16 +5361,27 @@ window.__ModuleLoader__.load({
|
|
|
5215
5361
|
//#region src/client/components/sliceList.tsx
|
|
5216
5362
|
function makeSliceList(kit) {
|
|
5217
5363
|
return function SliceList(props) {
|
|
5218
|
-
return /* @__PURE__ */ React.createElement("div", {
|
|
5364
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
5365
|
+
className: "lc-sl",
|
|
5366
|
+
onMouseLeave: () => {
|
|
5367
|
+
if (props.onHoverKey !== void 0) props.onHoverKey(null);
|
|
5368
|
+
}
|
|
5369
|
+
}, props.rows.map((r) => /* @__PURE__ */ React.createElement("div", {
|
|
5219
5370
|
key: r.key,
|
|
5220
|
-
className: "lc-sl-row"
|
|
5221
|
-
|
|
5371
|
+
className: "lc-sl-row" + (r.dim ? " lc-sl-row-dim" : "") + (props.hoverKey !== void 0 && props.hoverKey === r.key ? " lc-sl-row-on" : ""),
|
|
5372
|
+
onMouseEnter: () => {
|
|
5373
|
+
if (props.onHoverKey !== void 0) props.onHoverKey(r.key);
|
|
5374
|
+
}
|
|
5375
|
+
}, /* @__PURE__ */ React.createElement("div", { className: "lc-sl-main" }, /* @__PURE__ */ React.createElement("i", {
|
|
5222
5376
|
className: "lc-sl-dot",
|
|
5223
5377
|
style: { background: r.color }
|
|
5224
|
-
}), /* @__PURE__ */ React.createElement("span", {
|
|
5225
|
-
className: "lc-sl-
|
|
5378
|
+
}), /* @__PURE__ */ React.createElement("span", {
|
|
5379
|
+
className: "lc-sl-label",
|
|
5380
|
+
title: r.label
|
|
5381
|
+
}, r.label), /* @__PURE__ */ React.createElement("span", { className: "lc-sl-pct" }, r.pct)), r.count !== "" ? /* @__PURE__ */ React.createElement("div", {
|
|
5382
|
+
className: "lc-sl-sub",
|
|
5226
5383
|
title: r.count
|
|
5227
|
-
}, r.count) : null
|
|
5384
|
+
}, r.count) : null)));
|
|
5228
5385
|
};
|
|
5229
5386
|
}
|
|
5230
5387
|
//#endregion
|
|
@@ -5234,6 +5391,7 @@ window.__ModuleLoader__.load({
|
|
|
5234
5391
|
const SliceList = makeSliceList(kit);
|
|
5235
5392
|
return function StatsTiming(props) {
|
|
5236
5393
|
const lang = props.locale === "zh" ? "zh" : "en";
|
|
5394
|
+
const [hoverKey, setHoverKey] = React.useState(null);
|
|
5237
5395
|
const timing = props.timing;
|
|
5238
5396
|
const wall = timing !== null && Number.isFinite(timing.wallMs) && timing.wallMs > 0 ? timing.wallMs : 0;
|
|
5239
5397
|
let segments = [];
|
|
@@ -5243,6 +5401,11 @@ window.__ModuleLoader__.load({
|
|
|
5243
5401
|
const toolRing = Math.max(0, Math.min(timing.toolsMs, wall - lm));
|
|
5244
5402
|
const other = Math.max(0, wall - lm - toolRing);
|
|
5245
5403
|
const share = (ms) => wall > 0 ? ms / wall : 0;
|
|
5404
|
+
const countOf = (ms, times) => {
|
|
5405
|
+
const dur = fmtDuration(ms, lang);
|
|
5406
|
+
if (times === void 0) return dur;
|
|
5407
|
+
return ms > 0 ? `${dur} · ${times}` : times;
|
|
5408
|
+
};
|
|
5246
5409
|
segments = [
|
|
5247
5410
|
{
|
|
5248
5411
|
key: "lm",
|
|
@@ -5264,23 +5427,26 @@ window.__ModuleLoader__.load({
|
|
|
5264
5427
|
{
|
|
5265
5428
|
key: "lm",
|
|
5266
5429
|
color: "#3b82f6",
|
|
5267
|
-
label:
|
|
5430
|
+
label: t("timing.lm"),
|
|
5431
|
+
dim: timing.lmMs === 0,
|
|
5268
5432
|
pct: fmtShare(timing.lmMs, wall),
|
|
5269
|
-
count:
|
|
5433
|
+
count: countOf(timing.lmMs, t("timing.lmTimes", { n: fmt(timing.calls) }))
|
|
5270
5434
|
},
|
|
5271
5435
|
{
|
|
5272
5436
|
key: "tools",
|
|
5273
5437
|
color: "#14b8a6",
|
|
5274
|
-
label:
|
|
5438
|
+
label: t("timing.tools"),
|
|
5439
|
+
dim: timing.toolsMs === 0,
|
|
5275
5440
|
pct: fmtShare(timing.toolsMs, wall),
|
|
5276
|
-
count:
|
|
5441
|
+
count: countOf(timing.toolsMs, t("timing.toolTimes", { n: fmt(timing.toolCalls) }))
|
|
5277
5442
|
},
|
|
5278
5443
|
{
|
|
5279
5444
|
key: "other",
|
|
5280
5445
|
color: "#94a3b8",
|
|
5281
5446
|
label: t("timing.other"),
|
|
5447
|
+
dim: other === 0,
|
|
5282
5448
|
pct: fmtShare(other, wall),
|
|
5283
|
-
count:
|
|
5449
|
+
count: countOf(other)
|
|
5284
5450
|
}
|
|
5285
5451
|
];
|
|
5286
5452
|
}
|
|
@@ -5288,8 +5454,14 @@ window.__ModuleLoader__.load({
|
|
|
5288
5454
|
segments,
|
|
5289
5455
|
size: 96,
|
|
5290
5456
|
centerTop: wall > 0 ? fmtDuration(wall, lang) : "—",
|
|
5291
|
-
centerSub: t("timing.total")
|
|
5292
|
-
|
|
5457
|
+
centerSub: t("timing.total"),
|
|
5458
|
+
hoverKey,
|
|
5459
|
+
onHoverKey: setHoverKey
|
|
5460
|
+
}), /* @__PURE__ */ React.createElement(SliceList, {
|
|
5461
|
+
rows,
|
|
5462
|
+
hoverKey,
|
|
5463
|
+
onHoverKey: setHoverKey
|
|
5464
|
+
})));
|
|
5293
5465
|
};
|
|
5294
5466
|
}
|
|
5295
5467
|
//#endregion
|
|
@@ -5298,6 +5470,7 @@ window.__ModuleLoader__.load({
|
|
|
5298
5470
|
const { t, fmt, fmtShare } = kit;
|
|
5299
5471
|
const SliceList = makeSliceList(kit);
|
|
5300
5472
|
return function StatsTokens(props) {
|
|
5473
|
+
const [hoverKey, setHoverKey] = React.useState(null);
|
|
5301
5474
|
const reads = props.usage !== null ? numOf(props.usage.cacheReadTokens) : 0;
|
|
5302
5475
|
const writes = props.usage !== null ? numOf(props.usage.cacheWriteTokens) : 0;
|
|
5303
5476
|
const uncached = props.usage !== null ? numOf(props.usage.uncachedInputTokens) : 0;
|
|
@@ -5319,7 +5492,7 @@ window.__ModuleLoader__.load({
|
|
|
5319
5492
|
},
|
|
5320
5493
|
{
|
|
5321
5494
|
key: "uncached",
|
|
5322
|
-
color: "#
|
|
5495
|
+
color: "#a855f7",
|
|
5323
5496
|
label: t("tokens.uncached"),
|
|
5324
5497
|
value: uncached
|
|
5325
5498
|
},
|
|
@@ -5327,6 +5500,7 @@ window.__ModuleLoader__.load({
|
|
|
5327
5500
|
key: "output",
|
|
5328
5501
|
color: "#3b82f6",
|
|
5329
5502
|
label: t("tokens.output"),
|
|
5503
|
+
note: t("tokens.outputNote"),
|
|
5330
5504
|
value: output
|
|
5331
5505
|
}
|
|
5332
5506
|
];
|
|
@@ -5336,7 +5510,7 @@ window.__ModuleLoader__.load({
|
|
|
5336
5510
|
color: b.color,
|
|
5337
5511
|
label: b.label,
|
|
5338
5512
|
pct: fmtShare(b.value, billed),
|
|
5339
|
-
count: fmt(b.value)
|
|
5513
|
+
count: b.note === void 0 ? fmt(b.value) : `${fmt(b.value)} · ${b.note}`
|
|
5340
5514
|
}));
|
|
5341
5515
|
return /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col-stats lc-col-donut" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, /* @__PURE__ */ React.createElement("span", { className: "lc-card-title-text" }, t("tokens.title")), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("tokens.hint"))), /* @__PURE__ */ React.createElement("div", { className: "lc-donut-row" }, /* @__PURE__ */ React.createElement(Donut, {
|
|
5342
5516
|
segments: shown.map((b) => ({
|
|
@@ -5346,8 +5520,14 @@ window.__ModuleLoader__.load({
|
|
|
5346
5520
|
})),
|
|
5347
5521
|
size: 96,
|
|
5348
5522
|
centerTop: hit === null ? "—" : `${hit}%`,
|
|
5349
|
-
centerSub: t("tokens.cacheHit")
|
|
5350
|
-
|
|
5523
|
+
centerSub: t("tokens.cacheHit"),
|
|
5524
|
+
hoverKey,
|
|
5525
|
+
onHoverKey: setHoverKey
|
|
5526
|
+
}), /* @__PURE__ */ React.createElement(SliceList, {
|
|
5527
|
+
rows,
|
|
5528
|
+
hoverKey,
|
|
5529
|
+
onHoverKey: setHoverKey
|
|
5530
|
+
})));
|
|
5351
5531
|
};
|
|
5352
5532
|
}
|
|
5353
5533
|
//#endregion
|
|
@@ -5822,6 +6002,7 @@ window.__ModuleLoader__.load({
|
|
|
5822
6002
|
}, []);
|
|
5823
6003
|
const loadImage = React.useMemo(() => imageLoaderOf(ctx, typeof sessionId === "string" ? sessionId : void 0), [ctx, sessionId]);
|
|
5824
6004
|
const fetchContent = React.useMemo(() => typeof sessionId === "string" && sessionId !== "" ? makeContentFetcher(ctx, sessionId) : void 0, [ctx, sessionId]);
|
|
6005
|
+
const fetchHeader = React.useMemo(() => typeof sessionId === "string" && sessionId !== "" ? makeHeaderFetcher(ctx, sessionId) : void 0, [ctx, sessionId]);
|
|
5825
6006
|
const rootRef = React.useRef(null);
|
|
5826
6007
|
const scrollerRef = React.useRef(null);
|
|
5827
6008
|
const restoredRef = React.useRef(null);
|
|
@@ -6041,6 +6222,7 @@ window.__ModuleLoader__.load({
|
|
|
6041
6222
|
headers,
|
|
6042
6223
|
convNodes,
|
|
6043
6224
|
fetchContent,
|
|
6225
|
+
fetchHeader,
|
|
6044
6226
|
previewSeq: hoveredSeq,
|
|
6045
6227
|
pinSeq: pinnedReq !== null ? pinnedReq.seq : null,
|
|
6046
6228
|
hoverKey: hoverCat,
|
|
@@ -6180,7 +6362,7 @@ window.__ModuleLoader__.load({
|
|
|
6180
6362
|
}
|
|
6181
6363
|
//#endregion
|
|
6182
6364
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/stats.css.mjs
|
|
6183
|
-
const css$12 = ".lc-stats{grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;display:grid}.lc-stat{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;flex-direction:column;gap:2px;min-width:0;padding:6px;display:flex}.lc-stats .lc-stat{padding:6px 3px}.lc-stats .lc-stat-q{margin:0;position:absolute;top:3px;right:4px}.lc-stat-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;font-weight:600;overflow:hidden}.lc-stat-value{color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;text-align:center;font-size:14px;font-weight:600;overflow:hidden}.lc-stat-sub{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.lc-stat-tipped{position:relative}.lc-stat-q{text-align:center;width:11px;height:11px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);cursor:help;border-radius:50%;margin-left:4px;font-size:9px;font-style:normal;font-weight:700;line-height:11px;display:inline-block}.lc-stat-tipped:hover .lc-stat-q{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary)}.lc-stat-tip{max-width:280px;font-weight:400;line-height:1.5;top:calc(100% + 6px);left:0}.lc-stat-tipped:hover .lc-stat-tip{opacity:1}.lc-stat-tip-prices{border-top:1px dashed var(--dsw-alias-border-l1);margin-top:5px;padding-top:5px;display:block}.lc-stat-tip-head{font-weight:600;display:block}.lc-stat-tip-row{margin-top:2px;display:block}.lc-stat-tip-model{color:var(--dsw-alias-label-primary)}.lc-card-sub{color:var(--dsw-alias-label-secondary);margin-left:auto;font-size:12px;font-weight:400}.lc-overview-num{align-items:baseline;gap:6px;margin-bottom:8px;display:flex}.lc-overview-num>b{font-size:20px}.lc-overview-num span{color:var(--dsw-alias-label-secondary)}.lc-overview-pct{margin-left:auto;font-size:11px}.lc-overview-pct b{color:var(--dsw-alias-label-primary);margin-right:4px;font-size:20px}.lc-stat-head{color:var(--dsw-alias-label-secondary);margin:12px 0 8px;font-size:11px;font-weight:600}.lc-donut-row{justify-content:flex-start;align-items:center;gap:12px;min-width:0;display:flex}.lc-col-donut{flex-direction:column;display:flex}.lc-col-donut .lc-donut-row{flex:1}.lc-donut-row .lc-sl{flex:auto}.lc-donut{flex:none;position:relative}.lc-donut svg{display:block}.lc-donut-track{stroke:#8080802e}.lc-donut-center{pointer-events:none;text-align:center;box-sizing:border-box;flex-direction:column;justify-content:center;align-items:center;gap:1px;padding:0 7px;display:flex;position:absolute;inset:0}.lc-donut-center b{white-space:nowrap;text-overflow:ellipsis;max-width:100%;line-height:1.15;overflow:hidden}.lc-donut-center span{color:var(--dsw-alias-label-secondary);white-space:nowrap}.lc-sl{flex-direction:column;gap:
|
|
6365
|
+
const css$12 = ".lc-stats{grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;display:grid}.lc-stat{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;flex-direction:column;gap:2px;min-width:0;padding:6px;display:flex}.lc-stats .lc-stat{padding:6px 3px}.lc-stats .lc-stat-q{margin:0;position:absolute;top:3px;right:4px}.lc-stat-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;font-weight:600;overflow:hidden}.lc-stat-value{color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;text-align:center;font-size:14px;font-weight:600;overflow:hidden}.lc-stat-sub{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.lc-stat-tipped{position:relative}.lc-stat-q{text-align:center;width:11px;height:11px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);cursor:help;border-radius:50%;margin-left:4px;font-size:9px;font-style:normal;font-weight:700;line-height:11px;display:inline-block}.lc-stat-tipped:hover .lc-stat-q{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary)}.lc-stat-tip{max-width:280px;font-weight:400;line-height:1.5;top:calc(100% + 6px);left:0}.lc-stat-tipped:hover .lc-stat-tip{opacity:1}.lc-stat-tip-prices{border-top:1px dashed var(--dsw-alias-border-l1);margin-top:5px;padding-top:5px;display:block}.lc-stat-tip-head{font-weight:600;display:block}.lc-stat-tip-row{margin-top:2px;display:block}.lc-stat-tip-model{color:var(--dsw-alias-label-primary)}.lc-card-sub{color:var(--dsw-alias-label-secondary);margin-left:auto;font-size:12px;font-weight:400}.lc-overview-num{align-items:baseline;gap:6px;margin-bottom:8px;display:flex}.lc-overview-num>b{font-size:20px}.lc-overview-num span{color:var(--dsw-alias-label-secondary)}.lc-overview-pct{margin-left:auto;font-size:11px}.lc-overview-pct b{color:var(--dsw-alias-label-primary);margin-right:4px;font-size:20px}.lc-stat-head{color:var(--dsw-alias-label-secondary);margin:12px 0 8px;font-size:11px;font-weight:600}.lc-donut-row{justify-content:flex-start;align-items:center;gap:12px;min-width:0;display:flex}.lc-col-donut{flex-direction:column;display:flex}.lc-col-donut .lc-donut-row{flex:1}.lc-donut-row .lc-sl{flex:auto}.lc-donut{flex:none;position:relative}.lc-donut svg{display:block}.lc-donut-track{stroke:#8080802e}.lc-donut-seg{transition:opacity .12s}.lc-donut-dim .lc-donut-seg{opacity:.35}.lc-donut-dim .lc-donut-seg-on{opacity:1}.lc-donut-center{pointer-events:none;text-align:center;box-sizing:border-box;flex-direction:column;justify-content:center;align-items:center;gap:1px;padding:0 7px;display:flex;position:absolute;inset:0}.lc-donut-center b{white-space:nowrap;text-overflow:ellipsis;max-width:100%;line-height:1.15;overflow:hidden}.lc-donut-center span{color:var(--dsw-alias-label-secondary);white-space:nowrap}.lc-sl{flex-direction:column;gap:6px;min-width:0;display:flex;overflow:hidden}.lc-sl-row{border-radius:6px;flex-direction:column;gap:1px;min-width:0;margin:0 -6px;padding:1px 6px;font-size:12px;transition:background-color .12s;display:flex}.lc-sl-row-on{background:var(--dsw-alias-interactive-bg-hover)}.lc-sl-row-dim{opacity:.55}.lc-sl-main{align-items:center;gap:6px;min-width:0;display:flex}.lc-sl-dot{border-radius:2px;flex:none;width:8px;height:8px}.lc-sl-label{white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;font-weight:600;line-height:1.25;overflow:hidden}.lc-sl-pct{text-align:right;font-variant-numeric:tabular-nums;flex:none;min-width:34px;font-weight:700}.lc-sl-sub{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;text-overflow:ellipsis;margin-left:14px;font-size:11px;line-height:1.3;overflow:hidden}.lc-pi-grid{grid-template-columns:1fr;gap:8px;display:grid}.lc-pi-row-btn{appearance:none;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;width:100%;padding:0}.lc-pi-row{min-width:0;color:inherit;flex-direction:row;justify-content:space-between;align-items:baseline;gap:12px;text-decoration:none;display:flex}.lc-pi-row:hover .lc-pi-value{text-decoration:underline}.lc-pi-hint{text-decoration:none}.lc-pi-hint:hover{text-decoration:underline}.lc-pi-update{color:var(--dsw-alias-state-warn-primary);white-space:nowrap;margin-left:6px;font-size:11px}.lc-pi-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;flex:none;font-size:11px;font-weight:600;overflow:hidden}.lc-pi-value{min-width:0;color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;text-align:right;font-size:13px;font-weight:600;overflow:hidden}.lc-pi-row-btn .lc-pi-value{font-weight:400}@container lc-head-card (width<=320px){.lc-donut-row{gap:8px}.lc-stats{grid-template-columns:repeat(4,minmax(0,1fr))}}@container lc-head-card (width<=240px){.lc-donut-row{flex-wrap:wrap}.lc-donut{margin:0 auto}.lc-donut-row .lc-sl{flex-basis:100%}.lc-stats{grid-template-columns:repeat(2,minmax(0,1fr))}}";
|
|
6184
6366
|
const tagId$12 = "dsh-context/stats.css";
|
|
6185
6367
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$12) + "]") === null) {
|
|
6186
6368
|
const tag = document.createElement("style");
|
package/lib/index.d.ts
CHANGED
|
@@ -30,8 +30,27 @@ declare const Config: z.ZodPreprocess<z.ZodObject<{
|
|
|
30
30
|
}, z.core.$strict>>;
|
|
31
31
|
//#endregion
|
|
32
32
|
//#region src/host/headers.d.ts
|
|
33
|
+
/**
|
|
34
|
+
* One stored tool: the v1 row shape carried the producer description and the
|
|
35
|
+
* raw schema; folds since the #37 slim-down append metadata-only entries.
|
|
36
|
+
*/
|
|
37
|
+
interface StoredHeaderTool {
|
|
38
|
+
name: string;
|
|
39
|
+
tokens: number;
|
|
40
|
+
description?: string;
|
|
41
|
+
plugin?: string;
|
|
42
|
+
schema?: unknown;
|
|
43
|
+
}
|
|
44
|
+
/** One stored epoch: v1 rows carried `system`; folds since carry `systemTokens`. */
|
|
45
|
+
interface StoredHeaderRecord {
|
|
46
|
+
seq: number;
|
|
47
|
+
time: number;
|
|
48
|
+
system?: string;
|
|
49
|
+
systemTokens?: number;
|
|
50
|
+
tools: StoredHeaderTool[];
|
|
51
|
+
}
|
|
33
52
|
interface HeadersState {
|
|
34
|
-
headers:
|
|
53
|
+
headers: StoredHeaderRecord[];
|
|
35
54
|
}
|
|
36
55
|
//#endregion
|
|
37
56
|
//#region src/host/fold.d.ts
|
|
@@ -382,12 +401,10 @@ interface ContextEventRecord {
|
|
|
382
401
|
turn?: number;
|
|
383
402
|
step?: number;
|
|
384
403
|
}
|
|
385
|
-
/** One tool
|
|
404
|
+
/** One tool of a request-header epoch, with its display price. */
|
|
386
405
|
interface HeaderTool {
|
|
387
406
|
name: string;
|
|
388
407
|
tokens: number;
|
|
389
|
-
/** Producer-declared description (may be long; the browser truncates). */
|
|
390
|
-
description?: string;
|
|
391
408
|
/**
|
|
392
409
|
* The registering plugin's label, when attribution is known: either a
|
|
393
410
|
* `plugin` field carried by the raw header entry (harness-provided) or the
|
|
@@ -397,16 +414,21 @@ interface HeaderTool {
|
|
|
397
414
|
* the browser shows no tag.
|
|
398
415
|
*/
|
|
399
416
|
plugin?: string;
|
|
400
|
-
/** The raw JSON schema object the model received (plain JSON). */
|
|
401
|
-
schema?: unknown;
|
|
402
417
|
}
|
|
403
418
|
/**
|
|
404
|
-
* One request-header epoch: the
|
|
419
|
+
* One request-header epoch's METADATA: the epoch boundaries and token prices
|
|
420
|
+
* in force from this event's seq until the next epoch. The epoch CONTENT
|
|
421
|
+
* (full system prompt text, tool descriptions/schemas) is not projected —
|
|
422
|
+
* every session.list row, control baseline, push frame, and projection-cache
|
|
423
|
+
* checkpoint would otherwise carry it per session × epoch. The client
|
|
424
|
+
* fetches one epoch's content on demand (a seq-anchored history read off
|
|
425
|
+
* `seq`) as a {@link HeaderEpochContent}.
|
|
405
426
|
*/
|
|
406
427
|
interface HeaderRecord {
|
|
407
428
|
seq: number;
|
|
408
429
|
time: number;
|
|
409
|
-
system
|
|
430
|
+
/** The epoch's estimated system-prompt tokens; absent when it logged no system prompt. */
|
|
431
|
+
systemTokens?: number;
|
|
410
432
|
tools: HeaderTool[];
|
|
411
433
|
}
|
|
412
434
|
/** The `contextHeaders` projection value: the bounded epoch list (newest last). */
|
package/lib/index.js
CHANGED
|
@@ -549,42 +549,72 @@ function isInjection(source) {
|
|
|
549
549
|
//#endregion
|
|
550
550
|
//#region src/host/headers.ts
|
|
551
551
|
/**
|
|
552
|
-
* The `contextHeaders` session projection unit — the request-header
|
|
553
|
-
*
|
|
552
|
+
* The `contextHeaders` session projection unit — the request-header EPOCH
|
|
553
|
+
* METADATA behind the timeline's envelope figures.
|
|
554
554
|
*
|
|
555
555
|
* The hot `contextTimeline` unit carries only token prices of the system
|
|
556
|
-
* prompt and tool schemas; this companion unit keeps the
|
|
557
|
-
*
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
*
|
|
562
|
-
*
|
|
556
|
+
* prompt and tool schemas; this companion unit keeps the per-epoch METADATA
|
|
557
|
+
* (epoch seq/time boundaries, per-tool token prices and plugin attribution)
|
|
558
|
+
* so the Context browser can pick the header epoch in force at any step and
|
|
559
|
+
* size its sections immediately. The epoch CONTENT (full system prompt text,
|
|
560
|
+
* full tool JSON schemas) deliberately does NOT ride the projection VALUE:
|
|
561
|
+
* session projections are served whole in every `session.list` row, control
|
|
562
|
+
* baseline, push frame, and change notification, so carrying content here
|
|
563
|
+
* multiplied it by sessions × epochs across every channel. The client
|
|
564
|
+
* fetches one epoch's `request/header` event on demand — a seq-anchored
|
|
565
|
+
* history read off the epoch's `seq`, the same targeted read the browser
|
|
566
|
+
* already uses for message content — and caches it per session (history is
|
|
567
|
+
* immutable).
|
|
568
|
+
*
|
|
569
|
+
* Read-compat over the persisted state (the pinned decision behind keeping
|
|
570
|
+
* `stateVersion` at 1): the harness serves a cold session's projections from
|
|
571
|
+
* its CACHED checkpoint rows and has no refresh channel for an idle session
|
|
572
|
+
* — a version bump invalidates every row and orphans the key until the
|
|
573
|
+
* session goes live again (the #37 regression). The state therefore still
|
|
574
|
+
* ACCEPTS the v1 content-bearing record shape, current folds append
|
|
575
|
+
* metadata-only records alongside any seeded legacy ones, and the view
|
|
576
|
+
* normalizes BOTH to the metadata-only wire shape (pricing the legacy system
|
|
577
|
+
* text at read time). Cached v1 rows keep working, new checkpoint writes
|
|
578
|
+
* shrink as legacy epochs age out of the capped list, and the wire — the
|
|
579
|
+
* part every delivery channel carries — is metadata-only from day one.
|
|
563
580
|
*
|
|
564
581
|
* Same projection contract as the timeline unit: pure init/apply/view,
|
|
565
582
|
* `Object.is` reference stability for uninteresting events, plain-JSON
|
|
566
583
|
* bounded state (epoch list capped — see HEADERS_MAX).
|
|
567
584
|
*/
|
|
568
|
-
/** Retention cap on header epochs (changes are rare; 50 is generous). */
|
|
585
|
+
/** Retention cap on header epochs (metadata only; changes are rare; 50 is generous). */
|
|
569
586
|
const HEADERS_MAX = 50;
|
|
570
|
-
|
|
587
|
+
/**
|
|
588
|
+
* The persisted-state schema: the SUPERSET of both record generations, so a
|
|
589
|
+
* cached v1 row (content-bearing) seeds the fold instead of being discarded.
|
|
590
|
+
*/
|
|
591
|
+
const storedToolSchema = z.object({
|
|
571
592
|
name: z.string(),
|
|
572
593
|
tokens: z.number().int().nonnegative(),
|
|
573
594
|
description: z.string().optional(),
|
|
574
595
|
plugin: z.string().optional(),
|
|
575
596
|
schema: z.unknown().optional()
|
|
576
597
|
}).strict();
|
|
577
|
-
const
|
|
598
|
+
const storedEpochSchema = z.object({
|
|
578
599
|
seq: z.number(),
|
|
579
600
|
time: z.number(),
|
|
580
601
|
system: z.string().optional(),
|
|
581
|
-
|
|
602
|
+
systemTokens: z.number().int().nonnegative().optional(),
|
|
603
|
+
tools: z.array(storedToolSchema)
|
|
604
|
+
}).strict();
|
|
605
|
+
const contextHeadersStateSchema = z.object({ headers: z.array(storedEpochSchema) }).strict();
|
|
606
|
+
/** The wire schema: strict metadata — the shape every delivery channel carries. */
|
|
607
|
+
const headerToolWireSchema = z.object({
|
|
608
|
+
name: z.string(),
|
|
609
|
+
tokens: z.number().int().nonnegative(),
|
|
610
|
+
plugin: z.string().optional()
|
|
611
|
+
}).strict();
|
|
612
|
+
const contextHeadersSchema = z.object({ headers: z.array(z.object({
|
|
613
|
+
seq: z.number(),
|
|
614
|
+
time: z.number(),
|
|
615
|
+
systemTokens: z.number().int().nonnegative().optional(),
|
|
616
|
+
tools: z.array(headerToolWireSchema)
|
|
582
617
|
}).strict()) }).strict();
|
|
583
|
-
/**
|
|
584
|
-
* State and wire are the same shape (the view only shallow-copies each record), so one schema validates both under the dsh 0.1.1-rc.1+
|
|
585
|
-
* `stateSchema`/`wire` contract.
|
|
586
|
-
*/
|
|
587
|
-
const contextHeadersStateSchema = contextHeadersSchema;
|
|
588
618
|
function recordOf(event) {
|
|
589
619
|
if (event.type !== "request/header") return null;
|
|
590
620
|
const rawHeader = event.data.header;
|
|
@@ -598,40 +628,43 @@ function recordOf(event) {
|
|
|
598
628
|
const tool = t !== null && typeof t === "object" ? t : {};
|
|
599
629
|
const entry = {
|
|
600
630
|
name: typeof tool.name === "string" ? tool.name : "?",
|
|
601
|
-
tokens: estimateToolSchema(t)
|
|
602
|
-
schema: t
|
|
631
|
+
tokens: estimateToolSchema(t)
|
|
603
632
|
};
|
|
604
|
-
if (typeof tool.description === "string" && tool.description !== "") entry.description = tool.description;
|
|
605
633
|
if (typeof tool.plugin === "string" && tool.plugin !== "") entry.plugin = tool.plugin;
|
|
606
634
|
return entry;
|
|
607
635
|
})
|
|
608
636
|
};
|
|
609
|
-
if (typeof header.system === "string" && header.system.length > 0) record.
|
|
637
|
+
if (typeof header.system === "string" && header.system.length > 0) record.systemTokens = estimateSystem(header.system);
|
|
610
638
|
return record;
|
|
611
639
|
}
|
|
612
640
|
/**
|
|
613
641
|
* The context-headers projection unit; registered alongside the timeline unit (host/index.ts); clients read it through
|
|
614
|
-
* `useProjection('contextHeaders')` and
|
|
615
|
-
* compat.ts).
|
|
642
|
+
* `useProjection('contextHeaders')` and fetch an epoch's full content on demand via the session history (historyPage.ts).
|
|
643
|
+
* Contract mirror with a REQUIRED `wire` block (see compat.ts).
|
|
616
644
|
* @param resolve - best-effort tool-to-plugin attribution (see toolSources.ts); fills a missing `plugin` at view time so
|
|
617
645
|
* epochs folded without attribution still render a tag when the source is known.
|
|
618
646
|
*/
|
|
619
647
|
function createContextHeadersDefinition(resolve) {
|
|
620
|
-
const view = (state) => ({ headers: state.headers.map((h) =>
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
648
|
+
const view = (state) => ({ headers: state.headers.map((h) => {
|
|
649
|
+
const record = {
|
|
650
|
+
seq: h.seq,
|
|
651
|
+
time: h.time,
|
|
652
|
+
tools: h.tools.map((t) => {
|
|
653
|
+
const entry = {
|
|
654
|
+
name: t.name,
|
|
655
|
+
tokens: t.tokens
|
|
656
|
+
};
|
|
657
|
+
const plugin = t.plugin ?? (resolve !== void 0 ? resolve(t.name) : void 0);
|
|
658
|
+
if (plugin !== void 0) entry.plugin = plugin;
|
|
659
|
+
return entry;
|
|
660
|
+
})
|
|
661
|
+
};
|
|
662
|
+
const systemTokens = h.systemTokens ?? (typeof h.system === "string" && h.system !== "" ? estimateSystem(h.system) : void 0);
|
|
663
|
+
if (systemTokens !== void 0) record.systemTokens = systemTokens;
|
|
664
|
+
return record;
|
|
665
|
+
}) });
|
|
631
666
|
return {
|
|
632
667
|
key: "contextHeaders",
|
|
633
|
-
schema: contextHeadersSchema,
|
|
634
|
-
view,
|
|
635
668
|
stateSchema: contextHeadersStateSchema,
|
|
636
669
|
wire: {
|
|
637
670
|
viewSchema: contextHeadersSchema,
|
|
@@ -1432,23 +1465,20 @@ const timelineStateSchema = z.object({
|
|
|
1432
1465
|
* or fold semantics change (invalidation of cached rows); config-only
|
|
1433
1466
|
* changes never require it (bounds tune retention, not state shape).
|
|
1434
1467
|
*
|
|
1435
|
-
* The definition carries
|
|
1436
|
-
* `
|
|
1437
|
-
*
|
|
1438
|
-
*
|
|
1439
|
-
* `
|
|
1440
|
-
*
|
|
1441
|
-
*
|
|
1442
|
-
*
|
|
1443
|
-
* tab would stay on its loading screen forever).
|
|
1468
|
+
* The definition carries the session-projection contract served by every
|
|
1469
|
+
* supported harness (see compat.ts): `stateSchema` + a REQUIRED `wire` block.
|
|
1470
|
+
* (The return type is the mirrored contract, not the installed dts
|
|
1471
|
+
* `ProjectionDefinition`: the registry's wired-register overload demands
|
|
1472
|
+
* `wire` PRESENT, which the dts's optional `wire?` fails.) Without the
|
|
1473
|
+
* `wire` block the registry treats the unit as host-only and never delivers
|
|
1474
|
+
* `contextTimeline` to the browser (the Context tab would stay on its
|
|
1475
|
+
* loading screen forever).
|
|
1444
1476
|
*/
|
|
1445
1477
|
function createContextTimelineDefinition(config) {
|
|
1446
1478
|
const bounds = resolveBounds(config);
|
|
1447
1479
|
const view = (state) => buildTimelineView(state, bounds);
|
|
1448
1480
|
return {
|
|
1449
1481
|
key: "contextTimeline",
|
|
1450
|
-
schema: contextTimelineSchema,
|
|
1451
|
-
view,
|
|
1452
1482
|
stateSchema: timelineStateSchema,
|
|
1453
1483
|
wire: {
|
|
1454
1484
|
viewSchema: contextTimelineSchema,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-context",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
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": {
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
"register": "bash scripts/register.sh",
|
|
39
39
|
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.tests.json",
|
|
40
40
|
"test": "pnpm run typecheck && vitest run --coverage",
|
|
41
|
-
"test:bundle": "node scripts/bundle-smoke.mjs",
|
|
42
41
|
"coverage": "vitest run --coverage",
|
|
43
42
|
"release": "bash scripts/publish.sh",
|
|
44
43
|
"hooks": "bash scripts/install-hooks.sh",
|
|
@@ -73,9 +72,9 @@
|
|
|
73
72
|
},
|
|
74
73
|
"peerDependencies": {
|
|
75
74
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
76
|
-
"@deepseek-ai/dsh-client-ui-primitives": ">=0.1.
|
|
77
|
-
"@deepseek-ai/dsh-session": ">=0.1.
|
|
78
|
-
"@deepseek-ai/dsh-settings": ">=0.1.
|
|
75
|
+
"@deepseek-ai/dsh-client-ui-primitives": ">=0.1.1-rc.2",
|
|
76
|
+
"@deepseek-ai/dsh-session": ">=0.1.1-rc.2",
|
|
77
|
+
"@deepseek-ai/dsh-settings": ">=0.1.1-rc.2",
|
|
79
78
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
80
79
|
"react": "^18.3.1"
|
|
81
80
|
},
|
|
@@ -89,12 +88,11 @@
|
|
|
89
88
|
},
|
|
90
89
|
"devDependencies": {
|
|
91
90
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
92
|
-
"@deepseek-ai/dsh-client-ui-primitives": "
|
|
93
|
-
"@deepseek-ai/dsh-session": "
|
|
94
|
-
"@deepseek-ai/dsh-session-projection": "
|
|
95
|
-
"@deepseek-ai/dsh-settings": "
|
|
91
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.2-alpha.2",
|
|
92
|
+
"@deepseek-ai/dsh-session": "0.1.2-alpha.2",
|
|
93
|
+
"@deepseek-ai/dsh-session-projection": "0.1.2-alpha.2",
|
|
94
|
+
"@deepseek-ai/dsh-settings": "0.1.2-alpha.2",
|
|
96
95
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
97
|
-
"zod": "^4.4.3",
|
|
98
96
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
99
97
|
"@types/node": "^26.2.0",
|
|
100
98
|
"@types/react": "^18.3.31",
|
|
@@ -110,7 +108,8 @@
|
|
|
110
108
|
"react-dom": "^18.3.1",
|
|
111
109
|
"tsdown": "^0.22.14",
|
|
112
110
|
"typescript": "^7.0.2",
|
|
113
|
-
"vitest": "^4.1.11"
|
|
111
|
+
"vitest": "^4.1.11",
|
|
112
|
+
"zod": "^4.4.3"
|
|
114
113
|
},
|
|
115
114
|
"packageManager": "pnpm@11.9.0"
|
|
116
115
|
}
|