dsh-context 0.46.1 → 0.48.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 +2 -1
- package/lib/client.js +549 -295
- package/lib/index.d.ts +87 -4
- package/lib/index.js +350 -35
- package/package.json +6 -3
package/lib/client.js
CHANGED
|
@@ -31,15 +31,18 @@ window.__ModuleLoader__.load({
|
|
|
31
31
|
"stats.toolCalls": "工具调用",
|
|
32
32
|
"stats.images": "图片",
|
|
33
33
|
"stats.cost": "预估费用",
|
|
34
|
-
"stats.costTip": "按 DeepSeek 官方刊例价估算整个会话的累计费用:输入区分缓存命中/未命中,输出含思考;按请求时间区分高峰(北京时间工作日 9:00–12:00、14:00–18:00)与空闲时段(半价,周末全天均为空闲时段)。适用于 deepseek-v4-flash / deepseek-v4-pro(不限 provider
|
|
34
|
+
"stats.costTip": "按 DeepSeek 官方刊例价估算整个会话的累计费用:输入区分缓存命中/未命中,输出含思考;按请求时间区分高峰(北京时间工作日 9:00–12:00、14:00–18:00)与空闲时段(半价,周末全天均为空闲时段)。适用于 deepseek-v4.1-flash / deepseek-v4-pro(不限 provider;V4.1 Pro 上线前,V4 Pro 请求将被路由并按 V4.1 Flash 单价计费),价格写死在代码中,仅供参考。",
|
|
35
35
|
"stats.costPriceHead": "每百万 tokens 价格(高峰 | 空闲半价):",
|
|
36
36
|
"stats.costHit": "命中",
|
|
37
37
|
"stats.costMiss": "未命中",
|
|
38
38
|
"stats.costOut": "输出",
|
|
39
39
|
"timing.title": "耗时统计",
|
|
40
|
-
"timing.total": "
|
|
40
|
+
"timing.total": "活跃时长",
|
|
41
41
|
"timing.ttft": "模型等待",
|
|
42
42
|
"timing.gen": "模型生成",
|
|
43
|
+
"timing.reasoning": "模型思考",
|
|
44
|
+
"timing.text": "正文输出",
|
|
45
|
+
"timing.toolArgs": "工具参数",
|
|
43
46
|
"timing.tools": "工具执行",
|
|
44
47
|
"timing.other": "其他开销",
|
|
45
48
|
"timing.callTimes": "{n}次",
|
|
@@ -317,7 +320,7 @@ window.__ModuleLoader__.load({
|
|
|
317
320
|
"stats.toolCalls": "Tool Calls",
|
|
318
321
|
"stats.images": "Images",
|
|
319
322
|
"stats.cost": "Cost",
|
|
320
|
-
"stats.costTip": "Rough cumulative cost of the whole session at DeepSeek’s list prices: input split by cache hit/miss, output includes reasoning; each request is priced at the peak (Beijing Time weekdays 09:00–12:00, 14:00–18:00) or half-price off-peak rate by its time — weekends bill at off-peak all day. Applies to deepseek-v4-flash / deepseek-v4-pro on any provider; prices are hardcoded, for reference only.",
|
|
323
|
+
"stats.costTip": "Rough cumulative cost of the whole session at DeepSeek’s list prices: input split by cache hit/miss, output includes reasoning; each request is priced at the peak (Beijing Time weekdays 09:00–12:00, 14:00–18:00) or half-price off-peak rate by its time — weekends bill at off-peak all day. Applies to deepseek-v4.1-flash / deepseek-v4-pro on any provider (until V4.1 Pro ships, Pro requests are routed to and billed at V4.1 Flash rates); prices are hardcoded, for reference only.",
|
|
321
324
|
"stats.costPriceHead": "Per-1M-token rates (peak | off-peak at half price):",
|
|
322
325
|
"stats.costHit": "hit",
|
|
323
326
|
"stats.costMiss": "miss",
|
|
@@ -326,6 +329,9 @@ window.__ModuleLoader__.load({
|
|
|
326
329
|
"timing.total": "Active Time",
|
|
327
330
|
"timing.ttft": "TTFT",
|
|
328
331
|
"timing.gen": "LLM Gen",
|
|
332
|
+
"timing.reasoning": "Thinking",
|
|
333
|
+
"timing.text": "Answer",
|
|
334
|
+
"timing.toolArgs": "Tool args",
|
|
329
335
|
"timing.tools": "Tool runs",
|
|
330
336
|
"timing.other": "Overhead",
|
|
331
337
|
"timing.callTimes": "{n} calls",
|
|
@@ -954,7 +960,7 @@ window.__ModuleLoader__.load({
|
|
|
954
960
|
"assistant",
|
|
955
961
|
"tool",
|
|
956
962
|
"total"
|
|
957
|
-
].every((k) => typeof current[k] === "number") && recordsOnly(data.requests) && recordsOnly(data.events) && recordsOnly(data.nodes) && recordsOnly(data.archive) && timingFastOk(data.timing)) return data;
|
|
963
|
+
].every((k) => typeof current[k] === "number") && recordsOnly(data.requests) && recordsOnly(data.events) && recordsOnly(data.nodes) && recordsOnly(data.archive) && systemsFastOk(data.systems) && timingFastOk(data.timing)) return data;
|
|
958
964
|
const safeCurrent = current !== null && typeof current === "object" ? current : {};
|
|
959
965
|
const cost = typeof data.cost === "object" && data.cost !== null && !Array.isArray(data.cost) ? data.cost : void 0;
|
|
960
966
|
const timing = timingOf(data.timing);
|
|
@@ -988,6 +994,7 @@ window.__ModuleLoader__.load({
|
|
|
988
994
|
...typeof data.detailRev === "number" && Number.isFinite(data.detailRev) ? { detailRev: data.detailRev } : {},
|
|
989
995
|
...cost !== void 0 ? { cost } : {},
|
|
990
996
|
...timing !== null ? { timing } : {},
|
|
997
|
+
...data.systems !== void 0 ? { systems: systemsOf(data.systems) } : {},
|
|
991
998
|
...typeof data.surfaceFloor === "number" ? { surfaceFloor: data.surfaceFloor } : {},
|
|
992
999
|
...typeof data.archiveFloor === "number" ? { archiveFloor: data.archiveFloor } : {},
|
|
993
1000
|
...data.fileOps !== void 0 ? { fileOps: objectsOf(data.fileOps) } : {},
|
|
@@ -995,6 +1002,45 @@ window.__ModuleLoader__.load({
|
|
|
995
1002
|
};
|
|
996
1003
|
}
|
|
997
1004
|
/**
|
|
1005
|
+
* The live system-prompt nodes, re-proved per entry and sorted by seq: an
|
|
1006
|
+
* entry missing a finite seq/time/tokens drops out (the browser then falls
|
|
1007
|
+
* back to the header epoch), so a hostile collection can never produce a NaN
|
|
1008
|
+
* prompt figure or an unfetchable seq. Absent or empty stays absent.
|
|
1009
|
+
*/
|
|
1010
|
+
function systemsOf(value) {
|
|
1011
|
+
const list = objectsOf(value);
|
|
1012
|
+
const out = [];
|
|
1013
|
+
for (const entry of list) {
|
|
1014
|
+
const { seq, time, tokens } = entry;
|
|
1015
|
+
if (typeof seq !== "number" || !Number.isFinite(seq)) continue;
|
|
1016
|
+
if (typeof time !== "number" || !Number.isFinite(time)) continue;
|
|
1017
|
+
if (typeof tokens !== "number" || !Number.isFinite(tokens)) continue;
|
|
1018
|
+
out.push({
|
|
1019
|
+
seq,
|
|
1020
|
+
time,
|
|
1021
|
+
tokens
|
|
1022
|
+
});
|
|
1023
|
+
}
|
|
1024
|
+
return out.sort((a, b) => a.seq - b.seq);
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* The fast path's check for the live system-prompt nodes: every entry must
|
|
1028
|
+
* carry the three finite numbers the browser reads — `seq` for the per-step
|
|
1029
|
+
* resolution, `time` for the DNA band, `tokens` for its width. A primitive
|
|
1030
|
+
* entry, or one whose fields are not numbers, sends the payload down the
|
|
1031
|
+
* sanitizing slow path (`systemsOf` drops it) instead of leaking `undefined`
|
|
1032
|
+
* into the bar math. An absent list is fine.
|
|
1033
|
+
*/
|
|
1034
|
+
function systemsFastOk(value) {
|
|
1035
|
+
if (value === void 0) return true;
|
|
1036
|
+
if (!Array.isArray(value)) return false;
|
|
1037
|
+
return value.every((entry) => {
|
|
1038
|
+
if (entry === null || typeof entry !== "object") return false;
|
|
1039
|
+
const { seq, time, tokens } = entry;
|
|
1040
|
+
return typeof seq === "number" && Number.isFinite(seq) && typeof time === "number" && Number.isFinite(time) && typeof tokens === "number" && Number.isFinite(tokens);
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
998
1044
|
* The split head's count figures, re-proved field by field: a present-but-
|
|
999
1045
|
* partial record zeroes its unreadable fields (the stats board's no-NaN
|
|
1000
1046
|
* guarantee), an absent or non-record value stays absent (legacy generation
|
|
@@ -1094,6 +1140,14 @@ window.__ModuleLoader__.load({
|
|
|
1094
1140
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
|
|
1095
1141
|
}
|
|
1096
1142
|
/**
|
|
1143
|
+
* The OPTIONAL timing scalars (the generation split): a real non-negative
|
|
1144
|
+
* number passes, anything else — including absence — reads as undefined so the
|
|
1145
|
+
* field stays absent on the narrowed value (see `timingOf`).
|
|
1146
|
+
*/
|
|
1147
|
+
function optMsNumOf(value) {
|
|
1148
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
1149
|
+
}
|
|
1150
|
+
/**
|
|
1097
1151
|
* Cheap whole-value check for the pass-through path of `timelineOf`: absent
|
|
1098
1152
|
* timing passes; present timing must already be well-formed (every scalar
|
|
1099
1153
|
* numeric, every per-name row shaped) — anything else sends the payload down
|
|
@@ -1111,6 +1165,14 @@ window.__ModuleLoader__.load({
|
|
|
1111
1165
|
"toolsMs",
|
|
1112
1166
|
"toolCalls"
|
|
1113
1167
|
]) if (typeof t[k] !== "number") return false;
|
|
1168
|
+
for (const k of [
|
|
1169
|
+
"reasoningMs",
|
|
1170
|
+
"textMs",
|
|
1171
|
+
"toolArgMs"
|
|
1172
|
+
]) {
|
|
1173
|
+
const v = t[k];
|
|
1174
|
+
if (v !== void 0 && (typeof v !== "number" || !Number.isFinite(v) || v < 0)) return false;
|
|
1175
|
+
}
|
|
1114
1176
|
const tools = t.tools;
|
|
1115
1177
|
if (tools === null || typeof tools !== "object" || Array.isArray(tools)) return false;
|
|
1116
1178
|
for (const k in tools) {
|
|
@@ -1145,7 +1207,7 @@ window.__ModuleLoader__.load({
|
|
|
1145
1207
|
ms
|
|
1146
1208
|
};
|
|
1147
1209
|
}
|
|
1148
|
-
|
|
1210
|
+
const totals = {
|
|
1149
1211
|
wallMs: msNumOf(data.wallMs),
|
|
1150
1212
|
ttftMs: msNumOf(data.ttftMs),
|
|
1151
1213
|
genMs: msNumOf(data.genMs),
|
|
@@ -1154,6 +1216,13 @@ window.__ModuleLoader__.load({
|
|
|
1154
1216
|
toolCalls: msNumOf(data.toolCalls),
|
|
1155
1217
|
tools
|
|
1156
1218
|
};
|
|
1219
|
+
const reasoning = optMsNumOf(data.reasoningMs);
|
|
1220
|
+
if (reasoning !== void 0) totals.reasoningMs = reasoning;
|
|
1221
|
+
const textMs = optMsNumOf(data.textMs);
|
|
1222
|
+
if (textMs !== void 0) totals.textMs = textMs;
|
|
1223
|
+
const toolArgMs = optMsNumOf(data.toolArgMs);
|
|
1224
|
+
if (toolArgMs !== void 0) totals.toolArgMs = toolArgMs;
|
|
1225
|
+
return totals;
|
|
1157
1226
|
}
|
|
1158
1227
|
/**
|
|
1159
1228
|
* Narrow a delivered projection value to the plugin's `contextHeaders`
|
|
@@ -1323,6 +1392,25 @@ window.__ModuleLoader__.load({
|
|
|
1323
1392
|
return out.trim() === "" ? null : out;
|
|
1324
1393
|
}
|
|
1325
1394
|
/**
|
|
1395
|
+
* The system prompt's exact rendered text — every text block joined with NO
|
|
1396
|
+
* normalization: a whitespace-only prompt is still the prompt the model
|
|
1397
|
+
* received (the host prices it as text), so it must render rather than read
|
|
1398
|
+
* as absent. Null when the content carries no text block at all.
|
|
1399
|
+
*/
|
|
1400
|
+
function systemTextOf(blocks) {
|
|
1401
|
+
if (!Array.isArray(blocks)) return null;
|
|
1402
|
+
let out = "";
|
|
1403
|
+
let seen = false;
|
|
1404
|
+
for (const b of blocks) {
|
|
1405
|
+
const text = b !== null && typeof b === "object" ? b.text : void 0;
|
|
1406
|
+
if (typeof text === "string") {
|
|
1407
|
+
out += text;
|
|
1408
|
+
seen = true;
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
return seen ? out : null;
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1326
1414
|
* One assistant content block → the snapshot block vocabulary the browser
|
|
1327
1415
|
* already renders (`kind`: text/reasoning/image/tool-call); unmappable
|
|
1328
1416
|
* blocks pass through raw and degrade to the generic JSON section.
|
|
@@ -1548,13 +1636,23 @@ window.__ModuleLoader__.load({
|
|
|
1548
1636
|
};
|
|
1549
1637
|
}
|
|
1550
1638
|
/**
|
|
1551
|
-
* Map one raw
|
|
1552
|
-
*
|
|
1553
|
-
* description and raw schema
|
|
1554
|
-
*
|
|
1555
|
-
*
|
|
1639
|
+
* Map one raw durable event into the epoch content the browser renders. A
|
|
1640
|
+
* `request/header` yields the full system prompt text (V0/V2 envelope) plus
|
|
1641
|
+
* each tool's producer description and raw schema; a V3 `system/message`
|
|
1642
|
+
* yields the prompt text alone (its tools live in the request header). Both
|
|
1643
|
+
* mirror the host fold's per-entry guards — a null or primitive tool entry
|
|
1644
|
+
* degrades to an unnamed row instead of throwing the read. Null when the
|
|
1645
|
+
* envelope carries neither.
|
|
1556
1646
|
*/
|
|
1557
|
-
function headerContentOf(
|
|
1647
|
+
function headerContentOf(event) {
|
|
1648
|
+
const { type, data } = event;
|
|
1649
|
+
if (type === "system/message") {
|
|
1650
|
+
const system = systemTextOf((data.message !== null && typeof data.message === "object" ? data.message : null)?.content);
|
|
1651
|
+
return system === null ? null : {
|
|
1652
|
+
system,
|
|
1653
|
+
tools: []
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1558
1656
|
const rawHeader = data.header !== null && typeof data.header === "object" ? data.header : null;
|
|
1559
1657
|
if (rawHeader === null) return null;
|
|
1560
1658
|
const toolsRaw = Array.isArray(rawHeader.tools) ? rawHeader.tools : [];
|
|
@@ -1573,15 +1671,15 @@ window.__ModuleLoader__.load({
|
|
|
1573
1671
|
};
|
|
1574
1672
|
}
|
|
1575
1673
|
/**
|
|
1576
|
-
* The on-demand CONTENT fetch for
|
|
1577
|
-
* counterpart of the node fetcher above. One seq-anchored history
|
|
1578
|
-
* the
|
|
1579
|
-
*
|
|
1580
|
-
*
|
|
1581
|
-
* (history is immutable), and OLDER
|
|
1582
|
-
*
|
|
1583
|
-
* history face exists — the browser keeps a
|
|
1584
|
-
* instead.
|
|
1674
|
+
* The on-demand CONTENT fetch for the browser's System and Tools sections —
|
|
1675
|
+
* the lazy counterpart of the node fetcher above. One seq-anchored history
|
|
1676
|
+
* read off the requested seq returns the page holding that event (non-message
|
|
1677
|
+
* events ride the page verbatim); a `request/header` maps to the epoch's
|
|
1678
|
+
* tools (and its V0/V2 system text), a `system/message` to a V3 prompt's
|
|
1679
|
+
* text. Landed content caches per seq (history is immutable), and OLDER
|
|
1680
|
+
* epochs sharing the page cache for free — stepping back through epochs walks
|
|
1681
|
+
* the same pages. Undefined when no history face exists — the browser keeps a
|
|
1682
|
+
* metadata-only degradation instead.
|
|
1585
1683
|
*/
|
|
1586
1684
|
function makeHeaderFetcher(sessionId) {
|
|
1587
1685
|
const read = pageReaderOf(sessionId);
|
|
@@ -1594,8 +1692,8 @@ window.__ModuleLoader__.load({
|
|
|
1594
1692
|
let picked = null;
|
|
1595
1693
|
for (const entry of rows) {
|
|
1596
1694
|
const ev = eventOf(entry);
|
|
1597
|
-
if (ev === null || ev.type !== "request/header") continue;
|
|
1598
|
-
const content = headerContentOf(ev
|
|
1695
|
+
if (ev === null || ev.type !== "request/header" && ev.type !== "system/message") continue;
|
|
1696
|
+
const content = headerContentOf(ev);
|
|
1599
1697
|
if (content === null) continue;
|
|
1600
1698
|
cache.set(ev.seq, content);
|
|
1601
1699
|
if (ev.seq === seq) picked = content;
|
|
@@ -1872,6 +1970,30 @@ window.__ModuleLoader__.load({
|
|
|
1872
1970
|
for (let i = headers.headers.length - 1; i >= 0; i--) if (headers.headers[i].seq < seq) return headers.headers[i];
|
|
1873
1971
|
return null;
|
|
1874
1972
|
}
|
|
1973
|
+
/**
|
|
1974
|
+
* The system prompt in force at `seq` (null = none) — the LAST live system
|
|
1975
|
+
* node at or before it carrying tokens, which is exactly the host fold's
|
|
1976
|
+
* "last nonempty surviving system" rule and therefore agrees with the
|
|
1977
|
+
* per-step `system` figure the fold recorded. Rows folded before `systems`
|
|
1978
|
+
* existed carry none; the header epoch's envelope figure stands in for them
|
|
1979
|
+
* (the pre-V3 wire shape).
|
|
1980
|
+
*/
|
|
1981
|
+
function systemAt(data, header, seq) {
|
|
1982
|
+
const systems = data.systems;
|
|
1983
|
+
if (systems !== void 0 && systems.length > 0) {
|
|
1984
|
+
for (let i = systems.length - 1; i >= 0; i--) {
|
|
1985
|
+
const node = systems[i];
|
|
1986
|
+
if (node.tokens <= 0) continue;
|
|
1987
|
+
if (seq === null || node.seq < seq) return node;
|
|
1988
|
+
}
|
|
1989
|
+
return null;
|
|
1990
|
+
}
|
|
1991
|
+
return header !== null && header.systemTokens !== void 0 ? {
|
|
1992
|
+
seq: header.seq,
|
|
1993
|
+
time: header.time,
|
|
1994
|
+
tokens: header.systemTokens
|
|
1995
|
+
} : null;
|
|
1996
|
+
}
|
|
1875
1997
|
function assemble(data, headers, seq) {
|
|
1876
1998
|
const live = seq === null;
|
|
1877
1999
|
let nodes;
|
|
@@ -1888,9 +2010,11 @@ window.__ModuleLoader__.load({
|
|
|
1888
2010
|
if (live || data.surfaceFloor !== void 0 && seq > data.surfaceFloor) missingLive = data.droppedNodes;
|
|
1889
2011
|
}
|
|
1890
2012
|
const approximate = !live && data.archiveFloor !== void 0 && seq < data.archiveFloor;
|
|
2013
|
+
const header = headerAt(headers, seq);
|
|
1891
2014
|
return {
|
|
1892
2015
|
live,
|
|
1893
|
-
header
|
|
2016
|
+
header,
|
|
2017
|
+
system: systemAt(data, header, seq),
|
|
1894
2018
|
nodes,
|
|
1895
2019
|
missingLive,
|
|
1896
2020
|
approximate
|
|
@@ -1900,19 +2024,17 @@ window.__ModuleLoader__.load({
|
|
|
1900
2024
|
//#region src/client/dna.ts
|
|
1901
2025
|
function dnaOf(view) {
|
|
1902
2026
|
const items = [];
|
|
1903
|
-
if (view.
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
});
|
|
1915
|
-
}
|
|
2027
|
+
if (view.system !== null) items.push({
|
|
2028
|
+
key: "sys",
|
|
2029
|
+
cat: "system",
|
|
2030
|
+
tokens: view.system.tokens,
|
|
2031
|
+
time: view.system.time
|
|
2032
|
+
});
|
|
2033
|
+
if (view.header !== null) for (const tool of view.header.tools) items.push({
|
|
2034
|
+
key: "tool:" + tool.name,
|
|
2035
|
+
cat: "tools",
|
|
2036
|
+
tokens: tool.tokens
|
|
2037
|
+
});
|
|
1916
2038
|
for (const n of view.nodes) items.push({
|
|
1917
2039
|
key: "n" + String(n.seq),
|
|
1918
2040
|
cat: n.cat,
|
|
@@ -2358,22 +2480,20 @@ window.__ModuleLoader__.load({
|
|
|
2358
2480
|
return `${pct.toFixed(1)}%`;
|
|
2359
2481
|
}
|
|
2360
2482
|
/**
|
|
2361
|
-
* Whole-session durations for the timing card,
|
|
2362
|
-
* under a second, one-decimal seconds under a minute, then m/s and h/m.
|
|
2483
|
+
* Whole-session durations for the timing card, locale-free compact units: raw
|
|
2484
|
+
* ms under a second, one-decimal seconds under a minute, then m/s and h/m.
|
|
2363
2485
|
* Non-finite or non-positive input shows the dash (callers render their empty
|
|
2364
2486
|
* state anyway).
|
|
2365
2487
|
*/
|
|
2366
|
-
function fmtDuration(ms
|
|
2488
|
+
function fmtDuration(ms) {
|
|
2367
2489
|
if (!Number.isFinite(ms) || ms <= 0) return "—";
|
|
2368
2490
|
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
2369
|
-
|
|
2370
|
-
if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}${zh ? "秒" : "s"}`;
|
|
2491
|
+
if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
|
|
2371
2492
|
const totalSec = Math.floor(ms / 1e3);
|
|
2372
2493
|
const m = Math.floor(totalSec / 60);
|
|
2373
2494
|
const s = totalSec % 60;
|
|
2374
|
-
if (ms < 36e5) return
|
|
2375
|
-
|
|
2376
|
-
return zh ? `${h}时${m % 60}分` : `${h}h ${m % 60}m`;
|
|
2495
|
+
if (ms < 36e5) return `${m}m${s}s`;
|
|
2496
|
+
return `${Math.floor(m / 60)}h${m % 60}m`;
|
|
2377
2497
|
}
|
|
2378
2498
|
//#endregion
|
|
2379
2499
|
//#region src/shared/imageTokens.ts
|
|
@@ -3217,7 +3337,7 @@ window.__ModuleLoader__.load({
|
|
|
3217
3337
|
return m;
|
|
3218
3338
|
}
|
|
3219
3339
|
function countOf(asm, byCat, c) {
|
|
3220
|
-
if (c === "system") return asm.
|
|
3340
|
+
if (c === "system") return asm.system !== null ? 1 : 0;
|
|
3221
3341
|
if (c === "tools") return asm.header !== null ? asm.header.tools.length : 0;
|
|
3222
3342
|
return byCat[c]?.length ?? 0;
|
|
3223
3343
|
}
|
|
@@ -3302,7 +3422,8 @@ window.__ModuleLoader__.load({
|
|
|
3302
3422
|
const view = assemble(data, headers, seq);
|
|
3303
3423
|
const fetchHeader = props.fetchHeader;
|
|
3304
3424
|
const headerSeq = view.header !== null ? view.header.seq : null;
|
|
3305
|
-
const
|
|
3425
|
+
const systemSeq = view.system !== null ? view.system.seq : null;
|
|
3426
|
+
const epoch = useFetchOnMiss(openCat === "system" ? systemSeq : openCat === "tools" ? headerSeq : null, fetchHeader, "dsh-context: header content fetch failed");
|
|
3306
3427
|
const headerContent = epoch.values;
|
|
3307
3428
|
const headerNote = fetchMissNote(t, fetchHeader, epoch.state, epoch.retry, "browser.headerMetaOnly");
|
|
3308
3429
|
const breakdown = req !== null ? req : data.current;
|
|
@@ -3348,7 +3469,7 @@ window.__ModuleLoader__.load({
|
|
|
3348
3469
|
};
|
|
3349
3470
|
const toolCount = (c) => countOf(view, byCat, c);
|
|
3350
3471
|
const singleKeyOf = (c) => {
|
|
3351
|
-
if (c === "system") return view.
|
|
3472
|
+
if (c === "system") return view.system !== null ? "sys" : null;
|
|
3352
3473
|
if (c === "tools") {
|
|
3353
3474
|
const tools = view.header?.tools;
|
|
3354
3475
|
return tools !== void 0 && tools.length === 1 ? "tool:" + tools[0].name : null;
|
|
@@ -3418,11 +3539,12 @@ window.__ModuleLoader__.load({
|
|
|
3418
3539
|
};
|
|
3419
3540
|
const catBody = (c) => {
|
|
3420
3541
|
if (c === "system") {
|
|
3421
|
-
|
|
3542
|
+
const sys = view.system;
|
|
3543
|
+
if (sys === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3422
3544
|
className: "lc-br-note",
|
|
3423
3545
|
children: t(headers === null ? "browser.noHeader" : "browser.noEpoch")
|
|
3424
3546
|
});
|
|
3425
|
-
const content = headerContent.get(
|
|
3547
|
+
const content = headerContent.get(sys.seq);
|
|
3426
3548
|
if (content === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3427
3549
|
className: "lc-br-note",
|
|
3428
3550
|
children: headerNote
|
|
@@ -3827,7 +3949,7 @@ window.__ModuleLoader__.load({
|
|
|
3827
3949
|
className: "lc-stacked-seg" + (on ? " lc-stacked-seg-on" : "") + (pickKey !== void 0 ? " lc-stacked-seg-pick" : ""),
|
|
3828
3950
|
style: {
|
|
3829
3951
|
width: `${widths[i]}%`,
|
|
3830
|
-
|
|
3952
|
+
backgroundColor: p.color
|
|
3831
3953
|
},
|
|
3832
3954
|
onMouseEnter: () => {
|
|
3833
3955
|
if (props.onHoverKey !== void 0) props.onHoverKey(p.key);
|
|
@@ -5565,9 +5687,9 @@ window.__ModuleLoader__.load({
|
|
|
5565
5687
|
}
|
|
5566
5688
|
/**
|
|
5567
5689
|
* Compact duration: `42s`, `3m05s`, `1h07m` (shared by both locales).
|
|
5568
|
-
* Deliberately distinct from format.ts's
|
|
5569
|
-
*
|
|
5570
|
-
*
|
|
5690
|
+
* Deliberately distinct from format.ts's `fmtDuration` (the timing card's
|
|
5691
|
+
* `12.3s` / `3m25s`): the inspector's caption column needs whole-second,
|
|
5692
|
+
* fixed-width text.
|
|
5571
5693
|
*/
|
|
5572
5694
|
function fmtDurationCompact(ms) {
|
|
5573
5695
|
if (!Number.isFinite(ms) || ms < 0) return "—";
|
|
@@ -6482,7 +6604,7 @@ window.__ModuleLoader__.load({
|
|
|
6482
6604
|
return function PluginInfo() {
|
|
6483
6605
|
const [latest, setLatest] = (0, react.useState)(null);
|
|
6484
6606
|
(0, react.useEffect)(() => {
|
|
6485
|
-
if ("0.
|
|
6607
|
+
if ("0.48.0".includes("-dev")) return;
|
|
6486
6608
|
let on = true;
|
|
6487
6609
|
fetchLatestVersion().then((v) => {
|
|
6488
6610
|
if (on && v) setLatest(v);
|
|
@@ -6491,8 +6613,8 @@ window.__ModuleLoader__.load({
|
|
|
6491
6613
|
on = false;
|
|
6492
6614
|
};
|
|
6493
6615
|
}, []);
|
|
6494
|
-
const update = latest !== null && isNewerVersion(latest, "0.
|
|
6495
|
-
const nameText = "dsh-context (v0.
|
|
6616
|
+
const update = latest !== null && isNewerVersion(latest, "0.48.0") ? latest : null;
|
|
6617
|
+
const nameText = "dsh-context (v0.48.0)";
|
|
6496
6618
|
const nameValue = [nameText];
|
|
6497
6619
|
if (update) nameValue.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6498
6620
|
className: "lc-pi-update",
|
|
@@ -6949,61 +7071,49 @@ window.__ModuleLoader__.load({
|
|
|
6949
7071
|
}
|
|
6950
7072
|
//#endregion
|
|
6951
7073
|
//#region src/client/cost.ts
|
|
6952
|
-
|
|
7074
|
+
/** The Flash-series rates (peak = 2× off-peak), per currency. */
|
|
7075
|
+
const FLASH_RATES = {
|
|
6953
7076
|
usd: {
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
out: 1.32
|
|
6959
|
-
},
|
|
6960
|
-
off: {
|
|
6961
|
-
hit: .007,
|
|
6962
|
-
miss: .22,
|
|
6963
|
-
out: .66
|
|
6964
|
-
}
|
|
7077
|
+
peak: {
|
|
7078
|
+
hit: .006,
|
|
7079
|
+
miss: .3,
|
|
7080
|
+
out: 1.2
|
|
6965
7081
|
},
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
out: 3.96
|
|
6971
|
-
},
|
|
6972
|
-
off: {
|
|
6973
|
-
hit: .022,
|
|
6974
|
-
miss: .66,
|
|
6975
|
-
out: 1.98
|
|
6976
|
-
}
|
|
7082
|
+
off: {
|
|
7083
|
+
hit: .003,
|
|
7084
|
+
miss: .15,
|
|
7085
|
+
out: .6
|
|
6977
7086
|
}
|
|
6978
7087
|
},
|
|
6979
7088
|
cny: {
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
out: 9
|
|
6985
|
-
},
|
|
6986
|
-
off: {
|
|
6987
|
-
hit: .05,
|
|
6988
|
-
miss: 1.5,
|
|
6989
|
-
out: 4.5
|
|
6990
|
-
}
|
|
7089
|
+
peak: {
|
|
7090
|
+
hit: .04,
|
|
7091
|
+
miss: 2,
|
|
7092
|
+
out: 8
|
|
6991
7093
|
},
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
out: 27
|
|
6997
|
-
},
|
|
6998
|
-
off: {
|
|
6999
|
-
hit: .15,
|
|
7000
|
-
miss: 4.5,
|
|
7001
|
-
out: 13.5
|
|
7002
|
-
}
|
|
7094
|
+
off: {
|
|
7095
|
+
hit: .02,
|
|
7096
|
+
miss: 1,
|
|
7097
|
+
out: 4
|
|
7003
7098
|
}
|
|
7004
7099
|
}
|
|
7005
7100
|
};
|
|
7006
7101
|
/**
|
|
7102
|
+
* Pro rides the Flash triple: between the V4.1 Flash launch and the V4.1 Pro
|
|
7103
|
+
* release, DeepSeek routes every Pro request to V4.1 Flash and bills it at
|
|
7104
|
+
* the Flash rates — point `pro` at the new table once V4.1 Pro is priced.
|
|
7105
|
+
*/
|
|
7106
|
+
const PRICES = {
|
|
7107
|
+
usd: {
|
|
7108
|
+
flash: FLASH_RATES.usd,
|
|
7109
|
+
pro: FLASH_RATES.usd
|
|
7110
|
+
},
|
|
7111
|
+
cny: {
|
|
7112
|
+
flash: FLASH_RATES.cny,
|
|
7113
|
+
pro: FLASH_RATES.cny
|
|
7114
|
+
}
|
|
7115
|
+
};
|
|
7116
|
+
/**
|
|
7007
7117
|
* Price the session's cumulative billed-token totals. Cache reads bill at
|
|
7008
7118
|
* the hit rate; uncached input AND cache writes bill at the miss rate;
|
|
7009
7119
|
* output (reasoning included) bills at the out rate. Null when nothing was
|
|
@@ -7038,7 +7148,7 @@ window.__ModuleLoader__.load({
|
|
|
7038
7148
|
*/
|
|
7039
7149
|
function sessionPrices(currency) {
|
|
7040
7150
|
return ["flash", "pro"].map((id) => ({
|
|
7041
|
-
family: id === "flash" ? "deepseek-v4-flash" : "deepseek-v4-pro",
|
|
7151
|
+
family: id === "flash" ? "deepseek-v4.1-flash" : "deepseek-v4-pro",
|
|
7042
7152
|
peak: PRICES[currency][id].peak,
|
|
7043
7153
|
off: PRICES[currency][id].off
|
|
7044
7154
|
}));
|
|
@@ -7233,90 +7343,139 @@ window.__ModuleLoader__.load({
|
|
|
7233
7343
|
* token, the wait) and LLM generation (first token → assistant message) —
|
|
7234
7344
|
* and the tool-execution slice, with the residue as overhead; a call whose
|
|
7235
7345
|
* stream recorded no token delta (legacy or aborted) stays unattributed and
|
|
7236
|
-
* lands in the residue.
|
|
7237
|
-
*
|
|
7238
|
-
*
|
|
7239
|
-
*
|
|
7240
|
-
*
|
|
7346
|
+
* lands in the residue. When the host folded the generation split (see
|
|
7347
|
+
* TimingTotals), the generation slice expands into what was being decoded:
|
|
7348
|
+
* thinking, answer text, and tool-call arguments. The slice rows lead with
|
|
7349
|
+
* the true duration and qualify it with the call count on the secondary line —
|
|
7350
|
+
* except the decode slices, which count BLOCKS (zero to many per call, so a
|
|
7351
|
+
* call count would be a false tally) and therefore carry no qualifier. A slice
|
|
7352
|
+
* that never happened (zero time) is omitted entirely — the ring already skips
|
|
7353
|
+
* its arc, and a zero row would otherwise borrow the session's call count and
|
|
7354
|
+
* read as "no time, many calls". The donut and the rows sit side by side so
|
|
7355
|
+
* the head row stays half-height. Parallel tool calls each count, so the tools
|
|
7356
|
+
* figure can overlap — the ring clamps it into the post-model window while the
|
|
7357
|
+
* row numbers stay true.
|
|
7241
7358
|
*/
|
|
7359
|
+
const COLOR = {
|
|
7360
|
+
ttft: "#3b82f6",
|
|
7361
|
+
reasoning: "#8b5cf6",
|
|
7362
|
+
text: "#ec4899",
|
|
7363
|
+
toolarg: "#f59e0b",
|
|
7364
|
+
tools: "#14b8a6",
|
|
7365
|
+
other: "#94a3b8"
|
|
7366
|
+
};
|
|
7242
7367
|
function makeStatsTiming(kit, Donut) {
|
|
7243
7368
|
const { t, fmt, fmtDuration, fmtShare } = kit;
|
|
7244
7369
|
const SliceList = makeSliceList(kit);
|
|
7245
7370
|
return function StatsTiming(props) {
|
|
7246
|
-
const lang = props.locale === "zh" ? "zh" : "en";
|
|
7247
7371
|
const [hoverKey, setHoverKey] = (0, react.useState)(null);
|
|
7248
7372
|
const timing = props.timing;
|
|
7249
7373
|
const wall = timing !== null && Number.isFinite(timing.wallMs) && timing.wallMs > 0 ? timing.wallMs : 0;
|
|
7250
7374
|
let segments = [];
|
|
7251
7375
|
let rows = [];
|
|
7252
7376
|
if (timing !== null && (wall > 0 || timing.calls > 0 || timing.toolCalls > 0)) {
|
|
7253
|
-
const
|
|
7254
|
-
const
|
|
7255
|
-
|
|
7256
|
-
|
|
7377
|
+
const callTimes = t("timing.callTimes", { n: fmt(timing.calls) });
|
|
7378
|
+
const modelSlices = [{
|
|
7379
|
+
key: "ttft",
|
|
7380
|
+
color: COLOR.ttft,
|
|
7381
|
+
label: t("timing.ttft"),
|
|
7382
|
+
ms: timing.ttftMs,
|
|
7383
|
+
times: callTimes
|
|
7384
|
+
}];
|
|
7385
|
+
const buckets = [
|
|
7386
|
+
[
|
|
7387
|
+
"reasoning",
|
|
7388
|
+
COLOR.reasoning,
|
|
7389
|
+
t("timing.reasoning"),
|
|
7390
|
+
timing.reasoningMs ?? 0
|
|
7391
|
+
],
|
|
7392
|
+
[
|
|
7393
|
+
"text",
|
|
7394
|
+
COLOR.text,
|
|
7395
|
+
t("timing.text"),
|
|
7396
|
+
timing.textMs ?? 0
|
|
7397
|
+
],
|
|
7398
|
+
[
|
|
7399
|
+
"toolarg",
|
|
7400
|
+
COLOR.toolarg,
|
|
7401
|
+
t("timing.toolArgs"),
|
|
7402
|
+
timing.toolArgMs ?? 0
|
|
7403
|
+
]
|
|
7404
|
+
];
|
|
7405
|
+
if (buckets.some(([, , , ms]) => ms > 0)) for (const [key, color, label, ms] of buckets) modelSlices.push({
|
|
7406
|
+
key,
|
|
7407
|
+
color,
|
|
7408
|
+
label,
|
|
7409
|
+
ms
|
|
7410
|
+
});
|
|
7411
|
+
else modelSlices.push({
|
|
7412
|
+
key: "gen",
|
|
7413
|
+
color: COLOR.reasoning,
|
|
7414
|
+
label: t("timing.gen"),
|
|
7415
|
+
ms: timing.genMs
|
|
7416
|
+
});
|
|
7417
|
+
const ttftRing = Math.min(timing.ttftMs, wall);
|
|
7418
|
+
const genRing = Math.max(0, Math.min(timing.genMs, wall - ttftRing));
|
|
7419
|
+
const modelRings = [ttftRing];
|
|
7420
|
+
let used = ttftRing;
|
|
7421
|
+
const genEnd = ttftRing + genRing;
|
|
7422
|
+
for (const slice of modelSlices.slice(1)) {
|
|
7423
|
+
const take = Math.max(0, Math.min(slice.ms, genEnd - used));
|
|
7424
|
+
modelRings.push(take);
|
|
7425
|
+
used += take;
|
|
7426
|
+
}
|
|
7427
|
+
const toolRing = Math.max(0, Math.min(timing.toolsMs, wall - ttftRing - genRing));
|
|
7428
|
+
const other = Math.max(0, wall - ttftRing - genRing - toolRing);
|
|
7257
7429
|
const share = (ms) => wall > 0 ? ms / wall : 0;
|
|
7258
7430
|
const countOf = (ms, times) => {
|
|
7259
|
-
const dur = fmtDuration(ms
|
|
7431
|
+
const dur = fmtDuration(ms);
|
|
7260
7432
|
if (times === void 0) return dur;
|
|
7261
7433
|
return ms > 0 ? `${dur} · ${times}` : times;
|
|
7262
7434
|
};
|
|
7263
|
-
const
|
|
7435
|
+
const modelSegments = modelSlices.map((slice, index) => ({
|
|
7436
|
+
key: slice.key,
|
|
7437
|
+
color: slice.color,
|
|
7438
|
+
value: share(modelRings[index])
|
|
7439
|
+
}));
|
|
7440
|
+
const toolSlice = {
|
|
7441
|
+
key: "tools",
|
|
7442
|
+
color: COLOR.tools,
|
|
7443
|
+
label: t("timing.tools"),
|
|
7444
|
+
ms: timing.toolsMs,
|
|
7445
|
+
times: t("timing.toolTimes", { n: fmt(timing.toolCalls) })
|
|
7446
|
+
};
|
|
7447
|
+
const otherSlice = {
|
|
7448
|
+
key: "other",
|
|
7449
|
+
color: COLOR.other,
|
|
7450
|
+
label: t("timing.other"),
|
|
7451
|
+
ms: other
|
|
7452
|
+
};
|
|
7264
7453
|
segments = [
|
|
7265
|
-
|
|
7266
|
-
key: "ttft",
|
|
7267
|
-
color: "#3b82f6",
|
|
7268
|
-
value: share(ttft)
|
|
7269
|
-
},
|
|
7270
|
-
{
|
|
7271
|
-
key: "gen",
|
|
7272
|
-
color: "#8b5cf6",
|
|
7273
|
-
value: share(gen)
|
|
7274
|
-
},
|
|
7454
|
+
...modelSegments,
|
|
7275
7455
|
{
|
|
7276
7456
|
key: "tools",
|
|
7277
|
-
color:
|
|
7457
|
+
color: COLOR.tools,
|
|
7278
7458
|
value: share(toolRing)
|
|
7279
7459
|
},
|
|
7280
7460
|
{
|
|
7281
7461
|
key: "other",
|
|
7282
|
-
color:
|
|
7462
|
+
color: COLOR.other,
|
|
7283
7463
|
value: share(other)
|
|
7284
7464
|
}
|
|
7285
7465
|
];
|
|
7466
|
+
const toRow = (slice) => ({
|
|
7467
|
+
key: slice.key,
|
|
7468
|
+
color: slice.color,
|
|
7469
|
+
label: slice.label,
|
|
7470
|
+
dim: slice.ms === 0,
|
|
7471
|
+
pct: fmtShare(slice.ms, wall),
|
|
7472
|
+
count: countOf(slice.ms, slice.times)
|
|
7473
|
+
});
|
|
7286
7474
|
rows = [
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
dim: timing.ttftMs === 0,
|
|
7292
|
-
pct: fmtShare(timing.ttftMs, wall),
|
|
7293
|
-
count: countOf(timing.ttftMs, callTimes)
|
|
7294
|
-
},
|
|
7295
|
-
{
|
|
7296
|
-
key: "gen",
|
|
7297
|
-
color: "#8b5cf6",
|
|
7298
|
-
label: t("timing.gen"),
|
|
7299
|
-
dim: timing.genMs === 0,
|
|
7300
|
-
pct: fmtShare(timing.genMs, wall),
|
|
7301
|
-
count: countOf(timing.genMs, callTimes)
|
|
7302
|
-
},
|
|
7303
|
-
{
|
|
7304
|
-
key: "tools",
|
|
7305
|
-
color: "#14b8a6",
|
|
7306
|
-
label: t("timing.tools"),
|
|
7307
|
-
dim: timing.toolsMs === 0,
|
|
7308
|
-
pct: fmtShare(timing.toolsMs, wall),
|
|
7309
|
-
count: countOf(timing.toolsMs, t("timing.toolTimes", { n: fmt(timing.toolCalls) }))
|
|
7310
|
-
},
|
|
7311
|
-
{
|
|
7312
|
-
key: "other",
|
|
7313
|
-
color: "#94a3b8",
|
|
7314
|
-
label: t("timing.other"),
|
|
7315
|
-
dim: other === 0,
|
|
7316
|
-
pct: fmtShare(other, wall),
|
|
7317
|
-
count: countOf(other)
|
|
7318
|
-
}
|
|
7319
|
-
];
|
|
7475
|
+
...modelSlices.map(toRow),
|
|
7476
|
+
toRow(toolSlice),
|
|
7477
|
+
toRow(otherSlice)
|
|
7478
|
+
].filter((row) => !row.dim);
|
|
7320
7479
|
}
|
|
7321
7480
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7322
7481
|
className: "lc-card lc-col-stats lc-col-donut",
|
|
@@ -7334,7 +7493,7 @@ window.__ModuleLoader__.load({
|
|
|
7334
7493
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Donut, {
|
|
7335
7494
|
segments,
|
|
7336
7495
|
size: 96,
|
|
7337
|
-
centerTop: wall > 0 ? fmtDuration(wall
|
|
7496
|
+
centerTop: wall > 0 ? fmtDuration(wall) : "—",
|
|
7338
7497
|
centerSub: t("timing.total"),
|
|
7339
7498
|
hoverKey,
|
|
7340
7499
|
onHoverKey: setHoverKey
|
|
@@ -8067,6 +8226,7 @@ window.__ModuleLoader__.load({
|
|
|
8067
8226
|
const ErrorBoundary = makeErrorBoundary(t);
|
|
8068
8227
|
function ContextViewBody(props) {
|
|
8069
8228
|
const sessionId = props.sessionId;
|
|
8229
|
+
const inSidebar = props.host === "sidebar";
|
|
8070
8230
|
const source = useTimelineSource(ctx, props);
|
|
8071
8231
|
const data = source.data;
|
|
8072
8232
|
const pressure = projectionOf(props, "contextPressure", contextPressureOf);
|
|
@@ -8261,6 +8421,132 @@ window.__ModuleLoader__.load({
|
|
|
8261
8421
|
const activeLocale = localeSvc !== void 0 && typeof localeSvc.getLocale === "function" ? localeSvc.getLocale().active : "en";
|
|
8262
8422
|
const subtitle = (data.model ?? "") + (data.provider ? " · " + data.provider : "");
|
|
8263
8423
|
const gate = unsupportedOf(data.unsupported);
|
|
8424
|
+
const compositionCard = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CurrentComposition, {
|
|
8425
|
+
head,
|
|
8426
|
+
subtitle,
|
|
8427
|
+
hoverKey: hoverCat,
|
|
8428
|
+
onHoverKey: setHoverCat
|
|
8429
|
+
});
|
|
8430
|
+
const trendCard = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8431
|
+
className: "lc-card",
|
|
8432
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8433
|
+
className: "lc-card-title",
|
|
8434
|
+
children: [
|
|
8435
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8436
|
+
className: "lc-card-title-text",
|
|
8437
|
+
children: t("trend.title")
|
|
8438
|
+
}),
|
|
8439
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8440
|
+
className: "lc-gran lc-trend-adaptive",
|
|
8441
|
+
role: "group",
|
|
8442
|
+
title: t("trend.adaptiveHint"),
|
|
8443
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8444
|
+
type: "button",
|
|
8445
|
+
className: "lc-gran-btn" + (adaptive ? " lc-gran-on" : ""),
|
|
8446
|
+
onClick: () => {
|
|
8447
|
+
setAdaptive((on) => !on);
|
|
8448
|
+
},
|
|
8449
|
+
children: t("trend.adaptive")
|
|
8450
|
+
})
|
|
8451
|
+
}),
|
|
8452
|
+
focusCat !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8453
|
+
className: "lc-card-sub",
|
|
8454
|
+
children: t("trend.focus", { cat: kit.catLabel(focusCat) })
|
|
8455
|
+
}) : null,
|
|
8456
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8457
|
+
className: "lc-trend-ctl",
|
|
8458
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8459
|
+
className: "lc-gran",
|
|
8460
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8461
|
+
className: "lc-gran-btn" + (granularity === "step" ? " lc-gran-on" : ""),
|
|
8462
|
+
onClick: () => {
|
|
8463
|
+
setGranularity("step");
|
|
8464
|
+
},
|
|
8465
|
+
children: t("gran.step")
|
|
8466
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8467
|
+
className: "lc-gran-btn" + (granularity === "turn" ? " lc-gran-on" : ""),
|
|
8468
|
+
onClick: () => {
|
|
8469
|
+
setGranularity("turn");
|
|
8470
|
+
},
|
|
8471
|
+
children: t("gran.turn")
|
|
8472
|
+
})]
|
|
8473
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8474
|
+
className: "lc-gran",
|
|
8475
|
+
title: t("gran.modeHint"),
|
|
8476
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8477
|
+
className: "lc-gran-btn" + (trendMode === "total" ? " lc-gran-on" : ""),
|
|
8478
|
+
onClick: () => {
|
|
8479
|
+
setTrendMode("total");
|
|
8480
|
+
},
|
|
8481
|
+
children: t("gran.total")
|
|
8482
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8483
|
+
className: "lc-gran-btn" + (trendMode === "delta" ? " lc-gran-on" : ""),
|
|
8484
|
+
onClick: () => {
|
|
8485
|
+
setTrendMode("delta");
|
|
8486
|
+
},
|
|
8487
|
+
children: t("gran.delta")
|
|
8488
|
+
})]
|
|
8489
|
+
})]
|
|
8490
|
+
})
|
|
8491
|
+
]
|
|
8492
|
+
}), displayRequests.length === 0 ? detailReady ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8493
|
+
className: "lc-empty",
|
|
8494
|
+
children: t("trend.empty")
|
|
8495
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailNote, {
|
|
8496
|
+
state: source.detailState === "failed" ? "failed" : "loading",
|
|
8497
|
+
onRetry: source.retryDetail
|
|
8498
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrendChart, {
|
|
8499
|
+
requests: displayRequests,
|
|
8500
|
+
markers,
|
|
8501
|
+
selectedSeq: pinnedReq ? pinnedReq.seq : null,
|
|
8502
|
+
hoveredSeq,
|
|
8503
|
+
activeTurn,
|
|
8504
|
+
granularity,
|
|
8505
|
+
mode: trendMode,
|
|
8506
|
+
focusTurn,
|
|
8507
|
+
hoverCat: trendHoverCat,
|
|
8508
|
+
focusCat,
|
|
8509
|
+
adaptive,
|
|
8510
|
+
onSelect: setSelectedSeq,
|
|
8511
|
+
onHover: setHoveredSeq,
|
|
8512
|
+
onHoverTurn: setHoverTurn,
|
|
8513
|
+
onPickTurn: (turn) => {
|
|
8514
|
+
setGranularity("turn");
|
|
8515
|
+
setFocusTurn(turn);
|
|
8516
|
+
},
|
|
8517
|
+
onFocusTurnHandled: () => {
|
|
8518
|
+
setFocusTurn(null);
|
|
8519
|
+
}
|
|
8520
|
+
}, sessionId), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RequestDetail, {
|
|
8521
|
+
request: activeReq,
|
|
8522
|
+
prev: trendMode === "delta" && activeIdx >= 0 ? activeIdx > 0 ? displayRequests[activeIdx - 1] : null : void 0,
|
|
8523
|
+
/* v8 ignore next 1 -- RequestDetail renders only when
|
|
8524
|
+
displayRequests.length > 0, which forces activeReq
|
|
8525
|
+
non-null via the activeIdx fallback above. */
|
|
8526
|
+
marker: activeReq !== null ? markerOf(activeReq) : void 0,
|
|
8527
|
+
brief,
|
|
8528
|
+
convOf,
|
|
8529
|
+
onLocate: locateNode,
|
|
8530
|
+
hoverKey: trendHoverCat
|
|
8531
|
+
})] })]
|
|
8532
|
+
});
|
|
8533
|
+
const browserCard = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextBrowser, {
|
|
8534
|
+
data,
|
|
8535
|
+
headers,
|
|
8536
|
+
convNodes,
|
|
8537
|
+
fetchContent,
|
|
8538
|
+
fetchHeader,
|
|
8539
|
+
previewSeq: hoveredSeq,
|
|
8540
|
+
pinSeq: pinnedReq !== null ? pinnedReq.seq : null,
|
|
8541
|
+
hoverKey: hoverCat,
|
|
8542
|
+
onHoverKey: setHoverCat,
|
|
8543
|
+
onOpenCat: setFocusCat,
|
|
8544
|
+
nodeFocus,
|
|
8545
|
+
onNodeFocusHandled: clearNodeFocus,
|
|
8546
|
+
loadImage,
|
|
8547
|
+
detailState: source.detailState,
|
|
8548
|
+
onDetailRetry: source.retryDetail
|
|
8549
|
+
});
|
|
8264
8550
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8265
8551
|
className: "lc-root",
|
|
8266
8552
|
ref: rootRef,
|
|
@@ -8268,7 +8554,7 @@ window.__ModuleLoader__.load({
|
|
|
8268
8554
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8269
8555
|
className: "lc-cols lc-head",
|
|
8270
8556
|
children: [
|
|
8271
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatsContext, {
|
|
8557
|
+
inSidebar ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatsContext, {
|
|
8272
8558
|
counts: data.counts ?? countsOfRecords(requests, events),
|
|
8273
8559
|
toolCalls: data.toolCalls,
|
|
8274
8560
|
images: data.images,
|
|
@@ -8276,144 +8562,18 @@ window.__ModuleLoader__.load({
|
|
|
8276
8562
|
locale: activeLocale
|
|
8277
8563
|
}),
|
|
8278
8564
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatsTokens, { usage }),
|
|
8279
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatsTiming, {
|
|
8280
|
-
|
|
8281
|
-
locale: activeLocale
|
|
8282
|
-
}),
|
|
8283
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PluginInfo, {})
|
|
8565
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatsTiming, { timing: data.timing ?? null }),
|
|
8566
|
+
inSidebar ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PluginInfo, {})
|
|
8284
8567
|
]
|
|
8285
8568
|
}),
|
|
8286
8569
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8287
|
-
className: "lc-cols",
|
|
8570
|
+
className: "lc-cols lc-cols-main",
|
|
8288
8571
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8289
8572
|
className: "lc-col",
|
|
8290
|
-
children: [
|
|
8291
|
-
head,
|
|
8292
|
-
subtitle,
|
|
8293
|
-
hoverKey: hoverCat,
|
|
8294
|
-
onHoverKey: setHoverCat
|
|
8295
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8296
|
-
className: "lc-card",
|
|
8297
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8298
|
-
className: "lc-card-title",
|
|
8299
|
-
children: [
|
|
8300
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8301
|
-
className: "lc-card-title-text",
|
|
8302
|
-
children: t("trend.title")
|
|
8303
|
-
}),
|
|
8304
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8305
|
-
className: "lc-gran lc-trend-adaptive",
|
|
8306
|
-
role: "group",
|
|
8307
|
-
title: t("trend.adaptiveHint"),
|
|
8308
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8309
|
-
type: "button",
|
|
8310
|
-
className: "lc-gran-btn" + (adaptive ? " lc-gran-on" : ""),
|
|
8311
|
-
onClick: () => {
|
|
8312
|
-
setAdaptive((on) => !on);
|
|
8313
|
-
},
|
|
8314
|
-
children: t("trend.adaptive")
|
|
8315
|
-
})
|
|
8316
|
-
}),
|
|
8317
|
-
focusCat !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8318
|
-
className: "lc-card-sub",
|
|
8319
|
-
children: t("trend.focus", { cat: kit.catLabel(focusCat) })
|
|
8320
|
-
}) : null,
|
|
8321
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8322
|
-
className: "lc-trend-ctl",
|
|
8323
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8324
|
-
className: "lc-gran",
|
|
8325
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8326
|
-
className: "lc-gran-btn" + (granularity === "step" ? " lc-gran-on" : ""),
|
|
8327
|
-
onClick: () => {
|
|
8328
|
-
setGranularity("step");
|
|
8329
|
-
},
|
|
8330
|
-
children: t("gran.step")
|
|
8331
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8332
|
-
className: "lc-gran-btn" + (granularity === "turn" ? " lc-gran-on" : ""),
|
|
8333
|
-
onClick: () => {
|
|
8334
|
-
setGranularity("turn");
|
|
8335
|
-
},
|
|
8336
|
-
children: t("gran.turn")
|
|
8337
|
-
})]
|
|
8338
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8339
|
-
className: "lc-gran",
|
|
8340
|
-
title: t("gran.modeHint"),
|
|
8341
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8342
|
-
className: "lc-gran-btn" + (trendMode === "total" ? " lc-gran-on" : ""),
|
|
8343
|
-
onClick: () => {
|
|
8344
|
-
setTrendMode("total");
|
|
8345
|
-
},
|
|
8346
|
-
children: t("gran.total")
|
|
8347
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8348
|
-
className: "lc-gran-btn" + (trendMode === "delta" ? " lc-gran-on" : ""),
|
|
8349
|
-
onClick: () => {
|
|
8350
|
-
setTrendMode("delta");
|
|
8351
|
-
},
|
|
8352
|
-
children: t("gran.delta")
|
|
8353
|
-
})]
|
|
8354
|
-
})]
|
|
8355
|
-
})
|
|
8356
|
-
]
|
|
8357
|
-
}), displayRequests.length === 0 ? detailReady ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8358
|
-
className: "lc-empty",
|
|
8359
|
-
children: t("trend.empty")
|
|
8360
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailNote, {
|
|
8361
|
-
state: source.detailState === "failed" ? "failed" : "loading",
|
|
8362
|
-
onRetry: source.retryDetail
|
|
8363
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrendChart, {
|
|
8364
|
-
requests: displayRequests,
|
|
8365
|
-
markers,
|
|
8366
|
-
selectedSeq: pinnedReq ? pinnedReq.seq : null,
|
|
8367
|
-
hoveredSeq,
|
|
8368
|
-
activeTurn,
|
|
8369
|
-
granularity,
|
|
8370
|
-
mode: trendMode,
|
|
8371
|
-
focusTurn,
|
|
8372
|
-
hoverCat: trendHoverCat,
|
|
8373
|
-
focusCat,
|
|
8374
|
-
adaptive,
|
|
8375
|
-
onSelect: setSelectedSeq,
|
|
8376
|
-
onHover: setHoveredSeq,
|
|
8377
|
-
onHoverTurn: setHoverTurn,
|
|
8378
|
-
onPickTurn: (turn) => {
|
|
8379
|
-
setGranularity("turn");
|
|
8380
|
-
setFocusTurn(turn);
|
|
8381
|
-
},
|
|
8382
|
-
onFocusTurnHandled: () => {
|
|
8383
|
-
setFocusTurn(null);
|
|
8384
|
-
}
|
|
8385
|
-
}, sessionId), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RequestDetail, {
|
|
8386
|
-
request: activeReq,
|
|
8387
|
-
prev: trendMode === "delta" && activeIdx >= 0 ? activeIdx > 0 ? displayRequests[activeIdx - 1] : null : void 0,
|
|
8388
|
-
/* v8 ignore next 1 -- RequestDetail renders only when
|
|
8389
|
-
displayRequests.length > 0, which forces activeReq
|
|
8390
|
-
non-null via the activeIdx fallback above. */
|
|
8391
|
-
marker: activeReq !== null ? markerOf(activeReq) : void 0,
|
|
8392
|
-
brief,
|
|
8393
|
-
convOf,
|
|
8394
|
-
onLocate: locateNode,
|
|
8395
|
-
hoverKey: trendHoverCat
|
|
8396
|
-
})] })]
|
|
8397
|
-
})]
|
|
8573
|
+
children: [compositionCard, trendCard]
|
|
8398
8574
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8399
8575
|
className: "lc-col lc-col-browser",
|
|
8400
|
-
children:
|
|
8401
|
-
data,
|
|
8402
|
-
headers,
|
|
8403
|
-
convNodes,
|
|
8404
|
-
fetchContent,
|
|
8405
|
-
fetchHeader,
|
|
8406
|
-
previewSeq: hoveredSeq,
|
|
8407
|
-
pinSeq: pinnedReq !== null ? pinnedReq.seq : null,
|
|
8408
|
-
hoverKey: hoverCat,
|
|
8409
|
-
onHoverKey: setHoverCat,
|
|
8410
|
-
onOpenCat: setFocusCat,
|
|
8411
|
-
nodeFocus,
|
|
8412
|
-
onNodeFocusHandled: clearNodeFocus,
|
|
8413
|
-
loadImage,
|
|
8414
|
-
detailState: source.detailState,
|
|
8415
|
-
onDetailRetry: source.retryDetail
|
|
8416
|
-
})
|
|
8576
|
+
children: browserCard
|
|
8417
8577
|
})]
|
|
8418
8578
|
}),
|
|
8419
8579
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -8560,6 +8720,99 @@ window.__ModuleLoader__.load({
|
|
|
8560
8720
|
};
|
|
8561
8721
|
}
|
|
8562
8722
|
//#endregion
|
|
8723
|
+
//#region src/client/sidebar.ts
|
|
8724
|
+
/**
|
|
8725
|
+
* The right Sidebar's Context tab (dsh 0.1.5-alpha.2+).
|
|
8726
|
+
*
|
|
8727
|
+
* The tab reuses the Context conversation-view component VERBATIM: the
|
|
8728
|
+
* `sidebar.right.pane.tab` seat is session-scoped and delivers the same
|
|
8729
|
+
* framework standard kit (`sessionId`, `useProjection`, `useChat`, the locale
|
|
8730
|
+
* `t` seat) the `conversation.view` seat does, so the panel and the tab are
|
|
8731
|
+
* one component with one data path. The tab type contributes a guide entry, so
|
|
8732
|
+
* the sidebar's guide page offers "Context" and picking it opens the panel —
|
|
8733
|
+
* the product's own path, exactly as the shipped Files type does: a capsule of
|
|
8734
|
+
* glyph + title.
|
|
8735
|
+
*
|
|
8736
|
+
* OPTIONAL BY CONTRACT. `ctx.sidebarRightTabs` and the seat ship only on the
|
|
8737
|
+
* 0.1.5 line (0.1.5-alpha.2+ supported); the registration therefore rides a
|
|
8738
|
+
* DEFERRED inject (the plugin's hard injects stay `slots` + `locale`), so on
|
|
8739
|
+
* every older supported line the callback never fires, the plugin fiber never
|
|
8740
|
+
* pends, and nothing is registered. The registry is re-proved structurally and
|
|
8741
|
+
* the whole registration is guarded: a foreign or hostile registry (a throwing
|
|
8742
|
+
* `register`, a taken id/kind) leaves the sidebar without the tab instead of
|
|
8743
|
+
* taking the browser down.
|
|
8744
|
+
*
|
|
8745
|
+
* @module dsh-context/client/sidebar
|
|
8746
|
+
*/
|
|
8747
|
+
/** The tab type's identity in the sidebar's tab system (also its body-seat key). */
|
|
8748
|
+
const SIDEBAR_CONTEXT_ID = "dsh-context";
|
|
8749
|
+
/**
|
|
8750
|
+
* The kind `openTab` names. Namespaced rather than the bare `context`: the
|
|
8751
|
+
* registry THROWS when a kind collides with another registration in a
|
|
8752
|
+
* non-coexisting band, and a foreign plugin may well own `context`.
|
|
8753
|
+
*/
|
|
8754
|
+
const SIDEBAR_CONTEXT_KIND = "dsh-context";
|
|
8755
|
+
/** The guide capsule's position: after the shipped Files entry (order 10). */
|
|
8756
|
+
const GUIDE_ORDER = 20;
|
|
8757
|
+
/**
|
|
8758
|
+
* The guide capsule's glyph, read defensively: the icon is OPTIONAL in the
|
|
8759
|
+
* entry, and a primitives module that does not serve it — or whose namespace
|
|
8760
|
+
* THROWS on the read (an interop/mock shape does exactly that) — must cost the
|
|
8761
|
+
* glyph, never the whole tab.
|
|
8762
|
+
* @returns the icon component, or undefined to register the tab without one.
|
|
8763
|
+
*/
|
|
8764
|
+
function guideIcon() {
|
|
8765
|
+
try {
|
|
8766
|
+
return _deepseek_ai_dsh_client_ui_primitives.IconContextInjectionOutline16;
|
|
8767
|
+
} catch {
|
|
8768
|
+
return;
|
|
8769
|
+
}
|
|
8770
|
+
}
|
|
8771
|
+
/**
|
|
8772
|
+
* Register the Context tab type and its body on the right Sidebar, if — and
|
|
8773
|
+
* only if — this harness serves the sidebar tab registry.
|
|
8774
|
+
* @param ctx - client root context carrying `slots` and the locale service.
|
|
8775
|
+
* @param view - the Context view component factory result (the same one the
|
|
8776
|
+
* conversation tab mounts).
|
|
8777
|
+
* @param t - the plugin-namespace translate; the label thunks read the active
|
|
8778
|
+
* locale at call time, so a language switch relabels the guide entry.
|
|
8779
|
+
* @param ns - the plugin's locale namespace, put on the body registration so
|
|
8780
|
+
* the framework synthesizes the `t` seat for the panel too.
|
|
8781
|
+
*/
|
|
8782
|
+
function watchSidebarContextTab(ctx, view, t, ns) {
|
|
8783
|
+
ctx.inject(["sidebarRightTabs"], (raw) => {
|
|
8784
|
+
const injected = raw;
|
|
8785
|
+
try {
|
|
8786
|
+
const tabs = injected.sidebarRightTabs;
|
|
8787
|
+
if (tabs === void 0 || typeof tabs.register !== "function") return;
|
|
8788
|
+
const disposeType = tabs.register({
|
|
8789
|
+
id: SIDEBAR_CONTEXT_ID,
|
|
8790
|
+
kind: SIDEBAR_CONTEXT_KIND,
|
|
8791
|
+
title: () => t("tab"),
|
|
8792
|
+
guide: [{
|
|
8793
|
+
order: GUIDE_ORDER,
|
|
8794
|
+
title: () => t("tab"),
|
|
8795
|
+
icon: guideIcon()
|
|
8796
|
+
}]
|
|
8797
|
+
});
|
|
8798
|
+
const disposeBody = injected.slots.inject("sidebar.right.pane.tab", () => injected.slots.register({
|
|
8799
|
+
name: "sidebar.right.pane.tab",
|
|
8800
|
+
key: SIDEBAR_CONTEXT_ID,
|
|
8801
|
+
locale: ns
|
|
8802
|
+
}, (props) => view({
|
|
8803
|
+
...props,
|
|
8804
|
+
host: "sidebar"
|
|
8805
|
+
})));
|
|
8806
|
+
return () => {
|
|
8807
|
+
disposeType();
|
|
8808
|
+
if (typeof disposeBody === "function") disposeBody();
|
|
8809
|
+
};
|
|
8810
|
+
} catch {
|
|
8811
|
+
return;
|
|
8812
|
+
}
|
|
8813
|
+
});
|
|
8814
|
+
}
|
|
8815
|
+
//#endregion
|
|
8563
8816
|
//#region src/client/viewkit.ts
|
|
8564
8817
|
function makeViewKit(t) {
|
|
8565
8818
|
const { eventLabel, eventAt } = makeEventText(t);
|
|
@@ -8576,7 +8829,7 @@ window.__ModuleLoader__.load({
|
|
|
8576
8829
|
}
|
|
8577
8830
|
//#endregion
|
|
8578
8831
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/base.css.mjs
|
|
8579
|
-
const css$13 = ".lc-root{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-primary);padding:16px 20px 32px;font-size:13px;overflow-y:auto}.lc-card{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;margin-bottom:14px;padding:14px 16px}.lc-root .lc-card{margin-bottom:7px;padding:7px 8px;container:lc-card/inline-size}.lc-root .lc-cols{gap:7px;margin-bottom:7px}.lc-card-title{flex-wrap:wrap;align-items:baseline;gap:8px;margin-bottom:10px;font-weight:600;display:flex}.lc-card-title-text{white-space:nowrap;flex:none}.lc-gran,.lc-kinds{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;gap:2px;margin-left:auto;padding:1px;display:flex}.lc-trend-ctl{align-items:center;gap:6px;margin-left:auto;display:flex}.lc-trend-ctl .lc-gran{margin-left:0}.lc-trend-adaptive{flex:none;margin-left:0}.lc-gran-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;border-radius:5px;padding:3px 8px;font-family:inherit;font-size:11px;line-height:1}.lc-gran-btn:hover{color:var(--dsw-alias-label-primary)}.lc-gran-on,.lc-gran-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-tip{z-index:6;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv3,0 2px 8px #0000002e);pointer-events:none;opacity:0;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;padding:6px 10px;font-size:12px;position:absolute}.lc-events,.lc-fa-list{flex-direction:column;gap:2px;height:320px;display:flex;overflow-y:auto}.lc-cols{flex-wrap:wrap;gap:14px;margin-bottom:14px;display:flex}.lc-col{flex:1;min-width:min(
|
|
8832
|
+
const css$13 = ".lc-root{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-primary);padding:16px 20px 32px;font-size:13px;overflow-y:auto}[data-sidebar-right-open] .lc-root,[data-sidebar-right-float-host] .lc-root{height:auto;padding:12px;overflow:visible}.lc-card{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;margin-bottom:14px;padding:14px 16px}.lc-root .lc-card{margin-bottom:7px;padding:7px 8px;container:lc-card/inline-size}.lc-root .lc-cols{gap:7px;margin-bottom:7px}.lc-card-title{flex-wrap:wrap;align-items:baseline;gap:8px;margin-bottom:10px;font-weight:600;display:flex}.lc-card-title-text{white-space:nowrap;flex:none}.lc-gran,.lc-kinds{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;gap:2px;margin-left:auto;padding:1px;display:flex}.lc-trend-ctl{align-items:center;gap:6px;margin-left:auto;display:flex}.lc-trend-ctl .lc-gran{margin-left:0}.lc-trend-adaptive{flex:none;margin-left:0}.lc-gran-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;border-radius:5px;padding:3px 8px;font-family:inherit;font-size:11px;line-height:1}.lc-gran-btn:hover{color:var(--dsw-alias-label-primary)}.lc-gran-on,.lc-gran-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-tip{z-index:6;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv3,0 2px 8px #0000002e);pointer-events:none;opacity:0;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;padding:6px 10px;font-size:12px;position:absolute}.lc-events,.lc-fa-list{flex-direction:column;gap:2px;height:320px;display:flex;overflow-y:auto}.lc-cols{flex-wrap:wrap;gap:14px;margin-bottom:14px;display:flex}.lc-col{flex:1;min-width:min(360px,100%)}.lc-cols>.lc-card,.lc-col>.lc-card:last-child{margin-bottom:0}.lc-col-browser{flex-direction:column;display:flex}.lc-col-browser>.lc-card{flex:1}.lc-head{container:lc-head-row/inline-size}.lc-head>.lc-card{flex:1 1 0;min-width:0}@container lc-head-row (width<=1045px){.lc-head>.lc-card{flex-basis:40%}}@container lc-head-row (width<=480px){.lc-head>.lc-card{flex-basis:100%}}.lc-head>.lc-card:first-child{flex-direction:column;display:flex}.lc-head>.lc-card:first-child .lc-stats{flex:1;align-content:stretch}.lc-head>.lc-card:first-child .lc-stat{justify-content:center}.lc-empty{color:var(--dsw-alias-label-secondary);text-align:center;padding:18px 0}.lc-error{flex-direction:column;align-items:center;gap:8px;padding:40px 16px;display:flex}.lc-error-msg{font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, monospace);color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);overflow-wrap:anywhere;border-radius:6px;max-width:100%;padding:4px 8px;font-size:12px}.lc-error-retry{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;padding:4px 14px;font-size:12px}.lc-error-retry:hover{border-color:var(--dsw-alias-label-primary)}.lc-foot{color:var(--dsw-alias-label-secondary);margin-top:4px;font-size:12px}[data-conversation-scroll]:has(.lc-root)>[data-composer-seat]:not(:has([data-approval-key],[data-question-key],[data-plan-review-key])),[data-conversation-scroll]:has(.lc-root,.lc-modal-backdrop)~[data-width-handle]{display:none}";
|
|
8580
8833
|
const tagId$13 = "dsh-context/base.css";
|
|
8581
8834
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$13) + "]") === null) {
|
|
8582
8835
|
const tag = document.createElement("style");
|
|
@@ -8631,7 +8884,7 @@ window.__ModuleLoader__.load({
|
|
|
8631
8884
|
}
|
|
8632
8885
|
//#endregion
|
|
8633
8886
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/trendChart.css.mjs
|
|
8634
|
-
const css$8 = ".lc-chartrow{align-items:stretch;gap:6px;display:flex}.lc-axis{box-sizing:border-box;width:40px;height:150px;color:var(--dsw-alias-label-secondary);padding-top:18px;font-size:11px;position:relative}.lc-axis span{line-height:1;position:absolute;right:0}.lc-axis-top{top:13px}.lc-axis-q3{top:41px}.lc-axis-mid{top:69px}.lc-axis-q1{top:97px}.lc-axis-bot{top:125px}.lc-chart-wrap{flex:1;min-width:0;position:relative}.lc-chart-scroll{overscroll-behavior-x:contain;scrollbar-gutter:stable;padding-bottom:var(--dsh-scrollbar-width,8px);overflow:auto hidden}.lc-chart{box-sizing:border-box;align-items:flex-end;gap:2px;width:max-content;min-width:100%;height:130px;padding-top:18px;display:flex;position:relative}.lc-grid{border-top:1px dashed var(--dsw-alias-border-l2);pointer-events:none;position:absolute;left:0;right:0}.lc-grid-top{top:18px}.lc-grid-q3{top:46px}.lc-grid-mid{top:74px}.lc-grid-q1{top:102px}.lc-grid-zero{border-top-style:solid;border-top-color:#80808080;top:130px}.lc-bar{cursor:pointer;outline-offset:1px;width:14px;height:100%;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), outline-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:2px;outline:1px dashed #0000;flex:none;align-items:flex-end;display:flex;position:relative}.lc-chart-dim .lc-bar{opacity:.35}.lc-chart-dim .lc-bar-in-turn{opacity:1}.lc-chart-dim .lc-turn{opacity:.35}.lc-chart-dim .lc-turn-on{opacity:1}.lc-chart-tip{z-index:5;box-sizing:border-box;overflow-wrap:break-word;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);max-width:100%;color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;flex-direction:column;gap:2px;padding:3px 8px;font-size:12px;display:flex;position:absolute;bottom:calc(100% + 4px);left:0;box-shadow:0 2px 8px #0000002e}.lc-bar:hover{background:var(--dsw-alias-bg-layer-2)}.lc-bar-hovered{outline-color:var(--dsw-alias-brand-primary)}.lc-bar-selected{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.lc-bar-in-turn{background:#80808024}.lc-bar-stack{flex-direction:column-reverse;width:100%;display:flex}.lc-bar-stack>div{width:100%}.lc-bar-up,.lc-bar-down{width:100%;display:flex;position:absolute;left:0}.lc-bar-up{flex-direction:column-reverse}.lc-bar-down{flex-direction:column}.lc-bar-up>div,.lc-bar-down>div{width:100%}.lc-cat-seg{transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.lc-chart[data-catdim] .lc-cat-seg{opacity:.35}.lc-chart[data-catdim=system] .lc-cat-seg[data-cat=system],.lc-chart[data-catdim=tools] .lc-cat-seg[data-cat=tools],.lc-chart[data-catdim=user] .lc-cat-seg[data-cat=user],.lc-chart[data-catdim=inject] .lc-cat-seg[data-cat=inject],.lc-chart[data-catdim=assistant] .lc-cat-seg[data-cat=assistant],.lc-chart[data-catdim=tool] .lc-cat-seg[data-cat=tool]{opacity:1;filter:brightness(1.18)}.lc-bar-marker{color:var(--dsw-alias-state-warn-primary);font-size:11px;position:absolute;top:-16px;left:50%;transform:translate(-50%)}.lc-turns{gap:2px;width:max-content;min-width:100%;margin-top:4px;display:flex;overflow:hidden}.lc-turn{box-sizing:border-box;text-align:center;color:var(--dsw-alias-label-secondary);white-space:nowrap;cursor:pointer;height:14px;transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:3px;flex:none;font-size:10px;font-weight:600;line-height:14px}.lc-turn-on{filter:brightness(1.35);color:var(--dsw-alias-label-primary)}.lc-turn-label{display:inline-block}";
|
|
8887
|
+
const css$8 = ".lc-chartrow{align-items:stretch;gap:6px;display:flex}.lc-axis{box-sizing:border-box;width:40px;height:150px;color:var(--dsw-alias-label-secondary);padding-top:18px;font-size:11px;position:relative}.lc-axis span{line-height:1;position:absolute;right:0}.lc-axis-top{top:13px}.lc-axis-q3{top:41px}.lc-axis-mid{top:69px}.lc-axis-q1{top:97px}.lc-axis-bot{top:125px}.lc-chart-wrap{flex:1;min-width:0;position:relative}.lc-chart-scroll{overscroll-behavior-x:contain;scrollbar-gutter:stable;padding-bottom:var(--dsh-scrollbar-width,8px);overflow:auto hidden}.lc-chart{box-sizing:border-box;align-items:flex-end;gap:2px;width:max-content;min-width:100%;height:130px;padding-top:18px;display:flex;position:relative}.lc-grid{border-top:1px dashed var(--dsw-alias-border-l2);pointer-events:none;position:absolute;left:0;right:0}.lc-grid-top{top:18px}.lc-grid-q3{top:46px}.lc-grid-mid{top:74px}.lc-grid-q1{top:102px}.lc-grid-zero{border-top-style:solid;border-top-color:#80808080;top:130px}.lc-bar{cursor:pointer;outline-offset:1px;width:14px;height:100%;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), outline-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:2px;outline:1px dashed #0000;flex:none;align-items:flex-end;display:flex;position:relative}.lc-chart-dim .lc-bar{opacity:.35}.lc-chart-dim .lc-bar-in-turn{opacity:1}.lc-chart-dim .lc-turn{opacity:.35}.lc-chart-dim .lc-turn-on{opacity:1}.lc-chart-tip{z-index:5;box-sizing:border-box;overflow-wrap:break-word;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);max-width:100%;color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;flex-direction:column;gap:2px;padding:3px 8px;font-size:12px;display:flex;position:absolute;bottom:calc(100% + 4px);left:0;box-shadow:0 2px 8px #0000002e}.lc-bar:hover{background:var(--dsw-alias-bg-layer-2)}.lc-bar-hovered{outline-color:var(--dsw-alias-brand-primary)}.lc-bar-selected{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.lc-bar-in-turn{background:#80808024}.lc-bar-stack{flex-direction:column-reverse;width:100%;display:flex}.lc-bar-stack>div{width:100%}.lc-bar-stack>div:first-child{border-radius:0 0 2px 2px}.lc-bar-stack>div:last-child{border-radius:2px 2px 0 0}.lc-bar-stack>div:only-child{border-radius:2px}.lc-bar-up,.lc-bar-down{width:100%;display:flex;position:absolute;left:0}.lc-bar-up{flex-direction:column-reverse}.lc-bar-down{flex-direction:column}.lc-bar-up>div,.lc-bar-down>div{width:100%}.lc-bar-up>div:last-child{border-radius:2px 2px 0 0}.lc-bar-down>div:last-child{border-radius:0 0 2px 2px}.lc-cat-seg{transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.lc-chart[data-catdim] .lc-cat-seg{opacity:.35}.lc-chart[data-catdim=system] .lc-cat-seg[data-cat=system],.lc-chart[data-catdim=tools] .lc-cat-seg[data-cat=tools],.lc-chart[data-catdim=user] .lc-cat-seg[data-cat=user],.lc-chart[data-catdim=inject] .lc-cat-seg[data-cat=inject],.lc-chart[data-catdim=assistant] .lc-cat-seg[data-cat=assistant],.lc-chart[data-catdim=tool] .lc-cat-seg[data-cat=tool]{opacity:1;filter:brightness(1.18)}.lc-bar-marker{color:var(--dsw-alias-state-warn-primary);font-size:11px;position:absolute;top:-16px;left:50%;transform:translate(-50%)}.lc-turns{gap:2px;width:max-content;min-width:100%;margin-top:4px;display:flex;overflow:hidden}.lc-turn{box-sizing:border-box;text-align:center;color:var(--dsw-alias-label-secondary);white-space:nowrap;cursor:pointer;height:14px;transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:3px;flex:none;font-size:10px;font-weight:600;line-height:14px}.lc-turn-on{filter:brightness(1.35);color:var(--dsw-alias-label-primary)}.lc-turn-label{display:inline-block}";
|
|
8635
8888
|
const tagId$8 = "dsh-context/trendChart.css";
|
|
8636
8889
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$8) + "]") === null) {
|
|
8637
8890
|
const tag = document.createElement("style");
|
|
@@ -8686,7 +8939,7 @@ window.__ModuleLoader__.load({
|
|
|
8686
8939
|
}
|
|
8687
8940
|
//#endregion
|
|
8688
8941
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/browser.css.mjs
|
|
8689
|
-
const css$3 = ".lc-br-dna-ctl{flex:none;margin-left:0}.lc-br-bar-dna .lc-stacked-seg{
|
|
8942
|
+
const css$3 = ".lc-br-dna-ctl{flex:none;margin-left:0}.lc-br-bar-dna .lc-stacked-seg{background-image:linear-gradient(to right, transparent calc(100% - min(1px, 25%)), var(--dsw-alias-bg-layer-1) 0)}.lc-br-hint{color:var(--dsw-alias-label-secondary);white-space:nowrap;margin-left:auto;font-size:11px;font-weight:400}.lc-br-pick{font:inherit;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;max-width:240px;padding:3px 6px;font-size:12px}.lc-br-meta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:6px 16px;margin-bottom:8px;display:flex}.lc-br-meta b{color:var(--dsw-alias-label-primary)}.lc-br-meta .lc-actual{color:var(--dsw-alias-state-success-primary)}.lc-br-note{color:var(--dsw-alias-label-secondary);margin-top:8px;font-size:12px}.lc-br-retry{color:var(--dsw-alias-brand-primary);font:inherit;cursor:pointer;text-underline-offset:2px;transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;padding:0;font-size:12px;text-decoration:underline}.lc-br-retry:hover{filter:brightness(1.15)}.lc-br-cats{flex-direction:column;gap:4px;margin-top:10px;display:flex}.lc-br-cat{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:8px;overflow:hidden}.lc-br-cat-empty{opacity:.55}.lc-br-cat-row{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;transition:background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;align-items:center;gap:8px;padding:7px 10px;display:flex}.lc-br-cat-row:hover,.lc-br-cat-on{background:var(--dsw-alias-interactive-bg-hover)}.lc-br-cat-on i{box-shadow:0 0 0 1px var(--dsw-alias-brand-primary)}.lc-br-cat-row i{width:8px;height:8px;transition:box-shadow var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:2px;flex:none;display:inline-block}.lc-br-cat-label{font-weight:600}.lc-br-cat-count{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:12px}.lc-br-count-grp{flex:1;align-items:center;gap:4px;min-width:0;display:inline-flex}.lc-br-chev{width:12px;height:14px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:flex}.lc-br-chev:before{content:\"\";width:5px;height:5px;transition:transform var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-bottom:1px solid;border-right:1px solid;transform:rotate(-45deg)}.lc-br-chev-on:before{transform:rotate(45deg)}.lc-br-tokens{color:var(--dsw-alias-label-secondary);flex:none;font-size:12px}.lc-br-delta,.lc-br-tdelta{white-space:nowrap;border-radius:4px;flex:none;padding:0 5px;font-size:11px;font-weight:600}.lc-br-delta-up,.lc-br-tdelta-up{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent)}.lc-br-delta-down,.lc-br-tdelta-down{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 15%, transparent)}.lc-br-tokens-grp{flex:none;align-items:center;gap:4px;min-width:0;display:inline-flex}.lc-br-pct{text-align:right;width:36px;color:var(--dsw-alias-label-secondary);flex:none;font-size:12px}.lc-br-body{border-top:1px solid var(--dsw-alias-border-l1);flex-direction:column;gap:2px;padding:4px 6px;display:flex}.lc-br-elem{border-radius:6px}.lc-br-elem-on{background:var(--dsw-alias-interactive-bg-active)}.lc-br-elem-row{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;transition:background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;border-radius:6px;align-items:center;gap:8px;padding:5px 6px;font-size:12px;display:flex}.lc-br-elem-row:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-br-err-dot{background:var(--dsw-alias-state-error-primary);width:6px;height:6px;box-shadow:0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);border-radius:50%;flex:none}.lc-br-tag{min-width:0;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);text-overflow:ellipsis;white-space:nowrap;border-radius:4px;max-width:220px;padding:0 6px;font-size:11px;overflow:hidden}.lc-br-tool-plugin{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent);border-color:#0000;border-radius:6px;font-size:12px}.lc-br-preview{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.lc-br-time{color:var(--dsw-alias-label-secondary);flex:none;font-size:11px}.lc-br-content{flex-direction:column;gap:6px;padding:2px 6px 8px 26px;display:flex}.lc-br-dim{color:var(--dsw-alias-label-secondary)}";
|
|
8690
8943
|
const tagId$3 = "dsh-context/browser.css";
|
|
8691
8944
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
|
|
8692
8945
|
const tag = document.createElement("style");
|
|
@@ -8775,6 +9028,7 @@ window.__ModuleLoader__.load({
|
|
|
8775
9028
|
label: () => t("tab")
|
|
8776
9029
|
}, (props) => (0, react.createElement)(ContextView, props));
|
|
8777
9030
|
});
|
|
9031
|
+
watchSidebarContextTab(ctx, ContextView, t, NS);
|
|
8778
9032
|
const ContextJump = makeContextJumpButton(kit);
|
|
8779
9033
|
ctx.slots.inject("conversation.chat.assistant-actions", () => {
|
|
8780
9034
|
return ctx.slots.register({
|