@dan-ai-studio/dshopencodego 0.1.66 → 0.1.68
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 +6 -4
- package/README.md +6 -4
- package/lib/client.js +312 -209
- package/lib/index.js +56 -17
- package/lib/types/config.d.ts +4 -3
- package/lib/types/request-log/store.d.ts +60 -11
- package/lib/types/usage/meter.d.ts +16 -0
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -115,7 +115,7 @@ 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:
|
|
118
|
+
requestLogEnabled: true # request-log master switch, default on: off reads byte-for-byte as without the log
|
|
119
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
|
|
@@ -141,14 +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 / 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.
|
|
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, protocol, URL, body size, redacted headers, request shape, result and usage, reasoning split, cache writes, per-request cost, content span). 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.
|
|
151
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
|
+
- **The In column is uncached new input**: the gateway reports a prompt as "uncached plus cache hits" and the log records only the new part — a fully prefix-cached turn reads as a tiny input with a 100% hit, which is not a bug. Hover a column head for its definition.
|
|
152
154
|
- Session ids are **always stored whole**: an id is a conversation identity, not a credential, and a truncated one reads two conversations as one.
|
|
153
155
|
- 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.
|
|
154
156
|
- 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.
|
package/README.md
CHANGED
|
@@ -114,7 +114,7 @@ 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:
|
|
117
|
+
requestLogEnabled: true # 请求日志总开关,默认开启:关闭后请求路径与没有该日志逐字节一致
|
|
118
118
|
requestLogDebug: false # 排错详情:连接池事件与请求 UA;会话 id 始终完整记录
|
|
119
119
|
requestLogMaxEntries: 200 # 最多保留条数,50 ~ 500,超限丢弃最旧的
|
|
120
120
|
retryPolicy: # 可选:本路由的重试策略(由 dsh-llm-retry 执行)
|
|
@@ -140,14 +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/平均缓存命中/连接复用率)、筛选栏固定在上方,只有表格自己滚动。每行含时间、模型、会话、输入/输出/缓存、**缓存命中**、**tok/s**、首字、耗时与状态;点一行展开 HTTP
|
|
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;按会话分组的组头同样显示标题。
|
|
150
151
|
- **缓存命中**是输入 token 里走缓存的占比(缓存读取/(未缓存输入+缓存读取))。网关没报输入就没有占比——同样不编数。
|
|
152
|
+
- **输入列是未缓存的新增 token**:网关把整段 prompt 拆成"未缓存+缓存命中"两部分上报,输入列只记新增的——同一会话前缀缓存全中时输入很小、缓存命中 100%,不是 bug。悬停列头有口径说明。
|
|
151
153
|
- 会话 id **始终完整记录**(它是会话身份,不是凭据;截断后两个会话会读成一个)。
|
|
152
154
|
- 记录的是环形缓冲(超限丢最旧),进程重启即清;只读快照,不轮询,没人打开的页面零流量。
|
|
153
155
|
- 凭据永远不进记录:记录器根本不接收请求头参数,只收白名单里的会话 id 与 UA;失败的请求同样记一条(含错误码),中断到没有终端事件的不记(网关没报总数就不编数)。
|
package/lib/client.js
CHANGED
|
@@ -233,10 +233,14 @@ function parseEntry(value) {
|
|
|
233
233
|
const row = value;
|
|
234
234
|
const shape = row["shape"];
|
|
235
235
|
const headers = row["headers"];
|
|
236
|
+
const protocol = row["protocol"];
|
|
236
237
|
return {
|
|
237
238
|
seq: count("seq", row),
|
|
238
239
|
atMs: count("atMs", row),
|
|
239
240
|
model: text("model", row),
|
|
241
|
+
// Older rows predate the protocol recording; they read without one
|
|
242
|
+
// rather than failing the whole snapshot.
|
|
243
|
+
...protocol === "anthropic-messages" || protocol === "openai-completions" || protocol === "openai-responses" ? { protocol } : {},
|
|
240
244
|
session: text("session", row),
|
|
241
245
|
method: text("method", row),
|
|
242
246
|
url: text("url", row),
|
|
@@ -244,9 +248,14 @@ function parseEntry(value) {
|
|
|
244
248
|
...row["inputTokens"] === void 0 ? {} : { inputTokens: count("inputTokens", row) },
|
|
245
249
|
...row["outputTokens"] === void 0 ? {} : { outputTokens: count("outputTokens", row) },
|
|
246
250
|
...row["cacheReadTokens"] === void 0 ? {} : { cacheReadTokens: count("cacheReadTokens", row) },
|
|
251
|
+
...row["cacheWriteTokens"] === void 0 ? {} : { cacheWriteTokens: count("cacheWriteTokens", row) },
|
|
252
|
+
...row["reasoningTokens"] === void 0 ? {} : { reasoningTokens: count("reasoningTokens", row) },
|
|
253
|
+
...row["costUsd"] === void 0 ? {} : { costUsd: rate("costUsd", row) },
|
|
254
|
+
...row["requestBytes"] === void 0 ? {} : { requestBytes: count("requestBytes", row) },
|
|
247
255
|
...row["durationMs"] === void 0 ? {} : { durationMs: count("durationMs", row) },
|
|
248
256
|
...row["firstTokenMs"] === void 0 ? {} : { firstTokenMs: count("firstTokenMs", row) },
|
|
249
257
|
...row["decodeMs"] === void 0 ? {} : { decodeMs: count("decodeMs", row) },
|
|
258
|
+
...row["streamMs"] === void 0 ? {} : { streamMs: count("streamMs", row) },
|
|
250
259
|
...row["tps"] === void 0 ? {} : { tps: rate("tps", row) },
|
|
251
260
|
ok: row["ok"] === true,
|
|
252
261
|
...typeof row["code"] === "string" ? { code: row["code"] } : {},
|
|
@@ -498,7 +507,7 @@ var en = {
|
|
|
498
507
|
keepAliveLabel: "Connection kept idle (seconds)",
|
|
499
508
|
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
509
|
requestLogTitle: "Request log",
|
|
501
|
-
requestLogHint: "Per-request records for troubleshooting.
|
|
510
|
+
requestLogHint: "Per-request records for troubleshooting. On by default; turning it off returns the request path to exactly as without the log.",
|
|
502
511
|
requestLogPageHint: "One row per request. Click a column head to sort; the table scrolls and the filters stay put.",
|
|
503
512
|
requestLogEnabled: "Record requests",
|
|
504
513
|
requestLogDebug: "Debug detail",
|
|
@@ -536,22 +545,31 @@ var en = {
|
|
|
536
545
|
requestLogColModel: "Model",
|
|
537
546
|
requestLogColSession: "Session",
|
|
538
547
|
requestLogColIn: "In",
|
|
548
|
+
requestLogColInHint: "Uncached input tokens: what this turn added beyond the cache",
|
|
539
549
|
requestLogColOut: "Out",
|
|
550
|
+
requestLogColOutHint: "Generated output tokens",
|
|
540
551
|
requestLogColCache: "Cached",
|
|
552
|
+
requestLogColCacheHint: "Input tokens served from the cache",
|
|
541
553
|
requestLogColCacheRate: "Cache hit",
|
|
542
554
|
requestLogColLatency: "Latency",
|
|
543
555
|
requestLogColTps: "tok/s",
|
|
556
|
+
requestLogColStream: "Content span",
|
|
544
557
|
requestLogColFirstToken: "First token",
|
|
545
558
|
requestLogColStatus: "Status",
|
|
546
559
|
requestLogDetailRequest: "Request",
|
|
547
560
|
requestLogDetailTiming: "Timing",
|
|
548
561
|
requestLogDetailResult: "Result",
|
|
549
562
|
requestLogDetailMethod: "Method",
|
|
563
|
+
requestLogDetailProtocol: "Protocol",
|
|
550
564
|
requestLogDetailUrl: "URL",
|
|
565
|
+
requestLogDetailRequestBytes: "Request body",
|
|
551
566
|
requestLogDetailSession: "Session",
|
|
552
567
|
requestLogDetailPool: "Pool",
|
|
553
568
|
requestLogDetailError: "Error",
|
|
554
569
|
requestLogDetailTokens: "Tokens",
|
|
570
|
+
requestLogDetailReasoning: "Reasoning",
|
|
571
|
+
requestLogDetailCacheWrite: "Cache write",
|
|
572
|
+
requestLogDetailCost: "Cost",
|
|
555
573
|
requestLogDetailHeaders: "Headers",
|
|
556
574
|
requestLogDetailUserAgent: "User-Agent",
|
|
557
575
|
requestLogDetailShape: "Shape",
|
|
@@ -564,6 +582,7 @@ var en = {
|
|
|
564
582
|
requestLogStatFirstToken: "Mean first token",
|
|
565
583
|
requestLogStatTps: "Mean tok/s",
|
|
566
584
|
requestLogStatCacheRate: "Mean cache hit",
|
|
585
|
+
requestLogOfTotal: "of",
|
|
567
586
|
writeRejected: "The settings write was rejected (the namespace was reloaded) \u2014 try again",
|
|
568
587
|
writeFailed: "The settings write failed",
|
|
569
588
|
filterPlaceholder: "Filter by name or id",
|
|
@@ -677,7 +696,7 @@ var zh = {
|
|
|
677
696
|
keepAliveLabel: "\u8FDE\u63A5\u7A7A\u95F2\u4FDD\u7559\uFF08\u79D2\uFF09",
|
|
678
697
|
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",
|
|
679
698
|
requestLogTitle: "\u8BF7\u6C42\u65E5\u5FD7",
|
|
680
|
-
requestLogHint: "\u6392\u67E5\u7528\u7684\u9010\u8BF7\u6C42\u8BB0\u5F55\u3002\u9ED8\u8BA4\u5173\u95ED\
|
|
699
|
+
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",
|
|
681
700
|
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",
|
|
682
701
|
requestLogEnabled: "\u8BB0\u5F55\u8BF7\u6C42",
|
|
683
702
|
requestLogDebug: "\u6392\u9519\u8BE6\u60C5",
|
|
@@ -715,22 +734,31 @@ var zh = {
|
|
|
715
734
|
requestLogColModel: "\u6A21\u578B",
|
|
716
735
|
requestLogColSession: "\u4F1A\u8BDD",
|
|
717
736
|
requestLogColIn: "\u8F93\u5165",
|
|
737
|
+
requestLogColInHint: "\u672A\u7F13\u5B58\u7684\u8F93\u5165 token\uFF1A\u672C\u8F6E\u65B0\u589E\u7684\uFF0C\u4E0D\u542B\u7F13\u5B58\u547D\u4E2D\u7684\u90E8\u5206",
|
|
718
738
|
requestLogColOut: "\u8F93\u51FA",
|
|
739
|
+
requestLogColOutHint: "\u751F\u6210\u7684\u8F93\u51FA token",
|
|
719
740
|
requestLogColCache: "\u7F13\u5B58",
|
|
741
|
+
requestLogColCacheHint: "\u547D\u4E2D\u7F13\u5B58\u7684\u8F93\u5165 token",
|
|
720
742
|
requestLogColCacheRate: "\u7F13\u5B58\u547D\u4E2D",
|
|
721
743
|
requestLogColLatency: "\u8017\u65F6",
|
|
722
744
|
requestLogColTps: "tok/s",
|
|
745
|
+
requestLogColStream: "\u5185\u5BB9\u8DE8\u5EA6",
|
|
723
746
|
requestLogColFirstToken: "\u9996\u5B57",
|
|
724
747
|
requestLogColStatus: "\u72B6\u6001",
|
|
725
748
|
requestLogDetailRequest: "\u8BF7\u6C42",
|
|
726
749
|
requestLogDetailTiming: "\u8017\u65F6",
|
|
727
750
|
requestLogDetailResult: "\u7ED3\u679C",
|
|
728
751
|
requestLogDetailMethod: "\u65B9\u6CD5",
|
|
752
|
+
requestLogDetailProtocol: "\u534F\u8BAE",
|
|
729
753
|
requestLogDetailUrl: "\u5730\u5740",
|
|
754
|
+
requestLogDetailRequestBytes: "\u8BF7\u6C42\u4F53",
|
|
730
755
|
requestLogDetailSession: "\u4F1A\u8BDD",
|
|
731
756
|
requestLogDetailPool: "\u8FDE\u63A5\u6C60",
|
|
732
757
|
requestLogDetailError: "\u9519\u8BEF",
|
|
733
758
|
requestLogDetailTokens: "Token",
|
|
759
|
+
requestLogDetailReasoning: "\u63A8\u7406",
|
|
760
|
+
requestLogDetailCacheWrite: "\u7F13\u5B58\u5199\u5165",
|
|
761
|
+
requestLogDetailCost: "\u82B1\u8D39",
|
|
734
762
|
requestLogDetailHeaders: "\u8BF7\u6C42\u5934",
|
|
735
763
|
requestLogDetailUserAgent: "User-Agent",
|
|
736
764
|
requestLogDetailShape: "\u8BF7\u6C42\u6784\u6210",
|
|
@@ -743,6 +771,7 @@ var zh = {
|
|
|
743
771
|
requestLogStatFirstToken: "\u5E73\u5747\u9996\u5B57",
|
|
744
772
|
requestLogStatTps: "\u5E73\u5747 tok/s",
|
|
745
773
|
requestLogStatCacheRate: "\u5E73\u5747\u7F13\u5B58\u547D\u4E2D",
|
|
774
|
+
requestLogOfTotal: "\u5171",
|
|
746
775
|
writeRejected: "\u8BBE\u7F6E\u5199\u5165\u88AB\u62D2\u7EDD\uFF08\u5DF2\u91CD\u65B0\u8F7D\u5165\uFF09\uFF0C\u8BF7\u91CD\u8BD5",
|
|
747
776
|
writeFailed: "\u8BBE\u7F6E\u5199\u5165\u5931\u8D25",
|
|
748
777
|
filterPlaceholder: "\u6309\u540D\u79F0\u6216 ID \u7B5B\u9009",
|
|
@@ -1005,7 +1034,7 @@ function settingsOf(value) {
|
|
|
1005
1034
|
refreshMinutes: minutes,
|
|
1006
1035
|
pinnedAddresses: Object.fromEntries(pinEntries),
|
|
1007
1036
|
keepAliveTimeoutMs: typeof keepAlive === "number" ? keepAlive : DEFAULT_KEEP_ALIVE_TIMEOUT_MS,
|
|
1008
|
-
requestLogEnabled: typeof requestLogEnabled === "boolean" ? requestLogEnabled :
|
|
1037
|
+
requestLogEnabled: typeof requestLogEnabled === "boolean" ? requestLogEnabled : true,
|
|
1009
1038
|
requestLogDebug: typeof requestLogDebug === "boolean" ? requestLogDebug : false,
|
|
1010
1039
|
requestLogMaxEntries: typeof requestLogMaxEntries === "number" ? requestLogMaxEntries : DEFAULT_REQUEST_LOG_MAX_ENTRIES
|
|
1011
1040
|
};
|
|
@@ -1867,7 +1896,7 @@ function Section({ controller, t, getLocale, openRequestLog }) {
|
|
|
1867
1896
|
"input",
|
|
1868
1897
|
{
|
|
1869
1898
|
type: "checkbox",
|
|
1870
|
-
checked: state.settings?.requestLogEnabled ??
|
|
1899
|
+
checked: state.settings?.requestLogEnabled ?? true,
|
|
1871
1900
|
disabled: !editable || state.saving,
|
|
1872
1901
|
onChange: (event) => {
|
|
1873
1902
|
void act(async () => {
|
|
@@ -2042,10 +2071,10 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]"
|
|
|
2042
2071
|
const style = document.createElement("style");
|
|
2043
2072
|
style.dataset.plugin = "@dan-ai-studio/dshopencodego";
|
|
2044
2073
|
style.dataset.pluginCss = id2;
|
|
2045
|
-
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_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)}";
|
|
2074
|
+
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)}";
|
|
2046
2075
|
document.head.appendChild(style);
|
|
2047
2076
|
}
|
|
2048
|
-
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", "subtitle": "Lx7MOq_subtitle", "summary": "Lx7MOq_summary", "table": "Lx7MOq_table", "tableWrap": "Lx7MOq_tableWrap", "thSortable": "Lx7MOq_thSortable", "title": "Lx7MOq_title", "toolbar": "Lx7MOq_toolbar" };
|
|
2077
|
+
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" };
|
|
2049
2078
|
|
|
2050
2079
|
// src/client/RequestLogPage.tsx
|
|
2051
2080
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
@@ -2099,6 +2128,16 @@ function duration(value) {
|
|
|
2099
2128
|
function rate2(value) {
|
|
2100
2129
|
return value === void 0 ? "\u2014" : value.toFixed(1);
|
|
2101
2130
|
}
|
|
2131
|
+
function cost(value) {
|
|
2132
|
+
if (value === void 0) return "\u2014";
|
|
2133
|
+
return `$${value.toFixed(value < 0.01 ? 6 : 4)}`;
|
|
2134
|
+
}
|
|
2135
|
+
function bytes(value) {
|
|
2136
|
+
if (value === void 0) return "\u2014";
|
|
2137
|
+
if (value < 1024) return `${value} B`;
|
|
2138
|
+
if (value < 1024 * 1024) return `${(value / 1024).toFixed(1)} KB`;
|
|
2139
|
+
return `${(value / (1024 * 1024)).toFixed(2)} MB`;
|
|
2140
|
+
}
|
|
2102
2141
|
function cacheRate(entry) {
|
|
2103
2142
|
if (entry.inputTokens === void 0) return void 0;
|
|
2104
2143
|
const cached = entry.cacheReadTokens ?? 0;
|
|
@@ -2126,7 +2165,7 @@ function groupKey(entry, groupBy) {
|
|
|
2126
2165
|
return void 0;
|
|
2127
2166
|
}
|
|
2128
2167
|
}
|
|
2129
|
-
function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
2168
|
+
function RequestLogPage({ readLog, enabled, t, getLocale, sessionId, useSessions }) {
|
|
2130
2169
|
const [snapshot, setSnapshot] = (0, import_react2.useState)(void 0);
|
|
2131
2170
|
const [failure, setFailure] = (0, import_react2.useState)(void 0);
|
|
2132
2171
|
const [refreshing, setRefreshing] = (0, import_react2.useState)(false);
|
|
@@ -2141,6 +2180,27 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2141
2180
|
const [sortKey, setSortKey] = (0, import_react2.useState)("atMs");
|
|
2142
2181
|
const [sortDir, setSortDir] = (0, import_react2.useState)("desc");
|
|
2143
2182
|
const [onlySession, setOnlySession] = (0, import_react2.useState)(sessionId !== void 0);
|
|
2183
|
+
const stuckRef = (0, import_react2.useRef)(null);
|
|
2184
|
+
const [stuckTop, setStuckTop] = (0, import_react2.useState)(0);
|
|
2185
|
+
(0, import_react2.useEffect)(() => {
|
|
2186
|
+
const element = stuckRef.current;
|
|
2187
|
+
if (element === null) return;
|
|
2188
|
+
const measure = () => {
|
|
2189
|
+
setStuckTop(element.getBoundingClientRect().height);
|
|
2190
|
+
};
|
|
2191
|
+
measure();
|
|
2192
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
2193
|
+
const observer = new ResizeObserver(measure);
|
|
2194
|
+
observer.observe(element);
|
|
2195
|
+
return () => {
|
|
2196
|
+
observer.disconnect();
|
|
2197
|
+
};
|
|
2198
|
+
}, []);
|
|
2199
|
+
const catalog = useSessions?.((state) => state);
|
|
2200
|
+
const sessionLabel = (0, import_react2.useCallback)((id4) => {
|
|
2201
|
+
const title = catalog?.byId[id4]?.title?.trim();
|
|
2202
|
+
return title === void 0 || title === "" ? { text: id4 === "" ? "\u2014" : id4, titled: false } : { text: title, titled: true };
|
|
2203
|
+
}, [catalog]);
|
|
2144
2204
|
const toggleSort = (key) => {
|
|
2145
2205
|
if (key === sortKey) {
|
|
2146
2206
|
setSortDir(sortDir === "asc" ? "desc" : "asc");
|
|
@@ -2179,10 +2239,13 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2179
2239
|
if (result === "fail" && entry.ok) return false;
|
|
2180
2240
|
if (slowOnly && (entry.durationMs ?? 0) < Math.max(0, slowSeconds) * 1e3) return false;
|
|
2181
2241
|
if (onlySession && sessionId !== void 0 && entry.session !== sessionId) return false;
|
|
2182
|
-
if (query !== ""
|
|
2242
|
+
if (query !== "") {
|
|
2243
|
+
const label = sessionLabel(entry.session);
|
|
2244
|
+
if (!entry.session.includes(query) && !(label.titled && label.text.includes(query))) return false;
|
|
2245
|
+
}
|
|
2183
2246
|
return true;
|
|
2184
2247
|
});
|
|
2185
|
-
}, [snapshot, model, result, slowOnly, slowSeconds, sessionQuery, onlySession, sessionId]);
|
|
2248
|
+
}, [snapshot, model, result, slowOnly, slowSeconds, sessionQuery, onlySession, sessionId, sessionLabel]);
|
|
2186
2249
|
const pages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
|
|
2187
2250
|
const safePage = Math.min(page, pages - 1);
|
|
2188
2251
|
const sorted = (0, import_react2.useMemo)(() => {
|
|
@@ -2205,9 +2268,9 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2205
2268
|
return value === void 0 ? [] : [value];
|
|
2206
2269
|
}));
|
|
2207
2270
|
const reuse = snapshot !== void 0 && snapshot.totalRecords > 0 ? Math.max(0, Math.min(1, 1 - snapshot.newConnections / snapshot.totalRecords)) : void 0;
|
|
2208
|
-
const head = (key, label) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("th", { className: request_log_default.thSortable, onClick: () => {
|
|
2271
|
+
const head = (key, label, hint) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("th", { className: request_log_default.thSortable, onClick: () => {
|
|
2209
2272
|
toggleSort(key);
|
|
2210
|
-
}, children: [
|
|
2273
|
+
}, title: hint, children: [
|
|
2211
2274
|
label,
|
|
2212
2275
|
sortKey === key ? sortDir === "asc" ? " \u25B2" : " \u25BC" : ""
|
|
2213
2276
|
] });
|
|
@@ -2219,10 +2282,11 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2219
2282
|
if (group !== void 0 && group !== lastGroup) {
|
|
2220
2283
|
lastGroup = group;
|
|
2221
2284
|
out.push(
|
|
2222
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { className: request_log_default.group, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { colSpan: 11, children: group }) }, `group-${group}-${entry.seq}`)
|
|
2285
|
+
/* @__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}`)
|
|
2223
2286
|
);
|
|
2224
2287
|
}
|
|
2225
2288
|
const state = !entry.ok ? "rowFail" : entry.tps !== void 0 && entry.tps < 5 ? "rowSlow" : "rowOk";
|
|
2289
|
+
const session = sessionLabel(entry.session);
|
|
2226
2290
|
out.push(
|
|
2227
2291
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2228
2292
|
"tr",
|
|
@@ -2234,7 +2298,7 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2234
2298
|
children: [
|
|
2235
2299
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: new Date(entry.atMs).toLocaleTimeString(getLocale(), { hour12: false }) }),
|
|
2236
2300
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { className: request_log_default.mono, children: entry.model }),
|
|
2237
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", {
|
|
2301
|
+
/* @__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 }),
|
|
2238
2302
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: count2(entry.inputTokens) }),
|
|
2239
2303
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: count2(entry.outputTokens) }),
|
|
2240
2304
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: count2(entry.cacheReadTokens) }),
|
|
@@ -2255,13 +2319,28 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2255
2319
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailMethod") }),
|
|
2256
2320
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${request_log_default.detailValue} ${request_log_default.mono}`, children: entry.method })
|
|
2257
2321
|
] }),
|
|
2322
|
+
entry.protocol !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
|
|
2323
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailProtocol") }),
|
|
2324
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${request_log_default.detailValue} ${request_log_default.mono}`, children: entry.protocol })
|
|
2325
|
+
] }),
|
|
2258
2326
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
|
|
2259
2327
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailUrl") }),
|
|
2260
2328
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${request_log_default.detailValue} ${request_log_default.mono}`, children: entry.url })
|
|
2261
2329
|
] }),
|
|
2330
|
+
entry.requestBytes !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
|
|
2331
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailRequestBytes") }),
|
|
2332
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailValue, children: bytes(entry.requestBytes) })
|
|
2333
|
+
] }),
|
|
2262
2334
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
|
|
2263
2335
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailSession") }),
|
|
2264
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2336
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2337
|
+
"span",
|
|
2338
|
+
{
|
|
2339
|
+
className: `${request_log_default.detailValue} ${session.titled ? "" : request_log_default.mono}`,
|
|
2340
|
+
title: session.titled ? entry.session : void 0,
|
|
2341
|
+
children: session.titled ? `${session.text} \xB7 ${entry.session}` : session.text
|
|
2342
|
+
}
|
|
2343
|
+
)
|
|
2265
2344
|
] }),
|
|
2266
2345
|
entry.poolKey !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
|
|
2267
2346
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailPool") }),
|
|
@@ -2281,7 +2360,15 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2281
2360
|
] }),
|
|
2282
2361
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
|
|
2283
2362
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailTokens") }),
|
|
2284
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
2363
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: request_log_default.detailValue, children: [
|
|
2364
|
+
`${count2(entry.inputTokens)} / ${count2(entry.outputTokens)} / ${count2(entry.cacheReadTokens)}`,
|
|
2365
|
+
entry.cacheWriteTokens !== void 0 && ` \xB7 ${t("requestLogDetailCacheWrite")} ${count2(entry.cacheWriteTokens)}`,
|
|
2366
|
+
entry.reasoningTokens !== void 0 && ` \xB7 ${t("requestLogDetailReasoning")} ${count2(entry.reasoningTokens)}`
|
|
2367
|
+
] })
|
|
2368
|
+
] }),
|
|
2369
|
+
entry.costUsd !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
|
|
2370
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailCost") }),
|
|
2371
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailValue, children: cost(entry.costUsd) })
|
|
2285
2372
|
] }),
|
|
2286
2373
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
|
|
2287
2374
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogColCacheRate") }),
|
|
@@ -2291,6 +2378,10 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2291
2378
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogColTps") }),
|
|
2292
2379
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailValue, children: rate2(entry.tps) })
|
|
2293
2380
|
] }),
|
|
2381
|
+
entry.streamMs !== void 0 && entry.tps === void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
|
|
2382
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogColStream") }),
|
|
2383
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailValue, children: duration(entry.streamMs) })
|
|
2384
|
+
] }),
|
|
2294
2385
|
!entry.ok && entry.code !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
|
|
2295
2386
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailError") }),
|
|
2296
2387
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailValue, children: entry.code })
|
|
@@ -2301,201 +2392,213 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
|
|
|
2301
2392
|
}
|
|
2302
2393
|
return out;
|
|
2303
2394
|
};
|
|
2304
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
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
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2395
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2396
|
+
"div",
|
|
2397
|
+
{
|
|
2398
|
+
className: sessionId === void 0 ? request_log_default.page : `${request_log_default.page} ${request_log_default.pageLoose}`,
|
|
2399
|
+
style: { "--request-log-stuck": `${stuckTop}px` },
|
|
2400
|
+
children: [
|
|
2401
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.stuck, ref: stuckRef, children: [
|
|
2402
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.head, children: [
|
|
2403
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.headText, children: [
|
|
2404
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { className: request_log_default.title, children: t("requestLogTitle") }),
|
|
2405
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: request_log_default.subtitle, children: t("requestLogPageHint") })
|
|
2406
|
+
] }),
|
|
2407
|
+
/* @__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: () => {
|
|
2408
|
+
void load();
|
|
2409
|
+
}, disabled: refreshing, children: [
|
|
2410
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives.IconRefreshOutlineRegular, { size: 13 }),
|
|
2411
|
+
t("requestLogRefresh")
|
|
2412
|
+
] }) })
|
|
2413
|
+
] }),
|
|
2414
|
+
!enabled() && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: request_log_default.notice, children: t("requestLogDisabled") }),
|
|
2415
|
+
failure !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: `${request_log_default.notice} ${request_log_default.noticeError}`, children: failure }),
|
|
2416
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.summary, children: [
|
|
2417
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
|
|
2418
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatRequests") }),
|
|
2419
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: filtered.length.toLocaleString(getLocale()) })
|
|
2420
|
+
] }),
|
|
2421
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `${request_log_default.card} ${failures > 0 ? request_log_default.cardError : ""}`, children: [
|
|
2422
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatFailures") }),
|
|
2423
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: failures.toLocaleString(getLocale()) })
|
|
2424
|
+
] }),
|
|
2425
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
|
|
2426
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatLatency") }),
|
|
2427
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: duration(meanLatency) })
|
|
2428
|
+
] }),
|
|
2429
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
|
|
2430
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatFirstToken") }),
|
|
2431
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: duration(meanFirstToken) })
|
|
2432
|
+
] }),
|
|
2433
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
|
|
2434
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatTps") }),
|
|
2435
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: rate2(meanTps) })
|
|
2436
|
+
] }),
|
|
2437
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
|
|
2438
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatCacheRate") }),
|
|
2439
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: percent(meanCacheRate) })
|
|
2440
|
+
] }),
|
|
2441
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
|
|
2442
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogReuse") }),
|
|
2443
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: reuse === void 0 ? "\u2014" : `${(reuse * 100).toFixed(0)}%` })
|
|
2444
|
+
] })
|
|
2445
|
+
] }),
|
|
2446
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.toolbar, children: [
|
|
2447
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
|
|
2448
|
+
t("requestLogFilterModel"),
|
|
2449
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2450
|
+
"select",
|
|
2451
|
+
{
|
|
2452
|
+
className: request_log_default.select,
|
|
2453
|
+
value: model,
|
|
2454
|
+
onChange: (event) => {
|
|
2455
|
+
setModel(event.target.value);
|
|
2456
|
+
setPage(0);
|
|
2457
|
+
},
|
|
2458
|
+
children: [
|
|
2459
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "all", children: t("requestLogFilterModelAll") }),
|
|
2460
|
+
models.map((id4) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: id4, children: id4 }, id4))
|
|
2461
|
+
]
|
|
2462
|
+
}
|
|
2463
|
+
)
|
|
2464
|
+
] }),
|
|
2465
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
|
|
2466
|
+
t("requestLogFilterResult"),
|
|
2467
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2468
|
+
"select",
|
|
2469
|
+
{
|
|
2470
|
+
className: request_log_default.select,
|
|
2471
|
+
value: result,
|
|
2472
|
+
onChange: (event) => {
|
|
2473
|
+
setResult(event.target.value);
|
|
2474
|
+
setPage(0);
|
|
2475
|
+
},
|
|
2476
|
+
children: [
|
|
2477
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "all", children: t("requestLogResultAll") }),
|
|
2478
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "ok", children: t("requestLogResultOk") }),
|
|
2479
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "fail", children: t("requestLogResultFail") })
|
|
2480
|
+
]
|
|
2481
|
+
}
|
|
2482
|
+
)
|
|
2483
|
+
] }),
|
|
2484
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
|
|
2485
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2486
|
+
"input",
|
|
2487
|
+
{
|
|
2488
|
+
className: request_log_default.checkbox,
|
|
2489
|
+
type: "checkbox",
|
|
2490
|
+
checked: slowOnly,
|
|
2491
|
+
onChange: (event) => {
|
|
2492
|
+
setSlowOnly(event.target.checked);
|
|
2493
|
+
setPage(0);
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
),
|
|
2497
|
+
t("requestLogSlowOnly"),
|
|
2498
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2499
|
+
"input",
|
|
2500
|
+
{
|
|
2501
|
+
className: `${request_log_default.input} ${request_log_default.inputNumber}`,
|
|
2502
|
+
type: "number",
|
|
2503
|
+
min: 1,
|
|
2504
|
+
value: slowSeconds,
|
|
2505
|
+
disabled: !slowOnly,
|
|
2506
|
+
"aria-label": t("requestLogSlowSeconds"),
|
|
2507
|
+
onChange: (event) => {
|
|
2508
|
+
setSlowSeconds(Number(event.target.value));
|
|
2509
|
+
setPage(0);
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
),
|
|
2513
|
+
t("requestLogSlowSeconds")
|
|
2514
|
+
] }),
|
|
2515
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
|
|
2516
|
+
t("requestLogFilterSession"),
|
|
2517
|
+
sessionId !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2518
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2519
|
+
"input",
|
|
2520
|
+
{
|
|
2521
|
+
className: request_log_default.checkbox,
|
|
2522
|
+
type: "checkbox",
|
|
2523
|
+
checked: onlySession,
|
|
2524
|
+
onChange: (event) => {
|
|
2525
|
+
setOnlySession(event.target.checked);
|
|
2526
|
+
setPage(0);
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
),
|
|
2530
|
+
t("requestLogOnlySession")
|
|
2531
|
+
] }),
|
|
2532
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2533
|
+
"input",
|
|
2534
|
+
{
|
|
2535
|
+
className: request_log_default.input,
|
|
2536
|
+
type: "search",
|
|
2537
|
+
value: sessionQuery,
|
|
2538
|
+
disabled: onlySession,
|
|
2539
|
+
onChange: (event) => {
|
|
2540
|
+
setSessionQuery(event.target.value);
|
|
2541
|
+
setPage(0);
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
)
|
|
2545
|
+
] }),
|
|
2546
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
|
|
2547
|
+
t("requestLogGroupBy"),
|
|
2548
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2549
|
+
"select",
|
|
2550
|
+
{
|
|
2551
|
+
className: request_log_default.select,
|
|
2552
|
+
value: groupBy,
|
|
2553
|
+
onChange: (event) => {
|
|
2554
|
+
setGroupBy(event.target.value);
|
|
2555
|
+
setPage(0);
|
|
2556
|
+
},
|
|
2557
|
+
children: [
|
|
2558
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "none", children: t("requestLogGroupNone") }),
|
|
2559
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "session", children: t("requestLogGroupSession") }),
|
|
2560
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "model", children: t("requestLogGroupModel") }),
|
|
2561
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "result", children: t("requestLogGroupResult") })
|
|
2562
|
+
]
|
|
2563
|
+
}
|
|
2564
|
+
)
|
|
2565
|
+
] })
|
|
2566
|
+
] })
|
|
2434
2567
|
] }),
|
|
2435
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2436
|
-
"
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2452
|
-
"
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
setPage(
|
|
2459
|
-
},
|
|
2460
|
-
children:
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
] }),
|
|
2470
|
-
/* @__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: [
|
|
2471
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
|
|
2472
|
-
head("atMs", t("requestLogColTime")),
|
|
2473
|
-
head("model", t("requestLogColModel")),
|
|
2474
|
-
head("session", t("requestLogColSession")),
|
|
2475
|
-
head("inputTokens", t("requestLogColIn")),
|
|
2476
|
-
head("outputTokens", t("requestLogColOut")),
|
|
2477
|
-
head("cacheReadTokens", t("requestLogColCache")),
|
|
2478
|
-
head("cacheRate", t("requestLogColCacheRate")),
|
|
2479
|
-
head("tps", t("requestLogColTps")),
|
|
2480
|
-
head("firstTokenMs", t("requestLogColFirstToken")),
|
|
2481
|
-
head("durationMs", t("requestLogColLatency")),
|
|
2482
|
-
head("status", t("requestLogColStatus"))
|
|
2483
|
-
] }) }),
|
|
2484
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: rows() })
|
|
2485
|
-
] }) }),
|
|
2486
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.foot, children: [
|
|
2487
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: `${filtered.length.toLocaleString(getLocale())} / ${(snapshot?.totalRecords ?? 0).toLocaleString(getLocale())} ${t("requestLogStatRequests")}` }),
|
|
2488
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.pager, children: [
|
|
2489
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: request_log_default.button, disabled: safePage <= 0, onClick: () => {
|
|
2490
|
-
setPage(safePage - 1);
|
|
2491
|
-
}, children: t("requestLogPagePrev") }),
|
|
2492
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: `${safePage + 1} ${t("requestLogPageOf")} ${pages}` }),
|
|
2493
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: request_log_default.button, disabled: safePage >= pages - 1, onClick: () => {
|
|
2494
|
-
setPage(safePage + 1);
|
|
2495
|
-
}, children: t("requestLogPageNext") })
|
|
2496
|
-
] })
|
|
2497
|
-
] })
|
|
2498
|
-
] });
|
|
2568
|
+
/* @__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: [
|
|
2569
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
|
|
2570
|
+
head("atMs", t("requestLogColTime")),
|
|
2571
|
+
head("model", t("requestLogColModel")),
|
|
2572
|
+
head("session", t("requestLogColSession")),
|
|
2573
|
+
head("inputTokens", t("requestLogColIn"), t("requestLogColInHint")),
|
|
2574
|
+
head("outputTokens", t("requestLogColOut"), t("requestLogColOutHint")),
|
|
2575
|
+
head("cacheReadTokens", t("requestLogColCache"), t("requestLogColCacheHint")),
|
|
2576
|
+
head("cacheRate", t("requestLogColCacheRate")),
|
|
2577
|
+
head("tps", t("requestLogColTps")),
|
|
2578
|
+
head("firstTokenMs", t("requestLogColFirstToken")),
|
|
2579
|
+
head("durationMs", t("requestLogColLatency")),
|
|
2580
|
+
head("status", t("requestLogColStatus"))
|
|
2581
|
+
] }) }),
|
|
2582
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: rows() })
|
|
2583
|
+
] }) }),
|
|
2584
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.foot, children: [
|
|
2585
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
|
|
2586
|
+
`${t("requestLogStatRequests")}: ${filtered.length.toLocaleString(getLocale())}`,
|
|
2587
|
+
filtered.length !== (snapshot?.totalRecords ?? 0) ? ` (${t("requestLogOfTotal")} ${(snapshot?.totalRecords ?? 0).toLocaleString(getLocale())})` : ""
|
|
2588
|
+
] }),
|
|
2589
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.pager, children: [
|
|
2590
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: request_log_default.button, disabled: safePage <= 0, onClick: () => {
|
|
2591
|
+
setPage(safePage - 1);
|
|
2592
|
+
}, children: t("requestLogPagePrev") }),
|
|
2593
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: `${safePage + 1} ${t("requestLogPageOf")} ${pages}` }),
|
|
2594
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: request_log_default.button, disabled: safePage >= pages - 1, onClick: () => {
|
|
2595
|
+
setPage(safePage + 1);
|
|
2596
|
+
}, children: t("requestLogPageNext") })
|
|
2597
|
+
] })
|
|
2598
|
+
] })
|
|
2599
|
+
]
|
|
2600
|
+
}
|
|
2601
|
+
);
|
|
2499
2602
|
}
|
|
2500
2603
|
|
|
2501
2604
|
// src/client/RequestLogPanelIcon.tsx
|
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({}),
|
|
@@ -76520,6 +76522,10 @@ function spendOf(usage, rates2) {
|
|
|
76520
76522
|
const cacheWrite = usage.cacheWriteTokens ?? 0;
|
|
76521
76523
|
return (usage.inputTokens * rates2.input + usage.outputTokens * rates2.output + cacheRead * (rates2.cacheRead ?? fallback) + cacheWrite * (rates2.cacheWrite ?? fallback)) / 1e6;
|
|
76522
76524
|
}
|
|
76525
|
+
function costOf(usage, rates2) {
|
|
76526
|
+
if (rates2 === void 0) return void 0;
|
|
76527
|
+
return spendOf(usage, rates2);
|
|
76528
|
+
}
|
|
76523
76529
|
function add(totals, usage) {
|
|
76524
76530
|
const inputTokens = totals.inputTokens + usage.inputTokens;
|
|
76525
76531
|
const outputTokens = totals.outputTokens + usage.outputTokens;
|
|
@@ -76598,6 +76604,12 @@ function requestUrl(input) {
|
|
|
76598
76604
|
if (input instanceof URL) return input.toString();
|
|
76599
76605
|
return input.url;
|
|
76600
76606
|
}
|
|
76607
|
+
function bodyBytes(body) {
|
|
76608
|
+
if (typeof body === "string") return Buffer.byteLength(body);
|
|
76609
|
+
if (body instanceof ArrayBuffer) return body.byteLength;
|
|
76610
|
+
if (ArrayBuffer.isView(body)) return body.byteLength;
|
|
76611
|
+
return void 0;
|
|
76612
|
+
}
|
|
76601
76613
|
async function* observingTerminalUsage(events, observe) {
|
|
76602
76614
|
for await (const event of events) {
|
|
76603
76615
|
if (event.type === "done") observe(event.message.usage);
|
|
@@ -76771,6 +76783,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
76771
76783
|
const span = this.options.requestLog?.start({
|
|
76772
76784
|
model: options.model,
|
|
76773
76785
|
sessionId: options.sessionId === void 0 ? void 0 : String(options.sessionId),
|
|
76786
|
+
protocol: facts.api,
|
|
76774
76787
|
method: "POST",
|
|
76775
76788
|
url: config.baseURL,
|
|
76776
76789
|
messageCount: options.messages.length,
|
|
@@ -76786,7 +76799,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
76786
76799
|
const base = fetchFactory();
|
|
76787
76800
|
return (async (input, init) => {
|
|
76788
76801
|
const response = await base(input, init);
|
|
76789
|
-
span.request(typeof init?.method === "string" ? init.method : "POST", requestUrl(input));
|
|
76802
|
+
span.request(typeof init?.method === "string" ? init.method : "POST", requestUrl(input), bodyBytes(init?.body));
|
|
76790
76803
|
span.status(response.status);
|
|
76791
76804
|
return response;
|
|
76792
76805
|
});
|
|
@@ -76850,7 +76863,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
76850
76863
|
exhausted = true;
|
|
76851
76864
|
return;
|
|
76852
76865
|
}
|
|
76853
|
-
if (span !== void 0 && isTokenDelta(result.value)) span.
|
|
76866
|
+
if (span !== void 0 && isTokenDelta(result.value)) span.token();
|
|
76854
76867
|
if (result.value.type === "usage") {
|
|
76855
76868
|
pendingUsage = result.value.usage;
|
|
76856
76869
|
this.options.onUsage?.({
|
|
@@ -76866,14 +76879,18 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
76866
76879
|
} else if (result.value.type === "finish") {
|
|
76867
76880
|
const reason = result.value.reason;
|
|
76868
76881
|
const ok = reason.kind === "stop" || reason.kind === "tool-calls" || reason.kind === "max-tokens";
|
|
76882
|
+
const usage = pendingUsage === void 0 ? void 0 : {
|
|
76883
|
+
inputTokens: pendingUsage.inputTokens,
|
|
76884
|
+
outputTokens: pendingUsage.outputTokens,
|
|
76885
|
+
...pendingUsage.cacheReadTokens === void 0 ? {} : { cacheReadTokens: pendingUsage.cacheReadTokens },
|
|
76886
|
+
...pendingUsage.cacheWriteTokens === void 0 ? {} : { cacheWriteTokens: pendingUsage.cacheWriteTokens },
|
|
76887
|
+
...reportedReasoning === void 0 || reportedReasoning <= 0 ? {} : { reasoningTokens: reportedReasoning }
|
|
76888
|
+
};
|
|
76869
76889
|
span?.finish(
|
|
76870
76890
|
ok,
|
|
76871
76891
|
ok ? void 0 : reason.failure?.code,
|
|
76872
|
-
|
|
76873
|
-
|
|
76874
|
-
outputTokens: pendingUsage.outputTokens,
|
|
76875
|
-
...pendingUsage.cacheReadTokens === void 0 ? {} : { cacheReadTokens: pendingUsage.cacheReadTokens }
|
|
76876
|
-
}
|
|
76892
|
+
usage,
|
|
76893
|
+
usage === void 0 ? void 0 : costOf(usage, rates2)
|
|
76877
76894
|
);
|
|
76878
76895
|
}
|
|
76879
76896
|
yield result.value;
|
|
@@ -77109,10 +77126,14 @@ function parseEntry(value) {
|
|
|
77109
77126
|
const row = value;
|
|
77110
77127
|
const shape = row["shape"];
|
|
77111
77128
|
const headers = row["headers"];
|
|
77129
|
+
const protocol = row["protocol"];
|
|
77112
77130
|
return {
|
|
77113
77131
|
seq: count("seq", row),
|
|
77114
77132
|
atMs: count("atMs", row),
|
|
77115
77133
|
model: text("model", row),
|
|
77134
|
+
// Older rows predate the protocol recording; they read without one
|
|
77135
|
+
// rather than failing the whole snapshot.
|
|
77136
|
+
...protocol === "anthropic-messages" || protocol === "openai-completions" || protocol === "openai-responses" ? { protocol } : {},
|
|
77116
77137
|
session: text("session", row),
|
|
77117
77138
|
method: text("method", row),
|
|
77118
77139
|
url: text("url", row),
|
|
@@ -77120,9 +77141,14 @@ function parseEntry(value) {
|
|
|
77120
77141
|
...row["inputTokens"] === void 0 ? {} : { inputTokens: count("inputTokens", row) },
|
|
77121
77142
|
...row["outputTokens"] === void 0 ? {} : { outputTokens: count("outputTokens", row) },
|
|
77122
77143
|
...row["cacheReadTokens"] === void 0 ? {} : { cacheReadTokens: count("cacheReadTokens", row) },
|
|
77144
|
+
...row["cacheWriteTokens"] === void 0 ? {} : { cacheWriteTokens: count("cacheWriteTokens", row) },
|
|
77145
|
+
...row["reasoningTokens"] === void 0 ? {} : { reasoningTokens: count("reasoningTokens", row) },
|
|
77146
|
+
...row["costUsd"] === void 0 ? {} : { costUsd: rate("costUsd", row) },
|
|
77147
|
+
...row["requestBytes"] === void 0 ? {} : { requestBytes: count("requestBytes", row) },
|
|
77123
77148
|
...row["durationMs"] === void 0 ? {} : { durationMs: count("durationMs", row) },
|
|
77124
77149
|
...row["firstTokenMs"] === void 0 ? {} : { firstTokenMs: count("firstTokenMs", row) },
|
|
77125
77150
|
...row["decodeMs"] === void 0 ? {} : { decodeMs: count("decodeMs", row) },
|
|
77151
|
+
...row["streamMs"] === void 0 ? {} : { streamMs: count("streamMs", row) },
|
|
77126
77152
|
...row["tps"] === void 0 ? {} : { tps: rate("tps", row) },
|
|
77127
77153
|
ok: row["ok"] === true,
|
|
77128
77154
|
...typeof row["code"] === "string" ? { code: row["code"] } : {},
|
|
@@ -77666,6 +77692,7 @@ var OpencodeGoRequestLogService = class extends TypertRemoteService3 {
|
|
|
77666
77692
|
|
|
77667
77693
|
// src/request-log/store.ts
|
|
77668
77694
|
var MAX_POOL_EVENTS = 20;
|
|
77695
|
+
var MIN_STREAM_MS_FOR_RATE = 100;
|
|
77669
77696
|
var RequestLog = class {
|
|
77670
77697
|
gates;
|
|
77671
77698
|
entries = [];
|
|
@@ -77707,33 +77734,40 @@ var RequestLog = class {
|
|
|
77707
77734
|
const startedAt = Date.now();
|
|
77708
77735
|
const session = detail.sessionId ?? "";
|
|
77709
77736
|
let firstTokenAt;
|
|
77737
|
+
let lastTokenAt;
|
|
77710
77738
|
let method;
|
|
77711
77739
|
let url;
|
|
77740
|
+
let requestBytes;
|
|
77712
77741
|
let status;
|
|
77713
77742
|
let finished = false;
|
|
77714
77743
|
return {
|
|
77715
|
-
|
|
77716
|
-
|
|
77744
|
+
token: () => {
|
|
77745
|
+
const now = Date.now();
|
|
77746
|
+
if (firstTokenAt === void 0) firstTokenAt = now;
|
|
77747
|
+
lastTokenAt = now;
|
|
77717
77748
|
},
|
|
77718
|
-
request: (nextMethod, nextUrl) => {
|
|
77749
|
+
request: (nextMethod, nextUrl, nextRequestBytes) => {
|
|
77719
77750
|
if (method === void 0) {
|
|
77720
77751
|
method = nextMethod;
|
|
77721
77752
|
url = nextUrl;
|
|
77753
|
+
requestBytes = nextRequestBytes;
|
|
77722
77754
|
}
|
|
77723
77755
|
},
|
|
77724
77756
|
status: (value) => {
|
|
77725
77757
|
status = value;
|
|
77726
77758
|
},
|
|
77727
|
-
finish: (ok, code, usage) => {
|
|
77759
|
+
finish: (ok, code, usage, costUsd) => {
|
|
77728
77760
|
if (finished) return;
|
|
77729
77761
|
finished = true;
|
|
77730
77762
|
const endedAt = Date.now();
|
|
77731
77763
|
const decodeMs = firstTokenAt === void 0 ? void 0 : Math.max(0, endedAt - firstTokenAt);
|
|
77732
|
-
const
|
|
77764
|
+
const streamMs = firstTokenAt === void 0 || lastTokenAt === void 0 ? void 0 : Math.max(0, lastTokenAt - firstTokenAt);
|
|
77765
|
+
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);
|
|
77733
77766
|
const entry = {
|
|
77734
77767
|
seq: ++this.seq,
|
|
77735
77768
|
atMs: startedAt,
|
|
77736
77769
|
model: detail.model,
|
|
77770
|
+
...detail.protocol === void 0 ? {} : { protocol: detail.protocol },
|
|
77737
77771
|
session,
|
|
77738
77772
|
method: method ?? detail.method ?? "POST",
|
|
77739
77773
|
url: url ?? detail.url ?? "",
|
|
@@ -77741,11 +77775,16 @@ var RequestLog = class {
|
|
|
77741
77775
|
...usage === void 0 ? {} : {
|
|
77742
77776
|
inputTokens: usage.inputTokens,
|
|
77743
77777
|
outputTokens: usage.outputTokens,
|
|
77744
|
-
...usage.cacheReadTokens === void 0 || usage.cacheReadTokens <= 0 ? {} : { cacheReadTokens: usage.cacheReadTokens }
|
|
77778
|
+
...usage.cacheReadTokens === void 0 || usage.cacheReadTokens <= 0 ? {} : { cacheReadTokens: usage.cacheReadTokens },
|
|
77779
|
+
...usage.cacheWriteTokens === void 0 || usage.cacheWriteTokens <= 0 ? {} : { cacheWriteTokens: usage.cacheWriteTokens },
|
|
77780
|
+
...usage.reasoningTokens === void 0 || usage.reasoningTokens <= 0 ? {} : { reasoningTokens: usage.reasoningTokens }
|
|
77745
77781
|
},
|
|
77782
|
+
...costUsd === void 0 ? {} : { costUsd },
|
|
77783
|
+
...requestBytes === void 0 ? {} : { requestBytes },
|
|
77746
77784
|
durationMs: Math.max(0, endedAt - startedAt),
|
|
77747
77785
|
...firstTokenAt === void 0 ? {} : { firstTokenMs: Math.max(0, firstTokenAt - startedAt) },
|
|
77748
77786
|
...decodeMs === void 0 ? {} : { decodeMs },
|
|
77787
|
+
...streamMs === void 0 ? {} : { streamMs },
|
|
77749
77788
|
...tps === void 0 ? {} : { tps },
|
|
77750
77789
|
ok,
|
|
77751
77790
|
...code === void 0 ? {} : { code },
|
|
@@ -77886,7 +77925,7 @@ function createUpdateChecker(deps) {
|
|
|
77886
77925
|
}
|
|
77887
77926
|
|
|
77888
77927
|
// src/update/version.ts
|
|
77889
|
-
var PLUGIN_VERSION = true ? "0.1.
|
|
77928
|
+
var PLUGIN_VERSION = true ? "0.1.68" : "0.0.0-dev";
|
|
77890
77929
|
|
|
77891
77930
|
// src/update/service.ts
|
|
77892
77931
|
import { TypertRemoteService as TypertRemoteService4 } from "@deepseek-ai/dsh-typert-protocol";
|
package/lib/types/config.d.ts
CHANGED
|
@@ -76,9 +76,10 @@ 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
|
/**
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
*
|
|
20
20
|
* @module @dan-ai-studio/dshopencodego/request-log/store
|
|
21
21
|
*/
|
|
22
|
+
import type { WireProtocol } from '../catalog/protocol.ts';
|
|
22
23
|
/** One recorded request. Counts are provider-reported; timings are Host-measured. */
|
|
23
24
|
export interface RequestLogEntry {
|
|
24
25
|
/** Monotonic sequence within this process; gaps mean nothing was recorded. */
|
|
@@ -27,6 +28,11 @@ export interface RequestLogEntry {
|
|
|
27
28
|
readonly atMs: number;
|
|
28
29
|
/** The model id the request was made with. */
|
|
29
30
|
readonly model: string;
|
|
31
|
+
/**
|
|
32
|
+
* The wire protocol the request ran on, as the catalog resolved it.
|
|
33
|
+
* Present from the build that records it; older rows simply lack it.
|
|
34
|
+
*/
|
|
35
|
+
readonly protocol?: WireProtocol;
|
|
30
36
|
/** The session id the request belonged to, whole. */
|
|
31
37
|
readonly session: string;
|
|
32
38
|
/** HTTP method used. */
|
|
@@ -41,6 +47,32 @@ export interface RequestLogEntry {
|
|
|
41
47
|
readonly outputTokens?: number;
|
|
42
48
|
/** Provider-reported cache-read tokens, when positive. */
|
|
43
49
|
readonly cacheReadTokens?: number;
|
|
50
|
+
/** Provider-reported cache-write tokens, when positive. */
|
|
51
|
+
readonly cacheWriteTokens?: number;
|
|
52
|
+
/**
|
|
53
|
+
* Provider-reported reasoning tokens, when positive. A subset of
|
|
54
|
+
* `outputTokens` — never added to a total — recorded so a thinking turn's
|
|
55
|
+
* shape stays visible.
|
|
56
|
+
*/
|
|
57
|
+
readonly reasoningTokens?: number;
|
|
58
|
+
/**
|
|
59
|
+
* Estimated USD for this request at the rates in force when it ran, by the
|
|
60
|
+
* same function that prices the since-boot meter. Absent for unpriced
|
|
61
|
+
* models: no zero standing in for "unknown".
|
|
62
|
+
*/
|
|
63
|
+
readonly costUsd?: number;
|
|
64
|
+
/**
|
|
65
|
+
* Request body size in bytes, as handed to fetch. Explanatory, not
|
|
66
|
+
* sensitive: a multi-megabyte turn uploads slowly no matter the model.
|
|
67
|
+
*/
|
|
68
|
+
readonly requestBytes?: number;
|
|
69
|
+
/**
|
|
70
|
+
* Wall time from the first to the last content token, in milliseconds —
|
|
71
|
+
* the window the output actually streamed in. Absent when fewer than two
|
|
72
|
+
* content tokens arrived; a burst delivery reads here as ~zero while the
|
|
73
|
+
* whole reply still counts in the totals above.
|
|
74
|
+
*/
|
|
75
|
+
readonly streamMs?: number;
|
|
44
76
|
/** Wall time from request start to terminal event, in milliseconds. */
|
|
45
77
|
readonly durationMs?: number;
|
|
46
78
|
/** Wall time from request start to the first token delta, in milliseconds. */
|
|
@@ -54,9 +86,11 @@ export interface RequestLogEntry {
|
|
|
54
86
|
/**
|
|
55
87
|
* Output tokens per second over the decode window.
|
|
56
88
|
*
|
|
57
|
-
* Absent when the request produced no token,
|
|
58
|
-
* rounds to zero milliseconds
|
|
59
|
-
*
|
|
89
|
+
* Absent when the request produced no token, when the decode window
|
|
90
|
+
* rounds to zero milliseconds, or when the whole output arrived in one
|
|
91
|
+
* burst (see `MIN_STREAM_MS_FOR_RATE`): a rate divided by zero is not a
|
|
92
|
+
* rate, and a rate over a burst is not a generation speed. Either would
|
|
93
|
+
* misreport a buffered reply as infinitely quick.
|
|
60
94
|
*/
|
|
61
95
|
readonly tps?: number;
|
|
62
96
|
/** Whether the request completed. */
|
|
@@ -119,20 +153,30 @@ export interface RequestLogGates {
|
|
|
119
153
|
/**
|
|
120
154
|
* An in-flight request, handed back only when the log is enabled.
|
|
121
155
|
*
|
|
122
|
-
* Every method is cheap by construction:
|
|
123
|
-
* integer arithmetic across the whole span. No
|
|
124
|
-
* no body handling — the counts ride the usage
|
|
125
|
-
* holds, and the timings bracket work that
|
|
156
|
+
* Every method is cheap by construction: one `Date.now` read per content
|
|
157
|
+
* delta and small integer arithmetic across the whole span. No
|
|
158
|
+
* serialization, no hashing, no body handling — the counts ride the usage
|
|
159
|
+
* chunk the adapter already holds, and the timings bracket work that
|
|
160
|
+
* already happened.
|
|
126
161
|
*/
|
|
127
162
|
export interface RequestSpan {
|
|
128
|
-
/**
|
|
129
|
-
|
|
163
|
+
/**
|
|
164
|
+
* Mark one content token's arrival.
|
|
165
|
+
*
|
|
166
|
+
* The first call opens the decode window; every call moves the last-token
|
|
167
|
+
* mark, so the span between them is the window the output actually
|
|
168
|
+
* streamed in. The adapter calls this for every chunk its own first-token
|
|
169
|
+
* definition accepts — the same definition the Harness uses.
|
|
170
|
+
*/
|
|
171
|
+
token(): void;
|
|
130
172
|
/**
|
|
131
173
|
* Record the wire request line, from the fetch wrapper. Called at most
|
|
132
174
|
* once per span; a second call keeps the first, so retries never rewrite
|
|
133
175
|
* the original line.
|
|
176
|
+
* @param requestBytes - request body size in bytes, when the body was a
|
|
177
|
+
* measurable in-memory value rather than a stream.
|
|
134
178
|
*/
|
|
135
|
-
request(method: string, url: string): void;
|
|
179
|
+
request(method: string, url: string, requestBytes?: number): void;
|
|
136
180
|
/** Mark the response status line's arrival. */
|
|
137
181
|
status(status: number): void;
|
|
138
182
|
/**
|
|
@@ -140,17 +184,22 @@ export interface RequestSpan {
|
|
|
140
184
|
* @param ok - whether the request completed.
|
|
141
185
|
* @param code - failure code for a request that did not complete.
|
|
142
186
|
* @param usage - provider-reported counts, when the terminal usage arrived.
|
|
187
|
+
* @param costUsd - estimated USD at the call's rates, when priced.
|
|
143
188
|
*/
|
|
144
189
|
finish(ok: boolean, code?: string, usage?: {
|
|
145
190
|
readonly inputTokens: number;
|
|
146
191
|
readonly outputTokens: number;
|
|
147
192
|
readonly cacheReadTokens?: number;
|
|
148
|
-
|
|
193
|
+
readonly cacheWriteTokens?: number;
|
|
194
|
+
readonly reasoningTokens?: number;
|
|
195
|
+
}, costUsd?: number): void;
|
|
149
196
|
}
|
|
150
197
|
/** Detail the adapter hands the recorder for one request. */
|
|
151
198
|
export interface RequestStart {
|
|
152
199
|
readonly model: string;
|
|
153
200
|
readonly sessionId: string | undefined;
|
|
201
|
+
/** The wire protocol, as the catalog resolved it for this model. */
|
|
202
|
+
readonly protocol?: WireProtocol;
|
|
154
203
|
/** Fallback line, used only when the fetch wrapper never reported the real one. */
|
|
155
204
|
readonly method?: string;
|
|
156
205
|
readonly url?: string;
|
|
@@ -123,6 +123,22 @@ export interface GoMeter {
|
|
|
123
123
|
/** Per-model entries, busiest first. */
|
|
124
124
|
readonly models: readonly MeterModelEntry[];
|
|
125
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* What one call's tokens cost at the rates in force for it, without touching
|
|
128
|
+
* any accumulator.
|
|
129
|
+
*
|
|
130
|
+
* The request log prices one row through this while the meter keeps the
|
|
131
|
+
* since-boot totals: same function, same rates, so the two can never
|
|
132
|
+
* disagree. Unpriced calls have no estimate rather than a zero one.
|
|
133
|
+
* @param usage - the call's counts; reasoning tokens ride inside `output`
|
|
134
|
+
* and are never billed twice.
|
|
135
|
+
* @param rates - the rates published for the model at call time.
|
|
136
|
+
* @returns estimated USD, or undefined when the model published no rates.
|
|
137
|
+
*/
|
|
138
|
+
export declare function costOf(usage: Pick<TokenUsage, 'inputTokens' | 'outputTokens'> & {
|
|
139
|
+
readonly cacheReadTokens?: number;
|
|
140
|
+
readonly cacheWriteTokens?: number;
|
|
141
|
+
}, rates: MeterRates | undefined): number | undefined;
|
|
126
142
|
/** Accumulates provider-reported usage for the lifetime of one Host process. */
|
|
127
143
|
export declare class UsageMeter {
|
|
128
144
|
private readonly sinceMs;
|
package/package.json
CHANGED