@dan-ai-studio/dshopencodego 0.1.77 → 0.1.78
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 +2 -2
- package/README.md +2 -2
- package/lib/client.js +28 -10
- package/lib/index.js +54 -20
- package/lib/types/request-log/store.d.ts +27 -13
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -151,8 +151,8 @@ The API key comes from the Harness credential store (reference name `OPENCODE_GO
|
|
|
151
151
|
- **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
152
|
- **Content split**: below the body size the detail shows **Text X / Images Y** — images estimated as base64 per deduped attachment (each capped at the route's encoded target), text as the residual, so the two always sum to the total. Image-dominated turns read at a glance.
|
|
153
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.
|
|
154
|
-
- The log is a ring buffer (oldest dropped first) that dies with the process; snapshots are read on
|
|
155
|
-
- The credential never enters a record: the recorder takes no headers argument at all, only the allowlisted session id and user agent. Failed requests are recorded with their error code; a
|
|
154
|
+
- The log is a ring buffer (oldest dropped first) that dies with the process; snapshots are read on open and on manual refresh, plus once a second while any request is running, so a page nobody opens costs no traffic.
|
|
155
|
+
- The credential never enters a record: the recorder takes no headers argument at all, only the allowlisted session id and user agent. A request gets a "Requesting" placeholder row the moment it starts (the status column counts its seconds) and the row is completed in place when it ends. Failed requests are recorded with their error code; a stream the consumer abandoned early is recorded as `ABORTED` instead of vanishing silently.
|
|
156
156
|
|
|
157
157
|
**Images**: an over-budget image is refused explicitly rather than silently downscaled or dropped. The budgets ride one preset `imageBudgetPreset` (three choices, default `dsh`), not three numbers:
|
|
158
158
|
|
package/README.md
CHANGED
|
@@ -150,8 +150,8 @@ API Key 通过 Harness 凭证库提供(引用名 `OPENCODE_GO_API_KEY`),
|
|
|
150
150
|
- **输入列是未缓存的新增 token**:网关把整段 prompt 拆成"未缓存+缓存命中"两部分上报,输入列只记新增的——同一会话前缀缓存全中时输入很小、缓存命中 100%,不是 bug。悬停列头有口径说明。
|
|
151
151
|
- **内容拆分**:明细里"请求体"下面跟一行"文本 X /图片 Y"——图片是各去重后附件按 base64 估的占比(单张按路由的编码上限封顶),文本是总数减图片的剩余,两者恒等于请求体总数。图片 dominant 的请求一眼就能看出来。
|
|
152
152
|
- 会话 id **始终完整记录**(它是会话身份,不是凭据;截断后两个会话会读成一个)。
|
|
153
|
-
-
|
|
154
|
-
- 凭据永远不进记录:记录器根本不接收请求头参数,只收白名单里的会话 id 与 UA
|
|
153
|
+
- 记录的是环形缓冲(超限丢最旧),进程重启即清;页面平时只在打开与手动刷新时读快照,有请求中时每秒自动刷新一次直到结束,没人打开的页面零流量。
|
|
154
|
+
- 凭据永远不进记录:记录器根本不接收请求头参数,只收白名单里的会话 id 与 UA;请求一开始就有一条"请求中"占位行(状态列读秒),结束时原位补全为完整记录。失败的请求同样记一条(含错误码);消费者提前终止的流记一条 `ABORTED`,不再无声丢失。
|
|
155
155
|
|
|
156
156
|
**图片**:三个字段各管一层,超限的图片会被明确拒绝,而不是静默降质或丢弃:
|
|
157
157
|
|
package/lib/client.js
CHANGED
|
@@ -258,6 +258,9 @@ function parseEntry(value) {
|
|
|
258
258
|
...row["decodeMs"] === void 0 ? {} : { decodeMs: count("decodeMs", row) },
|
|
259
259
|
...row["streamMs"] === void 0 ? {} : { streamMs: count("streamMs", row) },
|
|
260
260
|
...row["tps"] === void 0 ? {} : { tps: rate("tps", row) },
|
|
261
|
+
// Running rows cross the wire too: a viewer opened mid-request must
|
|
262
|
+
// see them. Older snapshots predate the flag and read as finished.
|
|
263
|
+
...row["running"] === true ? { running: true } : {},
|
|
261
264
|
ok: row["ok"] === true,
|
|
262
265
|
...typeof row["code"] === "string" ? { code: row["code"] } : {},
|
|
263
266
|
...typeof row["poolKey"] === "string" ? { poolKey: row["poolKey"] } : {},
|
|
@@ -525,6 +528,7 @@ var en = {
|
|
|
525
528
|
requestLogOpenSessionFailed: "That session is archived and cannot be opened.",
|
|
526
529
|
requestLogClose: "Close",
|
|
527
530
|
requestLogRefresh: "Refresh",
|
|
531
|
+
requestLogRunning: "Requesting",
|
|
528
532
|
requestLogEmpty: "No requests recorded. Turn the log on, then make a request.",
|
|
529
533
|
requestLogDisabled: "The request log is off.",
|
|
530
534
|
requestLogFilterModel: "Model",
|
|
@@ -723,6 +727,7 @@ var zh = {
|
|
|
723
727
|
requestLogOpenSessionFailed: "\u8BE5\u4F1A\u8BDD\u5DF2\u5F52\u6863\uFF0C\u6253\u4E0D\u5F00\u3002",
|
|
724
728
|
requestLogClose: "\u5173\u95ED",
|
|
725
729
|
requestLogRefresh: "\u5237\u65B0",
|
|
730
|
+
requestLogRunning: "\u8BF7\u6C42\u4E2D",
|
|
726
731
|
requestLogEmpty: "\u6682\u65E0\u8BB0\u5F55\u3002\u5148\u6253\u5F00\u65E5\u5FD7\u5F00\u5173\uFF0C\u518D\u53D1\u8D77\u4E00\u6B21\u8BF7\u6C42\u3002",
|
|
727
732
|
requestLogDisabled: "\u8BF7\u6C42\u65E5\u5FD7\u672A\u5F00\u542F\u3002",
|
|
728
733
|
requestLogFilterModel: "\u6A21\u578B",
|
|
@@ -2140,10 +2145,10 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]"
|
|
|
2140
2145
|
const style = document.createElement("style");
|
|
2141
2146
|
style.dataset.plugin = "@dan-ai-studio/dshopencodego";
|
|
2142
2147
|
style.dataset.pluginCss = id2;
|
|
2143
|
-
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_sessionLink{color:var(--dsw-alias-link);font:inherit;text-align:left;cursor:pointer;white-space:nowrap;background:0 0;border:none;padding:0}.Lx7MOq_sessionLink:hover{text-decoration:underline}.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)}";
|
|
2148
|
+
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_sessionLink{color:var(--dsw-alias-link);font:inherit;text-align:left;cursor:pointer;white-space:nowrap;background:0 0;border:none;padding:0}.Lx7MOq_sessionLink:hover{text-decoration:underline}.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_rowRunning td:first-child{box-shadow:inset 3px 0 0 var(--dsw-alias-brand-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)}";
|
|
2144
2149
|
document.head.appendChild(style);
|
|
2145
2150
|
}
|
|
2146
|
-
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", "sessionLink": "Lx7MOq_sessionLink", "stuck": "Lx7MOq_stuck", "subtitle": "Lx7MOq_subtitle", "summary": "Lx7MOq_summary", "table": "Lx7MOq_table", "tableWrap": "Lx7MOq_tableWrap", "thSortable": "Lx7MOq_thSortable", "title": "Lx7MOq_title", "toolbar": "Lx7MOq_toolbar" };
|
|
2151
|
+
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", "rowRunning": "Lx7MOq_rowRunning", "rowSlow": "Lx7MOq_rowSlow", "select": "Lx7MOq_select", "sessionLink": "Lx7MOq_sessionLink", "stuck": "Lx7MOq_stuck", "subtitle": "Lx7MOq_subtitle", "summary": "Lx7MOq_summary", "table": "Lx7MOq_table", "tableWrap": "Lx7MOq_tableWrap", "thSortable": "Lx7MOq_thSortable", "title": "Lx7MOq_title", "toolbar": "Lx7MOq_toolbar" };
|
|
2147
2152
|
|
|
2148
2153
|
// src/client/RequestLogPage.tsx
|
|
2149
2154
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
@@ -2183,7 +2188,7 @@ function sortValue(entry, key) {
|
|
|
2183
2188
|
case "durationMs":
|
|
2184
2189
|
return entry.durationMs ?? -1;
|
|
2185
2190
|
case "status":
|
|
2186
|
-
return entry.ok ? `ok-${entry.status ?? ""}` : `fail-${entry.code ?? ""}`;
|
|
2191
|
+
return entry.running === true ? "running" : entry.ok ? `ok-${entry.status ?? ""}` : `fail-${entry.code ?? ""}`;
|
|
2187
2192
|
}
|
|
2188
2193
|
}
|
|
2189
2194
|
var PAGE_SIZE = 50;
|
|
@@ -2233,8 +2238,10 @@ function groupKey(entry, groupBy) {
|
|
|
2233
2238
|
return entry.session === "" ? "\u2014" : entry.session;
|
|
2234
2239
|
case "model":
|
|
2235
2240
|
return entry.model;
|
|
2241
|
+
// A running row is neither a success nor a failure yet: it groups on
|
|
2242
|
+
// its own instead of inflating either outcome.
|
|
2236
2243
|
case "result":
|
|
2237
|
-
return entry.ok ? "ok" : entry.code ?? "fail";
|
|
2244
|
+
return entry.running === true ? "running" : entry.ok ? "ok" : entry.code ?? "fail";
|
|
2238
2245
|
case "none":
|
|
2239
2246
|
return void 0;
|
|
2240
2247
|
}
|
|
@@ -2276,6 +2283,7 @@ function RequestLogPage({ readLog, enabled, canOpenSession, openSession, t, getL
|
|
|
2276
2283
|
const title = catalog?.byId[id4]?.title?.trim();
|
|
2277
2284
|
return title === void 0 || title === "" ? { text: id4 === "" ? "\u2014" : id4, titled: false } : { text: title, titled: true };
|
|
2278
2285
|
}, [catalog]);
|
|
2286
|
+
const resultGroupLabel = (group) => group === "ok" ? t("requestLogResultOk") : group === "fail" ? t("requestLogResultFail") : group === "running" ? t("requestLogRunning") : group;
|
|
2279
2287
|
const toggleSort = (key) => {
|
|
2280
2288
|
if (key === sortKey) {
|
|
2281
2289
|
setSortDir(sortDir === "asc" ? "desc" : "asc");
|
|
@@ -2301,6 +2309,16 @@ function RequestLogPage({ readLog, enabled, canOpenSession, openSession, t, getL
|
|
|
2301
2309
|
(0, import_react2.useEffect)(() => {
|
|
2302
2310
|
void load();
|
|
2303
2311
|
}, [load]);
|
|
2312
|
+
const hasRunning = (snapshot?.entries ?? []).some((entry) => entry.running === true);
|
|
2313
|
+
(0, import_react2.useEffect)(() => {
|
|
2314
|
+
if (!hasRunning) return;
|
|
2315
|
+
const timer = setInterval(() => {
|
|
2316
|
+
void load();
|
|
2317
|
+
}, 1e3);
|
|
2318
|
+
return () => {
|
|
2319
|
+
clearInterval(timer);
|
|
2320
|
+
};
|
|
2321
|
+
}, [hasRunning, load]);
|
|
2304
2322
|
const models = (0, import_react2.useMemo)(() => {
|
|
2305
2323
|
const ids = /* @__PURE__ */ new Set();
|
|
2306
2324
|
for (const entry of snapshot?.entries ?? []) ids.add(entry.model);
|
|
@@ -2311,7 +2329,7 @@ function RequestLogPage({ readLog, enabled, canOpenSession, openSession, t, getL
|
|
|
2311
2329
|
return (snapshot?.entries ?? []).filter((entry) => {
|
|
2312
2330
|
if (model !== "all" && entry.model !== model) return false;
|
|
2313
2331
|
if (result === "ok" && !entry.ok) return false;
|
|
2314
|
-
if (result === "fail" && entry.ok) return false;
|
|
2332
|
+
if (result === "fail" && (entry.ok || entry.running === true)) return false;
|
|
2315
2333
|
if (slowOnly && (entry.durationMs ?? 0) < Math.max(0, slowSeconds) * 1e3) return false;
|
|
2316
2334
|
if (onlySession && sessionId !== void 0 && entry.session !== sessionId) return false;
|
|
2317
2335
|
if (query !== "") {
|
|
@@ -2334,7 +2352,7 @@ function RequestLogPage({ readLog, enabled, canOpenSession, openSession, t, getL
|
|
|
2334
2352
|
return next;
|
|
2335
2353
|
}, [filtered, sortKey, sortDir]);
|
|
2336
2354
|
const pageEntries = sorted.slice(safePage * PAGE_SIZE, (safePage + 1) * PAGE_SIZE);
|
|
2337
|
-
const failures = filtered.filter((entry) => !entry.ok).length;
|
|
2355
|
+
const failures = filtered.filter((entry) => !entry.ok && entry.running !== true).length;
|
|
2338
2356
|
const meanLatency = average(filtered.flatMap((entry) => entry.durationMs === void 0 ? [] : [entry.durationMs]));
|
|
2339
2357
|
const meanFirstToken = average(filtered.flatMap((entry) => entry.firstTokenMs === void 0 ? [] : [entry.firstTokenMs]));
|
|
2340
2358
|
const meanTps = average(filtered.flatMap((entry) => entry.tps === void 0 ? [] : [entry.tps]));
|
|
@@ -2357,10 +2375,10 @@ function RequestLogPage({ readLog, enabled, canOpenSession, openSession, t, getL
|
|
|
2357
2375
|
if (group !== void 0 && group !== lastGroup) {
|
|
2358
2376
|
lastGroup = group;
|
|
2359
2377
|
out.push(
|
|
2360
|
-
/* @__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}`)
|
|
2378
|
+
/* @__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 : groupBy === "result" ? resultGroupLabel(group) : group }) }, `group-${group}-${entry.seq}`)
|
|
2361
2379
|
);
|
|
2362
2380
|
}
|
|
2363
|
-
const state = !entry.ok ? "rowFail" : entry.tps !== void 0 && entry.tps < 5 ? "rowSlow" : "rowOk";
|
|
2381
|
+
const state = entry.running === true ? "rowRunning" : !entry.ok ? "rowFail" : entry.tps !== void 0 && entry.tps < 5 ? "rowSlow" : "rowOk";
|
|
2364
2382
|
const session = sessionLabel(entry.session);
|
|
2365
2383
|
out.push(
|
|
2366
2384
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
@@ -2398,8 +2416,8 @@ function RequestLogPage({ readLog, enabled, canOpenSession, openSession, t, getL
|
|
|
2398
2416
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: percent(cacheRate(entry)) }),
|
|
2399
2417
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: rate2(entry.tps) }),
|
|
2400
2418
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: duration(entry.firstTokenMs) }),
|
|
2401
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: duration(entry.durationMs) }),
|
|
2402
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: entry.ok ? entry.status === void 0 ? "\u2713" : String(entry.status) : entry.code ?? "\u2717" })
|
|
2419
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: entry.running === true ? duration(Math.max(0, Date.now() - entry.atMs)) : duration(entry.durationMs) }),
|
|
2420
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: entry.running === true ? `${t("requestLogRunning")} \xB7 ${duration(Math.max(0, Date.now() - entry.atMs))}` : entry.ok ? entry.status === void 0 ? "\u2713" : String(entry.status) : entry.code ?? "\u2717" })
|
|
2403
2421
|
]
|
|
2404
2422
|
},
|
|
2405
2423
|
entry.seq
|
package/lib/index.js
CHANGED
|
@@ -77068,6 +77068,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
77068
77068
|
} finally {
|
|
77069
77069
|
if (!exhausted) {
|
|
77070
77070
|
timedOut = timeoutOf(watchdog.signal, "LLM_STREAM_IDLE_TIMEOUT") !== void 0;
|
|
77071
|
+
span?.finish(false, "ABORTED");
|
|
77071
77072
|
consumer.abort("opencode-go stream consumer stopped");
|
|
77072
77073
|
try {
|
|
77073
77074
|
void Promise.resolve(iterator.return(void 0)).catch(() => {
|
|
@@ -77321,6 +77322,9 @@ function parseEntry(value) {
|
|
|
77321
77322
|
...row["decodeMs"] === void 0 ? {} : { decodeMs: count("decodeMs", row) },
|
|
77322
77323
|
...row["streamMs"] === void 0 ? {} : { streamMs: count("streamMs", row) },
|
|
77323
77324
|
...row["tps"] === void 0 ? {} : { tps: rate("tps", row) },
|
|
77325
|
+
// Running rows cross the wire too: a viewer opened mid-request must
|
|
77326
|
+
// see them. Older snapshots predate the flag and read as finished.
|
|
77327
|
+
...row["running"] === true ? { running: true } : {},
|
|
77324
77328
|
ok: row["ok"] === true,
|
|
77325
77329
|
...typeof row["code"] === "string" ? { code: row["code"] } : {},
|
|
77326
77330
|
...typeof row["poolKey"] === "string" ? { poolKey: row["poolKey"] } : {},
|
|
@@ -77897,52 +77901,77 @@ var RequestLog = class {
|
|
|
77897
77901
|
* Begin one request's span, or nothing when the log is disabled.
|
|
77898
77902
|
*
|
|
77899
77903
|
* This is the single gate on the request path: a disabled log costs one
|
|
77900
|
-
* method call and one boolean read, and constructs nothing.
|
|
77904
|
+
* method call and one boolean read, and constructs nothing. When enabled,
|
|
77905
|
+
* the running row is appended before the span is returned, so the viewer
|
|
77906
|
+
* sees the request while it runs; `request` and `status` mutate that same
|
|
77907
|
+
* visible row as the wire facts arrive.
|
|
77901
77908
|
*/
|
|
77902
77909
|
start(detail) {
|
|
77903
77910
|
if (!this.gates.enabled()) return void 0;
|
|
77904
77911
|
const debug = this.gates.debug();
|
|
77905
77912
|
const startedAt = Date.now();
|
|
77906
77913
|
const session = detail.sessionId ?? "";
|
|
77914
|
+
const record2 = {
|
|
77915
|
+
seq: ++this.seq,
|
|
77916
|
+
atMs: startedAt,
|
|
77917
|
+
model: detail.model,
|
|
77918
|
+
...detail.protocol === void 0 ? {} : { protocol: detail.protocol },
|
|
77919
|
+
session,
|
|
77920
|
+
method: detail.method ?? "POST",
|
|
77921
|
+
url: detail.url ?? "",
|
|
77922
|
+
running: true,
|
|
77923
|
+
ok: false,
|
|
77924
|
+
shape: { messages: detail.messageCount, hasImage: detail.hasImage, tools: detail.toolCount },
|
|
77925
|
+
...detail.imageBytes === void 0 ? {} : { imageBytes: detail.imageBytes },
|
|
77926
|
+
...!debug ? {} : {
|
|
77927
|
+
headers: {
|
|
77928
|
+
...detail.headers.session === void 0 ? {} : { session: detail.headers.session },
|
|
77929
|
+
...detail.headers.userAgent === void 0 ? {} : { userAgent: detail.headers.userAgent }
|
|
77930
|
+
}
|
|
77931
|
+
}
|
|
77932
|
+
};
|
|
77933
|
+
this.insert(record2, true);
|
|
77907
77934
|
let firstTokenAt;
|
|
77908
77935
|
let lastTokenAt;
|
|
77909
|
-
let
|
|
77910
|
-
let url;
|
|
77911
|
-
let requestBytes;
|
|
77912
|
-
let status;
|
|
77936
|
+
let reported = false;
|
|
77913
77937
|
let finished = false;
|
|
77914
77938
|
return {
|
|
77915
77939
|
token: () => {
|
|
77916
77940
|
const now = Date.now();
|
|
77917
|
-
if (firstTokenAt === void 0)
|
|
77941
|
+
if (firstTokenAt === void 0) {
|
|
77942
|
+
firstTokenAt = now;
|
|
77943
|
+
record2.firstTokenMs = Math.max(0, now - startedAt);
|
|
77944
|
+
}
|
|
77918
77945
|
lastTokenAt = now;
|
|
77919
77946
|
},
|
|
77920
77947
|
request: (nextMethod, nextUrl, nextRequestBytes) => {
|
|
77921
|
-
if (
|
|
77922
|
-
|
|
77923
|
-
|
|
77924
|
-
|
|
77948
|
+
if (!reported) {
|
|
77949
|
+
reported = true;
|
|
77950
|
+
record2.method = nextMethod;
|
|
77951
|
+
record2.url = nextUrl;
|
|
77952
|
+
if (nextRequestBytes !== void 0) record2.requestBytes = nextRequestBytes;
|
|
77925
77953
|
}
|
|
77926
77954
|
},
|
|
77927
77955
|
status: (value) => {
|
|
77928
|
-
status = value;
|
|
77956
|
+
record2.status = value;
|
|
77929
77957
|
},
|
|
77930
77958
|
finish: (ok, code, usage, costUsd) => {
|
|
77931
77959
|
if (finished) return;
|
|
77932
77960
|
finished = true;
|
|
77961
|
+
const seq = record2.seq;
|
|
77933
77962
|
const endedAt = Date.now();
|
|
77934
77963
|
const decodeMs = firstTokenAt === void 0 ? void 0 : Math.max(0, endedAt - firstTokenAt);
|
|
77935
77964
|
const streamMs = firstTokenAt === void 0 || lastTokenAt === void 0 ? void 0 : Math.max(0, lastTokenAt - firstTokenAt);
|
|
77936
77965
|
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);
|
|
77937
77966
|
const entry = {
|
|
77938
|
-
seq
|
|
77967
|
+
seq,
|
|
77939
77968
|
atMs: startedAt,
|
|
77940
77969
|
model: detail.model,
|
|
77941
77970
|
...detail.protocol === void 0 ? {} : { protocol: detail.protocol },
|
|
77942
77971
|
session,
|
|
77943
|
-
method:
|
|
77944
|
-
url:
|
|
77945
|
-
...status === void 0 ? {} : { status },
|
|
77972
|
+
method: record2.method,
|
|
77973
|
+
url: record2.url,
|
|
77974
|
+
...record2.status === void 0 ? {} : { status: record2.status },
|
|
77946
77975
|
...usage === void 0 ? {} : {
|
|
77947
77976
|
inputTokens: usage.inputTokens,
|
|
77948
77977
|
outputTokens: usage.outputTokens,
|
|
@@ -77951,7 +77980,7 @@ var RequestLog = class {
|
|
|
77951
77980
|
...usage.reasoningTokens === void 0 || usage.reasoningTokens <= 0 ? {} : { reasoningTokens: usage.reasoningTokens }
|
|
77952
77981
|
},
|
|
77953
77982
|
...costUsd === void 0 ? {} : { costUsd },
|
|
77954
|
-
...requestBytes === void 0 ? {} : { requestBytes },
|
|
77983
|
+
...record2.requestBytes === void 0 ? {} : { requestBytes: record2.requestBytes },
|
|
77955
77984
|
...detail.imageBytes === void 0 ? {} : { imageBytes: detail.imageBytes },
|
|
77956
77985
|
durationMs: Math.max(0, endedAt - startedAt),
|
|
77957
77986
|
...firstTokenAt === void 0 ? {} : { firstTokenMs: Math.max(0, firstTokenAt - startedAt) },
|
|
@@ -77972,12 +78001,17 @@ var RequestLog = class {
|
|
|
77972
78001
|
}
|
|
77973
78002
|
}
|
|
77974
78003
|
};
|
|
77975
|
-
this.
|
|
78004
|
+
const at = this.entries.findIndex((candidate) => candidate.seq === seq);
|
|
78005
|
+
if (at === -1) {
|
|
78006
|
+
this.insert(entry, false);
|
|
78007
|
+
} else {
|
|
78008
|
+
this.entries[at] = entry;
|
|
78009
|
+
}
|
|
77976
78010
|
}
|
|
77977
78011
|
};
|
|
77978
78012
|
}
|
|
77979
|
-
|
|
77980
|
-
this.totalRecords += 1;
|
|
78013
|
+
insert(entry, count2) {
|
|
78014
|
+
if (count2) this.totalRecords += 1;
|
|
77981
78015
|
const bound = Math.max(1, Math.floor(this.gates.maxEntries()));
|
|
77982
78016
|
const next = [entry, ...this.entries].slice(0, bound);
|
|
77983
78017
|
this.droppedRecords += this.entries.length + 1 - next.length;
|
|
@@ -78097,7 +78131,7 @@ function createUpdateChecker(deps) {
|
|
|
78097
78131
|
}
|
|
78098
78132
|
|
|
78099
78133
|
// src/update/version.ts
|
|
78100
|
-
var PLUGIN_VERSION = true ? "0.1.
|
|
78134
|
+
var PLUGIN_VERSION = true ? "0.1.78" : "0.0.0-dev";
|
|
78101
78135
|
|
|
78102
78136
|
// src/update/service.ts
|
|
78103
78137
|
import { TypertRemoteService as TypertRemoteService4 } from "@deepseek-ai/dsh-typert-protocol";
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* Everything here is inert unless the profile enables it. The recorder is
|
|
5
5
|
* constructed only when `requestLogEnabled` reads true, so a disabled log
|
|
6
6
|
* changes nothing on the request path — not one extra allocation. When
|
|
7
|
-
* enabled,
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* enabled, `start` appends a running placeholder immediately — so a request
|
|
8
|
+
* is visible from the moment it begins, not only after it ends — and
|
|
9
|
+
* `finish` completes that same row in place. The oldest entries are dropped
|
|
10
|
+
* past the configured bound, so the log can never grow with the session.
|
|
10
11
|
*
|
|
11
12
|
* Two facts are structural rather than conventional:
|
|
12
13
|
*
|
|
@@ -101,7 +102,16 @@ export interface RequestLogEntry {
|
|
|
101
102
|
* misreport a buffered reply as infinitely quick.
|
|
102
103
|
*/
|
|
103
104
|
readonly tps?: number;
|
|
104
|
-
/**
|
|
105
|
+
/**
|
|
106
|
+
* Whether the request is still in flight. Present only while it runs:
|
|
107
|
+
* `finish` removes it. A running row always reads `ok: false` with no
|
|
108
|
+
* `code`, so readers must check this flag before counting a failure.
|
|
109
|
+
*/
|
|
110
|
+
readonly running?: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Whether the request completed successfully. Always false while
|
|
113
|
+
* `running` is true.
|
|
114
|
+
*/
|
|
105
115
|
readonly ok: boolean;
|
|
106
116
|
/** Failure code (`TIMEOUT`, `TRANSPORT`, …) for a request that did not complete. */
|
|
107
117
|
readonly code?: string;
|
|
@@ -136,7 +146,7 @@ export interface PoolLogEvent {
|
|
|
136
146
|
}
|
|
137
147
|
/** What the viewer reads: the entries plus the counters a rate needs. */
|
|
138
148
|
export interface RequestLogSnapshot {
|
|
139
|
-
/** Newest first, at most the configured bound. */
|
|
149
|
+
/** Newest first, at most the configured bound — finished rows plus running ones. */
|
|
140
150
|
readonly entries: readonly RequestLogEntry[];
|
|
141
151
|
/** Recent pool lifecycle, newest first, capped. */
|
|
142
152
|
readonly poolEvents: readonly PoolLogEvent[];
|
|
@@ -161,11 +171,12 @@ export interface RequestLogGates {
|
|
|
161
171
|
/**
|
|
162
172
|
* An in-flight request, handed back only when the log is enabled.
|
|
163
173
|
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
* already
|
|
174
|
+
* `start` already appended its running row, so every method mutates the
|
|
175
|
+
* visible entry in place. Every method stays cheap by construction: one
|
|
176
|
+
* `Date.now` read per content delta, field writes for the wire line, and
|
|
177
|
+
* small integer arithmetic at close. No serialization, no hashing, no body
|
|
178
|
+
* handling — the counts ride the usage chunk the adapter already holds,
|
|
179
|
+
* and the timings bracket work that already happened.
|
|
169
180
|
*/
|
|
170
181
|
export interface RequestSpan {
|
|
171
182
|
/**
|
|
@@ -188,7 +199,7 @@ export interface RequestSpan {
|
|
|
188
199
|
/** Mark the response status line's arrival. */
|
|
189
200
|
status(status: number): void;
|
|
190
201
|
/**
|
|
191
|
-
* Close the span and
|
|
202
|
+
* Close the span and complete its running row in place.
|
|
192
203
|
* @param ok - whether the request completed.
|
|
193
204
|
* @param code - failure code for a request that did not complete.
|
|
194
205
|
* @param usage - provider-reported counts, when the terminal usage arrived.
|
|
@@ -254,10 +265,13 @@ export declare class RequestLog {
|
|
|
254
265
|
* Begin one request's span, or nothing when the log is disabled.
|
|
255
266
|
*
|
|
256
267
|
* This is the single gate on the request path: a disabled log costs one
|
|
257
|
-
* method call and one boolean read, and constructs nothing.
|
|
268
|
+
* method call and one boolean read, and constructs nothing. When enabled,
|
|
269
|
+
* the running row is appended before the span is returned, so the viewer
|
|
270
|
+
* sees the request while it runs; `request` and `status` mutate that same
|
|
271
|
+
* visible row as the wire facts arrive.
|
|
258
272
|
*/
|
|
259
273
|
start(detail: RequestStart): RequestSpan | undefined;
|
|
260
|
-
private
|
|
274
|
+
private insert;
|
|
261
275
|
/** Shrink the ring to a new bound immediately; growing backfills nothing. */
|
|
262
276
|
setMaxEntries(bound: number): void;
|
|
263
277
|
/** The current reading, newest first. Computed lazily: nothing on the hot path. */
|
package/package.json
CHANGED