@dan-ai-studio/dshopencodego 0.1.66 → 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 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: false # request-log master switch, default off: off reads byte-for-byte as without the log
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,13 +141,14 @@ 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, off by default; enabling them changes nothing about what requests do. The settings page's "Request log" group holds the master switch, the debug switch (pool events and the request user agent), and the retention count (default 200).
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
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.
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.
152
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.
153
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.
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: false # 请求日志总开关,默认关闭:关闭时请求路径与没有该日志逐字节一致
117
+ requestLogEnabled: true # 请求日志总开关,默认开启:关闭后请求路径与没有该日志逐字节一致
118
118
  requestLogDebug: false # 排错详情:连接池事件与请求 UA;会话 id 始终完整记录
119
119
  requestLogMaxEntries: 200 # 最多保留条数,50 ~ 500,超限丢弃最旧的
120
120
  retryPolicy: # 可选:本路由的重试策略(由 dsh-llm-retry 执行)
@@ -140,13 +140,14 @@ API Key 通过 Harness 凭证库提供(引用名 `OPENCODE_GO_API_KEY`),
140
140
  - 设置页里以**秒**显示与填写(毫秒的数字人读不出量级),存储时换算成毫秒。取值 1 ~ 1800000 毫秒。
141
141
  - 空闲满这个时间之后,连接由连接池**自己回收**,不需要额外的清理机制(实际释放时间比设置值多约 2 秒,那是客户端在服务端给的期限之外自留的一点缓冲)。插件被卸载时,连接池也会**一并关掉**——它是插件的,不该留在机器上。
142
142
 
143
- **请求日志**:默认关闭的逐请求记录,打开它不改变请求的任何行为。设置页"请求日志"分组里有总开关、排错详情开关(连接池事件与请求 UA)、保留条数(默认 200)。
143
+ **请求日志**:默认开启的逐请求记录,关掉它请求路径与没有该日志逐字节一致。设置页"请求日志"分组里有总开关、排错详情开关(连接池事件与请求 UA,默认关闭)、保留条数(默认 200)。
144
144
 
145
145
  - **两个入口,同一个页面**:
146
146
  - **侧边栏图标 → 主区域整页**:跨会话看全部请求。日志是进程级的数据,放在侧边栏最合理——位置固定、常驻可见,和 DSH 自己的插件管理器同一个范式。
147
147
  - **会话里的「请求日志」标签页**:就地看**本会话**的请求,回答"刚才那轮为什么慢"不用离开对话。
148
148
  - 页面是一整页而不是浮层:标题、统计(请求数/失败数/平均耗时/平均首字/平均 tok/s/平均缓存命中/连接复用率)、筛选栏固定在上方,只有表格自己滚动。每行含时间、模型、会话、输入/输出/缓存、**缓存命中**、**tok/s**、首字、耗时与状态;点一行展开 HTTP 明细(方法、地址、脱敏后的请求头、请求构成、结果与用量)。筛选有模型/结果/慢请求/会话,分组有会话/模型/结果;**点列头按该列排序**,再点一次反向。
149
- - **tok/s** 是**首字到结束**这段解码窗口上的输出速率,口径与 Harness 自己的每轮读数一致(含推理 token)。没有 token 的请求没有速率——不编数。
149
+ - **tok/s** 是**首字到结束**这段解码窗口上的输出速率,口径与 Harness 自己的每轮读数一致(含推理 token)。没有 token 的请求没有速率——不编数。**突发推送同样没有速率**:网关把一整轮攒到最后一次性推过来时(推理模型常见:8 秒思考在 wire 上不可见,然后上百个 token 几毫秒内到达),内容跨度不足 100ms,算出来的"每秒几万 token"不是生成速度——显示为 —,也不计入平均。
150
+ - 会话列显示**会话标题**(标题来自会话目录;拿不到时回退显示 id,悬停可见完整 id)。会话筛选同时匹配标题与 id;按会话分组的组头同样显示标题。
150
151
  - **缓存命中**是输入 token 里走缓存的占比(缓存读取/(未缓存输入+缓存读取))。网关没报输入就没有占比——同样不编数。
151
152
  - 会话 id **始终完整记录**(它是会话身份,不是凭据;截断后两个会话会读成一个)。
152
153
  - 记录的是环形缓冲(超限丢最旧),进程重启即清;只读快照,不轮询,没人打开的页面零流量。
package/lib/client.js CHANGED
@@ -498,7 +498,7 @@ 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. Off by default; enabling it does not change what requests do.",
501
+ requestLogHint: "Per-request records for troubleshooting. On by default; turning it off returns the request path to exactly as without the log.",
502
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",
@@ -564,6 +564,7 @@ var en = {
564
564
  requestLogStatFirstToken: "Mean first token",
565
565
  requestLogStatTps: "Mean tok/s",
566
566
  requestLogStatCacheRate: "Mean cache hit",
567
+ requestLogOfTotal: "of",
567
568
  writeRejected: "The settings write was rejected (the namespace was reloaded) \u2014 try again",
568
569
  writeFailed: "The settings write failed",
569
570
  filterPlaceholder: "Filter by name or id",
@@ -677,7 +678,7 @@ var zh = {
677
678
  keepAliveLabel: "\u8FDE\u63A5\u7A7A\u95F2\u4FDD\u7559\uFF08\u79D2\uFF09",
678
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",
679
680
  requestLogTitle: "\u8BF7\u6C42\u65E5\u5FD7",
680
- requestLogHint: "\u6392\u67E5\u7528\u7684\u9010\u8BF7\u6C42\u8BB0\u5F55\u3002\u9ED8\u8BA4\u5173\u95ED\uFF1B\u6253\u5F00\u5B83\u4E0D\u4F1A\u6539\u53D8\u8BF7\u6C42\u672C\u8EAB\u7684\u884C\u4E3A\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",
681
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",
682
683
  requestLogEnabled: "\u8BB0\u5F55\u8BF7\u6C42",
683
684
  requestLogDebug: "\u6392\u9519\u8BE6\u60C5",
@@ -743,6 +744,7 @@ var zh = {
743
744
  requestLogStatFirstToken: "\u5E73\u5747\u9996\u5B57",
744
745
  requestLogStatTps: "\u5E73\u5747 tok/s",
745
746
  requestLogStatCacheRate: "\u5E73\u5747\u7F13\u5B58\u547D\u4E2D",
747
+ requestLogOfTotal: "\u5171",
746
748
  writeRejected: "\u8BBE\u7F6E\u5199\u5165\u88AB\u62D2\u7EDD\uFF08\u5DF2\u91CD\u65B0\u8F7D\u5165\uFF09\uFF0C\u8BF7\u91CD\u8BD5",
747
749
  writeFailed: "\u8BBE\u7F6E\u5199\u5165\u5931\u8D25",
748
750
  filterPlaceholder: "\u6309\u540D\u79F0\u6216 ID \u7B5B\u9009",
@@ -1005,7 +1007,7 @@ function settingsOf(value) {
1005
1007
  refreshMinutes: minutes,
1006
1008
  pinnedAddresses: Object.fromEntries(pinEntries),
1007
1009
  keepAliveTimeoutMs: typeof keepAlive === "number" ? keepAlive : DEFAULT_KEEP_ALIVE_TIMEOUT_MS,
1008
- requestLogEnabled: typeof requestLogEnabled === "boolean" ? requestLogEnabled : false,
1010
+ requestLogEnabled: typeof requestLogEnabled === "boolean" ? requestLogEnabled : true,
1009
1011
  requestLogDebug: typeof requestLogDebug === "boolean" ? requestLogDebug : false,
1010
1012
  requestLogMaxEntries: typeof requestLogMaxEntries === "number" ? requestLogMaxEntries : DEFAULT_REQUEST_LOG_MAX_ENTRIES
1011
1013
  };
@@ -1867,7 +1869,7 @@ function Section({ controller, t, getLocale, openRequestLog }) {
1867
1869
  "input",
1868
1870
  {
1869
1871
  type: "checkbox",
1870
- checked: state.settings?.requestLogEnabled ?? false,
1872
+ checked: state.settings?.requestLogEnabled ?? true,
1871
1873
  disabled: !editable || state.saving,
1872
1874
  onChange: (event) => {
1873
1875
  void act(async () => {
@@ -2042,10 +2044,10 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]"
2042
2044
  const style = document.createElement("style");
2043
2045
  style.dataset.plugin = "@dan-ai-studio/dshopencodego";
2044
2046
  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)}";
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)}";
2046
2048
  document.head.appendChild(style);
2047
2049
  }
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" };
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" };
2049
2051
 
2050
2052
  // src/client/RequestLogPage.tsx
2051
2053
  var import_jsx_runtime2 = require("react/jsx-runtime");
@@ -2126,7 +2128,7 @@ function groupKey(entry, groupBy) {
2126
2128
  return void 0;
2127
2129
  }
2128
2130
  }
2129
- function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
2131
+ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId, useSessions }) {
2130
2132
  const [snapshot, setSnapshot] = (0, import_react2.useState)(void 0);
2131
2133
  const [failure, setFailure] = (0, import_react2.useState)(void 0);
2132
2134
  const [refreshing, setRefreshing] = (0, import_react2.useState)(false);
@@ -2141,6 +2143,27 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
2141
2143
  const [sortKey, setSortKey] = (0, import_react2.useState)("atMs");
2142
2144
  const [sortDir, setSortDir] = (0, import_react2.useState)("desc");
2143
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]);
2144
2167
  const toggleSort = (key) => {
2145
2168
  if (key === sortKey) {
2146
2169
  setSortDir(sortDir === "asc" ? "desc" : "asc");
@@ -2179,10 +2202,13 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
2179
2202
  if (result === "fail" && entry.ok) return false;
2180
2203
  if (slowOnly && (entry.durationMs ?? 0) < Math.max(0, slowSeconds) * 1e3) return false;
2181
2204
  if (onlySession && sessionId !== void 0 && entry.session !== sessionId) return false;
2182
- if (query !== "" && !entry.session.includes(query)) 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
+ }
2183
2209
  return true;
2184
2210
  });
2185
- }, [snapshot, model, result, slowOnly, slowSeconds, sessionQuery, onlySession, sessionId]);
2211
+ }, [snapshot, model, result, slowOnly, slowSeconds, sessionQuery, onlySession, sessionId, sessionLabel]);
2186
2212
  const pages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
2187
2213
  const safePage = Math.min(page, pages - 1);
2188
2214
  const sorted = (0, import_react2.useMemo)(() => {
@@ -2219,10 +2245,11 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
2219
2245
  if (group !== void 0 && group !== lastGroup) {
2220
2246
  lastGroup = group;
2221
2247
  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}`)
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}`)
2223
2249
  );
2224
2250
  }
2225
2251
  const state = !entry.ok ? "rowFail" : entry.tps !== void 0 && entry.tps < 5 ? "rowSlow" : "rowOk";
2252
+ const session = sessionLabel(entry.session);
2226
2253
  out.push(
2227
2254
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2228
2255
  "tr",
@@ -2234,7 +2261,7 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
2234
2261
  children: [
2235
2262
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: new Date(entry.atMs).toLocaleTimeString(getLocale(), { hour12: false }) }),
2236
2263
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { className: request_log_default.mono, children: entry.model }),
2237
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { className: request_log_default.mono, children: entry.session === "" ? "\u2014" : entry.session }),
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 }),
2238
2265
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: count2(entry.inputTokens) }),
2239
2266
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: count2(entry.outputTokens) }),
2240
2267
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: count2(entry.cacheReadTokens) }),
@@ -2261,7 +2288,14 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
2261
2288
  ] }),
2262
2289
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
2263
2290
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailSession") }),
2264
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${request_log_default.detailValue} ${request_log_default.mono}`, children: entry.session === "" ? "\u2014" : entry.session })
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
+ )
2265
2299
  ] }),
2266
2300
  entry.poolKey !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
2267
2301
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailPool") }),
@@ -2301,201 +2335,213 @@ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
2301
2335
  }
2302
2336
  return out;
2303
2337
  };
2304
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: sessionId === void 0 ? request_log_default.page : `${request_log_default.page} ${request_log_default.pageLoose}`, children: [
2305
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.head, children: [
2306
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.headText, children: [
2307
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { className: request_log_default.title, children: t("requestLogTitle") }),
2308
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: request_log_default.subtitle, children: t("requestLogPageHint") })
2309
- ] }),
2310
- /* @__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: () => {
2311
- void load();
2312
- }, disabled: refreshing, children: [
2313
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives.IconRefreshOutlineRegular, { size: 13 }),
2314
- t("requestLogRefresh")
2315
- ] }) })
2316
- ] }),
2317
- !enabled() && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: request_log_default.notice, children: t("requestLogDisabled") }),
2318
- failure !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: `${request_log_default.notice} ${request_log_default.noticeError}`, children: failure }),
2319
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.summary, children: [
2320
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
2321
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatRequests") }),
2322
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: filtered.length.toLocaleString(getLocale()) })
2323
- ] }),
2324
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `${request_log_default.card} ${failures > 0 ? request_log_default.cardError : ""}`, children: [
2325
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatFailures") }),
2326
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: failures.toLocaleString(getLocale()) })
2327
- ] }),
2328
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
2329
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatLatency") }),
2330
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: duration(meanLatency) })
2331
- ] }),
2332
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
2333
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatFirstToken") }),
2334
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: duration(meanFirstToken) })
2335
- ] }),
2336
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
2337
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatTps") }),
2338
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: rate2(meanTps) })
2339
- ] }),
2340
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
2341
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatCacheRate") }),
2342
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: percent(meanCacheRate) })
2343
- ] }),
2344
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
2345
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogReuse") }),
2346
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: reuse === void 0 ? "\u2014" : `${(reuse * 100).toFixed(0)}%` })
2347
- ] })
2348
- ] }),
2349
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.toolbar, children: [
2350
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
2351
- t("requestLogFilterModel"),
2352
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2353
- "select",
2354
- {
2355
- className: request_log_default.select,
2356
- value: model,
2357
- onChange: (event) => {
2358
- setModel(event.target.value);
2359
- setPage(0);
2360
- },
2361
- children: [
2362
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "all", children: t("requestLogFilterModelAll") }),
2363
- models.map((id4) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: id4, children: id4 }, id4))
2364
- ]
2365
- }
2366
- )
2367
- ] }),
2368
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
2369
- t("requestLogFilterResult"),
2370
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2371
- "select",
2372
- {
2373
- className: request_log_default.select,
2374
- value: result,
2375
- onChange: (event) => {
2376
- setResult(event.target.value);
2377
- setPage(0);
2378
- },
2379
- children: [
2380
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "all", children: t("requestLogResultAll") }),
2381
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "ok", children: t("requestLogResultOk") }),
2382
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "fail", children: t("requestLogResultFail") })
2383
- ]
2384
- }
2385
- )
2386
- ] }),
2387
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
2388
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2389
- "input",
2390
- {
2391
- className: request_log_default.checkbox,
2392
- type: "checkbox",
2393
- checked: slowOnly,
2394
- onChange: (event) => {
2395
- setSlowOnly(event.target.checked);
2396
- setPage(0);
2397
- }
2398
- }
2399
- ),
2400
- t("requestLogSlowOnly"),
2401
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2402
- "input",
2403
- {
2404
- className: `${request_log_default.input} ${request_log_default.inputNumber}`,
2405
- type: "number",
2406
- min: 1,
2407
- value: slowSeconds,
2408
- disabled: !slowOnly,
2409
- "aria-label": t("requestLogSlowSeconds"),
2410
- onChange: (event) => {
2411
- setSlowSeconds(Number(event.target.value));
2412
- setPage(0);
2413
- }
2414
- }
2415
- ),
2416
- t("requestLogSlowSeconds")
2417
- ] }),
2418
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
2419
- t("requestLogFilterSession"),
2420
- sessionId !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
2421
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2422
- "input",
2423
- {
2424
- className: request_log_default.checkbox,
2425
- type: "checkbox",
2426
- checked: onlySession,
2427
- onChange: (event) => {
2428
- setOnlySession(event.target.checked);
2429
- setPage(0);
2430
- }
2431
- }
2432
- ),
2433
- t("requestLogOnlySession")
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
+ ] })
2434
2510
  ] }),
2435
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2436
- "input",
2437
- {
2438
- className: request_log_default.input,
2439
- type: "search",
2440
- value: sessionQuery,
2441
- disabled: onlySession,
2442
- onChange: (event) => {
2443
- setSessionQuery(event.target.value);
2444
- setPage(0);
2445
- }
2446
- }
2447
- )
2448
- ] }),
2449
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
2450
- t("requestLogGroupBy"),
2451
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2452
- "select",
2453
- {
2454
- className: request_log_default.select,
2455
- value: groupBy,
2456
- onChange: (event) => {
2457
- setGroupBy(event.target.value);
2458
- setPage(0);
2459
- },
2460
- children: [
2461
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "none", children: t("requestLogGroupNone") }),
2462
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "session", children: t("requestLogGroupSession") }),
2463
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "model", children: t("requestLogGroupModel") }),
2464
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "result", children: t("requestLogGroupResult") })
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
- ] });
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
+ );
2499
2545
  }
2500
2546
 
2501
2547
  // 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
- // Off by default: the request path must read exactly as it does without
75761
- // the log, so the recorder is constructed only when this is true.
75762
- requestLogEnabled: Schema.boolean().default(false),
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.firstToken();
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?.({
@@ -77666,6 +77668,7 @@ var OpencodeGoRequestLogService = class extends TypertRemoteService3 {
77666
77668
 
77667
77669
  // src/request-log/store.ts
77668
77670
  var MAX_POOL_EVENTS = 20;
77671
+ var MIN_STREAM_MS_FOR_RATE = 100;
77669
77672
  var RequestLog = class {
77670
77673
  gates;
77671
77674
  entries = [];
@@ -77707,13 +77710,16 @@ var RequestLog = class {
77707
77710
  const startedAt = Date.now();
77708
77711
  const session = detail.sessionId ?? "";
77709
77712
  let firstTokenAt;
77713
+ let lastTokenAt;
77710
77714
  let method;
77711
77715
  let url;
77712
77716
  let status;
77713
77717
  let finished = false;
77714
77718
  return {
77715
- firstToken: () => {
77716
- if (firstTokenAt === void 0) firstTokenAt = Date.now();
77719
+ token: () => {
77720
+ const now = Date.now();
77721
+ if (firstTokenAt === void 0) firstTokenAt = now;
77722
+ lastTokenAt = now;
77717
77723
  },
77718
77724
  request: (nextMethod, nextUrl) => {
77719
77725
  if (method === void 0) {
@@ -77729,7 +77735,8 @@ var RequestLog = class {
77729
77735
  finished = true;
77730
77736
  const endedAt = Date.now();
77731
77737
  const decodeMs = firstTokenAt === void 0 ? void 0 : Math.max(0, endedAt - firstTokenAt);
77732
- const tps = decodeMs === void 0 || decodeMs <= 0 || usage === void 0 ? void 0 : usage.outputTokens / (decodeMs / 1e3);
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);
77733
77740
  const entry = {
77734
77741
  seq: ++this.seq,
77735
77742
  atMs: startedAt,
@@ -77886,7 +77893,7 @@ function createUpdateChecker(deps) {
77886
77893
  }
77887
77894
 
77888
77895
  // src/update/version.ts
77889
- var PLUGIN_VERSION = true ? "0.1.66" : "0.0.0-dev";
77896
+ var PLUGIN_VERSION = true ? "0.1.67" : "0.0.0-dev";
77890
77897
 
77891
77898
  // src/update/service.ts
77892
77899
  import { TypertRemoteService as TypertRemoteService4 } from "@deepseek-ai/dsh-typert-protocol";
@@ -76,9 +76,10 @@ export interface OpencodeGoConfig {
76
76
  */
77
77
  modelProtocols: Record<string, string>;
78
78
  /**
79
- * Whether the per-request log records anything at all. Off by default: a
80
- * disabled log changes nothing on the request path — not one extra
81
- * allocation — because the recorder is never constructed.
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
  /**
@@ -54,9 +54,11 @@ export interface RequestLogEntry {
54
54
  /**
55
55
  * Output tokens per second over the decode window.
56
56
  *
57
- * Absent when the request produced no token, or when the decode window
58
- * rounds to zero milliseconds: a rate divided by zero is not a rate, and
59
- * inventing one would misreport a fast reply as infinitely quick.
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.
60
62
  */
61
63
  readonly tps?: number;
62
64
  /** Whether the request completed. */
@@ -119,14 +121,22 @@ export interface RequestLogGates {
119
121
  /**
120
122
  * An in-flight request, handed back only when the log is enabled.
121
123
  *
122
- * Every method is cheap by construction: two `Date.now` reads and small
123
- * integer arithmetic across the whole span. No serialization, no hashing,
124
- * no body handling — the counts ride the usage chunk the adapter already
125
- * holds, and the timings bracket work that already happened.
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.
126
129
  */
127
130
  export interface RequestSpan {
128
- /** Mark the first token delta's arrival. Idempotent: only the first call counts. */
129
- firstToken(): void;
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;
130
140
  /**
131
141
  * Record the wire request line, from the fetch wrapper. Called at most
132
142
  * once per span; a second call keeps the first, so retries never rewrite
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dan-ai-studio/dshopencodego",
3
- "version": "0.1.66",
3
+ "version": "0.1.67",
4
4
  "description": "OpenCode Go provider for DeepSeek Harness: live gateway catalog, per-conversation session header, usage",
5
5
  "type": "module",
6
6
  "license": "MIT",