@dan-ai-studio/dshopencodego 0.1.65 → 0.1.67
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.en.md +8 -5
- package/README.md +8 -5
- package/lib/client.js +372 -220
- package/lib/index.js +16 -11
- package/lib/types/config.d.ts +7 -6
- package/lib/types/request-log/store.d.ts +23 -15
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -115,8 +115,8 @@ Configuration lives in the profile's `cordis.patch.yml`:
|
|
|
115
115
|
some-new-model: openai-responses # the only legal values are anthropic-messages / openai-completions / openai-responses
|
|
116
116
|
pinnedAddresses: # fixed IP: host -> address (only the gateway host counts)
|
|
117
117
|
opencode.ai: 104.18.32.47 # IPv4 or IPv6; an invalid or absent address uses the system DNS
|
|
118
|
-
requestLogEnabled:
|
|
119
|
-
requestLogDebug: false # debug detail: pool events and
|
|
118
|
+
requestLogEnabled: true # request-log master switch, default on: off reads byte-for-byte as without the log
|
|
119
|
+
requestLogDebug: false # debug detail: pool events and the request user agent; session ids are always whole
|
|
120
120
|
requestLogMaxEntries: 200 # most entries to keep, 50 to 500; oldest are dropped first
|
|
121
121
|
retryPolicy: # optional: this route's retry policy, executed by dsh-llm-retry
|
|
122
122
|
mode: normal # or always (retry every failure; maxRetries is ignored)
|
|
@@ -141,13 +141,16 @@ The API key comes from the Harness credential store (reference name `OPENCODE_GO
|
|
|
141
141
|
- The settings page shows and accepts the value in **seconds** (a number of milliseconds is not readable at a glance) and stores it in milliseconds. Range: 1 to 1800000 milliseconds.
|
|
142
142
|
- Once a connection has been idle that long, the pool **reclaims it** on its own — no separate mechanism is needed. The actual release comes a couple of seconds later than the setting, which is the client's own small margin beyond the deadline the server states. When the plugin is unloaded, the pool is **closed with it**: the pool belongs to the plugin and should not be left behind on the machine.
|
|
143
143
|
|
|
144
|
-
**Request log**: per-request records,
|
|
144
|
+
**Request log**: per-request records, on by default; turning them off returns the request path to exactly as without the log. The settings page's "Request log" group holds the master switch, the debug switch (pool events and the request user agent, default off), and the retention count (default 200).
|
|
145
145
|
|
|
146
146
|
- **Two entries, one page**:
|
|
147
147
|
- **A sidebar icon → a full page in the main column**: every request across sessions. The log is a process-wide thing, so the sidebar is where it belongs — a fixed, always-visible spot, and the same pattern the Harness's own plugin manager uses.
|
|
148
148
|
- **A "Request log" View inside the conversation**: this session's requests, in place — answering "why was that turn slow" without leaving the chat.
|
|
149
|
-
- It is a page, not a floating card: the head, the summary (requests / failures / mean latency / mean first token / mean tok/s / connection reuse) and the filters stay put while the table scrolls. Each row carries time, model, session, input/output/cache, **tok/s**, first token, latency and status; clicking one expands its HTTP detail (method, URL, redacted headers, request shape, result and usage). Filters: model, result, slow requests, session; groups: session, model, result.
|
|
150
|
-
- **tok/s** is the output rate over the decode window (first token to the end), on the same scale as the Harness's own per-turn reading (reasoning tokens included). A request that produced no token has no rate — none is invented.
|
|
149
|
+
- It is a page, not a floating card: the head, the summary (requests / failures / mean latency / mean first token / mean tok/s / mean cache hit / connection reuse) and the filters stay put while the table scrolls. Each row carries time, model, session, input/output/cache, **cache hit**, **tok/s**, first token, latency and status; clicking one expands its HTTP detail (method, URL, redacted headers, request shape, result and usage). Filters: model, result, slow requests, session; groups: session, model, result; **click a column head to sort by it**, click again to flip.
|
|
150
|
+
- **tok/s** is the output rate over the decode window (first token to the end), on the same scale as the Harness's own per-turn reading (reasoning tokens included). A request that produced no token has no rate — none is invented. **A burst delivery has no rate either**: when the gateway holds a whole turn and flushes it at the end (common with reasoning models: 8 seconds of thinking invisible on the wire, then a hundred tokens in a few milliseconds), a sub-100ms content span is delivery shape, not generation speed — it shows as — and stays out of the mean.
|
|
151
|
+
- The session column names the **session title** (from the session catalog; falls back to the id, whose full spelling stays one hover away). The session filter matches titles and ids; session groups are headed the same way.
|
|
152
|
+
- **Cache hit** is the share of input tokens served from cache (cache reads over uncached input plus cache reads). No reported input means no share — none is invented either.
|
|
153
|
+
- Session ids are **always stored whole**: an id is a conversation identity, not a credential, and a truncated one reads two conversations as one.
|
|
151
154
|
- The log is a ring buffer (oldest dropped first) that dies with the process; snapshots are read on demand, never polled, so a page nobody opens costs no traffic.
|
|
152
155
|
- The credential never enters a record: the recorder takes no headers argument at all, only the allowlisted session id and user agent. Failed requests are recorded with their error code; a request cut off before any terminal event is not recorded — no total reported, none invented.
|
|
153
156
|
|
package/README.md
CHANGED
|
@@ -114,8 +114,8 @@ DSH 桌面端是 Electron 壳 + 完整的 dsh Web 应用,本插件对它同样
|
|
|
114
114
|
some-new-model: openai-responses # 合法值只有 anthropic-messages / openai-completions / openai-responses
|
|
115
115
|
pinnedAddresses: # 固定 IP:域名 → 地址(只对网关域名生效)
|
|
116
116
|
opencode.ai: 104.18.32.47 # 可写 IPv4 或 IPv6;不合法或未设置时走系统 DNS
|
|
117
|
-
requestLogEnabled:
|
|
118
|
-
requestLogDebug: false #
|
|
117
|
+
requestLogEnabled: true # 请求日志总开关,默认开启:关闭后请求路径与没有该日志逐字节一致
|
|
118
|
+
requestLogDebug: false # 排错详情:连接池事件与请求 UA;会话 id 始终完整记录
|
|
119
119
|
requestLogMaxEntries: 200 # 最多保留条数,50 ~ 500,超限丢弃最旧的
|
|
120
120
|
retryPolicy: # 可选:本路由的重试策略(由 dsh-llm-retry 执行)
|
|
121
121
|
mode: normal # 也可用 always(对所有失败重试,maxRetries 被忽略)
|
|
@@ -140,13 +140,16 @@ API Key 通过 Harness 凭证库提供(引用名 `OPENCODE_GO_API_KEY`),
|
|
|
140
140
|
- 设置页里以**秒**显示与填写(毫秒的数字人读不出量级),存储时换算成毫秒。取值 1 ~ 1800000 毫秒。
|
|
141
141
|
- 空闲满这个时间之后,连接由连接池**自己回收**,不需要额外的清理机制(实际释放时间比设置值多约 2 秒,那是客户端在服务端给的期限之外自留的一点缓冲)。插件被卸载时,连接池也会**一并关掉**——它是插件的,不该留在机器上。
|
|
142
142
|
|
|
143
|
-
|
|
143
|
+
**请求日志**:默认开启的逐请求记录,关掉它请求路径与没有该日志逐字节一致。设置页"请求日志"分组里有总开关、排错详情开关(连接池事件与请求 UA,默认关闭)、保留条数(默认 200)。
|
|
144
144
|
|
|
145
145
|
- **两个入口,同一个页面**:
|
|
146
146
|
- **侧边栏图标 → 主区域整页**:跨会话看全部请求。日志是进程级的数据,放在侧边栏最合理——位置固定、常驻可见,和 DSH 自己的插件管理器同一个范式。
|
|
147
147
|
- **会话里的「请求日志」标签页**:就地看**本会话**的请求,回答"刚才那轮为什么慢"不用离开对话。
|
|
148
|
-
- 页面是一整页而不是浮层:标题、统计(请求数/失败数/平均耗时/平均首字/平均 tok/s
|
|
149
|
-
- **tok/s** 是**首字到结束**这段解码窗口上的输出速率,口径与 Harness 自己的每轮读数一致(含推理 token)。没有 token
|
|
148
|
+
- 页面是一整页而不是浮层:标题、统计(请求数/失败数/平均耗时/平均首字/平均 tok/s/平均缓存命中/连接复用率)、筛选栏固定在上方,只有表格自己滚动。每行含时间、模型、会话、输入/输出/缓存、**缓存命中**、**tok/s**、首字、耗时与状态;点一行展开 HTTP 明细(方法、地址、脱敏后的请求头、请求构成、结果与用量)。筛选有模型/结果/慢请求/会话,分组有会话/模型/结果;**点列头按该列排序**,再点一次反向。
|
|
149
|
+
- **tok/s** 是**首字到结束**这段解码窗口上的输出速率,口径与 Harness 自己的每轮读数一致(含推理 token)。没有 token 的请求没有速率——不编数。**突发推送同样没有速率**:网关把一整轮攒到最后一次性推过来时(推理模型常见:8 秒思考在 wire 上不可见,然后上百个 token 几毫秒内到达),内容跨度不足 100ms,算出来的"每秒几万 token"不是生成速度——显示为 —,也不计入平均。
|
|
150
|
+
- 会话列显示**会话标题**(标题来自会话目录;拿不到时回退显示 id,悬停可见完整 id)。会话筛选同时匹配标题与 id;按会话分组的组头同样显示标题。
|
|
151
|
+
- **缓存命中**是输入 token 里走缓存的占比(缓存读取/(未缓存输入+缓存读取))。网关没报输入就没有占比——同样不编数。
|
|
152
|
+
- 会话 id **始终完整记录**(它是会话身份,不是凭据;截断后两个会话会读成一个)。
|
|
150
153
|
- 记录的是环形缓冲(超限丢最旧),进程重启即清;只读快照,不轮询,没人打开的页面零流量。
|
|
151
154
|
- 凭据永远不进记录:记录器根本不接收请求头参数,只收白名单里的会话 id 与 UA;失败的请求同样记一条(含错误码),中断到没有终端事件的不记(网关没报总数就不编数)。
|
|
152
155
|
|
package/lib/client.js
CHANGED
|
@@ -498,14 +498,15 @@ var en = {
|
|
|
498
498
|
keepAliveLabel: "Connection kept idle (seconds)",
|
|
499
499
|
keepAliveHint: "How long a connection to the gateway is held between requests. Longer pauses in a conversation cost one handshake each; the timer restarts on every answer.",
|
|
500
500
|
requestLogTitle: "Request log",
|
|
501
|
-
requestLogHint: "Per-request records for troubleshooting.
|
|
502
|
-
requestLogPageHint: "One row per request.
|
|
501
|
+
requestLogHint: "Per-request records for troubleshooting. On by default; turning it off returns the request path to exactly as without the log.",
|
|
502
|
+
requestLogPageHint: "One row per request. Click a column head to sort; the table scrolls and the filters stay put.",
|
|
503
503
|
requestLogEnabled: "Record requests",
|
|
504
504
|
requestLogDebug: "Debug detail",
|
|
505
|
-
requestLogDebugHint: "Pool events and
|
|
505
|
+
requestLogDebugHint: "Pool events and the request user agent.",
|
|
506
506
|
requestLogMaxEntries: "Keep at most (entries)",
|
|
507
507
|
requestLogMaxEntriesHint: "50 to 500; oldest entries are dropped first. Default 200.",
|
|
508
508
|
requestLogOpen: "Open request log",
|
|
509
|
+
requestLogOpenFailed: "The request-log page could not be opened. Use the sidebar entry.",
|
|
509
510
|
requestLogClose: "Close",
|
|
510
511
|
requestLogRefresh: "Refresh",
|
|
511
512
|
requestLogEmpty: "No requests recorded. Turn the log on, then make a request.",
|
|
@@ -537,6 +538,7 @@ var en = {
|
|
|
537
538
|
requestLogColIn: "In",
|
|
538
539
|
requestLogColOut: "Out",
|
|
539
540
|
requestLogColCache: "Cached",
|
|
541
|
+
requestLogColCacheRate: "Cache hit",
|
|
540
542
|
requestLogColLatency: "Latency",
|
|
541
543
|
requestLogColTps: "tok/s",
|
|
542
544
|
requestLogColFirstToken: "First token",
|
|
@@ -561,6 +563,8 @@ var en = {
|
|
|
561
563
|
requestLogStatLatency: "Mean latency",
|
|
562
564
|
requestLogStatFirstToken: "Mean first token",
|
|
563
565
|
requestLogStatTps: "Mean tok/s",
|
|
566
|
+
requestLogStatCacheRate: "Mean cache hit",
|
|
567
|
+
requestLogOfTotal: "of",
|
|
564
568
|
writeRejected: "The settings write was rejected (the namespace was reloaded) \u2014 try again",
|
|
565
569
|
writeFailed: "The settings write failed",
|
|
566
570
|
filterPlaceholder: "Filter by name or id",
|
|
@@ -674,14 +678,15 @@ var zh = {
|
|
|
674
678
|
keepAliveLabel: "\u8FDE\u63A5\u7A7A\u95F2\u4FDD\u7559\uFF08\u79D2\uFF09",
|
|
675
679
|
keepAliveHint: "\u4E0E\u7F51\u5173\u7684\u8FDE\u63A5\u5728\u4E24\u6B21\u8BF7\u6C42\u4E4B\u95F4\u4FDD\u7559\u591A\u4E45\u3002\u5BF9\u8BDD\u4E2D\u6BCF\u6B21\u505C\u987F\u8F83\u4E45\u90FD\u8981\u91CD\u65B0\u63E1\u624B\u4E00\u6B21\uFF1B\u6BCF\u6B21\u6536\u5230\u56DE\u7B54\u540E\u8BA1\u65F6\u90FD\u4F1A\u91CD\u65B0\u5F00\u59CB\u3002",
|
|
676
680
|
requestLogTitle: "\u8BF7\u6C42\u65E5\u5FD7",
|
|
677
|
-
requestLogHint: "\u6392\u67E5\u7528\u7684\u9010\u8BF7\u6C42\u8BB0\u5F55\u3002\u9ED8\u8BA4\u5173\u95ED\
|
|
678
|
-
requestLogPageHint: "\u6BCF\u4E2A\u8BF7\u6C42\u4E00\u884C\u3002\u8868\u683C\u6EDA\u52A8\uFF0C\u7B5B\u9009\u680F\u56FA\u5B9A\u5728\u4E0A\u65B9\u3002",
|
|
681
|
+
requestLogHint: "\u6392\u67E5\u7528\u7684\u9010\u8BF7\u6C42\u8BB0\u5F55\u3002\u9ED8\u8BA4\u5F00\u542F\uFF1B\u5173\u95ED\u540E\u8BF7\u6C42\u8DEF\u5F84\u4E0E\u6CA1\u6709\u8BE5\u65E5\u5FD7\u9010\u5B57\u8282\u4E00\u81F4\u3002",
|
|
682
|
+
requestLogPageHint: "\u6BCF\u4E2A\u8BF7\u6C42\u4E00\u884C\u3002\u70B9\u5217\u5934\u53EF\u6392\u5E8F\uFF1B\u8868\u683C\u6EDA\u52A8\uFF0C\u7B5B\u9009\u680F\u56FA\u5B9A\u5728\u4E0A\u65B9\u3002",
|
|
679
683
|
requestLogEnabled: "\u8BB0\u5F55\u8BF7\u6C42",
|
|
680
684
|
requestLogDebug: "\u6392\u9519\u8BE6\u60C5",
|
|
681
|
-
requestLogDebugHint: "\u8FDE\u63A5\u6C60\u4E8B\u4EF6\u4E0E\
|
|
685
|
+
requestLogDebugHint: "\u8FDE\u63A5\u6C60\u4E8B\u4EF6\u4E0E\u8BF7\u6C42 UA\u3002",
|
|
682
686
|
requestLogMaxEntries: "\u6700\u591A\u4FDD\u7559\uFF08\u6761\uFF09",
|
|
683
687
|
requestLogMaxEntriesHint: "50\uFF5E500 \u6761\uFF0C\u8D85\u9650\u4E22\u5F03\u6700\u65E7\u7684\u3002\u9ED8\u8BA4 200 \u6761\u3002",
|
|
684
688
|
requestLogOpen: "\u6253\u5F00\u8BF7\u6C42\u65E5\u5FD7",
|
|
689
|
+
requestLogOpenFailed: "\u6253\u4E0D\u5F00\u8BF7\u6C42\u65E5\u5FD7\u9875\u9762\uFF0C\u8BF7\u4ECE\u4FA7\u8FB9\u680F\u7684\u5165\u53E3\u6253\u5F00\u3002",
|
|
685
690
|
requestLogClose: "\u5173\u95ED",
|
|
686
691
|
requestLogRefresh: "\u5237\u65B0",
|
|
687
692
|
requestLogEmpty: "\u6682\u65E0\u8BB0\u5F55\u3002\u5148\u6253\u5F00\u65E5\u5FD7\u5F00\u5173\uFF0C\u518D\u53D1\u8D77\u4E00\u6B21\u8BF7\u6C42\u3002",
|
|
@@ -713,6 +718,7 @@ var zh = {
|
|
|
713
718
|
requestLogColIn: "\u8F93\u5165",
|
|
714
719
|
requestLogColOut: "\u8F93\u51FA",
|
|
715
720
|
requestLogColCache: "\u7F13\u5B58",
|
|
721
|
+
requestLogColCacheRate: "\u7F13\u5B58\u547D\u4E2D",
|
|
716
722
|
requestLogColLatency: "\u8017\u65F6",
|
|
717
723
|
requestLogColTps: "tok/s",
|
|
718
724
|
requestLogColFirstToken: "\u9996\u5B57",
|
|
@@ -737,6 +743,8 @@ var zh = {
|
|
|
737
743
|
requestLogStatLatency: "\u5E73\u5747\u8017\u65F6",
|
|
738
744
|
requestLogStatFirstToken: "\u5E73\u5747\u9996\u5B57",
|
|
739
745
|
requestLogStatTps: "\u5E73\u5747 tok/s",
|
|
746
|
+
requestLogStatCacheRate: "\u5E73\u5747\u7F13\u5B58\u547D\u4E2D",
|
|
747
|
+
requestLogOfTotal: "\u5171",
|
|
740
748
|
writeRejected: "\u8BBE\u7F6E\u5199\u5165\u88AB\u62D2\u7EDD\uFF08\u5DF2\u91CD\u65B0\u8F7D\u5165\uFF09\uFF0C\u8BF7\u91CD\u8BD5",
|
|
741
749
|
writeFailed: "\u8BBE\u7F6E\u5199\u5165\u5931\u8D25",
|
|
742
750
|
filterPlaceholder: "\u6309\u540D\u79F0\u6216 ID \u7B5B\u9009",
|
|
@@ -999,7 +1007,7 @@ function settingsOf(value) {
|
|
|
999
1007
|
refreshMinutes: minutes,
|
|
1000
1008
|
pinnedAddresses: Object.fromEntries(pinEntries),
|
|
1001
1009
|
keepAliveTimeoutMs: typeof keepAlive === "number" ? keepAlive : DEFAULT_KEEP_ALIVE_TIMEOUT_MS,
|
|
1002
|
-
requestLogEnabled: typeof requestLogEnabled === "boolean" ? requestLogEnabled :
|
|
1010
|
+
requestLogEnabled: typeof requestLogEnabled === "boolean" ? requestLogEnabled : true,
|
|
1003
1011
|
requestLogDebug: typeof requestLogDebug === "boolean" ? requestLogDebug : false,
|
|
1004
1012
|
requestLogMaxEntries: typeof requestLogMaxEntries === "number" ? requestLogMaxEntries : DEFAULT_REQUEST_LOG_MAX_ENTRIES
|
|
1005
1013
|
};
|
|
@@ -1623,6 +1631,7 @@ function Section({ controller, t, getLocale, openRequestLog }) {
|
|
|
1623
1631
|
const [keyDraft, setKeyDraft] = (0, import_react.useState)("");
|
|
1624
1632
|
const [pinDraft, setPinDraft] = (0, import_react.useState)("");
|
|
1625
1633
|
const [busy, setBusy] = (0, import_react.useState)(false);
|
|
1634
|
+
const [logOpenFailed, setLogOpenFailed] = (0, import_react.useState)(false);
|
|
1626
1635
|
const act = (0, import_react.useCallback)(async (operation) => {
|
|
1627
1636
|
setBusy(true);
|
|
1628
1637
|
try {
|
|
@@ -1860,7 +1869,7 @@ function Section({ controller, t, getLocale, openRequestLog }) {
|
|
|
1860
1869
|
"input",
|
|
1861
1870
|
{
|
|
1862
1871
|
type: "checkbox",
|
|
1863
|
-
checked: state.settings?.requestLogEnabled ??
|
|
1872
|
+
checked: state.settings?.requestLogEnabled ?? true,
|
|
1864
1873
|
disabled: !editable || state.saving,
|
|
1865
1874
|
onChange: (event) => {
|
|
1866
1875
|
void act(async () => {
|
|
@@ -1911,9 +1920,12 @@ function Section({ controller, t, getLocale, openRequestLog }) {
|
|
|
1911
1920
|
),
|
|
1912
1921
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.hint, children: t("requestLogMaxEntriesHint") })
|
|
1913
1922
|
] }),
|
|
1914
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
1915
|
-
|
|
1916
|
-
|
|
1923
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.row, children: [
|
|
1924
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: section_default.button, onClick: () => {
|
|
1925
|
+
setLogOpenFailed(!(openRequestLog?.() ?? false));
|
|
1926
|
+
}, children: t("requestLogOpen") }),
|
|
1927
|
+
logOpenFailed && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.warn, children: t("requestLogOpenFailed") })
|
|
1928
|
+
] }),
|
|
1917
1929
|
state.writeFailure !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: section_default.warn, children: state.writeFailure.kind === "rejected" ? t("writeRejected") : state.writeFailure.message.length === 0 ? t("writeFailed") : `${t("writeFailed")}: ${state.writeFailure.message}` }),
|
|
1918
1930
|
reading !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.row, children: [
|
|
1919
1931
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -2032,13 +2044,52 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]"
|
|
|
2032
2044
|
const style = document.createElement("style");
|
|
2033
2045
|
style.dataset.plugin = "@dan-ai-studio/dshopencodego";
|
|
2034
2046
|
style.dataset.pluginCss = id2;
|
|
2035
|
-
style.textContent = ".Lx7MOq_page{box-sizing:border-box;background:var(--dsw-alias-bg-base);height:100%;min-height:0;color:var(--dsw-alias-label-primary);flex-direction:column;display:flex
|
|
2047
|
+
style.textContent = ".Lx7MOq_page{box-sizing:border-box;background:var(--dsw-alias-bg-base);height:100%;min-height:0;color:var(--dsw-alias-label-primary);flex-direction:column;display:flex}.Lx7MOq_pageLoose{height:auto}.Lx7MOq_pageLoose .Lx7MOq_tableWrap{overflow:visible}.Lx7MOq_pageLoose .Lx7MOq_stuck{z-index:3;background:var(--dsw-alias-bg-base);position:sticky;top:0}.Lx7MOq_pageLoose .Lx7MOq_table th{top:var(--request-log-stuck,0px)}.Lx7MOq_pageLoose .Lx7MOq_foot{z-index:2;background:var(--dsw-alias-bg-base);position:sticky;bottom:0}.Lx7MOq_head{flex-wrap:wrap;flex:none;align-items:center;gap:12px;padding:20px clamp(16px,3vw,32px) 12px;display:flex}.Lx7MOq_headText{min-width:0}.Lx7MOq_title{margin:0;font-size:20px;font-weight:500;line-height:28px}.Lx7MOq_subtitle{color:var(--dsw-alias-label-secondary);margin:4px 0 0;font-size:13px;line-height:20px}.Lx7MOq_headActions{flex:none;align-items:center;gap:8px;margin-left:auto;display:flex}.Lx7MOq_button{border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-bg-layer-1);height:28px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;align-items:center;gap:6px;padding:0 12px;font-size:13px;display:inline-flex}.Lx7MOq_button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.Lx7MOq_button:disabled{cursor:default;opacity:.5}.Lx7MOq_summary{flex-wrap:wrap;flex:none;gap:8px;padding:0 clamp(16px,3vw,32px) 12px;display:flex}.Lx7MOq_card{border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);flex-direction:column;gap:2px;min-width:104px;padding:8px 12px;display:flex}.Lx7MOq_cardLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:16px}.Lx7MOq_cardValue{font-variant-numeric:tabular-nums;font-size:16px;font-weight:500;line-height:22px}.Lx7MOq_cardError .Lx7MOq_cardValue{color:var(--dsw-alias-state-error-primary)}.Lx7MOq_cardWarn .Lx7MOq_cardValue{color:var(--dsw-alias-state-warn-primary)}.Lx7MOq_toolbar{flex-wrap:wrap;flex:none;align-items:center;gap:8px 12px;padding:0 clamp(16px,3vw,32px) 12px;display:flex}.Lx7MOq_field{color:var(--dsw-alias-label-secondary);align-items:center;gap:6px;font-size:13px;line-height:20px;display:inline-flex}.Lx7MOq_select,.Lx7MOq_input{border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-bg-layer-1);height:28px;color:var(--dsw-alias-label-primary);font:inherit;padding:0 8px;font-size:13px}.Lx7MOq_input{width:160px}.Lx7MOq_inputNumber{width:72px}.Lx7MOq_checkbox{accent-color:var(--dsw-alias-brand-primary)}.Lx7MOq_tableWrap{border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);flex:1;min-height:0;margin:0 clamp(16px,3vw,32px);overflow:auto}.Lx7MOq_table{border-collapse:separate;border-spacing:0;width:100%;min-width:940px;font-size:13px;line-height:20px}.Lx7MOq_table th{z-index:1;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-tertiary);text-align:left;white-space:nowrap;padding:8px 10px;font-size:12px;font-weight:500;position:sticky;top:0}.Lx7MOq_thSortable{cursor:pointer;user-select:none}.Lx7MOq_thSortable:hover{color:var(--dsw-alias-label-primary)}.Lx7MOq_table td{border-bottom:1px solid var(--dsw-alias-border-l1);white-space:nowrap;font-variant-numeric:tabular-nums;padding:6px 10px}.Lx7MOq_table tbody tr:last-child td{border-bottom:none}.Lx7MOq_row{cursor:pointer}.Lx7MOq_row:hover td{background:var(--dsw-alias-interactive-bg-hover)}.Lx7MOq_rowOk td:first-child{box-shadow:inset 3px 0 0 var(--dsw-alias-border-l3)}.Lx7MOq_rowSlow td:first-child{box-shadow:inset 3px 0 0 var(--dsw-alias-state-warn-primary)}.Lx7MOq_rowFail td:first-child{box-shadow:inset 3px 0 0 var(--dsw-alias-state-error-primary)}.Lx7MOq_rowFail td:last-child,.Lx7MOq_rowSlow td:last-child{color:var(--dsw-alias-state-error-primary)}.Lx7MOq_group td{border-bottom:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);padding-top:12px;font-weight:500}.Lx7MOq_detail td{border-bottom:1px solid var(--dsw-alias-border-l1);white-space:normal;background:var(--dsw-alias-bg-layer-2);padding:12px 10px 16px}.Lx7MOq_detailGrid{grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:6px 24px;display:grid}.Lx7MOq_detailItem{gap:8px;min-width:0;font-size:13px;line-height:20px;display:flex}.Lx7MOq_detailLabel{color:var(--dsw-alias-label-tertiary);flex:none}.Lx7MOq_detailValue{overflow-wrap:anywhere;min-width:0;color:var(--dsw-alias-label-primary)}.Lx7MOq_mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px}.Lx7MOq_empty{text-align:center;color:var(--dsw-alias-label-tertiary);padding:48px 16px}.Lx7MOq_foot{color:var(--dsw-alias-label-tertiary);flex-wrap:wrap;flex:none;align-items:center;gap:12px;padding:12px clamp(16px,3vw,32px) 20px;font-size:12px;display:flex}.Lx7MOq_pager{align-items:center;gap:8px;margin-left:auto;display:flex}.Lx7MOq_notice{color:var(--dsw-alias-label-secondary);padding:0 clamp(16px,3vw,32px) 12px;font-size:13px;line-height:20px}.Lx7MOq_noticeError{color:var(--dsw-alias-state-error-primary)}";
|
|
2036
2048
|
document.head.appendChild(style);
|
|
2037
2049
|
}
|
|
2038
|
-
var request_log_default = { "button": "Lx7MOq_button", "card": "Lx7MOq_card", "cardError": "Lx7MOq_cardError", "cardLabel": "Lx7MOq_cardLabel", "cardValue": "Lx7MOq_cardValue", "cardWarn": "Lx7MOq_cardWarn", "checkbox": "Lx7MOq_checkbox", "detail": "Lx7MOq_detail", "detailGrid": "Lx7MOq_detailGrid", "detailItem": "Lx7MOq_detailItem", "detailLabel": "Lx7MOq_detailLabel", "detailValue": "Lx7MOq_detailValue", "empty": "Lx7MOq_empty", "field": "Lx7MOq_field", "foot": "Lx7MOq_foot", "group": "Lx7MOq_group", "head": "Lx7MOq_head", "headActions": "Lx7MOq_headActions", "headText": "Lx7MOq_headText", "input": "Lx7MOq_input", "inputNumber": "Lx7MOq_inputNumber", "mono": "Lx7MOq_mono", "notice": "Lx7MOq_notice", "noticeError": "Lx7MOq_noticeError", "page": "Lx7MOq_page", "pager": "Lx7MOq_pager", "row": "Lx7MOq_row", "rowFail": "Lx7MOq_rowFail", "rowOk": "Lx7MOq_rowOk", "rowSlow": "Lx7MOq_rowSlow", "select": "Lx7MOq_select", "subtitle": "Lx7MOq_subtitle", "summary": "Lx7MOq_summary", "table": "Lx7MOq_table", "tableWrap": "Lx7MOq_tableWrap", "title": "Lx7MOq_title", "toolbar": "Lx7MOq_toolbar" };
|
|
2050
|
+
var request_log_default = { "button": "Lx7MOq_button", "card": "Lx7MOq_card", "cardError": "Lx7MOq_cardError", "cardLabel": "Lx7MOq_cardLabel", "cardValue": "Lx7MOq_cardValue", "cardWarn": "Lx7MOq_cardWarn", "checkbox": "Lx7MOq_checkbox", "detail": "Lx7MOq_detail", "detailGrid": "Lx7MOq_detailGrid", "detailItem": "Lx7MOq_detailItem", "detailLabel": "Lx7MOq_detailLabel", "detailValue": "Lx7MOq_detailValue", "empty": "Lx7MOq_empty", "field": "Lx7MOq_field", "foot": "Lx7MOq_foot", "group": "Lx7MOq_group", "head": "Lx7MOq_head", "headActions": "Lx7MOq_headActions", "headText": "Lx7MOq_headText", "input": "Lx7MOq_input", "inputNumber": "Lx7MOq_inputNumber", "mono": "Lx7MOq_mono", "notice": "Lx7MOq_notice", "noticeError": "Lx7MOq_noticeError", "page": "Lx7MOq_page", "pageLoose": "Lx7MOq_pageLoose", "pager": "Lx7MOq_pager", "row": "Lx7MOq_row", "rowFail": "Lx7MOq_rowFail", "rowOk": "Lx7MOq_rowOk", "rowSlow": "Lx7MOq_rowSlow", "select": "Lx7MOq_select", "stuck": "Lx7MOq_stuck", "subtitle": "Lx7MOq_subtitle", "summary": "Lx7MOq_summary", "table": "Lx7MOq_table", "tableWrap": "Lx7MOq_tableWrap", "thSortable": "Lx7MOq_thSortable", "title": "Lx7MOq_title", "toolbar": "Lx7MOq_toolbar" };
|
|
2039
2051
|
|
|
2040
2052
|
// src/client/RequestLogPage.tsx
|
|
2041
2053
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2054
|
+
var SORT_DEFAULT_DIR = {
|
|
2055
|
+
atMs: "desc",
|
|
2056
|
+
model: "asc",
|
|
2057
|
+
session: "asc",
|
|
2058
|
+
inputTokens: "desc",
|
|
2059
|
+
outputTokens: "desc",
|
|
2060
|
+
cacheReadTokens: "desc",
|
|
2061
|
+
cacheRate: "desc",
|
|
2062
|
+
tps: "desc",
|
|
2063
|
+
firstTokenMs: "desc",
|
|
2064
|
+
durationMs: "desc",
|
|
2065
|
+
status: "asc"
|
|
2066
|
+
};
|
|
2067
|
+
function sortValue(entry, key) {
|
|
2068
|
+
switch (key) {
|
|
2069
|
+
case "atMs":
|
|
2070
|
+
return entry.atMs;
|
|
2071
|
+
case "model":
|
|
2072
|
+
return entry.model;
|
|
2073
|
+
case "session":
|
|
2074
|
+
return entry.session;
|
|
2075
|
+
case "inputTokens":
|
|
2076
|
+
return entry.inputTokens ?? -1;
|
|
2077
|
+
case "outputTokens":
|
|
2078
|
+
return entry.outputTokens ?? -1;
|
|
2079
|
+
case "cacheReadTokens":
|
|
2080
|
+
return entry.cacheReadTokens ?? -1;
|
|
2081
|
+
case "cacheRate":
|
|
2082
|
+
return cacheRate(entry) ?? -1;
|
|
2083
|
+
case "tps":
|
|
2084
|
+
return entry.tps ?? -1;
|
|
2085
|
+
case "firstTokenMs":
|
|
2086
|
+
return entry.firstTokenMs ?? -1;
|
|
2087
|
+
case "durationMs":
|
|
2088
|
+
return entry.durationMs ?? -1;
|
|
2089
|
+
case "status":
|
|
2090
|
+
return entry.ok ? `ok-${entry.status ?? ""}` : `fail-${entry.code ?? ""}`;
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2042
2093
|
var PAGE_SIZE = 50;
|
|
2043
2094
|
function count2(value) {
|
|
2044
2095
|
return value === void 0 ? "\u2014" : value.toLocaleString();
|
|
@@ -2050,6 +2101,15 @@ function duration(value) {
|
|
|
2050
2101
|
function rate2(value) {
|
|
2051
2102
|
return value === void 0 ? "\u2014" : value.toFixed(1);
|
|
2052
2103
|
}
|
|
2104
|
+
function cacheRate(entry) {
|
|
2105
|
+
if (entry.inputTokens === void 0) return void 0;
|
|
2106
|
+
const cached = entry.cacheReadTokens ?? 0;
|
|
2107
|
+
const total = entry.inputTokens + cached;
|
|
2108
|
+
return total > 0 ? cached / total : void 0;
|
|
2109
|
+
}
|
|
2110
|
+
function percent(value) {
|
|
2111
|
+
return value === void 0 ? "\u2014" : `${(value * 100).toFixed(0)}%`;
|
|
2112
|
+
}
|
|
2053
2113
|
function average(values) {
|
|
2054
2114
|
if (values.length === 0) return void 0;
|
|
2055
2115
|
let sum = 0;
|
|
@@ -2068,7 +2128,7 @@ function groupKey(entry, groupBy) {
|
|
|
2068
2128
|
return void 0;
|
|
2069
2129
|
}
|
|
2070
2130
|
}
|
|
2071
|
-
function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
2131
|
+
function RequestLogPage({ readLog, enabled, t, getLocale, sessionId, useSessions }) {
|
|
2072
2132
|
const [snapshot, setSnapshot] = (0, import_react2.useState)(void 0);
|
|
2073
2133
|
const [failure, setFailure] = (0, import_react2.useState)(void 0);
|
|
2074
2134
|
const [refreshing, setRefreshing] = (0, import_react2.useState)(false);
|
|
@@ -2080,8 +2140,40 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2080
2140
|
const [groupBy, setGroupBy] = (0, import_react2.useState)("none");
|
|
2081
2141
|
const [page, setPage] = (0, import_react2.useState)(0);
|
|
2082
2142
|
const [expanded, setExpanded] = (0, import_react2.useState)(null);
|
|
2083
|
-
const
|
|
2084
|
-
const [
|
|
2143
|
+
const [sortKey, setSortKey] = (0, import_react2.useState)("atMs");
|
|
2144
|
+
const [sortDir, setSortDir] = (0, import_react2.useState)("desc");
|
|
2145
|
+
const [onlySession, setOnlySession] = (0, import_react2.useState)(sessionId !== void 0);
|
|
2146
|
+
const stuckRef = (0, import_react2.useRef)(null);
|
|
2147
|
+
const [stuckTop, setStuckTop] = (0, import_react2.useState)(0);
|
|
2148
|
+
(0, import_react2.useEffect)(() => {
|
|
2149
|
+
const element = stuckRef.current;
|
|
2150
|
+
if (element === null) return;
|
|
2151
|
+
const measure = () => {
|
|
2152
|
+
setStuckTop(element.getBoundingClientRect().height);
|
|
2153
|
+
};
|
|
2154
|
+
measure();
|
|
2155
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
2156
|
+
const observer = new ResizeObserver(measure);
|
|
2157
|
+
observer.observe(element);
|
|
2158
|
+
return () => {
|
|
2159
|
+
observer.disconnect();
|
|
2160
|
+
};
|
|
2161
|
+
}, []);
|
|
2162
|
+
const catalog = useSessions?.((state) => state);
|
|
2163
|
+
const sessionLabel = (0, import_react2.useCallback)((id4) => {
|
|
2164
|
+
const title = catalog?.byId[id4]?.title?.trim();
|
|
2165
|
+
return title === void 0 || title === "" ? { text: id4 === "" ? "\u2014" : id4, titled: false } : { text: title, titled: true };
|
|
2166
|
+
}, [catalog]);
|
|
2167
|
+
const toggleSort = (key) => {
|
|
2168
|
+
if (key === sortKey) {
|
|
2169
|
+
setSortDir(sortDir === "asc" ? "desc" : "asc");
|
|
2170
|
+
} else {
|
|
2171
|
+
setSortKey(key);
|
|
2172
|
+
setSortDir(SORT_DEFAULT_DIR[key]);
|
|
2173
|
+
}
|
|
2174
|
+
setPage(0);
|
|
2175
|
+
setExpanded(null);
|
|
2176
|
+
};
|
|
2085
2177
|
const load = (0, import_react2.useCallback)(async () => {
|
|
2086
2178
|
setRefreshing(true);
|
|
2087
2179
|
try {
|
|
@@ -2109,19 +2201,42 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2109
2201
|
if (result === "ok" && !entry.ok) return false;
|
|
2110
2202
|
if (result === "fail" && entry.ok) return false;
|
|
2111
2203
|
if (slowOnly && (entry.durationMs ?? 0) < Math.max(0, slowSeconds) * 1e3) return false;
|
|
2112
|
-
if (onlySession &&
|
|
2113
|
-
if (query !== ""
|
|
2204
|
+
if (onlySession && sessionId !== void 0 && entry.session !== sessionId) return false;
|
|
2205
|
+
if (query !== "") {
|
|
2206
|
+
const label = sessionLabel(entry.session);
|
|
2207
|
+
if (!entry.session.includes(query) && !(label.titled && label.text.includes(query))) return false;
|
|
2208
|
+
}
|
|
2114
2209
|
return true;
|
|
2115
2210
|
});
|
|
2116
|
-
}, [snapshot, model, result, slowOnly, slowSeconds, sessionQuery, onlySession,
|
|
2211
|
+
}, [snapshot, model, result, slowOnly, slowSeconds, sessionQuery, onlySession, sessionId, sessionLabel]);
|
|
2117
2212
|
const pages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
|
|
2118
2213
|
const safePage = Math.min(page, pages - 1);
|
|
2119
|
-
const
|
|
2214
|
+
const sorted = (0, import_react2.useMemo)(() => {
|
|
2215
|
+
const next = [...filtered];
|
|
2216
|
+
next.sort((a, b) => {
|
|
2217
|
+
const first = sortValue(a, sortKey);
|
|
2218
|
+
const second = sortValue(b, sortKey);
|
|
2219
|
+
const compared = typeof first === "number" && typeof second === "number" ? first - second : String(first) < String(second) ? -1 : String(first) > String(second) ? 1 : 0;
|
|
2220
|
+
return sortDir === "asc" ? compared : -compared;
|
|
2221
|
+
});
|
|
2222
|
+
return next;
|
|
2223
|
+
}, [filtered, sortKey, sortDir]);
|
|
2224
|
+
const pageEntries = sorted.slice(safePage * PAGE_SIZE, (safePage + 1) * PAGE_SIZE);
|
|
2120
2225
|
const failures = filtered.filter((entry) => !entry.ok).length;
|
|
2121
2226
|
const meanLatency = average(filtered.flatMap((entry) => entry.durationMs === void 0 ? [] : [entry.durationMs]));
|
|
2122
2227
|
const meanFirstToken = average(filtered.flatMap((entry) => entry.firstTokenMs === void 0 ? [] : [entry.firstTokenMs]));
|
|
2123
2228
|
const meanTps = average(filtered.flatMap((entry) => entry.tps === void 0 ? [] : [entry.tps]));
|
|
2229
|
+
const meanCacheRate = average(filtered.flatMap((entry) => {
|
|
2230
|
+
const value = cacheRate(entry);
|
|
2231
|
+
return value === void 0 ? [] : [value];
|
|
2232
|
+
}));
|
|
2124
2233
|
const reuse = snapshot !== void 0 && snapshot.totalRecords > 0 ? Math.max(0, Math.min(1, 1 - snapshot.newConnections / snapshot.totalRecords)) : void 0;
|
|
2234
|
+
const head = (key, label) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("th", { className: request_log_default.thSortable, onClick: () => {
|
|
2235
|
+
toggleSort(key);
|
|
2236
|
+
}, children: [
|
|
2237
|
+
label,
|
|
2238
|
+
sortKey === key ? sortDir === "asc" ? " \u25B2" : " \u25BC" : ""
|
|
2239
|
+
] });
|
|
2125
2240
|
const rows = () => {
|
|
2126
2241
|
const out = [];
|
|
2127
2242
|
let lastGroup;
|
|
@@ -2130,10 +2245,11 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2130
2245
|
if (group !== void 0 && group !== lastGroup) {
|
|
2131
2246
|
lastGroup = group;
|
|
2132
2247
|
out.push(
|
|
2133
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { className: request_log_default.group, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { colSpan:
|
|
2248
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { className: request_log_default.group, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { colSpan: 11, children: groupBy === "session" ? sessionLabel(group).text : group }) }, `group-${group}-${entry.seq}`)
|
|
2134
2249
|
);
|
|
2135
2250
|
}
|
|
2136
2251
|
const state = !entry.ok ? "rowFail" : entry.tps !== void 0 && entry.tps < 5 ? "rowSlow" : "rowOk";
|
|
2252
|
+
const session = sessionLabel(entry.session);
|
|
2137
2253
|
out.push(
|
|
2138
2254
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2139
2255
|
"tr",
|
|
@@ -2145,10 +2261,11 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2145
2261
|
children: [
|
|
2146
2262
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: new Date(entry.atMs).toLocaleTimeString(getLocale(), { hour12: false }) }),
|
|
2147
2263
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { className: request_log_default.mono, children: entry.model }),
|
|
2148
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", {
|
|
2264
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { title: session.titled ? entry.session : void 0, className: session.titled ? void 0 : request_log_default.mono, children: session.text }),
|
|
2149
2265
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: count2(entry.inputTokens) }),
|
|
2150
2266
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: count2(entry.outputTokens) }),
|
|
2151
2267
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: count2(entry.cacheReadTokens) }),
|
|
2268
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: percent(cacheRate(entry)) }),
|
|
2152
2269
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: rate2(entry.tps) }),
|
|
2153
2270
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: duration(entry.firstTokenMs) }),
|
|
2154
2271
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: duration(entry.durationMs) }),
|
|
@@ -2160,7 +2277,7 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2160
2277
|
);
|
|
2161
2278
|
if (expanded === entry.seq) {
|
|
2162
2279
|
out.push(
|
|
2163
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { className: request_log_default.detail, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { colSpan:
|
|
2280
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { className: request_log_default.detail, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { colSpan: 11, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailGrid, children: [
|
|
2164
2281
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
|
|
2165
2282
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailMethod") }),
|
|
2166
2283
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${request_log_default.detailValue} ${request_log_default.mono}`, children: entry.method })
|
|
@@ -2171,7 +2288,14 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2171
2288
|
] }),
|
|
2172
2289
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
|
|
2173
2290
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailSession") }),
|
|
2174
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2291
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2292
|
+
"span",
|
|
2293
|
+
{
|
|
2294
|
+
className: `${request_log_default.detailValue} ${session.titled ? "" : request_log_default.mono}`,
|
|
2295
|
+
title: session.titled ? entry.session : void 0,
|
|
2296
|
+
children: session.titled ? `${session.text} \xB7 ${entry.session}` : session.text
|
|
2297
|
+
}
|
|
2298
|
+
)
|
|
2175
2299
|
] }),
|
|
2176
2300
|
entry.poolKey !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
|
|
2177
2301
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailPool") }),
|
|
@@ -2193,6 +2317,10 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2193
2317
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailTokens") }),
|
|
2194
2318
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailValue, children: `${count2(entry.inputTokens)} / ${count2(entry.outputTokens)} / ${count2(entry.cacheReadTokens)}` })
|
|
2195
2319
|
] }),
|
|
2320
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
|
|
2321
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogColCacheRate") }),
|
|
2322
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailValue, children: percent(cacheRate(entry)) })
|
|
2323
|
+
] }),
|
|
2196
2324
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
|
|
2197
2325
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogColTps") }),
|
|
2198
2326
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailValue, children: rate2(entry.tps) })
|
|
@@ -2207,196 +2335,213 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2207
2335
|
}
|
|
2208
2336
|
return out;
|
|
2209
2337
|
};
|
|
2210
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2338
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2339
|
+
"div",
|
|
2340
|
+
{
|
|
2341
|
+
className: sessionId === void 0 ? request_log_default.page : `${request_log_default.page} ${request_log_default.pageLoose}`,
|
|
2342
|
+
style: { "--request-log-stuck": `${stuckTop}px` },
|
|
2343
|
+
children: [
|
|
2344
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.stuck, ref: stuckRef, children: [
|
|
2345
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.head, children: [
|
|
2346
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.headText, children: [
|
|
2347
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { className: request_log_default.title, children: t("requestLogTitle") }),
|
|
2348
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: request_log_default.subtitle, children: t("requestLogPageHint") })
|
|
2349
|
+
] }),
|
|
2350
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: request_log_default.headActions, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { type: "button", className: request_log_default.button, onClick: () => {
|
|
2351
|
+
void load();
|
|
2352
|
+
}, disabled: refreshing, children: [
|
|
2353
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives.IconRefreshOutlineRegular, { size: 13 }),
|
|
2354
|
+
t("requestLogRefresh")
|
|
2355
|
+
] }) })
|
|
2356
|
+
] }),
|
|
2357
|
+
!enabled() && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: request_log_default.notice, children: t("requestLogDisabled") }),
|
|
2358
|
+
failure !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: `${request_log_default.notice} ${request_log_default.noticeError}`, children: failure }),
|
|
2359
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.summary, children: [
|
|
2360
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
|
|
2361
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatRequests") }),
|
|
2362
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: filtered.length.toLocaleString(getLocale()) })
|
|
2363
|
+
] }),
|
|
2364
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `${request_log_default.card} ${failures > 0 ? request_log_default.cardError : ""}`, children: [
|
|
2365
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatFailures") }),
|
|
2366
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: failures.toLocaleString(getLocale()) })
|
|
2367
|
+
] }),
|
|
2368
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
|
|
2369
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatLatency") }),
|
|
2370
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: duration(meanLatency) })
|
|
2371
|
+
] }),
|
|
2372
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
|
|
2373
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatFirstToken") }),
|
|
2374
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: duration(meanFirstToken) })
|
|
2375
|
+
] }),
|
|
2376
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
|
|
2377
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatTps") }),
|
|
2378
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: rate2(meanTps) })
|
|
2379
|
+
] }),
|
|
2380
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
|
|
2381
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatCacheRate") }),
|
|
2382
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: percent(meanCacheRate) })
|
|
2383
|
+
] }),
|
|
2384
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
|
|
2385
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogReuse") }),
|
|
2386
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: reuse === void 0 ? "\u2014" : `${(reuse * 100).toFixed(0)}%` })
|
|
2387
|
+
] })
|
|
2388
|
+
] }),
|
|
2389
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.toolbar, children: [
|
|
2390
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
|
|
2391
|
+
t("requestLogFilterModel"),
|
|
2392
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2393
|
+
"select",
|
|
2394
|
+
{
|
|
2395
|
+
className: request_log_default.select,
|
|
2396
|
+
value: model,
|
|
2397
|
+
onChange: (event) => {
|
|
2398
|
+
setModel(event.target.value);
|
|
2399
|
+
setPage(0);
|
|
2400
|
+
},
|
|
2401
|
+
children: [
|
|
2402
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "all", children: t("requestLogFilterModelAll") }),
|
|
2403
|
+
models.map((id4) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: id4, children: id4 }, id4))
|
|
2404
|
+
]
|
|
2405
|
+
}
|
|
2406
|
+
)
|
|
2407
|
+
] }),
|
|
2408
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
|
|
2409
|
+
t("requestLogFilterResult"),
|
|
2410
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2411
|
+
"select",
|
|
2412
|
+
{
|
|
2413
|
+
className: request_log_default.select,
|
|
2414
|
+
value: result,
|
|
2415
|
+
onChange: (event) => {
|
|
2416
|
+
setResult(event.target.value);
|
|
2417
|
+
setPage(0);
|
|
2418
|
+
},
|
|
2419
|
+
children: [
|
|
2420
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "all", children: t("requestLogResultAll") }),
|
|
2421
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "ok", children: t("requestLogResultOk") }),
|
|
2422
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "fail", children: t("requestLogResultFail") })
|
|
2423
|
+
]
|
|
2424
|
+
}
|
|
2425
|
+
)
|
|
2426
|
+
] }),
|
|
2427
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
|
|
2428
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2429
|
+
"input",
|
|
2430
|
+
{
|
|
2431
|
+
className: request_log_default.checkbox,
|
|
2432
|
+
type: "checkbox",
|
|
2433
|
+
checked: slowOnly,
|
|
2434
|
+
onChange: (event) => {
|
|
2435
|
+
setSlowOnly(event.target.checked);
|
|
2436
|
+
setPage(0);
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
),
|
|
2440
|
+
t("requestLogSlowOnly"),
|
|
2441
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2442
|
+
"input",
|
|
2443
|
+
{
|
|
2444
|
+
className: `${request_log_default.input} ${request_log_default.inputNumber}`,
|
|
2445
|
+
type: "number",
|
|
2446
|
+
min: 1,
|
|
2447
|
+
value: slowSeconds,
|
|
2448
|
+
disabled: !slowOnly,
|
|
2449
|
+
"aria-label": t("requestLogSlowSeconds"),
|
|
2450
|
+
onChange: (event) => {
|
|
2451
|
+
setSlowSeconds(Number(event.target.value));
|
|
2452
|
+
setPage(0);
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
),
|
|
2456
|
+
t("requestLogSlowSeconds")
|
|
2457
|
+
] }),
|
|
2458
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
|
|
2459
|
+
t("requestLogFilterSession"),
|
|
2460
|
+
sessionId !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2461
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2462
|
+
"input",
|
|
2463
|
+
{
|
|
2464
|
+
className: request_log_default.checkbox,
|
|
2465
|
+
type: "checkbox",
|
|
2466
|
+
checked: onlySession,
|
|
2467
|
+
onChange: (event) => {
|
|
2468
|
+
setOnlySession(event.target.checked);
|
|
2469
|
+
setPage(0);
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
),
|
|
2473
|
+
t("requestLogOnlySession")
|
|
2474
|
+
] }),
|
|
2475
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2476
|
+
"input",
|
|
2477
|
+
{
|
|
2478
|
+
className: request_log_default.input,
|
|
2479
|
+
type: "search",
|
|
2480
|
+
value: sessionQuery,
|
|
2481
|
+
disabled: onlySession,
|
|
2482
|
+
onChange: (event) => {
|
|
2483
|
+
setSessionQuery(event.target.value);
|
|
2484
|
+
setPage(0);
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
)
|
|
2488
|
+
] }),
|
|
2489
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
|
|
2490
|
+
t("requestLogGroupBy"),
|
|
2491
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2492
|
+
"select",
|
|
2493
|
+
{
|
|
2494
|
+
className: request_log_default.select,
|
|
2495
|
+
value: groupBy,
|
|
2496
|
+
onChange: (event) => {
|
|
2497
|
+
setGroupBy(event.target.value);
|
|
2498
|
+
setPage(0);
|
|
2499
|
+
},
|
|
2500
|
+
children: [
|
|
2501
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "none", children: t("requestLogGroupNone") }),
|
|
2502
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "session", children: t("requestLogGroupSession") }),
|
|
2503
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "model", children: t("requestLogGroupModel") }),
|
|
2504
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "result", children: t("requestLogGroupResult") })
|
|
2505
|
+
]
|
|
2506
|
+
}
|
|
2507
|
+
)
|
|
2508
|
+
] })
|
|
2509
|
+
] })
|
|
2336
2510
|
] }),
|
|
2337
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2338
|
-
"
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2354
|
-
"
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
setPage(
|
|
2361
|
-
},
|
|
2362
|
-
children:
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
] }),
|
|
2372
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: request_log_default.tableWrap, children: filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: request_log_default.empty, children: t("requestLogEmpty") }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { className: request_log_default.table, children: [
|
|
2373
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
|
|
2374
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColTime") }),
|
|
2375
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColModel") }),
|
|
2376
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColSession") }),
|
|
2377
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColIn") }),
|
|
2378
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColOut") }),
|
|
2379
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColCache") }),
|
|
2380
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColTps") }),
|
|
2381
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColFirstToken") }),
|
|
2382
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColLatency") }),
|
|
2383
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColStatus") })
|
|
2384
|
-
] }) }),
|
|
2385
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: rows() })
|
|
2386
|
-
] }) }),
|
|
2387
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.foot, children: [
|
|
2388
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: `${filtered.length.toLocaleString(getLocale())} / ${(snapshot?.totalRecords ?? 0).toLocaleString(getLocale())} ${t("requestLogStatRequests")}` }),
|
|
2389
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.pager, children: [
|
|
2390
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: request_log_default.button, disabled: safePage <= 0, onClick: () => {
|
|
2391
|
-
setPage(safePage - 1);
|
|
2392
|
-
}, children: t("requestLogPagePrev") }),
|
|
2393
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: `${safePage + 1} ${t("requestLogPageOf")} ${pages}` }),
|
|
2394
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: request_log_default.button, disabled: safePage >= pages - 1, onClick: () => {
|
|
2395
|
-
setPage(safePage + 1);
|
|
2396
|
-
}, children: t("requestLogPageNext") })
|
|
2397
|
-
] })
|
|
2398
|
-
] })
|
|
2399
|
-
] });
|
|
2511
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: request_log_default.tableWrap, children: filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: request_log_default.empty, children: t("requestLogEmpty") }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { className: request_log_default.table, children: [
|
|
2512
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
|
|
2513
|
+
head("atMs", t("requestLogColTime")),
|
|
2514
|
+
head("model", t("requestLogColModel")),
|
|
2515
|
+
head("session", t("requestLogColSession")),
|
|
2516
|
+
head("inputTokens", t("requestLogColIn")),
|
|
2517
|
+
head("outputTokens", t("requestLogColOut")),
|
|
2518
|
+
head("cacheReadTokens", t("requestLogColCache")),
|
|
2519
|
+
head("cacheRate", t("requestLogColCacheRate")),
|
|
2520
|
+
head("tps", t("requestLogColTps")),
|
|
2521
|
+
head("firstTokenMs", t("requestLogColFirstToken")),
|
|
2522
|
+
head("durationMs", t("requestLogColLatency")),
|
|
2523
|
+
head("status", t("requestLogColStatus"))
|
|
2524
|
+
] }) }),
|
|
2525
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: rows() })
|
|
2526
|
+
] }) }),
|
|
2527
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.foot, children: [
|
|
2528
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
|
|
2529
|
+
`${t("requestLogStatRequests")}: ${filtered.length.toLocaleString(getLocale())}`,
|
|
2530
|
+
filtered.length !== (snapshot?.totalRecords ?? 0) ? ` (${t("requestLogOfTotal")} ${(snapshot?.totalRecords ?? 0).toLocaleString(getLocale())})` : ""
|
|
2531
|
+
] }),
|
|
2532
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.pager, children: [
|
|
2533
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: request_log_default.button, disabled: safePage <= 0, onClick: () => {
|
|
2534
|
+
setPage(safePage - 1);
|
|
2535
|
+
}, children: t("requestLogPagePrev") }),
|
|
2536
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: `${safePage + 1} ${t("requestLogPageOf")} ${pages}` }),
|
|
2537
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: request_log_default.button, disabled: safePage >= pages - 1, onClick: () => {
|
|
2538
|
+
setPage(safePage + 1);
|
|
2539
|
+
}, children: t("requestLogPageNext") })
|
|
2540
|
+
] })
|
|
2541
|
+
] })
|
|
2542
|
+
]
|
|
2543
|
+
}
|
|
2544
|
+
);
|
|
2400
2545
|
}
|
|
2401
2546
|
|
|
2402
2547
|
// src/client/RequestLogPanelIcon.tsx
|
|
@@ -2602,6 +2747,13 @@ var REQUEST_LOG_PANEL = "dshopencodego-request-log";
|
|
|
2602
2747
|
var inject = ["slots", "locale", "remote"];
|
|
2603
2748
|
function apply(ctx) {
|
|
2604
2749
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "dshopencodego: copy dictionaries");
|
|
2750
|
+
const layout = { current: void 0 };
|
|
2751
|
+
ctx.inject(["layout"], (layoutScope) => {
|
|
2752
|
+
layout.current = layoutScope.layout;
|
|
2753
|
+
return () => {
|
|
2754
|
+
layout.current = void 0;
|
|
2755
|
+
};
|
|
2756
|
+
});
|
|
2605
2757
|
const mounted = ctx.remote.$mount({
|
|
2606
2758
|
package: usageRemote.package,
|
|
2607
2759
|
descriptors: [
|
|
@@ -2696,18 +2848,18 @@ function apply(ctx) {
|
|
|
2696
2848
|
t: (key) => translate(key),
|
|
2697
2849
|
getLocale: () => scope.locale.getLocale().active,
|
|
2698
2850
|
// The settings page opens the log in the main column, beside this
|
|
2699
|
-
// page rather than over it.
|
|
2700
|
-
//
|
|
2851
|
+
// page rather than over it. It reports whether it worked: a button
|
|
2852
|
+
// that silently does nothing is worse than one that says why.
|
|
2701
2853
|
openRequestLog: () => {
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2854
|
+
const service = layout.current;
|
|
2855
|
+
if (service === void 0) return false;
|
|
2856
|
+
service.selectPanel(REQUEST_LOG_PANEL);
|
|
2857
|
+
return true;
|
|
2706
2858
|
}
|
|
2707
2859
|
})
|
|
2708
2860
|
}, Section));
|
|
2709
2861
|
});
|
|
2710
|
-
ctx.inject(["modelDirectories", "remote.opencodeGoUsage"], (scope) => {
|
|
2862
|
+
ctx.inject(["modelDirectories", "remote.opencodeGoUsage", "remote.session"], (scope) => {
|
|
2711
2863
|
const translate = scope.locale.bind(NS);
|
|
2712
2864
|
scope.slots.inject("conversation.input.right", () => scope.slots.register({
|
|
2713
2865
|
name: "conversation.input.right",
|
package/lib/index.js
CHANGED
|
@@ -75757,9 +75757,11 @@ var fields = {
|
|
|
75757
75757
|
maxTokens: Schema.union([Schema.const(null), Schema.number().step(1).min(1).max(Number.MAX_SAFE_INTEGER)])
|
|
75758
75758
|
})])).default({}),
|
|
75759
75759
|
modelProtocols: Schema.dict(Schema.string()).default({}),
|
|
75760
|
-
//
|
|
75761
|
-
//
|
|
75762
|
-
|
|
75760
|
+
// On by default: recording costs one call and one boolean per request
|
|
75761
|
+
// plus a bounded ring, and buys a per-request trail whenever something
|
|
75762
|
+
// looks wrong. Off returns the request path to exactly as without the
|
|
75763
|
+
// log, because the recorder is never constructed then.
|
|
75764
|
+
requestLogEnabled: Schema.boolean().default(true),
|
|
75763
75765
|
requestLogDebug: Schema.boolean().default(false),
|
|
75764
75766
|
requestLogMaxEntries: Schema.number().step(1).min(MIN_REQUEST_LOG_MAX_ENTRIES).max(MAX_REQUEST_LOG_MAX_ENTRIES).default(DEFAULT_REQUEST_LOG_MAX_ENTRIES),
|
|
75765
75767
|
pinnedAddresses: Schema.dict(Schema.string()).default({}),
|
|
@@ -76850,7 +76852,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
76850
76852
|
exhausted = true;
|
|
76851
76853
|
return;
|
|
76852
76854
|
}
|
|
76853
|
-
if (span !== void 0 && isTokenDelta(result.value)) span.
|
|
76855
|
+
if (span !== void 0 && isTokenDelta(result.value)) span.token();
|
|
76854
76856
|
if (result.value.type === "usage") {
|
|
76855
76857
|
pendingUsage = result.value.usage;
|
|
76856
76858
|
this.options.onUsage?.({
|
|
@@ -77665,8 +77667,8 @@ var OpencodeGoRequestLogService = class extends TypertRemoteService3 {
|
|
|
77665
77667
|
};
|
|
77666
77668
|
|
|
77667
77669
|
// src/request-log/store.ts
|
|
77668
|
-
var SESSION_PREFIX_LENGTH = 8;
|
|
77669
77670
|
var MAX_POOL_EVENTS = 20;
|
|
77671
|
+
var MIN_STREAM_MS_FOR_RATE = 100;
|
|
77670
77672
|
var RequestLog = class {
|
|
77671
77673
|
gates;
|
|
77672
77674
|
entries = [];
|
|
@@ -77706,16 +77708,18 @@ var RequestLog = class {
|
|
|
77706
77708
|
if (!this.gates.enabled()) return void 0;
|
|
77707
77709
|
const debug = this.gates.debug();
|
|
77708
77710
|
const startedAt = Date.now();
|
|
77709
|
-
const
|
|
77710
|
-
const session = debug || full.length === 0 ? full : full.slice(0, SESSION_PREFIX_LENGTH);
|
|
77711
|
+
const session = detail.sessionId ?? "";
|
|
77711
77712
|
let firstTokenAt;
|
|
77713
|
+
let lastTokenAt;
|
|
77712
77714
|
let method;
|
|
77713
77715
|
let url;
|
|
77714
77716
|
let status;
|
|
77715
77717
|
let finished = false;
|
|
77716
77718
|
return {
|
|
77717
|
-
|
|
77718
|
-
|
|
77719
|
+
token: () => {
|
|
77720
|
+
const now = Date.now();
|
|
77721
|
+
if (firstTokenAt === void 0) firstTokenAt = now;
|
|
77722
|
+
lastTokenAt = now;
|
|
77719
77723
|
},
|
|
77720
77724
|
request: (nextMethod, nextUrl) => {
|
|
77721
77725
|
if (method === void 0) {
|
|
@@ -77731,7 +77735,8 @@ var RequestLog = class {
|
|
|
77731
77735
|
finished = true;
|
|
77732
77736
|
const endedAt = Date.now();
|
|
77733
77737
|
const decodeMs = firstTokenAt === void 0 ? void 0 : Math.max(0, endedAt - firstTokenAt);
|
|
77734
|
-
const
|
|
77738
|
+
const streamMs = firstTokenAt === void 0 || lastTokenAt === void 0 ? void 0 : Math.max(0, lastTokenAt - firstTokenAt);
|
|
77739
|
+
const tps = decodeMs === void 0 || decodeMs <= 0 || usage === void 0 || streamMs === void 0 || streamMs < MIN_STREAM_MS_FOR_RATE ? void 0 : usage.outputTokens / (decodeMs / 1e3);
|
|
77735
77740
|
const entry = {
|
|
77736
77741
|
seq: ++this.seq,
|
|
77737
77742
|
atMs: startedAt,
|
|
@@ -77888,7 +77893,7 @@ function createUpdateChecker(deps) {
|
|
|
77888
77893
|
}
|
|
77889
77894
|
|
|
77890
77895
|
// src/update/version.ts
|
|
77891
|
-
var PLUGIN_VERSION = true ? "0.1.
|
|
77896
|
+
var PLUGIN_VERSION = true ? "0.1.67" : "0.0.0-dev";
|
|
77892
77897
|
|
|
77893
77898
|
// src/update/service.ts
|
|
77894
77899
|
import { TypertRemoteService as TypertRemoteService4 } from "@deepseek-ai/dsh-typert-protocol";
|
package/lib/types/config.d.ts
CHANGED
|
@@ -76,15 +76,16 @@ export interface OpencodeGoConfig {
|
|
|
76
76
|
*/
|
|
77
77
|
modelProtocols: Record<string, string>;
|
|
78
78
|
/**
|
|
79
|
-
* Whether the
|
|
80
|
-
*
|
|
81
|
-
*
|
|
79
|
+
* Whether the request log records anything at all. On by default: one
|
|
80
|
+
* call and one boolean per request, plus a bounded ring. Off returns the
|
|
81
|
+
* request path to exactly as without the log — the recorder is never
|
|
82
|
+
* constructed.
|
|
82
83
|
*/
|
|
83
84
|
requestLogEnabled: boolean;
|
|
84
85
|
/**
|
|
85
|
-
* Whether the request log also records pool lifecycle and
|
|
86
|
-
*
|
|
87
|
-
*
|
|
86
|
+
* Whether the request log also records pool lifecycle and request headers.
|
|
87
|
+
* Debug only: the common log carries no pool events and no header detail,
|
|
88
|
+
* which is enough to follow one conversation.
|
|
88
89
|
*/
|
|
89
90
|
requestLogDebug: boolean;
|
|
90
91
|
/**
|
|
@@ -13,14 +13,12 @@
|
|
|
13
13
|
* - Authorization never enters a record. The recorder takes no headers
|
|
14
14
|
* argument at all; the only header-derived value it stores is the session
|
|
15
15
|
* id it is handed, already separated from the credential by the caller.
|
|
16
|
-
* - The session id is stored
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* - The session id is stored whole. It is a conversation identity, not a
|
|
17
|
+
* secret, and a truncated one cannot group a conversation's requests —
|
|
18
|
+
* two conversations sharing an eight-character prefix would read as one.
|
|
19
19
|
*
|
|
20
20
|
* @module @dan-ai-studio/dshopencodego/request-log/store
|
|
21
21
|
*/
|
|
22
|
-
/** How many session-id characters the common (non-debug) log keeps. */
|
|
23
|
-
export declare const SESSION_PREFIX_LENGTH = 8;
|
|
24
22
|
/** One recorded request. Counts are provider-reported; timings are Host-measured. */
|
|
25
23
|
export interface RequestLogEntry {
|
|
26
24
|
/** Monotonic sequence within this process; gaps mean nothing was recorded. */
|
|
@@ -29,7 +27,7 @@ export interface RequestLogEntry {
|
|
|
29
27
|
readonly atMs: number;
|
|
30
28
|
/** The model id the request was made with. */
|
|
31
29
|
readonly model: string;
|
|
32
|
-
/** The session id
|
|
30
|
+
/** The session id the request belonged to, whole. */
|
|
33
31
|
readonly session: string;
|
|
34
32
|
/** HTTP method used. */
|
|
35
33
|
readonly method: string;
|
|
@@ -56,9 +54,11 @@ export interface RequestLogEntry {
|
|
|
56
54
|
/**
|
|
57
55
|
* Output tokens per second over the decode window.
|
|
58
56
|
*
|
|
59
|
-
* Absent when the request produced no token,
|
|
60
|
-
* rounds to zero milliseconds
|
|
61
|
-
*
|
|
57
|
+
* Absent when the request produced no token, when the decode window
|
|
58
|
+
* rounds to zero milliseconds, or when the whole output arrived in one
|
|
59
|
+
* burst (see `MIN_STREAM_MS_FOR_RATE`): a rate divided by zero is not a
|
|
60
|
+
* rate, and a rate over a burst is not a generation speed. Either would
|
|
61
|
+
* misreport a buffered reply as infinitely quick.
|
|
62
62
|
*/
|
|
63
63
|
readonly tps?: number;
|
|
64
64
|
/** Whether the request completed. */
|
|
@@ -121,14 +121,22 @@ export interface RequestLogGates {
|
|
|
121
121
|
/**
|
|
122
122
|
* An in-flight request, handed back only when the log is enabled.
|
|
123
123
|
*
|
|
124
|
-
* Every method is cheap by construction:
|
|
125
|
-
* integer arithmetic across the whole span. No
|
|
126
|
-
* no body handling — the counts ride the usage
|
|
127
|
-
* holds, and the timings bracket work that
|
|
124
|
+
* Every method is cheap by construction: one `Date.now` read per content
|
|
125
|
+
* delta and small integer arithmetic across the whole span. No
|
|
126
|
+
* serialization, no hashing, no body handling — the counts ride the usage
|
|
127
|
+
* chunk the adapter already holds, and the timings bracket work that
|
|
128
|
+
* already happened.
|
|
128
129
|
*/
|
|
129
130
|
export interface RequestSpan {
|
|
130
|
-
/**
|
|
131
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Mark one content token's arrival.
|
|
133
|
+
*
|
|
134
|
+
* The first call opens the decode window; every call moves the last-token
|
|
135
|
+
* mark, so the span between them is the window the output actually
|
|
136
|
+
* streamed in. The adapter calls this for every chunk its own first-token
|
|
137
|
+
* definition accepts — the same definition the Harness uses.
|
|
138
|
+
*/
|
|
139
|
+
token(): void;
|
|
132
140
|
/**
|
|
133
141
|
* Record the wire request line, from the fetch wrapper. Called at most
|
|
134
142
|
* once per span; a second call keeps the first, so retries never rewrite
|
package/package.json
CHANGED