@dan-ai-studio/dshopencodego 0.1.81 → 0.1.83
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 +1 -1
- package/README.md +1 -1
- package/lib/client.js +59 -27
- package/lib/index.js +109 -28
- package/lib/types/adapter.d.ts +19 -0
- package/lib/types/request-log/store.d.ts +27 -4
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -152,7 +152,7 @@ The API key comes from the Harness credential store (reference name `OPENCODE_GO
|
|
|
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
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
|
|
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 — including failures before the first byte (unresolvable models, missing credentials), whose rows carry the reason but no usage. 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
|
@@ -151,7 +151,7 @@ API Key 通过 Harness 凭证库提供(引用名 `OPENCODE_GO_API_KEY`),
|
|
|
151
151
|
- **内容拆分**:明细里"请求体"下面跟一行"文本 X /图片 Y"——图片是各去重后附件按 base64 估的占比(单张按路由的编码上限封顶),文本是总数减图片的剩余,两者恒等于请求体总数。图片 dominant 的请求一眼就能看出来。
|
|
152
152
|
- 会话 id **始终完整记录**(它是会话身份,不是凭据;截断后两个会话会读成一个)。
|
|
153
153
|
- 记录的是环形缓冲(超限丢最旧),进程重启即清;页面平时只在打开与手动刷新时读快照,有请求中时每秒自动刷新一次直到结束,没人打开的页面零流量。
|
|
154
|
-
- 凭据永远不进记录:记录器根本不接收请求头参数,只收白名单里的会话 id 与 UA;请求一开始就有一条"请求中"
|
|
154
|
+
- 凭据永远不进记录:记录器根本不接收请求头参数,只收白名单里的会话 id 与 UA;请求一开始就有一条"请求中"占位行(状态列读秒),结束时原位补全为完整记录。失败的请求同样记一条(含错误码)——包括目录解析失败(未知模型)与凭证缺失这类"第一个字节之前"的失败,行里没有用量只有原因;消费者提前终止的流记一条 `ABORTED`,不再无声丢失。
|
|
155
155
|
|
|
156
156
|
**图片**:三个字段各管一层,超限的图片会被明确拒绝,而不是静默降质或丢弃:
|
|
157
157
|
|
package/lib/client.js
CHANGED
|
@@ -566,6 +566,10 @@ var en = {
|
|
|
566
566
|
requestLogColLatency: "Latency",
|
|
567
567
|
requestLogColTps: "tok/s",
|
|
568
568
|
requestLogColPrep: "Prep",
|
|
569
|
+
requestLogColWait: "Wait",
|
|
570
|
+
requestLogTimelineWait: "Waiting for first token",
|
|
571
|
+
requestLogTimelineStream: "Streaming",
|
|
572
|
+
requestLogTimelineBurst: "Delivered in one burst",
|
|
569
573
|
requestLogColStream: "Content span",
|
|
570
574
|
requestLogColFirstToken: "First token",
|
|
571
575
|
requestLogColStatus: "Status",
|
|
@@ -577,8 +581,6 @@ var en = {
|
|
|
577
581
|
requestLogDetailUrl: "URL",
|
|
578
582
|
requestLogDetailRequestBytes: "Request body",
|
|
579
583
|
requestLogDetailPrep: "Preparation",
|
|
580
|
-
requestLogTimelineWait: "Waiting for first token",
|
|
581
|
-
requestLogTimelineStream: "Streaming",
|
|
582
584
|
requestLogDetailContentSplit: "Content split",
|
|
583
585
|
requestLogDetailText: "Text",
|
|
584
586
|
requestLogDetailImages: "Images",
|
|
@@ -769,6 +771,10 @@ var zh = {
|
|
|
769
771
|
requestLogColLatency: "\u8017\u65F6",
|
|
770
772
|
requestLogColTps: "tok/s",
|
|
771
773
|
requestLogColPrep: "\u51C6\u5907",
|
|
774
|
+
requestLogColWait: "\u7B49\u5F85",
|
|
775
|
+
requestLogTimelineWait: "\u7B49\u5F85\u9996\u5B57",
|
|
776
|
+
requestLogTimelineStream: "\u8F93\u51FA\u4E2D",
|
|
777
|
+
requestLogTimelineBurst: "\u6574\u8F6E\u4E00\u6B21\u9001\u8FBE",
|
|
772
778
|
requestLogColStream: "\u5185\u5BB9\u8DE8\u5EA6",
|
|
773
779
|
requestLogColFirstToken: "\u9996\u5B57",
|
|
774
780
|
requestLogColStatus: "\u72B6\u6001",
|
|
@@ -780,8 +786,6 @@ var zh = {
|
|
|
780
786
|
requestLogDetailUrl: "\u5730\u5740",
|
|
781
787
|
requestLogDetailRequestBytes: "\u8BF7\u6C42\u4F53",
|
|
782
788
|
requestLogDetailPrep: "\u51C6\u5907\u8017\u65F6",
|
|
783
|
-
requestLogTimelineWait: "\u7B49\u5F85\u9996\u5B57",
|
|
784
|
-
requestLogTimelineStream: "\u8F93\u51FA\u4E2D",
|
|
785
789
|
requestLogDetailContentSplit: "\u5185\u5BB9\u62C6\u5206",
|
|
786
790
|
requestLogDetailText: "\u6587\u672C",
|
|
787
791
|
requestLogDetailImages: "\u56FE\u7247",
|
|
@@ -2148,16 +2152,19 @@ function Section({ controller, t, getLocale, openRequestLog }) {
|
|
|
2148
2152
|
var import_react2 = require("react");
|
|
2149
2153
|
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
2150
2154
|
|
|
2155
|
+
// src/request-log/store.ts
|
|
2156
|
+
var MIN_STREAM_MS_FOR_RATE = 100;
|
|
2157
|
+
|
|
2151
2158
|
// plugin-css:/home/runner/work/dshopencodego/dshopencodego/src/client/request-log.module.css
|
|
2152
2159
|
var id2 = "@dan-ai-studio/dshopencodego/request-log.module.css";
|
|
2153
2160
|
if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]")) {
|
|
2154
2161
|
const style = document.createElement("style");
|
|
2155
2162
|
style.dataset.plugin = "@dan-ai-studio/dshopencodego";
|
|
2156
2163
|
style.dataset.pluginCss = id2;
|
|
2157
|
-
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_sessionText{text-overflow:ellipsis;vertical-align:bottom;max-width:340px;display:inline-block;overflow:hidden}.Lx7MOq_modelText{text-overflow:ellipsis;vertical-align:bottom;max-width:220px;display:inline-block;overflow:hidden}.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_timeline{flex-direction:column;grid-column:1/-1;gap:6px;padding:4px 0 8px;display:flex}.Lx7MOq_timelineTrack{background:var(--dsw-alias-bg-layer-1);border-radius:999px;height:10px;position:relative;overflow:hidden}.Lx7MOq_timelineSeg{min-width:2px;position:absolute;top:0;bottom:0}.Lx7MOq_timelinePrep{background:var(--dsw-alias-brand-primary)}.Lx7MOq_timelineWait{background:var(--dsw-alias-state-warn-primary)}.Lx7MOq_timelineStream{background:var(--dsw-alias-brand-primary);opacity:.45}.Lx7MOq_timelineTick{background:var(--dsw-alias-label-primary);width:2px;margin-left:-2px;position:absolute;top:-2px;bottom:-2px;left:100%}.Lx7MOq_timelineLegend{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex-wrap:wrap;gap:4px 16px;font-size:12px;display:flex}.Lx7MOq_timelineItem{white-space:nowrap;align-items:center;gap:6px;display:inline-flex}.Lx7MOq_timelineSwatch{border-radius:2px;width:8px;height:8px}.Lx7MOq_timelineTickSwatch{background:var(--dsw-alias-label-primary)}.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)}";
|
|
2164
|
+
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_sessionText{text-overflow:ellipsis;vertical-align:bottom;max-width:340px;display:inline-block;overflow:hidden}.Lx7MOq_modelText{text-overflow:ellipsis;vertical-align:bottom;max-width:220px;display:inline-block;overflow:hidden}.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_timeline{flex-direction:column;grid-column:1/-1;gap:6px;padding:4px 0 8px;display:flex}.Lx7MOq_timelineTrackWrap{padding-bottom:18px;position:relative}.Lx7MOq_timelineTrack{background:var(--dsw-alias-bg-layer-1);border-radius:999px;height:10px;position:relative;overflow:hidden}.Lx7MOq_timelineMidTick{background:var(--dsw-alias-label-tertiary);opacity:.7;width:1px;position:absolute;top:0;bottom:0;left:50%}.Lx7MOq_timelineMid{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-variant-numeric:tabular-nums;font-size:11px;line-height:16px;position:absolute;top:100%;transform:translate(-50%)}.Lx7MOq_timelineSeg{min-width:2px;position:absolute;top:0;bottom:0}.Lx7MOq_timelinePrep{background:var(--dsw-alias-brand-primary)}.Lx7MOq_timelineWait{background:var(--dsw-alias-state-warn-primary)}.Lx7MOq_timelineStream{background:var(--dsw-alias-brand-primary);opacity:.45}.Lx7MOq_timelineTick{background:var(--dsw-alias-label-primary);width:2px;margin-left:-2px;position:absolute;top:-2px;bottom:-2px;left:100%}.Lx7MOq_timelineLegend{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex-wrap:wrap;gap:4px 16px;font-size:12px;display:flex}.Lx7MOq_timelineItem{white-space:nowrap;align-items:center;gap:6px;display:inline-flex}.Lx7MOq_timelineSwatch{border-radius:2px;width:8px;height:8px}.Lx7MOq_timelineTickSwatch{background:var(--dsw-alias-label-primary)}.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)}";
|
|
2158
2165
|
document.head.appendChild(style);
|
|
2159
2166
|
}
|
|
2160
|
-
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", "modelText": "Lx7MOq_modelText", "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", "sessionText": "Lx7MOq_sessionText", "stuck": "Lx7MOq_stuck", "subtitle": "Lx7MOq_subtitle", "summary": "Lx7MOq_summary", "table": "Lx7MOq_table", "tableWrap": "Lx7MOq_tableWrap", "thSortable": "Lx7MOq_thSortable", "timeline": "Lx7MOq_timeline", "timelineItem": "Lx7MOq_timelineItem", "timelineLegend": "Lx7MOq_timelineLegend", "timelinePrep": "Lx7MOq_timelinePrep", "timelineSeg": "Lx7MOq_timelineSeg", "timelineStream": "Lx7MOq_timelineStream", "timelineSwatch": "Lx7MOq_timelineSwatch", "timelineTick": "Lx7MOq_timelineTick", "timelineTickSwatch": "Lx7MOq_timelineTickSwatch", "timelineTrack": "Lx7MOq_timelineTrack", "timelineWait": "Lx7MOq_timelineWait", "title": "Lx7MOq_title", "toolbar": "Lx7MOq_toolbar" };
|
|
2167
|
+
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", "modelText": "Lx7MOq_modelText", "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", "sessionText": "Lx7MOq_sessionText", "stuck": "Lx7MOq_stuck", "subtitle": "Lx7MOq_subtitle", "summary": "Lx7MOq_summary", "table": "Lx7MOq_table", "tableWrap": "Lx7MOq_tableWrap", "thSortable": "Lx7MOq_thSortable", "timeline": "Lx7MOq_timeline", "timelineItem": "Lx7MOq_timelineItem", "timelineLegend": "Lx7MOq_timelineLegend", "timelineMid": "Lx7MOq_timelineMid", "timelineMidTick": "Lx7MOq_timelineMidTick", "timelinePrep": "Lx7MOq_timelinePrep", "timelineSeg": "Lx7MOq_timelineSeg", "timelineStream": "Lx7MOq_timelineStream", "timelineSwatch": "Lx7MOq_timelineSwatch", "timelineTick": "Lx7MOq_timelineTick", "timelineTickSwatch": "Lx7MOq_timelineTickSwatch", "timelineTrack": "Lx7MOq_timelineTrack", "timelineTrackWrap": "Lx7MOq_timelineTrackWrap", "timelineWait": "Lx7MOq_timelineWait", "title": "Lx7MOq_title", "toolbar": "Lx7MOq_toolbar" };
|
|
2161
2168
|
|
|
2162
2169
|
// src/client/RequestLogPage.tsx
|
|
2163
2170
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
@@ -2171,6 +2178,7 @@ var SORT_DEFAULT_DIR = {
|
|
|
2171
2178
|
cacheRate: "desc",
|
|
2172
2179
|
tps: "desc",
|
|
2173
2180
|
prepMs: "desc",
|
|
2181
|
+
waitMs: "desc",
|
|
2174
2182
|
firstTokenMs: "desc",
|
|
2175
2183
|
durationMs: "desc",
|
|
2176
2184
|
status: "asc"
|
|
@@ -2195,6 +2203,8 @@ function sortValue(entry, key) {
|
|
|
2195
2203
|
return entry.tps ?? -1;
|
|
2196
2204
|
case "prepMs":
|
|
2197
2205
|
return entry.prepMs ?? -1;
|
|
2206
|
+
case "waitMs":
|
|
2207
|
+
return waitMs(entry) ?? -1;
|
|
2198
2208
|
case "firstTokenMs":
|
|
2199
2209
|
return entry.firstTokenMs ?? -1;
|
|
2200
2210
|
case "durationMs":
|
|
@@ -2236,7 +2246,8 @@ function cacheRate(entry) {
|
|
|
2236
2246
|
return total > 0 ? cached / total : void 0;
|
|
2237
2247
|
}
|
|
2238
2248
|
function timelineOf(entry, t) {
|
|
2239
|
-
const
|
|
2249
|
+
const running = entry.running === true;
|
|
2250
|
+
const end = entry.durationMs ?? (running ? Math.max(0, Date.now() - entry.atMs) : void 0);
|
|
2240
2251
|
if (end === void 0 || end <= 0) return void 0;
|
|
2241
2252
|
const prep = entry.prepMs;
|
|
2242
2253
|
const first = entry.firstTokenMs;
|
|
@@ -2261,11 +2272,19 @@ function timelineOf(entry, t) {
|
|
|
2261
2272
|
}
|
|
2262
2273
|
}
|
|
2263
2274
|
if (slices.length === 0) return void 0;
|
|
2264
|
-
return {
|
|
2275
|
+
return {
|
|
2276
|
+
slices,
|
|
2277
|
+
end,
|
|
2278
|
+
burst: !running && first !== void 0 && (entry.streamMs === void 0 || entry.streamMs < MIN_STREAM_MS_FOR_RATE)
|
|
2279
|
+
};
|
|
2265
2280
|
}
|
|
2266
2281
|
function percent(value) {
|
|
2267
2282
|
return value === void 0 ? "\u2014" : `${(value * 100).toFixed(0)}%`;
|
|
2268
2283
|
}
|
|
2284
|
+
function waitMs(entry) {
|
|
2285
|
+
if (entry.firstTokenMs === void 0) return void 0;
|
|
2286
|
+
return Math.max(0, entry.firstTokenMs - (entry.prepMs ?? 0));
|
|
2287
|
+
}
|
|
2269
2288
|
function average(values) {
|
|
2270
2289
|
if (values.length === 0) return void 0;
|
|
2271
2290
|
let sum = 0;
|
|
@@ -2354,7 +2373,7 @@ function RequestLogPage({ readLog, enabled, canOpenSession, openSession, t, getL
|
|
|
2354
2373
|
if (!hasRunning) return;
|
|
2355
2374
|
const timer = setInterval(() => {
|
|
2356
2375
|
void load();
|
|
2357
|
-
},
|
|
2376
|
+
}, 2e3);
|
|
2358
2377
|
return () => {
|
|
2359
2378
|
clearInterval(timer);
|
|
2360
2379
|
};
|
|
@@ -2415,7 +2434,7 @@ function RequestLogPage({ readLog, enabled, canOpenSession, openSession, t, getL
|
|
|
2415
2434
|
if (group !== void 0 && group !== lastGroup) {
|
|
2416
2435
|
lastGroup = group;
|
|
2417
2436
|
out.push(
|
|
2418
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { className: request_log_default.group, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { colSpan:
|
|
2437
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { className: request_log_default.group, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { colSpan: 13, children: groupBy === "session" ? sessionLabel(group).text : groupBy === "result" ? resultGroupLabel(group) : group }) }, `group-${group}-${entry.seq}`)
|
|
2419
2438
|
);
|
|
2420
2439
|
}
|
|
2421
2440
|
const state = entry.running === true ? "rowRunning" : !entry.ok ? "rowFail" : entry.tps !== void 0 && entry.tps < 5 ? "rowSlow" : "rowOk";
|
|
@@ -2456,6 +2475,7 @@ function RequestLogPage({ readLog, enabled, canOpenSession, openSession, t, getL
|
|
|
2456
2475
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: percent(cacheRate(entry)) }),
|
|
2457
2476
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: rate2(entry.tps) }),
|
|
2458
2477
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: duration(entry.prepMs) }),
|
|
2478
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: duration(waitMs(entry)) }),
|
|
2459
2479
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: duration(entry.firstTokenMs) }),
|
|
2460
2480
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: entry.running === true ? duration(Math.max(0, Date.now() - entry.atMs)) : duration(entry.durationMs) }),
|
|
2461
2481
|
/* @__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" })
|
|
@@ -2466,28 +2486,38 @@ function RequestLogPage({ readLog, enabled, canOpenSession, openSession, t, getL
|
|
|
2466
2486
|
);
|
|
2467
2487
|
if (expanded === entry.seq) {
|
|
2468
2488
|
out.push(
|
|
2469
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { className: request_log_default.detail, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { colSpan:
|
|
2489
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { className: request_log_default.detail, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { colSpan: 13, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailGrid, children: [
|
|
2470
2490
|
(() => {
|
|
2471
2491
|
const timeline = timelineOf(entry, t);
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2492
|
+
if (timeline === void 0) return null;
|
|
2493
|
+
const kindClass = (kind) => kind === "prep" ? request_log_default.timelinePrep : kind === "wait" ? request_log_default.timelineWait : request_log_default.timelineStream;
|
|
2494
|
+
const spoken = [
|
|
2495
|
+
...timeline.slices.map((slice) => `${slice.label} ${duration(slice.to - slice.from)}`),
|
|
2496
|
+
`${t("requestLogColLatency")} ${duration(timeline.end)}`
|
|
2497
|
+
].join(", ");
|
|
2498
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.timeline, role: "img", "aria-label": spoken, children: [
|
|
2499
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.timelineTrackWrap, children: [
|
|
2500
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.timelineTrack, children: [
|
|
2501
|
+
timeline.slices.map((slice) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2502
|
+
"div",
|
|
2503
|
+
{
|
|
2504
|
+
className: `${request_log_default.timelineSeg} ${kindClass(slice.kind)}`,
|
|
2505
|
+
style: {
|
|
2506
|
+
left: `${(slice.from / timeline.end * 100).toFixed(2)}%`,
|
|
2507
|
+
width: `${Math.max(0, (slice.to - slice.from) / timeline.end * 100).toFixed(2)}%`
|
|
2508
|
+
},
|
|
2509
|
+
title: `${slice.label} ${duration(slice.to - slice.from)}`
|
|
2481
2510
|
},
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2511
|
+
slice.kind
|
|
2512
|
+
)),
|
|
2513
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: request_log_default.timelineMidTick }),
|
|
2514
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: request_log_default.timelineTick, title: duration(timeline.end) })
|
|
2515
|
+
] }),
|
|
2516
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: request_log_default.timelineMid, title: duration(timeline.end / 2), children: duration(timeline.end / 2) })
|
|
2487
2517
|
] }),
|
|
2488
2518
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.timelineLegend, children: [
|
|
2489
2519
|
timeline.slices.map((slice) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: request_log_default.timelineItem, children: [
|
|
2490
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${request_log_default.timelineSwatch} ${
|
|
2520
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${request_log_default.timelineSwatch} ${kindClass(slice.kind)}` }),
|
|
2491
2521
|
slice.label,
|
|
2492
2522
|
" ",
|
|
2493
2523
|
duration(slice.to - slice.from)
|
|
@@ -2497,7 +2527,8 @@ function RequestLogPage({ readLog, enabled, canOpenSession, openSession, t, getL
|
|
|
2497
2527
|
t("requestLogColLatency"),
|
|
2498
2528
|
" ",
|
|
2499
2529
|
duration(timeline.end)
|
|
2500
|
-
] })
|
|
2530
|
+
] }),
|
|
2531
|
+
timeline.burst && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.timelineItem, children: t("requestLogTimelineBurst") })
|
|
2501
2532
|
] })
|
|
2502
2533
|
] });
|
|
2503
2534
|
})(),
|
|
@@ -2771,6 +2802,7 @@ function RequestLogPage({ readLog, enabled, canOpenSession, openSession, t, getL
|
|
|
2771
2802
|
head("cacheRate", t("requestLogColCacheRate")),
|
|
2772
2803
|
head("tps", t("requestLogColTps")),
|
|
2773
2804
|
head("prepMs", t("requestLogColPrep")),
|
|
2805
|
+
head("waitMs", t("requestLogColWait")),
|
|
2774
2806
|
head("firstTokenMs", t("requestLogColFirstToken")),
|
|
2775
2807
|
head("durationMs", t("requestLogColLatency")),
|
|
2776
2808
|
head("status", t("requestLogColStatus"))
|
package/lib/index.js
CHANGED
|
@@ -76907,30 +76907,113 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
76907
76907
|
"UNSUPPORTED_REASONING_EFFORT"
|
|
76908
76908
|
);
|
|
76909
76909
|
}
|
|
76910
|
+
/**
|
|
76911
|
+
* Open the request's log row.
|
|
76912
|
+
*
|
|
76913
|
+
* Called before any wait the request may hit — the catalog included — so
|
|
76914
|
+
* a cold catalog reads as preparation instead of invisible time, and a
|
|
76915
|
+
* failure before the first byte still leaves a row behind. Everything
|
|
76916
|
+
* here is already known or pure: the protocol arrives later, through
|
|
76917
|
+
* `identify`, once the catalog has answered.
|
|
76918
|
+
*/
|
|
76919
|
+
startSpan(options, config, protocol) {
|
|
76920
|
+
const containsImage = options.messages.some((message) => contentHasImage2(message.content));
|
|
76921
|
+
const headers = providerHeaders(options.sessionId === void 0 ? void 0 : String(options.sessionId));
|
|
76922
|
+
const imageBudget = IMAGE_BUDGETS[config.imageBudgetPreset];
|
|
76923
|
+
const imageBytes = containsImage ? estimateImageWireBytes(options.messages, imageBudget.maxBytes) : void 0;
|
|
76924
|
+
return this.options.requestLog?.start({
|
|
76925
|
+
model: options.model,
|
|
76926
|
+
sessionId: options.sessionId === void 0 ? void 0 : String(options.sessionId),
|
|
76927
|
+
...protocol === void 0 ? {} : { protocol },
|
|
76928
|
+
method: "POST",
|
|
76929
|
+
url: config.baseURL,
|
|
76930
|
+
messageCount: options.messages.length,
|
|
76931
|
+
hasImage: containsImage,
|
|
76932
|
+
toolCount: options.tools?.length ?? 0,
|
|
76933
|
+
...imageBytes === void 0 ? {} : { imageBytes },
|
|
76934
|
+
headers: {
|
|
76935
|
+
...options.sessionId === void 0 ? {} : { session: String(options.sessionId) },
|
|
76936
|
+
...typeof headers["user-agent"] === "string" ? { userAgent: headers["user-agent"] } : {}
|
|
76937
|
+
}
|
|
76938
|
+
});
|
|
76939
|
+
}
|
|
76940
|
+
/**
|
|
76941
|
+
* Record a failure that happened before any request was built.
|
|
76942
|
+
*
|
|
76943
|
+
* Preparation (unlike dispatch) knows no session and no messages, so the
|
|
76944
|
+
* row reads as unbuilt rather than empty — but it still names the model
|
|
76945
|
+
* and the code, instead of leaving the caller with an error the log never
|
|
76946
|
+
* heard of.
|
|
76947
|
+
*/
|
|
76948
|
+
logUnstartedFailure(config, model, error) {
|
|
76949
|
+
this.options.requestLog?.start({
|
|
76950
|
+
model,
|
|
76951
|
+
sessionId: void 0,
|
|
76952
|
+
method: "POST",
|
|
76953
|
+
url: config.baseURL,
|
|
76954
|
+
messageCount: 0,
|
|
76955
|
+
hasImage: false,
|
|
76956
|
+
toolCount: 0,
|
|
76957
|
+
headers: {}
|
|
76958
|
+
})?.finish(false, error instanceof LlmError9 ? error.code : void 0);
|
|
76959
|
+
}
|
|
76910
76960
|
async prepareCall(_provider, model, _signal) {
|
|
76911
76961
|
const config = this.options.config();
|
|
76912
76962
|
assertStreamIdleTimeoutMs(config.streamIdleTimeoutMs);
|
|
76913
|
-
|
|
76963
|
+
let snapshot2;
|
|
76964
|
+
try {
|
|
76965
|
+
snapshot2 = await this.catalogOf(config).forModel(model);
|
|
76966
|
+
} catch (error) {
|
|
76967
|
+
this.logUnstartedFailure(config, model, error);
|
|
76968
|
+
throw error;
|
|
76969
|
+
}
|
|
76914
76970
|
const facts = snapshot2.facts.get(model);
|
|
76915
|
-
if (facts === void 0)
|
|
76971
|
+
if (facts === void 0) {
|
|
76972
|
+
const error = new LlmError9(`opencode-go has no model "${model}"`, "UNKNOWN_MODEL");
|
|
76973
|
+
this.logUnstartedFailure(config, model, error);
|
|
76974
|
+
throw error;
|
|
76975
|
+
}
|
|
76916
76976
|
const prepared = this.modelInfo(withModelLimit(toPiModel(facts, config.baseURL), config.modelLimits));
|
|
76917
76977
|
return {
|
|
76918
76978
|
model: prepared,
|
|
76919
|
-
stream: (options) =>
|
|
76979
|
+
stream: (options) => {
|
|
76980
|
+
const span = this.startSpan(options, config, facts.api);
|
|
76981
|
+
return this.streamWithSnapshot(options, config, snapshot2, span);
|
|
76982
|
+
}
|
|
76920
76983
|
};
|
|
76921
76984
|
}
|
|
76922
76985
|
async *stream(options) {
|
|
76923
76986
|
const config = this.options.config();
|
|
76924
76987
|
assertStreamIdleTimeoutMs(config.streamIdleTimeoutMs);
|
|
76925
|
-
const
|
|
76926
|
-
|
|
76988
|
+
const span = this.startSpan(options, config);
|
|
76989
|
+
let snapshot2;
|
|
76990
|
+
try {
|
|
76991
|
+
snapshot2 = await this.catalogOf(config).forModel(options.model);
|
|
76992
|
+
} catch (error) {
|
|
76993
|
+
span?.finish(false, error instanceof LlmError9 ? error.code : void 0);
|
|
76994
|
+
throw error;
|
|
76995
|
+
}
|
|
76996
|
+
yield* this.streamWithSnapshot(options, config, snapshot2, span);
|
|
76927
76997
|
}
|
|
76928
|
-
async *streamWithSnapshot(options, config, snapshot2) {
|
|
76998
|
+
async *streamWithSnapshot(options, config, snapshot2, outerSpan) {
|
|
76929
76999
|
var _stack = [];
|
|
76930
77000
|
try {
|
|
76931
|
-
|
|
77001
|
+
const span = outerSpan ?? this.startSpan(options, config);
|
|
77002
|
+
const failSpan = (error) => {
|
|
77003
|
+
span?.finish(false, error instanceof LlmError9 ? error.code : void 0);
|
|
77004
|
+
throw error;
|
|
77005
|
+
};
|
|
77006
|
+
try {
|
|
77007
|
+
assertStreamIdleTimeoutMs(config.streamIdleTimeoutMs);
|
|
77008
|
+
} catch (error) {
|
|
77009
|
+
failSpan(error);
|
|
77010
|
+
}
|
|
76932
77011
|
const facts = snapshot2.facts.get(options.model);
|
|
76933
|
-
if (facts === void 0)
|
|
77012
|
+
if (facts === void 0) {
|
|
77013
|
+
const error = new LlmError9(`opencode-go has no model "${options.model}"`, "UNKNOWN_MODEL");
|
|
77014
|
+
span?.finish(false, error.code);
|
|
77015
|
+
throw error;
|
|
77016
|
+
}
|
|
76934
77017
|
const model = withModelLimit(toPiModel(facts, config.baseURL), config.modelLimits);
|
|
76935
77018
|
const rates2 = usableRates(facts.cost);
|
|
76936
77019
|
const stop = stopSequencesFor(model, options.stop);
|
|
@@ -76938,32 +77021,24 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
76938
77021
|
const maxTokens = options.maxTokens === void 0 || ceiling === null || ceiling === void 0 ? options.maxTokens : Math.min(options.maxTokens, ceiling);
|
|
76939
77022
|
const apiKey = await this.options.resolveApiKey();
|
|
76940
77023
|
if (apiKey === void 0 || apiKey.length === 0) {
|
|
76941
|
-
|
|
77024
|
+
const error = new LlmError9("dshopencodego: no credential resolved for the opencode-go route", "MISSING_CREDENTIAL");
|
|
77025
|
+
span?.finish(false, error.code);
|
|
77026
|
+
throw error;
|
|
77027
|
+
}
|
|
77028
|
+
let reasoning;
|
|
77029
|
+
try {
|
|
77030
|
+
reasoning = this.resolveReasoningLevel(model, options.reasoningEffort);
|
|
77031
|
+
} catch (error) {
|
|
77032
|
+
failSpan(error);
|
|
76942
77033
|
}
|
|
76943
|
-
const reasoning = this.resolveReasoningLevel(model, options.reasoningEffort);
|
|
76944
77034
|
const consumer = new AbortController();
|
|
76945
77035
|
const upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);
|
|
76946
77036
|
const watchdog = __using(_stack, idleWatchdog(upstream, config.streamIdleTimeoutMs, "LLM_STREAM_IDLE_TIMEOUT"));
|
|
76947
77037
|
let timedOut = false;
|
|
77038
|
+
span?.identify(facts.api);
|
|
76948
77039
|
const containsImage = options.messages.some((message) => contentHasImage2(message.content));
|
|
76949
77040
|
const headers = providerHeaders(options.sessionId === void 0 ? void 0 : String(options.sessionId));
|
|
76950
77041
|
const imageBudget = IMAGE_BUDGETS[config.imageBudgetPreset];
|
|
76951
|
-
const imageBytes = containsImage ? estimateImageWireBytes(options.messages, imageBudget.maxBytes) : void 0;
|
|
76952
|
-
const span = this.options.requestLog?.start({
|
|
76953
|
-
model: options.model,
|
|
76954
|
-
sessionId: options.sessionId === void 0 ? void 0 : String(options.sessionId),
|
|
76955
|
-
protocol: facts.api,
|
|
76956
|
-
method: "POST",
|
|
76957
|
-
url: config.baseURL,
|
|
76958
|
-
messageCount: options.messages.length,
|
|
76959
|
-
hasImage: containsImage,
|
|
76960
|
-
toolCount: options.tools?.length ?? 0,
|
|
76961
|
-
...imageBytes === void 0 ? {} : { imageBytes },
|
|
76962
|
-
headers: {
|
|
76963
|
-
...options.sessionId === void 0 ? {} : { session: String(options.sessionId) },
|
|
76964
|
-
...typeof headers["user-agent"] === "string" ? { userAgent: headers["user-agent"] } : {}
|
|
76965
|
-
}
|
|
76966
|
-
});
|
|
76967
77042
|
const fetchFactory = this.options.fetch;
|
|
76968
77043
|
const requestFetch = span === void 0 || fetchFactory === void 0 ? fetchFactory : () => {
|
|
76969
77044
|
const base = fetchFactory();
|
|
@@ -77937,6 +78012,9 @@ var RequestLog = class {
|
|
|
77937
78012
|
let reported = false;
|
|
77938
78013
|
let finished = false;
|
|
77939
78014
|
return {
|
|
78015
|
+
identify: (protocol) => {
|
|
78016
|
+
if (record2.protocol === void 0) record2.protocol = protocol;
|
|
78017
|
+
},
|
|
77940
78018
|
token: () => {
|
|
77941
78019
|
const now = Date.now();
|
|
77942
78020
|
if (firstTokenAt === void 0) {
|
|
@@ -77969,7 +78047,10 @@ var RequestLog = class {
|
|
|
77969
78047
|
seq,
|
|
77970
78048
|
atMs: startedAt,
|
|
77971
78049
|
model: detail.model,
|
|
77972
|
-
|
|
78050
|
+
// The protocol may have arrived after the row opened, through
|
|
78051
|
+
// `identify` — the running row and the completion read the same
|
|
78052
|
+
// field, so they never disagree.
|
|
78053
|
+
...record2.protocol === void 0 ? {} : { protocol: record2.protocol },
|
|
77973
78054
|
session,
|
|
77974
78055
|
method: record2.method,
|
|
77975
78056
|
url: record2.url,
|
|
@@ -78134,7 +78215,7 @@ function createUpdateChecker(deps) {
|
|
|
78134
78215
|
}
|
|
78135
78216
|
|
|
78136
78217
|
// src/update/version.ts
|
|
78137
|
-
var PLUGIN_VERSION = true ? "0.1.
|
|
78218
|
+
var PLUGIN_VERSION = true ? "0.1.83" : "0.0.0-dev";
|
|
78138
78219
|
|
|
78139
78220
|
// src/update/service.ts
|
|
78140
78221
|
import { TypertRemoteService as TypertRemoteService4 } from "@deepseek-ai/dsh-typert-protocol";
|
package/lib/types/adapter.d.ts
CHANGED
|
@@ -156,6 +156,25 @@ export declare class OpencodeGoAdapter extends LlmAdapter {
|
|
|
156
156
|
providerRetryPolicy(_provider: string): ResolvedRetryPolicy | undefined;
|
|
157
157
|
/** Validate an explicit effort against the model's own levels, without clamping. */
|
|
158
158
|
private resolveReasoningLevel;
|
|
159
|
+
/**
|
|
160
|
+
* Open the request's log row.
|
|
161
|
+
*
|
|
162
|
+
* Called before any wait the request may hit — the catalog included — so
|
|
163
|
+
* a cold catalog reads as preparation instead of invisible time, and a
|
|
164
|
+
* failure before the first byte still leaves a row behind. Everything
|
|
165
|
+
* here is already known or pure: the protocol arrives later, through
|
|
166
|
+
* `identify`, once the catalog has answered.
|
|
167
|
+
*/
|
|
168
|
+
private startSpan;
|
|
169
|
+
/**
|
|
170
|
+
* Record a failure that happened before any request was built.
|
|
171
|
+
*
|
|
172
|
+
* Preparation (unlike dispatch) knows no session and no messages, so the
|
|
173
|
+
* row reads as unbuilt rather than empty — but it still names the model
|
|
174
|
+
* and the code, instead of leaving the caller with an error the log never
|
|
175
|
+
* heard of.
|
|
176
|
+
*/
|
|
177
|
+
private logUnstartedFailure;
|
|
159
178
|
prepareCall(_provider: string, model: string, _signal?: AbortSignal): Promise<PreparedAdapterCall>;
|
|
160
179
|
stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
|
|
161
180
|
private streamWithSnapshot;
|
|
@@ -83,10 +83,12 @@ export interface RequestLogEntry {
|
|
|
83
83
|
*/
|
|
84
84
|
readonly streamMs?: number;
|
|
85
85
|
/**
|
|
86
|
-
* Wall time from request start to the moment the fetch
|
|
87
|
-
* in milliseconds — the local
|
|
88
|
-
*
|
|
89
|
-
*
|
|
86
|
+
* Wall time from request start to the moment the fetch went out,
|
|
87
|
+
* in milliseconds — the whole local path, catalog wait included: the row
|
|
88
|
+
* opens before the catalog is consulted, so a cold catalog reads as
|
|
89
|
+
* preparation rather than invisible time. The rest of the first-token
|
|
90
|
+
* wait belongs to the wire and the gateway. Absent when the request never
|
|
91
|
+
* reached the wire (rejected up front).
|
|
90
92
|
*/
|
|
91
93
|
readonly prepMs?: number;
|
|
92
94
|
/** Wall time from request start to terminal event, in milliseconds. */
|
|
@@ -175,6 +177,19 @@ export interface RequestLogGates {
|
|
|
175
177
|
/** How many entries to keep; the ring trims to it on every append. */
|
|
176
178
|
readonly maxEntries: () => number;
|
|
177
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Minimum content span for a meaningful rate, in milliseconds.
|
|
182
|
+
*
|
|
183
|
+
* A rate needs a window, and a sub-100ms arrival spread is delivery shape,
|
|
184
|
+
* not generation speed: wall-clock timers resolve to a millisecond, one
|
|
185
|
+
* network flush fans its events out across several event-loop turns, and no
|
|
186
|
+
* served LLM sustains thousands of tokens per second. Below this line the
|
|
187
|
+
* tokens arrived in one burst — the reply's speed on the wire is unknown,
|
|
188
|
+
* so no rate is reported rather than a fabricated one. The viewer reuses
|
|
189
|
+
* the same line to name that shape instead of leaving the missing output
|
|
190
|
+
* slice unexplained.
|
|
191
|
+
*/
|
|
192
|
+
export declare const MIN_STREAM_MS_FOR_RATE = 100;
|
|
178
193
|
/**
|
|
179
194
|
* An in-flight request, handed back only when the log is enabled.
|
|
180
195
|
*
|
|
@@ -205,6 +220,14 @@ export interface RequestSpan {
|
|
|
205
220
|
request(method: string, url: string, requestBytes?: number): void;
|
|
206
221
|
/** Mark the response status line's arrival. */
|
|
207
222
|
status(status: number): void;
|
|
223
|
+
/**
|
|
224
|
+
* Fill in the wire protocol once the catalog has answered.
|
|
225
|
+
*
|
|
226
|
+
* The row opens before the catalog wait (so the wait itself is recorded),
|
|
227
|
+
* but the protocol is only known after it. Called at most once, before
|
|
228
|
+
* `finish`; a second call keeps the first.
|
|
229
|
+
*/
|
|
230
|
+
identify(protocol: WireProtocol): void;
|
|
208
231
|
/**
|
|
209
232
|
* Close the span and complete its running row in place.
|
|
210
233
|
* @param ok - whether the request completed.
|
package/package.json
CHANGED