@dan-ai-studio/dshopencodego 0.1.85 → 0.1.86
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 +93 -36
- package/lib/index.js +315 -212
- package/lib/types/context-fit.d.ts +58 -0
- package/lib/types/request-log/store.d.ts +21 -0
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -291,7 +291,7 @@ npm run seed # refresh the bundled catalog seed before a release (see "Re
|
|
|
291
291
|
|
|
292
292
|
**Order matters**: `npm run build` must come before `npm test` — `tests/pack-contents.spec.ts` walks every `exports` target, and whether `lib/` exists decides whether that check runs or is silently skipped (it does not fail, it just stops protecting you). `package.json` no longer carries `prepare`, so `npm ci` will not build for you; all three CI workflows run `npm run build` explicitly.
|
|
293
293
|
|
|
294
|
-
The suite covers configuration validation, the protocol ladder, gateway and online metadata, the catalog projection, the adapter on the wire (all three protocols), Remote contracts and services, session-header invariants, usage windows and the meter, the client controller and usage pill, both halves' mounting and registration, the error mapping for stream idle timeouts and aborts, the exit-code contract of the verification scripts, and several **structural invariants** (inject declarations match the source's reads, peer coverage holds both ways, the READMEs match the manifest, and the READMEs' claims about the upstream match the upstream actually installed). That is **
|
|
294
|
+
The suite covers configuration validation, the protocol ladder, gateway and online metadata, the catalog projection, the adapter on the wire (all three protocols), Remote contracts and services, session-header invariants, usage windows and the meter, the client controller and usage pill, both halves' mounting and registration, the error mapping for stream idle timeouts and aborts, the exit-code contract of the verification scripts, and several **structural invariants** (inject declarations match the source's reads, peer coverage holds both ways, the READMEs match the manifest, and the READMEs' claims about the upstream match the upstream actually installed). That is **61 test files** — a number `tests/readme-consistency.spec.ts` checks against the `tests/` directory, so it cannot drift.
|
|
295
295
|
|
|
296
296
|
## Releasing (maintainers)
|
|
297
297
|
|
package/README.md
CHANGED
|
@@ -290,7 +290,7 @@ npm run seed # 发版前刷新捆绑的目录种子(见「发布」)
|
|
|
290
290
|
|
|
291
291
|
**顺序有讲究**:`npm run build` 要排在 `npm test` 之前——`tests/pack-contents.spec.ts` 会遍历 `exports` 的每个目标,`lib/` 存在与否决定这条检查是执行还是被跳过(不报错,但会少一层保护)。`package.json` 已移除 `prepare`,因此 `npm ci` 不会再替你隐式构建;三个 CI workflow 都显式跑了 `npm run build`。
|
|
292
292
|
|
|
293
|
-
测试覆盖配置校验、协议阶梯、网关与在线元数据、目录投影、适配器(三种协议的线上请求)、Remote 契约与服务、会话头不变量、用量窗口与计量、客户端控制器与用量组件、两半的挂载与登记、流空闲超时与中止的错误映射、验证脚本的退出码契约、以及几条**结构性不变量**(inject 声明与源码读取一致、peer 覆盖双向、README 与 manifest 一致、README 对上游的断言与实装的上游一致)。共 **
|
|
293
|
+
测试覆盖配置校验、协议阶梯、网关与在线元数据、目录投影、适配器(三种协议的线上请求)、Remote 契约与服务、会话头不变量、用量窗口与计量、客户端控制器与用量组件、两半的挂载与登记、流空闲超时与中止的错误映射、验证脚本的退出码契约、以及几条**结构性不变量**(inject 声明与源码读取一致、peer 覆盖双向、README 与 manifest 一致、README 对上游的断言与实装的上游一致)。共 **61 个测试文件**——这个数字由 `tests/readme-consistency.spec.ts` 对着 `tests/` 目录校验,不会漂移。
|
|
294
294
|
|
|
295
295
|
## 发布(维护者)
|
|
296
296
|
|
package/lib/client.js
CHANGED
|
@@ -208,6 +208,10 @@ var networkRemote = {
|
|
|
208
208
|
]
|
|
209
209
|
};
|
|
210
210
|
|
|
211
|
+
// src/request-log/store.ts
|
|
212
|
+
var MAX_STREAM_MARKS = 200;
|
|
213
|
+
var MIN_STREAM_MS_FOR_RATE = 100;
|
|
214
|
+
|
|
211
215
|
// src/request-log/contract.ts
|
|
212
216
|
function count(key, row, optional) {
|
|
213
217
|
const entry = row[key];
|
|
@@ -254,6 +258,8 @@ function parseEntry(value) {
|
|
|
254
258
|
...row["costUsd"] === void 0 ? {} : { costUsd: rate("costUsd", row) },
|
|
255
259
|
...row["requestBytes"] === void 0 ? {} : { requestBytes: count("requestBytes", row) },
|
|
256
260
|
...row["prepMs"] === void 0 ? {} : { prepMs: count("prepMs", row) },
|
|
261
|
+
...row["responseMs"] === void 0 ? {} : { responseMs: count("responseMs", row) },
|
|
262
|
+
...row["streamMarksMs"] === void 0 ? {} : { streamMarksMs: parseMarks(row["streamMarksMs"]) },
|
|
257
263
|
...row["imageBytes"] === void 0 ? {} : { imageBytes: count("imageBytes", row) },
|
|
258
264
|
...row["durationMs"] === void 0 ? {} : { durationMs: count("durationMs", row) },
|
|
259
265
|
...row["firstTokenMs"] === void 0 ? {} : { firstTokenMs: count("firstTokenMs", row) },
|
|
@@ -281,6 +287,15 @@ function parseEntry(value) {
|
|
|
281
287
|
} : {}
|
|
282
288
|
};
|
|
283
289
|
}
|
|
290
|
+
function parseMarks(value) {
|
|
291
|
+
if (!Array.isArray(value)) throw new Error("invalid request-log stream marks");
|
|
292
|
+
const kept = [];
|
|
293
|
+
for (const mark of value) {
|
|
294
|
+
if (typeof mark !== "number" || !Number.isFinite(mark) || mark < 0 || kept.length >= MAX_STREAM_MARKS) continue;
|
|
295
|
+
kept.push(mark);
|
|
296
|
+
}
|
|
297
|
+
return kept;
|
|
298
|
+
}
|
|
284
299
|
function rate(key, row) {
|
|
285
300
|
const entry = row[key];
|
|
286
301
|
if (typeof entry !== "number" || !Number.isFinite(entry) || entry < 0) {
|
|
@@ -569,6 +584,7 @@ var en = {
|
|
|
569
584
|
requestLogColPrep: "Prep",
|
|
570
585
|
requestLogColWait: "Wait",
|
|
571
586
|
requestLogTimelineWait: "Waiting for first token",
|
|
587
|
+
requestLogTimelineFirstByte: "First byte",
|
|
572
588
|
requestLogTimelineStream: "Streaming",
|
|
573
589
|
requestLogTimelineBurst: "Delivered in one burst",
|
|
574
590
|
requestLogColStream: "Content span",
|
|
@@ -787,6 +803,7 @@ var zh = {
|
|
|
787
803
|
requestLogDetailUrl: "\u5730\u5740",
|
|
788
804
|
requestLogDetailRequestBytes: "\u8BF7\u6C42\u4F53",
|
|
789
805
|
requestLogDetailPrep: "\u51C6\u5907\u8017\u65F6",
|
|
806
|
+
requestLogTimelineFirstByte: "\u9996\u5B57\u8282",
|
|
790
807
|
requestLogDetailContentSplit: "\u5185\u5BB9\u62C6\u5206",
|
|
791
808
|
requestLogDetailText: "\u6587\u672C",
|
|
792
809
|
requestLogDetailImages: "\u56FE\u7247",
|
|
@@ -2190,19 +2207,16 @@ function Section({ controller, t, getLocale, openRequestLog }) {
|
|
|
2190
2207
|
var import_react2 = require("react");
|
|
2191
2208
|
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
2192
2209
|
|
|
2193
|
-
// src/request-log/store.ts
|
|
2194
|
-
var MIN_STREAM_MS_FOR_RATE = 100;
|
|
2195
|
-
|
|
2196
2210
|
// plugin-css:/home/runner/work/dshopencodego/dshopencodego/src/client/request-log.module.css
|
|
2197
2211
|
var id2 = "@dan-ai-studio/dshopencodego/request-log.module.css";
|
|
2198
2212
|
if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]")) {
|
|
2199
2213
|
const style = document.createElement("style");
|
|
2200
2214
|
style.dataset.plugin = "@dan-ai-studio/dshopencodego";
|
|
2201
2215
|
style.dataset.pluginCss = id2;
|
|
2202
|
-
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)}";
|
|
2216
|
+
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_timelineStreamAlt{background:var(--dsw-alias-brand-primary);opacity:.9}.Lx7MOq_timelineRespTick{background:var(--dsw-alias-label-primary);opacity:.7;width:1px;position:absolute;top:-2px;bottom:-2px}.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{width:88px;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)}";
|
|
2203
2217
|
document.head.appendChild(style);
|
|
2204
2218
|
}
|
|
2205
|
-
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" };
|
|
2219
|
+
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", "timelineRespTick": "Lx7MOq_timelineRespTick", "timelineSeg": "Lx7MOq_timelineSeg", "timelineStream": "Lx7MOq_timelineStream", "timelineStreamAlt": "Lx7MOq_timelineStreamAlt", "timelineSwatch": "Lx7MOq_timelineSwatch", "timelineTick": "Lx7MOq_timelineTick", "timelineTickSwatch": "Lx7MOq_timelineTickSwatch", "timelineTrack": "Lx7MOq_timelineTrack", "timelineTrackWrap": "Lx7MOq_timelineTrackWrap", "timelineWait": "Lx7MOq_timelineWait", "title": "Lx7MOq_title", "toolbar": "Lx7MOq_toolbar" };
|
|
2206
2220
|
|
|
2207
2221
|
// src/client/RequestLogPage.tsx
|
|
2208
2222
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
@@ -2291,13 +2305,15 @@ function timelineOf(entry, t) {
|
|
|
2291
2305
|
const first = entry.firstTokenMs;
|
|
2292
2306
|
if (prep === void 0 && first === void 0) return void 0;
|
|
2293
2307
|
const start = prep ?? 0;
|
|
2294
|
-
const
|
|
2308
|
+
const blocks = [];
|
|
2295
2309
|
if (prep !== void 0 && prep > 0) {
|
|
2296
|
-
|
|
2310
|
+
blocks.push({ kind: "prep", label: t("requestLogDetailPrep"), from: 0, to: Math.min(prep, end) });
|
|
2297
2311
|
}
|
|
2312
|
+
const responseAt = entry.responseMs === void 0 ? void 0 : Math.min(Math.max(entry.responseMs, 0), end);
|
|
2313
|
+
let streamTotal;
|
|
2298
2314
|
if (first !== void 0) {
|
|
2299
2315
|
if (first > start) {
|
|
2300
|
-
|
|
2316
|
+
blocks.push({
|
|
2301
2317
|
kind: "wait",
|
|
2302
2318
|
label: t("requestLogTimelineWait"),
|
|
2303
2319
|
from: Math.min(start, end),
|
|
@@ -2306,14 +2322,30 @@ function timelineOf(entry, t) {
|
|
|
2306
2322
|
}
|
|
2307
2323
|
if (entry.streamMs !== void 0 && entry.streamMs > 0) {
|
|
2308
2324
|
const last = Math.min(first + entry.streamMs, end);
|
|
2309
|
-
if (last > first)
|
|
2325
|
+
if (last > first) {
|
|
2326
|
+
const cuts = [first, ...(entry.streamMarksMs ?? []).filter((mark) => mark > first && mark < last), last];
|
|
2327
|
+
for (let index = 0; index + 1 < cuts.length; index += 1) {
|
|
2328
|
+
const from = cuts[index];
|
|
2329
|
+
const to = cuts[index + 1];
|
|
2330
|
+
if (from === void 0 || to === void 0) continue;
|
|
2331
|
+
blocks.push({
|
|
2332
|
+
kind: index % 2 === 0 ? "stream" : "streamAlt",
|
|
2333
|
+
label: t("requestLogTimelineStream"),
|
|
2334
|
+
from,
|
|
2335
|
+
to
|
|
2336
|
+
});
|
|
2337
|
+
}
|
|
2338
|
+
streamTotal = last - first;
|
|
2339
|
+
}
|
|
2310
2340
|
}
|
|
2311
2341
|
}
|
|
2312
|
-
if (
|
|
2342
|
+
if (blocks.length === 0) return void 0;
|
|
2313
2343
|
return {
|
|
2314
|
-
|
|
2344
|
+
blocks,
|
|
2315
2345
|
end,
|
|
2316
|
-
burst: !running && first !== void 0 && (entry.streamMs === void 0 || entry.streamMs < MIN_STREAM_MS_FOR_RATE)
|
|
2346
|
+
burst: !running && first !== void 0 && (entry.streamMs === void 0 || entry.streamMs < MIN_STREAM_MS_FOR_RATE),
|
|
2347
|
+
responseAt,
|
|
2348
|
+
streamTotal
|
|
2317
2349
|
};
|
|
2318
2350
|
}
|
|
2319
2351
|
function percent(value) {
|
|
@@ -2528,44 +2560,69 @@ function RequestLogPage({ readLog, enabled, canOpenSession, openSession, t, getL
|
|
|
2528
2560
|
(() => {
|
|
2529
2561
|
const timeline = timelineOf(entry, t);
|
|
2530
2562
|
if (timeline === void 0) return null;
|
|
2531
|
-
const kindClass = (kind) => kind === "prep" ? request_log_default.timelinePrep : kind === "wait" ? request_log_default.timelineWait : request_log_default.timelineStream;
|
|
2532
|
-
const
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2563
|
+
const kindClass = (kind) => kind === "prep" ? request_log_default.timelinePrep : kind === "wait" ? request_log_default.timelineWait : kind === "stream" ? request_log_default.timelineStream : request_log_default.timelineStreamAlt;
|
|
2564
|
+
const legend = [];
|
|
2565
|
+
const legendKey = (kind) => kind === "streamAlt" ? "stream" : kind;
|
|
2566
|
+
for (const block of timeline.blocks) {
|
|
2567
|
+
const key = legendKey(block.kind);
|
|
2568
|
+
const seen = legend.some((item) => item.key === key);
|
|
2569
|
+
if (!seen) {
|
|
2570
|
+
legend.push({
|
|
2571
|
+
key,
|
|
2572
|
+
swatch: kindClass(key),
|
|
2573
|
+
text: `${block.label} ${duration(
|
|
2574
|
+
timeline.blocks.filter((other) => legendKey(other.kind) === key).reduce((sum, other) => sum + (other.to - other.from), 0)
|
|
2575
|
+
)}`
|
|
2576
|
+
});
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
if (timeline.responseAt !== void 0) {
|
|
2580
|
+
legend.push({
|
|
2581
|
+
key: "response",
|
|
2582
|
+
swatch: request_log_default.timelineTickSwatch,
|
|
2583
|
+
text: `${t("requestLogTimelineFirstByte")} ${duration(timeline.responseAt)}`
|
|
2584
|
+
});
|
|
2585
|
+
}
|
|
2586
|
+
legend.push({
|
|
2587
|
+
key: "total",
|
|
2588
|
+
swatch: request_log_default.timelineTickSwatch,
|
|
2589
|
+
text: `${t("requestLogColLatency")} ${duration(timeline.end)}`
|
|
2590
|
+
});
|
|
2591
|
+
const spoken = legend.map((item) => item.text).join(", ");
|
|
2592
|
+
const percent2 = (at) => `${(at / timeline.end * 100).toFixed(2)}%`;
|
|
2536
2593
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.timeline, role: "img", "aria-label": spoken, children: [
|
|
2537
2594
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.timelineTrackWrap, children: [
|
|
2538
2595
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.timelineTrack, children: [
|
|
2539
|
-
timeline.
|
|
2596
|
+
timeline.blocks.map((block, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2540
2597
|
"div",
|
|
2541
2598
|
{
|
|
2542
|
-
className: `${request_log_default.timelineSeg} ${kindClass(
|
|
2599
|
+
className: `${request_log_default.timelineSeg} ${kindClass(block.kind)}`,
|
|
2543
2600
|
style: {
|
|
2544
|
-
left:
|
|
2545
|
-
width:
|
|
2601
|
+
left: percent2(block.from),
|
|
2602
|
+
width: percent2(Math.max(0, block.to - block.from))
|
|
2546
2603
|
},
|
|
2547
|
-
title: `${
|
|
2604
|
+
title: `${block.label} ${duration(block.to - block.from)}`
|
|
2548
2605
|
},
|
|
2549
|
-
|
|
2606
|
+
`${block.kind}-${index}`
|
|
2550
2607
|
)),
|
|
2608
|
+
timeline.responseAt !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2609
|
+
"div",
|
|
2610
|
+
{
|
|
2611
|
+
className: request_log_default.timelineRespTick,
|
|
2612
|
+
style: { left: percent2(Math.min(timeline.responseAt, timeline.end)) },
|
|
2613
|
+
title: `${t("requestLogTimelineFirstByte")} ${duration(timeline.responseAt)}`
|
|
2614
|
+
}
|
|
2615
|
+
),
|
|
2551
2616
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: request_log_default.timelineMidTick }),
|
|
2552
2617
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: request_log_default.timelineTick, title: duration(timeline.end) })
|
|
2553
2618
|
] }),
|
|
2554
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: request_log_default.timelineMid, title: duration(timeline.end / 2), children: duration(timeline.end / 2) })
|
|
2619
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: request_log_default.timelineMid, style: { left: "50%" }, title: duration(timeline.end / 2), children: duration(timeline.end / 2) })
|
|
2555
2620
|
] }),
|
|
2556
2621
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.timelineLegend, children: [
|
|
2557
|
-
|
|
2558
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${request_log_default.timelineSwatch} ${
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
duration(slice.to - slice.from)
|
|
2562
|
-
] }, slice.kind)),
|
|
2563
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: request_log_default.timelineItem, children: [
|
|
2564
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${request_log_default.timelineSwatch} ${request_log_default.timelineTickSwatch}` }),
|
|
2565
|
-
t("requestLogColLatency"),
|
|
2566
|
-
" ",
|
|
2567
|
-
duration(timeline.end)
|
|
2568
|
-
] }),
|
|
2622
|
+
legend.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: request_log_default.timelineItem, children: [
|
|
2623
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${request_log_default.timelineSwatch} ${item.swatch ?? ""}` }),
|
|
2624
|
+
item.text
|
|
2625
|
+
] }, item.key)),
|
|
2569
2626
|
timeline.burst && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.timelineItem, children: t("requestLogTimelineBurst") })
|
|
2570
2627
|
] })
|
|
2571
2628
|
] });
|
package/lib/index.js
CHANGED
|
@@ -73672,7 +73672,7 @@ import dc from "node:diagnostics_channel";
|
|
|
73672
73672
|
import { credentialRef } from "@deepseek-ai/dsh-credentials";
|
|
73673
73673
|
import { launchEnvironmentOf } from "@deepseek-ai/dsh-launch-environment";
|
|
73674
73674
|
import * as llm2 from "@deepseek-ai/dsh-llm";
|
|
73675
|
-
import { LlmError as
|
|
73675
|
+
import { LlmError as LlmError14 } from "@deepseek-ai/dsh-llm";
|
|
73676
73676
|
|
|
73677
73677
|
// src/adapter.ts
|
|
73678
73678
|
init_models();
|
|
@@ -73682,7 +73682,7 @@ import {
|
|
|
73682
73682
|
contentHasImage as contentHasImage2,
|
|
73683
73683
|
isTokenDelta,
|
|
73684
73684
|
LlmAdapter,
|
|
73685
|
-
LlmError as
|
|
73685
|
+
LlmError as LlmError10,
|
|
73686
73686
|
ReasoningEffortId,
|
|
73687
73687
|
resolveRetryPolicy
|
|
73688
73688
|
} from "@deepseek-ai/dsh-llm";
|
|
@@ -77887,6 +77887,74 @@ function sortModels(models, now = Date.now()) {
|
|
|
77887
77887
|
return [...models].sort((left, right) => rank(left) - rank(right) || (isNewModel(left, now) && isNewModel(right, now) ? right.releaseDate.localeCompare(left.releaseDate) : 0));
|
|
77888
77888
|
}
|
|
77889
77889
|
|
|
77890
|
+
// src/context-fit.ts
|
|
77891
|
+
import { CONTEXT_WINDOW_EXCEEDED_CODE as CONTEXT_WINDOW_EXCEEDED_CODE2, LlmError as LlmError9 } from "@deepseek-ai/dsh-llm";
|
|
77892
|
+
var CONTEXT_FIT_RESERVE_TOKENS = 2048;
|
|
77893
|
+
var CONTEXT_FIT_MIN_OUTPUT_TOKENS = 256;
|
|
77894
|
+
var CHARS_PER_TOKEN2 = 3;
|
|
77895
|
+
var TOKENS_PER_MESSAGE = 8;
|
|
77896
|
+
var TOKENS_PER_IMAGE = 2e3;
|
|
77897
|
+
var IMAGE_BYTES_PER_TOKEN = 2e3;
|
|
77898
|
+
var TOKENS_PER_FILE = 500;
|
|
77899
|
+
var FILE_BYTES_PER_TOKEN = 4e3;
|
|
77900
|
+
function estimateInputTokens(options) {
|
|
77901
|
+
let chars = 0;
|
|
77902
|
+
let images = 0;
|
|
77903
|
+
let imageBytes = 0;
|
|
77904
|
+
let files = 0;
|
|
77905
|
+
let fileBytes = 0;
|
|
77906
|
+
if (typeof options.system === "string") chars += options.system.length;
|
|
77907
|
+
for (const message of options.messages) {
|
|
77908
|
+
for (const block of message.content) {
|
|
77909
|
+
switch (block.type) {
|
|
77910
|
+
case "text":
|
|
77911
|
+
case "reasoning":
|
|
77912
|
+
chars += block.text.length;
|
|
77913
|
+
break;
|
|
77914
|
+
case "tool-call":
|
|
77915
|
+
chars += block.name.length + block.arguments.length;
|
|
77916
|
+
break;
|
|
77917
|
+
case "image":
|
|
77918
|
+
if (block.offloaded === true) {
|
|
77919
|
+
chars += 200;
|
|
77920
|
+
} else {
|
|
77921
|
+
images += 1;
|
|
77922
|
+
imageBytes += block.attachment.bytes;
|
|
77923
|
+
}
|
|
77924
|
+
break;
|
|
77925
|
+
case "file":
|
|
77926
|
+
files += 1;
|
|
77927
|
+
fileBytes += block.attachment.bytes;
|
|
77928
|
+
chars += block.attachment.name.length;
|
|
77929
|
+
break;
|
|
77930
|
+
default:
|
|
77931
|
+
break;
|
|
77932
|
+
}
|
|
77933
|
+
}
|
|
77934
|
+
}
|
|
77935
|
+
if (options.tools !== void 0 && options.tools.length > 0) {
|
|
77936
|
+
chars += JSON.stringify(options.tools).length;
|
|
77937
|
+
}
|
|
77938
|
+
const estimate = Math.ceil(chars / CHARS_PER_TOKEN2) + options.messages.length * TOKENS_PER_MESSAGE + images * TOKENS_PER_IMAGE + Math.ceil(imageBytes / IMAGE_BYTES_PER_TOKEN) + files * TOKENS_PER_FILE + Math.ceil(fileBytes / FILE_BYTES_PER_TOKEN);
|
|
77939
|
+
return Number.isFinite(estimate) && estimate > 0 ? Math.floor(estimate) : 0;
|
|
77940
|
+
}
|
|
77941
|
+
function resolveFittedMaxTokens(fit) {
|
|
77942
|
+
const { modelId, contextWindow, routeMaxTokens, requestedMaxTokens, estimatedInputTokens } = fit;
|
|
77943
|
+
if (!Number.isFinite(contextWindow) || contextWindow <= 0) return requestedMaxTokens;
|
|
77944
|
+
const input = Number.isFinite(estimatedInputTokens) && estimatedInputTokens > 0 ? Math.floor(estimatedInputTokens) : 0;
|
|
77945
|
+
const allowed = Math.floor(contextWindow - input - CONTEXT_FIT_RESERVE_TOKENS);
|
|
77946
|
+
const over = (what) => new LlmError9(
|
|
77947
|
+
`opencode-go model "${modelId}" ${what} (~${input} input tokens) leaves no room inside context window ${contextWindow} (reserve ${CONTEXT_FIT_RESERVE_TOKENS}); compact the conversation or lower maxTokens`,
|
|
77948
|
+
CONTEXT_WINDOW_EXCEEDED_CODE2
|
|
77949
|
+
);
|
|
77950
|
+
if (allowed < CONTEXT_FIT_MIN_OUTPUT_TOKENS) throw over("input");
|
|
77951
|
+
const effective = requestedMaxTokens ?? routeMaxTokens;
|
|
77952
|
+
if (effective === void 0) return void 0;
|
|
77953
|
+
if (!Number.isFinite(effective) || effective <= 0) return requestedMaxTokens;
|
|
77954
|
+
if (effective <= allowed) return requestedMaxTokens;
|
|
77955
|
+
return allowed;
|
|
77956
|
+
}
|
|
77957
|
+
|
|
77890
77958
|
// src/session-header.ts
|
|
77891
77959
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
77892
77960
|
import { attributionHeaders as attributionHeaders4 } from "@deepseek-ai/dsh-llm";
|
|
@@ -78008,7 +78076,7 @@ function withModelLimit(model, limits) {
|
|
|
78008
78076
|
function stopSequencesFor(model, stop) {
|
|
78009
78077
|
if (stop === void 0) return void 0;
|
|
78010
78078
|
if (model.api === "openai-completions") return stop;
|
|
78011
|
-
throw new
|
|
78079
|
+
throw new LlmError10(
|
|
78012
78080
|
`opencode-go model "${model.id}" speaks ${model.api}, which has no stop-sequence parameter this adapter can reach; drop GenerateOptions.stop for this model`,
|
|
78013
78081
|
"UNSUPPORTED_OPTION"
|
|
78014
78082
|
);
|
|
@@ -78128,7 +78196,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
78128
78196
|
const config = this.options.config();
|
|
78129
78197
|
const snapshot2 = await this.catalogOf(config).forModel(model);
|
|
78130
78198
|
const facts = snapshot2.facts.get(model);
|
|
78131
|
-
if (facts === void 0) throw new
|
|
78199
|
+
if (facts === void 0) throw new LlmError10(`opencode-go has no model "${model}"`, "UNKNOWN_MODEL");
|
|
78132
78200
|
return this.modelInfo(withModelLimit(toPiModel(facts, config.baseURL), config.modelLimits));
|
|
78133
78201
|
}
|
|
78134
78202
|
/** Describe one model: capacities plus the reasoning levels it really offers. */
|
|
@@ -78174,7 +78242,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
78174
78242
|
if (effort === void 0 || effort === "off") return void 0;
|
|
78175
78243
|
const supported = getSupportedThinkingLevels(model);
|
|
78176
78244
|
if (supported.some((level) => level === effort)) return effort;
|
|
78177
|
-
throw new
|
|
78245
|
+
throw new LlmError10(
|
|
78178
78246
|
`opencode-go model "${model.id}" does not support reasoning effort "${effort}"`,
|
|
78179
78247
|
"UNSUPPORTED_REASONING_EFFORT"
|
|
78180
78248
|
);
|
|
@@ -78227,7 +78295,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
78227
78295
|
hasImage: false,
|
|
78228
78296
|
toolCount: 0,
|
|
78229
78297
|
headers: {}
|
|
78230
|
-
})?.finish(false, error instanceof
|
|
78298
|
+
})?.finish(false, error instanceof LlmError10 ? error.code : void 0);
|
|
78231
78299
|
}
|
|
78232
78300
|
async prepareCall(_provider, model, _signal) {
|
|
78233
78301
|
const config = this.options.config();
|
|
@@ -78241,7 +78309,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
78241
78309
|
}
|
|
78242
78310
|
const facts = snapshot2.facts.get(model);
|
|
78243
78311
|
if (facts === void 0) {
|
|
78244
|
-
const error = new
|
|
78312
|
+
const error = new LlmError10(`opencode-go has no model "${model}"`, "UNKNOWN_MODEL");
|
|
78245
78313
|
this.logUnstartedFailure(config, model, error);
|
|
78246
78314
|
throw error;
|
|
78247
78315
|
}
|
|
@@ -78262,7 +78330,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
78262
78330
|
try {
|
|
78263
78331
|
snapshot2 = await this.catalogOf(config).forModel(options.model);
|
|
78264
78332
|
} catch (error) {
|
|
78265
|
-
span?.finish(false, error instanceof
|
|
78333
|
+
span?.finish(false, error instanceof LlmError10 ? error.code : void 0);
|
|
78266
78334
|
throw error;
|
|
78267
78335
|
}
|
|
78268
78336
|
yield* this.streamWithSnapshot(options, config, snapshot2, span);
|
|
@@ -78272,7 +78340,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
78272
78340
|
try {
|
|
78273
78341
|
const span = outerSpan ?? this.startSpan(options, config);
|
|
78274
78342
|
const failSpan = (error) => {
|
|
78275
|
-
span?.finish(false, error instanceof
|
|
78343
|
+
span?.finish(false, error instanceof LlmError10 ? error.code : void 0);
|
|
78276
78344
|
throw error;
|
|
78277
78345
|
};
|
|
78278
78346
|
try {
|
|
@@ -78282,7 +78350,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
78282
78350
|
}
|
|
78283
78351
|
const facts = snapshot2.facts.get(options.model);
|
|
78284
78352
|
if (facts === void 0) {
|
|
78285
|
-
const error = new
|
|
78353
|
+
const error = new LlmError10(`opencode-go has no model "${options.model}"`, "UNKNOWN_MODEL");
|
|
78286
78354
|
span?.finish(false, error.code);
|
|
78287
78355
|
throw error;
|
|
78288
78356
|
}
|
|
@@ -78290,10 +78358,22 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
78290
78358
|
const rates2 = usableRates(facts.cost);
|
|
78291
78359
|
const stop = stopSequencesFor(model, options.stop);
|
|
78292
78360
|
const ceiling = config.modelLimits[model.id]?.maxTokens;
|
|
78293
|
-
const
|
|
78361
|
+
const requested = options.maxTokens === void 0 || ceiling === null || ceiling === void 0 ? options.maxTokens : Math.min(options.maxTokens, ceiling);
|
|
78362
|
+
let maxTokens;
|
|
78363
|
+
try {
|
|
78364
|
+
maxTokens = resolveFittedMaxTokens({
|
|
78365
|
+
modelId: model.id,
|
|
78366
|
+
contextWindow: model.contextWindow,
|
|
78367
|
+
routeMaxTokens: model.maxTokens,
|
|
78368
|
+
requestedMaxTokens: requested,
|
|
78369
|
+
estimatedInputTokens: estimateInputTokens(options)
|
|
78370
|
+
});
|
|
78371
|
+
} catch (error) {
|
|
78372
|
+
failSpan(error);
|
|
78373
|
+
}
|
|
78294
78374
|
const apiKey = await this.options.resolveApiKey();
|
|
78295
78375
|
if (apiKey === void 0 || apiKey.length === 0) {
|
|
78296
|
-
const error = new
|
|
78376
|
+
const error = new LlmError10("dshopencodego: no credential resolved for the opencode-go route", "MISSING_CREDENTIAL");
|
|
78297
78377
|
span?.finish(false, error.code);
|
|
78298
78378
|
throw error;
|
|
78299
78379
|
}
|
|
@@ -78323,14 +78403,14 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
78323
78403
|
};
|
|
78324
78404
|
try {
|
|
78325
78405
|
if (containsImage && !model.input.includes("image")) {
|
|
78326
|
-
throw new
|
|
78406
|
+
throw new LlmError10(`opencode-go model "${model.id}" does not support image input`, "UNSUPPORTED_CONTENT");
|
|
78327
78407
|
}
|
|
78328
78408
|
let imageRequest;
|
|
78329
78409
|
if (containsImage) {
|
|
78330
78410
|
const access2 = this.options.imageAccess;
|
|
78331
78411
|
const store = access2?.resolveAttachments();
|
|
78332
78412
|
if (access2 === void 0 || store === void 0) {
|
|
78333
|
-
throw new
|
|
78413
|
+
throw new LlmError10("dshopencodego image input requires the durable attachment service", "UNSUPPORTED_CONTENT");
|
|
78334
78414
|
}
|
|
78335
78415
|
imageRequest = {
|
|
78336
78416
|
attachments: store,
|
|
@@ -78374,7 +78454,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
78374
78454
|
while (true) {
|
|
78375
78455
|
const result = await watchdog.next(iterator);
|
|
78376
78456
|
if (timeoutOf(watchdog.signal, "LLM_STREAM_IDLE_TIMEOUT") !== void 0) {
|
|
78377
|
-
throw new
|
|
78457
|
+
throw new LlmError10("opencode-go stream idle timeout", "TIMEOUT");
|
|
78378
78458
|
}
|
|
78379
78459
|
if (result.done) {
|
|
78380
78460
|
exhausted = true;
|
|
@@ -78427,13 +78507,13 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
78427
78507
|
} catch (error) {
|
|
78428
78508
|
if (timedOut || timeoutOf(watchdog.signal, "LLM_STREAM_IDLE_TIMEOUT") !== void 0) {
|
|
78429
78509
|
span?.finish(false, "TIMEOUT");
|
|
78430
|
-
throw new
|
|
78510
|
+
throw new LlmError10("opencode-go stream idle timeout", "TIMEOUT", { cause: error });
|
|
78431
78511
|
}
|
|
78432
78512
|
if (options.signal?.aborted) {
|
|
78433
78513
|
span?.finish(false, "ABORTED");
|
|
78434
|
-
throw new
|
|
78514
|
+
throw new LlmError10("opencode-go request aborted by caller", "ABORTED", { cause: error });
|
|
78435
78515
|
}
|
|
78436
|
-
span?.finish(false, error instanceof
|
|
78516
|
+
span?.finish(false, error instanceof LlmError10 ? error.code : void 0);
|
|
78437
78517
|
throw error;
|
|
78438
78518
|
} finally {
|
|
78439
78519
|
consumer.abort("opencode-go stream consumer stopped");
|
|
@@ -78618,6 +78698,199 @@ var networkRemote = {
|
|
|
78618
78698
|
]
|
|
78619
78699
|
};
|
|
78620
78700
|
|
|
78701
|
+
// src/request-log/store.ts
|
|
78702
|
+
var MAX_POOL_EVENTS = 20;
|
|
78703
|
+
var STREAM_MARK_EVERY = 10;
|
|
78704
|
+
var MAX_STREAM_MARKS = 200;
|
|
78705
|
+
var MIN_STREAM_MS_FOR_RATE = 100;
|
|
78706
|
+
var RequestLog = class {
|
|
78707
|
+
gates;
|
|
78708
|
+
entries = [];
|
|
78709
|
+
poolEvents = [];
|
|
78710
|
+
seq = 0;
|
|
78711
|
+
totalRecords = 0;
|
|
78712
|
+
droppedRecords = 0;
|
|
78713
|
+
newConnections = 0;
|
|
78714
|
+
poolKey;
|
|
78715
|
+
constructor(gates) {
|
|
78716
|
+
this.gates = gates;
|
|
78717
|
+
}
|
|
78718
|
+
/**
|
|
78719
|
+
* Count one accepted socket. Called from the diagnostics channel, not the
|
|
78720
|
+
* request path, so its cost never lands on a request.
|
|
78721
|
+
*/
|
|
78722
|
+
connectionOpened() {
|
|
78723
|
+
this.newConnections += 1;
|
|
78724
|
+
}
|
|
78725
|
+
/**
|
|
78726
|
+
* Record one pool lifecycle event. Pools live for minutes, so this is rare
|
|
78727
|
+
* by construction; still gated on debug so the common log stays request-only.
|
|
78728
|
+
*/
|
|
78729
|
+
poolEvent(type, key) {
|
|
78730
|
+
if (!this.gates.enabled() || !this.gates.debug()) return;
|
|
78731
|
+
this.poolKey = type === "create" ? key : this.poolKey;
|
|
78732
|
+
if (type === "close" && this.poolKey === key) this.poolKey = void 0;
|
|
78733
|
+
this.poolEvents = [{ atMs: Date.now(), type, key }, ...this.poolEvents].slice(0, MAX_POOL_EVENTS);
|
|
78734
|
+
}
|
|
78735
|
+
/**
|
|
78736
|
+
* Begin one request's span, or nothing when the log is disabled.
|
|
78737
|
+
*
|
|
78738
|
+
* This is the single gate on the request path: a disabled log costs one
|
|
78739
|
+
* method call and one boolean read, and constructs nothing. When enabled,
|
|
78740
|
+
* the running row is appended before the span is returned, so the viewer
|
|
78741
|
+
* sees the request while it runs; `request` and `status` mutate that same
|
|
78742
|
+
* visible row as the wire facts arrive.
|
|
78743
|
+
*/
|
|
78744
|
+
start(detail) {
|
|
78745
|
+
if (!this.gates.enabled()) return void 0;
|
|
78746
|
+
const debug = this.gates.debug();
|
|
78747
|
+
const startedAt = Date.now();
|
|
78748
|
+
const session = detail.sessionId ?? "";
|
|
78749
|
+
const record2 = {
|
|
78750
|
+
seq: ++this.seq,
|
|
78751
|
+
atMs: startedAt,
|
|
78752
|
+
model: detail.model,
|
|
78753
|
+
...detail.protocol === void 0 ? {} : { protocol: detail.protocol },
|
|
78754
|
+
session,
|
|
78755
|
+
method: detail.method ?? "POST",
|
|
78756
|
+
url: detail.url ?? "",
|
|
78757
|
+
running: true,
|
|
78758
|
+
ok: false,
|
|
78759
|
+
shape: { messages: detail.messageCount, hasImage: detail.hasImage, tools: detail.toolCount },
|
|
78760
|
+
...detail.imageBytes === void 0 ? {} : { imageBytes: detail.imageBytes },
|
|
78761
|
+
...!debug ? {} : {
|
|
78762
|
+
headers: {
|
|
78763
|
+
...detail.headers.session === void 0 ? {} : { session: detail.headers.session },
|
|
78764
|
+
...detail.headers.userAgent === void 0 ? {} : { userAgent: detail.headers.userAgent }
|
|
78765
|
+
}
|
|
78766
|
+
}
|
|
78767
|
+
};
|
|
78768
|
+
this.insert(record2, true);
|
|
78769
|
+
let firstTokenAt;
|
|
78770
|
+
let lastTokenAt;
|
|
78771
|
+
let tokenDeltas = 0;
|
|
78772
|
+
const marks = [];
|
|
78773
|
+
let reported = false;
|
|
78774
|
+
let finished = false;
|
|
78775
|
+
return {
|
|
78776
|
+
identify: (protocol) => {
|
|
78777
|
+
if (record2.protocol === void 0) record2.protocol = protocol;
|
|
78778
|
+
},
|
|
78779
|
+
token: () => {
|
|
78780
|
+
const now = Date.now();
|
|
78781
|
+
if (firstTokenAt === void 0) {
|
|
78782
|
+
firstTokenAt = now;
|
|
78783
|
+
record2.firstTokenMs = Math.max(0, now - startedAt);
|
|
78784
|
+
}
|
|
78785
|
+
lastTokenAt = now;
|
|
78786
|
+
tokenDeltas += 1;
|
|
78787
|
+
if (tokenDeltas % STREAM_MARK_EVERY === 0 && marks.length < MAX_STREAM_MARKS) {
|
|
78788
|
+
marks.push(Math.max(0, now - startedAt));
|
|
78789
|
+
record2.streamMarksMs = marks;
|
|
78790
|
+
}
|
|
78791
|
+
},
|
|
78792
|
+
request: (nextMethod, nextUrl, nextRequestBytes) => {
|
|
78793
|
+
if (!reported) {
|
|
78794
|
+
reported = true;
|
|
78795
|
+
record2.method = nextMethod;
|
|
78796
|
+
record2.url = nextUrl;
|
|
78797
|
+
if (nextRequestBytes !== void 0) record2.requestBytes = nextRequestBytes;
|
|
78798
|
+
record2.prepMs = Math.max(0, Date.now() - startedAt);
|
|
78799
|
+
}
|
|
78800
|
+
},
|
|
78801
|
+
status: (value) => {
|
|
78802
|
+
record2.status = value;
|
|
78803
|
+
if (record2.responseMs === void 0) record2.responseMs = Math.max(0, Date.now() - startedAt);
|
|
78804
|
+
},
|
|
78805
|
+
finish: (ok, code, usage, costUsd) => {
|
|
78806
|
+
if (finished) return;
|
|
78807
|
+
finished = true;
|
|
78808
|
+
const seq = record2.seq;
|
|
78809
|
+
const endedAt = Date.now();
|
|
78810
|
+
const decodeMs = firstTokenAt === void 0 ? void 0 : Math.max(0, endedAt - firstTokenAt);
|
|
78811
|
+
const streamMs = firstTokenAt === void 0 || lastTokenAt === void 0 ? void 0 : Math.max(0, lastTokenAt - firstTokenAt);
|
|
78812
|
+
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);
|
|
78813
|
+
const entry = {
|
|
78814
|
+
seq,
|
|
78815
|
+
atMs: startedAt,
|
|
78816
|
+
model: detail.model,
|
|
78817
|
+
// The protocol may have arrived after the row opened, through
|
|
78818
|
+
// `identify` — the running row and the completion read the same
|
|
78819
|
+
// field, so they never disagree.
|
|
78820
|
+
...record2.protocol === void 0 ? {} : { protocol: record2.protocol },
|
|
78821
|
+
session,
|
|
78822
|
+
method: record2.method,
|
|
78823
|
+
url: record2.url,
|
|
78824
|
+
...record2.status === void 0 ? {} : { status: record2.status },
|
|
78825
|
+
...record2.prepMs === void 0 ? {} : { prepMs: record2.prepMs },
|
|
78826
|
+
...record2.responseMs === void 0 ? {} : { responseMs: record2.responseMs },
|
|
78827
|
+
...record2.streamMarksMs === void 0 ? {} : { streamMarksMs: [...record2.streamMarksMs] },
|
|
78828
|
+
...usage === void 0 ? {} : {
|
|
78829
|
+
inputTokens: usage.inputTokens,
|
|
78830
|
+
outputTokens: usage.outputTokens,
|
|
78831
|
+
...usage.cacheReadTokens === void 0 || usage.cacheReadTokens <= 0 ? {} : { cacheReadTokens: usage.cacheReadTokens },
|
|
78832
|
+
...usage.cacheWriteTokens === void 0 || usage.cacheWriteTokens <= 0 ? {} : { cacheWriteTokens: usage.cacheWriteTokens },
|
|
78833
|
+
...usage.reasoningTokens === void 0 || usage.reasoningTokens <= 0 ? {} : { reasoningTokens: usage.reasoningTokens }
|
|
78834
|
+
},
|
|
78835
|
+
...costUsd === void 0 ? {} : { costUsd },
|
|
78836
|
+
...record2.requestBytes === void 0 ? {} : { requestBytes: record2.requestBytes },
|
|
78837
|
+
...detail.imageBytes === void 0 ? {} : { imageBytes: detail.imageBytes },
|
|
78838
|
+
durationMs: Math.max(0, endedAt - startedAt),
|
|
78839
|
+
...firstTokenAt === void 0 ? {} : { firstTokenMs: Math.max(0, firstTokenAt - startedAt) },
|
|
78840
|
+
...decodeMs === void 0 ? {} : { decodeMs },
|
|
78841
|
+
...streamMs === void 0 ? {} : { streamMs },
|
|
78842
|
+
...tps === void 0 ? {} : { tps },
|
|
78843
|
+
ok,
|
|
78844
|
+
...code === void 0 ? {} : { code },
|
|
78845
|
+
// The pool in force when the request finished. Pool switches are
|
|
78846
|
+
// rare enough that attributing the finishing pool is honest; the
|
|
78847
|
+
// create/close events carry the exact history.
|
|
78848
|
+
...this.poolKey === void 0 ? {} : { poolKey: this.poolKey },
|
|
78849
|
+
shape: { messages: detail.messageCount, hasImage: detail.hasImage, tools: detail.toolCount },
|
|
78850
|
+
...!debug ? {} : {
|
|
78851
|
+
headers: {
|
|
78852
|
+
...detail.headers.session === void 0 ? {} : { session: detail.headers.session },
|
|
78853
|
+
...detail.headers.userAgent === void 0 ? {} : { userAgent: detail.headers.userAgent }
|
|
78854
|
+
}
|
|
78855
|
+
}
|
|
78856
|
+
};
|
|
78857
|
+
const at = this.entries.findIndex((candidate) => candidate.seq === seq);
|
|
78858
|
+
if (at === -1) {
|
|
78859
|
+
this.insert(entry, false);
|
|
78860
|
+
} else {
|
|
78861
|
+
this.entries[at] = entry;
|
|
78862
|
+
}
|
|
78863
|
+
}
|
|
78864
|
+
};
|
|
78865
|
+
}
|
|
78866
|
+
insert(entry, count2) {
|
|
78867
|
+
if (count2) this.totalRecords += 1;
|
|
78868
|
+
const bound = Math.max(1, Math.floor(this.gates.maxEntries()));
|
|
78869
|
+
const next = [entry, ...this.entries].slice(0, bound);
|
|
78870
|
+
this.droppedRecords += this.entries.length + 1 - next.length;
|
|
78871
|
+
this.entries = next;
|
|
78872
|
+
}
|
|
78873
|
+
/** Shrink the ring to a new bound immediately; growing backfills nothing. */
|
|
78874
|
+
setMaxEntries(bound) {
|
|
78875
|
+
if (!Number.isSafeInteger(bound) || bound < 1) return;
|
|
78876
|
+
if (this.entries.length > bound) {
|
|
78877
|
+
this.droppedRecords += this.entries.length - bound;
|
|
78878
|
+
this.entries = this.entries.slice(0, bound);
|
|
78879
|
+
}
|
|
78880
|
+
}
|
|
78881
|
+
/** The current reading, newest first. Computed lazily: nothing on the hot path. */
|
|
78882
|
+
snapshot() {
|
|
78883
|
+
return {
|
|
78884
|
+
entries: this.entries,
|
|
78885
|
+
poolEvents: this.poolEvents,
|
|
78886
|
+
totalRecords: this.totalRecords,
|
|
78887
|
+
droppedRecords: this.droppedRecords,
|
|
78888
|
+
newConnections: this.newConnections,
|
|
78889
|
+
...this.poolKey === void 0 ? {} : { poolKey: this.poolKey }
|
|
78890
|
+
};
|
|
78891
|
+
}
|
|
78892
|
+
};
|
|
78893
|
+
|
|
78621
78894
|
// src/request-log/contract.ts
|
|
78622
78895
|
function count(key, row, optional) {
|
|
78623
78896
|
const entry = row[key];
|
|
@@ -78664,6 +78937,8 @@ function parseEntry(value) {
|
|
|
78664
78937
|
...row["costUsd"] === void 0 ? {} : { costUsd: rate("costUsd", row) },
|
|
78665
78938
|
...row["requestBytes"] === void 0 ? {} : { requestBytes: count("requestBytes", row) },
|
|
78666
78939
|
...row["prepMs"] === void 0 ? {} : { prepMs: count("prepMs", row) },
|
|
78940
|
+
...row["responseMs"] === void 0 ? {} : { responseMs: count("responseMs", row) },
|
|
78941
|
+
...row["streamMarksMs"] === void 0 ? {} : { streamMarksMs: parseMarks(row["streamMarksMs"]) },
|
|
78667
78942
|
...row["imageBytes"] === void 0 ? {} : { imageBytes: count("imageBytes", row) },
|
|
78668
78943
|
...row["durationMs"] === void 0 ? {} : { durationMs: count("durationMs", row) },
|
|
78669
78944
|
...row["firstTokenMs"] === void 0 ? {} : { firstTokenMs: count("firstTokenMs", row) },
|
|
@@ -78691,6 +78966,15 @@ function parseEntry(value) {
|
|
|
78691
78966
|
} : {}
|
|
78692
78967
|
};
|
|
78693
78968
|
}
|
|
78969
|
+
function parseMarks(value) {
|
|
78970
|
+
if (!Array.isArray(value)) throw new Error("invalid request-log stream marks");
|
|
78971
|
+
const kept = [];
|
|
78972
|
+
for (const mark of value) {
|
|
78973
|
+
if (typeof mark !== "number" || !Number.isFinite(mark) || mark < 0 || kept.length >= MAX_STREAM_MARKS) continue;
|
|
78974
|
+
kept.push(mark);
|
|
78975
|
+
}
|
|
78976
|
+
return kept;
|
|
78977
|
+
}
|
|
78694
78978
|
function rate(key, row) {
|
|
78695
78979
|
const entry = row[key];
|
|
78696
78980
|
if (typeof entry !== "number" || !Number.isFinite(entry) || entry < 0) {
|
|
@@ -78906,7 +79190,7 @@ function registerRemotes(ctx) {
|
|
|
78906
79190
|
|
|
78907
79191
|
// src/catalog/service.ts
|
|
78908
79192
|
import { RemoteError, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
78909
|
-
import { LlmError as
|
|
79193
|
+
import { LlmError as LlmError11 } from "@deepseek-ai/dsh-llm";
|
|
78910
79194
|
|
|
78911
79195
|
// src/catalog/reading.ts
|
|
78912
79196
|
function catalogReading(snapshot2, visibility, listingFailure, now) {
|
|
@@ -78987,7 +79271,7 @@ var OpencodeGoCatalogService = class extends TypertRemoteService {
|
|
|
78987
79271
|
const reading = catalogReading(
|
|
78988
79272
|
snapshot2,
|
|
78989
79273
|
visibility,
|
|
78990
|
-
failure === void 0 ? void 0 : failure instanceof
|
|
79274
|
+
failure === void 0 ? void 0 : failure instanceof LlmError11 || failure instanceof Error ? failure.message : String(failure)
|
|
78991
79275
|
);
|
|
78992
79276
|
this.reportUnadvertised(snapshot2, visibility);
|
|
78993
79277
|
return reading;
|
|
@@ -79213,187 +79497,6 @@ var OpencodeGoRequestLogService = class extends TypertRemoteService3 {
|
|
|
79213
79497
|
}
|
|
79214
79498
|
};
|
|
79215
79499
|
|
|
79216
|
-
// src/request-log/store.ts
|
|
79217
|
-
var MAX_POOL_EVENTS = 20;
|
|
79218
|
-
var MIN_STREAM_MS_FOR_RATE = 100;
|
|
79219
|
-
var RequestLog = class {
|
|
79220
|
-
gates;
|
|
79221
|
-
entries = [];
|
|
79222
|
-
poolEvents = [];
|
|
79223
|
-
seq = 0;
|
|
79224
|
-
totalRecords = 0;
|
|
79225
|
-
droppedRecords = 0;
|
|
79226
|
-
newConnections = 0;
|
|
79227
|
-
poolKey;
|
|
79228
|
-
constructor(gates) {
|
|
79229
|
-
this.gates = gates;
|
|
79230
|
-
}
|
|
79231
|
-
/**
|
|
79232
|
-
* Count one accepted socket. Called from the diagnostics channel, not the
|
|
79233
|
-
* request path, so its cost never lands on a request.
|
|
79234
|
-
*/
|
|
79235
|
-
connectionOpened() {
|
|
79236
|
-
this.newConnections += 1;
|
|
79237
|
-
}
|
|
79238
|
-
/**
|
|
79239
|
-
* Record one pool lifecycle event. Pools live for minutes, so this is rare
|
|
79240
|
-
* by construction; still gated on debug so the common log stays request-only.
|
|
79241
|
-
*/
|
|
79242
|
-
poolEvent(type, key) {
|
|
79243
|
-
if (!this.gates.enabled() || !this.gates.debug()) return;
|
|
79244
|
-
this.poolKey = type === "create" ? key : this.poolKey;
|
|
79245
|
-
if (type === "close" && this.poolKey === key) this.poolKey = void 0;
|
|
79246
|
-
this.poolEvents = [{ atMs: Date.now(), type, key }, ...this.poolEvents].slice(0, MAX_POOL_EVENTS);
|
|
79247
|
-
}
|
|
79248
|
-
/**
|
|
79249
|
-
* Begin one request's span, or nothing when the log is disabled.
|
|
79250
|
-
*
|
|
79251
|
-
* This is the single gate on the request path: a disabled log costs one
|
|
79252
|
-
* method call and one boolean read, and constructs nothing. When enabled,
|
|
79253
|
-
* the running row is appended before the span is returned, so the viewer
|
|
79254
|
-
* sees the request while it runs; `request` and `status` mutate that same
|
|
79255
|
-
* visible row as the wire facts arrive.
|
|
79256
|
-
*/
|
|
79257
|
-
start(detail) {
|
|
79258
|
-
if (!this.gates.enabled()) return void 0;
|
|
79259
|
-
const debug = this.gates.debug();
|
|
79260
|
-
const startedAt = Date.now();
|
|
79261
|
-
const session = detail.sessionId ?? "";
|
|
79262
|
-
const record2 = {
|
|
79263
|
-
seq: ++this.seq,
|
|
79264
|
-
atMs: startedAt,
|
|
79265
|
-
model: detail.model,
|
|
79266
|
-
...detail.protocol === void 0 ? {} : { protocol: detail.protocol },
|
|
79267
|
-
session,
|
|
79268
|
-
method: detail.method ?? "POST",
|
|
79269
|
-
url: detail.url ?? "",
|
|
79270
|
-
running: true,
|
|
79271
|
-
ok: false,
|
|
79272
|
-
shape: { messages: detail.messageCount, hasImage: detail.hasImage, tools: detail.toolCount },
|
|
79273
|
-
...detail.imageBytes === void 0 ? {} : { imageBytes: detail.imageBytes },
|
|
79274
|
-
...!debug ? {} : {
|
|
79275
|
-
headers: {
|
|
79276
|
-
...detail.headers.session === void 0 ? {} : { session: detail.headers.session },
|
|
79277
|
-
...detail.headers.userAgent === void 0 ? {} : { userAgent: detail.headers.userAgent }
|
|
79278
|
-
}
|
|
79279
|
-
}
|
|
79280
|
-
};
|
|
79281
|
-
this.insert(record2, true);
|
|
79282
|
-
let firstTokenAt;
|
|
79283
|
-
let lastTokenAt;
|
|
79284
|
-
let reported = false;
|
|
79285
|
-
let finished = false;
|
|
79286
|
-
return {
|
|
79287
|
-
identify: (protocol) => {
|
|
79288
|
-
if (record2.protocol === void 0) record2.protocol = protocol;
|
|
79289
|
-
},
|
|
79290
|
-
token: () => {
|
|
79291
|
-
const now = Date.now();
|
|
79292
|
-
if (firstTokenAt === void 0) {
|
|
79293
|
-
firstTokenAt = now;
|
|
79294
|
-
record2.firstTokenMs = Math.max(0, now - startedAt);
|
|
79295
|
-
}
|
|
79296
|
-
lastTokenAt = now;
|
|
79297
|
-
},
|
|
79298
|
-
request: (nextMethod, nextUrl, nextRequestBytes) => {
|
|
79299
|
-
if (!reported) {
|
|
79300
|
-
reported = true;
|
|
79301
|
-
record2.method = nextMethod;
|
|
79302
|
-
record2.url = nextUrl;
|
|
79303
|
-
if (nextRequestBytes !== void 0) record2.requestBytes = nextRequestBytes;
|
|
79304
|
-
record2.prepMs = Math.max(0, Date.now() - startedAt);
|
|
79305
|
-
}
|
|
79306
|
-
},
|
|
79307
|
-
status: (value) => {
|
|
79308
|
-
record2.status = value;
|
|
79309
|
-
},
|
|
79310
|
-
finish: (ok, code, usage, costUsd) => {
|
|
79311
|
-
if (finished) return;
|
|
79312
|
-
finished = true;
|
|
79313
|
-
const seq = record2.seq;
|
|
79314
|
-
const endedAt = Date.now();
|
|
79315
|
-
const decodeMs = firstTokenAt === void 0 ? void 0 : Math.max(0, endedAt - firstTokenAt);
|
|
79316
|
-
const streamMs = firstTokenAt === void 0 || lastTokenAt === void 0 ? void 0 : Math.max(0, lastTokenAt - firstTokenAt);
|
|
79317
|
-
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);
|
|
79318
|
-
const entry = {
|
|
79319
|
-
seq,
|
|
79320
|
-
atMs: startedAt,
|
|
79321
|
-
model: detail.model,
|
|
79322
|
-
// The protocol may have arrived after the row opened, through
|
|
79323
|
-
// `identify` — the running row and the completion read the same
|
|
79324
|
-
// field, so they never disagree.
|
|
79325
|
-
...record2.protocol === void 0 ? {} : { protocol: record2.protocol },
|
|
79326
|
-
session,
|
|
79327
|
-
method: record2.method,
|
|
79328
|
-
url: record2.url,
|
|
79329
|
-
...record2.status === void 0 ? {} : { status: record2.status },
|
|
79330
|
-
...record2.prepMs === void 0 ? {} : { prepMs: record2.prepMs },
|
|
79331
|
-
...usage === void 0 ? {} : {
|
|
79332
|
-
inputTokens: usage.inputTokens,
|
|
79333
|
-
outputTokens: usage.outputTokens,
|
|
79334
|
-
...usage.cacheReadTokens === void 0 || usage.cacheReadTokens <= 0 ? {} : { cacheReadTokens: usage.cacheReadTokens },
|
|
79335
|
-
...usage.cacheWriteTokens === void 0 || usage.cacheWriteTokens <= 0 ? {} : { cacheWriteTokens: usage.cacheWriteTokens },
|
|
79336
|
-
...usage.reasoningTokens === void 0 || usage.reasoningTokens <= 0 ? {} : { reasoningTokens: usage.reasoningTokens }
|
|
79337
|
-
},
|
|
79338
|
-
...costUsd === void 0 ? {} : { costUsd },
|
|
79339
|
-
...record2.requestBytes === void 0 ? {} : { requestBytes: record2.requestBytes },
|
|
79340
|
-
...detail.imageBytes === void 0 ? {} : { imageBytes: detail.imageBytes },
|
|
79341
|
-
durationMs: Math.max(0, endedAt - startedAt),
|
|
79342
|
-
...firstTokenAt === void 0 ? {} : { firstTokenMs: Math.max(0, firstTokenAt - startedAt) },
|
|
79343
|
-
...decodeMs === void 0 ? {} : { decodeMs },
|
|
79344
|
-
...streamMs === void 0 ? {} : { streamMs },
|
|
79345
|
-
...tps === void 0 ? {} : { tps },
|
|
79346
|
-
ok,
|
|
79347
|
-
...code === void 0 ? {} : { code },
|
|
79348
|
-
// The pool in force when the request finished. Pool switches are
|
|
79349
|
-
// rare enough that attributing the finishing pool is honest; the
|
|
79350
|
-
// create/close events carry the exact history.
|
|
79351
|
-
...this.poolKey === void 0 ? {} : { poolKey: this.poolKey },
|
|
79352
|
-
shape: { messages: detail.messageCount, hasImage: detail.hasImage, tools: detail.toolCount },
|
|
79353
|
-
...!debug ? {} : {
|
|
79354
|
-
headers: {
|
|
79355
|
-
...detail.headers.session === void 0 ? {} : { session: detail.headers.session },
|
|
79356
|
-
...detail.headers.userAgent === void 0 ? {} : { userAgent: detail.headers.userAgent }
|
|
79357
|
-
}
|
|
79358
|
-
}
|
|
79359
|
-
};
|
|
79360
|
-
const at = this.entries.findIndex((candidate) => candidate.seq === seq);
|
|
79361
|
-
if (at === -1) {
|
|
79362
|
-
this.insert(entry, false);
|
|
79363
|
-
} else {
|
|
79364
|
-
this.entries[at] = entry;
|
|
79365
|
-
}
|
|
79366
|
-
}
|
|
79367
|
-
};
|
|
79368
|
-
}
|
|
79369
|
-
insert(entry, count2) {
|
|
79370
|
-
if (count2) this.totalRecords += 1;
|
|
79371
|
-
const bound = Math.max(1, Math.floor(this.gates.maxEntries()));
|
|
79372
|
-
const next = [entry, ...this.entries].slice(0, bound);
|
|
79373
|
-
this.droppedRecords += this.entries.length + 1 - next.length;
|
|
79374
|
-
this.entries = next;
|
|
79375
|
-
}
|
|
79376
|
-
/** Shrink the ring to a new bound immediately; growing backfills nothing. */
|
|
79377
|
-
setMaxEntries(bound) {
|
|
79378
|
-
if (!Number.isSafeInteger(bound) || bound < 1) return;
|
|
79379
|
-
if (this.entries.length > bound) {
|
|
79380
|
-
this.droppedRecords += this.entries.length - bound;
|
|
79381
|
-
this.entries = this.entries.slice(0, bound);
|
|
79382
|
-
}
|
|
79383
|
-
}
|
|
79384
|
-
/** The current reading, newest first. Computed lazily: nothing on the hot path. */
|
|
79385
|
-
snapshot() {
|
|
79386
|
-
return {
|
|
79387
|
-
entries: this.entries,
|
|
79388
|
-
poolEvents: this.poolEvents,
|
|
79389
|
-
totalRecords: this.totalRecords,
|
|
79390
|
-
droppedRecords: this.droppedRecords,
|
|
79391
|
-
newConnections: this.newConnections,
|
|
79392
|
-
...this.poolKey === void 0 ? {} : { poolKey: this.poolKey }
|
|
79393
|
-
};
|
|
79394
|
-
}
|
|
79395
|
-
};
|
|
79396
|
-
|
|
79397
79500
|
// src/update/check.ts
|
|
79398
79501
|
var PACKAGE_NAME = "@dan-ai-studio/dshopencodego";
|
|
79399
79502
|
var REGISTRY_LATEST_URL = `https://registry.npmjs.org/${encodeURIComponent(PACKAGE_NAME)}/latest`;
|
|
@@ -79487,7 +79590,7 @@ function createUpdateChecker(deps) {
|
|
|
79487
79590
|
}
|
|
79488
79591
|
|
|
79489
79592
|
// src/update/version.ts
|
|
79490
|
-
var PLUGIN_VERSION = true ? "0.1.
|
|
79593
|
+
var PLUGIN_VERSION = true ? "0.1.86" : "0.0.0-dev";
|
|
79491
79594
|
|
|
79492
79595
|
// src/update/service.ts
|
|
79493
79596
|
import { TypertRemoteService as TypertRemoteService4 } from "@deepseek-ai/dsh-typert-protocol";
|
|
@@ -79516,7 +79619,7 @@ var OpencodeGoUpdateService = class extends TypertRemoteService4 {
|
|
|
79516
79619
|
};
|
|
79517
79620
|
|
|
79518
79621
|
// src/usage/windows.ts
|
|
79519
|
-
import { attributionHeaders as attributionHeaders6, LlmError as
|
|
79622
|
+
import { attributionHeaders as attributionHeaders6, LlmError as LlmError12 } from "@deepseek-ai/dsh-llm";
|
|
79520
79623
|
var USAGE_MAX_BYTES = 1024 * 1024;
|
|
79521
79624
|
var USAGE_TIMEOUT_MS = 1e4;
|
|
79522
79625
|
function parseGoUsage(value) {
|
|
@@ -79534,7 +79637,7 @@ function parseGoUsage(value) {
|
|
|
79534
79637
|
}
|
|
79535
79638
|
async function readUsageWindows(options) {
|
|
79536
79639
|
if (options.apiKey === void 0 || options.apiKey.length === 0) {
|
|
79537
|
-
throw new
|
|
79640
|
+
throw new LlmError12("dshopencodego: no credential is configured for the opencode-go route", "USAGE_UNAVAILABLE");
|
|
79538
79641
|
}
|
|
79539
79642
|
const url = `${options.baseURL.replace(/\/+$/, "")}/usage`;
|
|
79540
79643
|
const timeout = AbortSignal.timeout(USAGE_TIMEOUT_MS);
|
|
@@ -79551,12 +79654,12 @@ async function readUsageWindows(options) {
|
|
|
79551
79654
|
signal: options.signal === void 0 ? timeout : AbortSignal.any([options.signal, timeout])
|
|
79552
79655
|
});
|
|
79553
79656
|
} catch (error) {
|
|
79554
|
-
throw new
|
|
79657
|
+
throw new LlmError12(`could not reach ${url}`, "USAGE_UNAVAILABLE", { cause: error });
|
|
79555
79658
|
}
|
|
79556
79659
|
if (!response.ok) {
|
|
79557
79660
|
await response.body?.cancel().catch(() => {
|
|
79558
79661
|
});
|
|
79559
|
-
throw new
|
|
79662
|
+
throw new LlmError12(`${url} answered HTTP ${response.status}`, "USAGE_UNAVAILABLE");
|
|
79560
79663
|
}
|
|
79561
79664
|
const body = await readBoundedJson(response, url, USAGE_MAX_BYTES);
|
|
79562
79665
|
try {
|
|
@@ -79565,16 +79668,16 @@ async function readUsageWindows(options) {
|
|
|
79565
79668
|
...options.source === void 0 ? {} : { source: options.source }
|
|
79566
79669
|
};
|
|
79567
79670
|
} catch (error) {
|
|
79568
|
-
throw new
|
|
79671
|
+
throw new LlmError12(`${url} returned an invalid usage document`, "USAGE_UNAVAILABLE", { cause: error });
|
|
79569
79672
|
}
|
|
79570
79673
|
}
|
|
79571
79674
|
|
|
79572
79675
|
// src/usage/service.ts
|
|
79573
79676
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
79574
79677
|
import { RemoteError as RemoteError2, TypertRemoteService as TypertRemoteService5 } from "@deepseek-ai/dsh-typert-protocol";
|
|
79575
|
-
import { LlmError as
|
|
79678
|
+
import { LlmError as LlmError13 } from "@deepseek-ai/dsh-llm";
|
|
79576
79679
|
function usageFailure(error, source) {
|
|
79577
|
-
const missing = error instanceof
|
|
79680
|
+
const missing = error instanceof LlmError13 && error.code === "MISSING_CREDENTIAL";
|
|
79578
79681
|
return new RemoteError2(
|
|
79579
79682
|
"dshopencodego/usage-unavailable",
|
|
79580
79683
|
error instanceof Error ? error.message : "OpenCode Go usage is unavailable",
|
|
@@ -79601,7 +79704,7 @@ var OpencodeGoUsageService = class extends TypertRemoteService5 {
|
|
|
79601
79704
|
}
|
|
79602
79705
|
if (key === void 0 || key.length === 0) {
|
|
79603
79706
|
this.identity = void 0;
|
|
79604
|
-
throw usageFailure(new
|
|
79707
|
+
throw usageFailure(new LlmError13("No OpenCode Go API key is configured", "MISSING_CREDENTIAL"), void 0);
|
|
79605
79708
|
}
|
|
79606
79709
|
if (this.identity?.baseURL !== baseURL || this.identity.key !== key) {
|
|
79607
79710
|
this.identity = { baseURL, key, source: randomUUID3() };
|
|
@@ -79650,7 +79753,7 @@ function apply(ctx, raw) {
|
|
|
79650
79753
|
const credentials = ctx.get("credentials");
|
|
79651
79754
|
const hit = credentials !== void 0 ? (await credentials.resolve(credentialRef(ref)))?.value : launchEnvironmentOf(ctx).get(ref)?.value;
|
|
79652
79755
|
if (hit !== void 0 && hit.length > 0) return llm2.assertUsableApiKey(hit, name, ref);
|
|
79653
|
-
throw new
|
|
79756
|
+
throw new LlmError14(
|
|
79654
79757
|
`dshopencodego: no credential; the profile resolves ${ref}, which is not set \u2014 store ${ref} through the credentials service (the Web Models page writes it) or export it`,
|
|
79655
79758
|
"MISSING_CREDENTIAL"
|
|
79656
79759
|
);
|
|
@@ -79796,7 +79899,7 @@ function apply(ctx, raw) {
|
|
|
79796
79899
|
settingsNs,
|
|
79797
79900
|
async (request, signal) => {
|
|
79798
79901
|
if (request.provider !== PROVIDER_ID && !(request.baseURL ?? "").includes("opencode.ai")) {
|
|
79799
|
-
throw new
|
|
79902
|
+
throw new LlmError14(
|
|
79800
79903
|
"dshopencodego discovers only OpenCode Go/Console endpoints; enter this provider's models by hand",
|
|
79801
79904
|
"DISCOVERY_UNSUPPORTED"
|
|
79802
79905
|
);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 发送前按上下文窗口装配一次请求。
|
|
3
|
+
*
|
|
4
|
+
* 宿主拥有压缩会话的职责,插件拥有不上报谎言的职责:网关按
|
|
5
|
+
* `input + max_tokens <= contextWindow` 做严格校验(`muse-spark`
|
|
6
|
+
* 系 `1048576 / 131072` 即为一例),而宿主在 `input` 已占 `87%`
|
|
7
|
+
* 时仍可能按满额输出请求。本模块在发网关之前做两件事:
|
|
8
|
+
*
|
|
9
|
+
* - 输入本身已超窗:直接抛 `CONTEXT_WINDOW_EXCEEDED`,让宿主走压缩/
|
|
10
|
+
* 重试分支,而不是等网关 `400 context_length_exceeded` 再失败;
|
|
11
|
+
* - 输入加请求输出会超窗:把本次 `maxTokens` 收缩到剩余窗口内。
|
|
12
|
+
* 收缩是保底成功,不是替代压缩:历史照旧原样发送,不截断、不总结。
|
|
13
|
+
*
|
|
14
|
+
* 估算是有意保守的上界:网关分词器未知,按 `3 字符 ≈ 1 token`
|
|
15
|
+
* 加固定开销估算,多估只会多收一点输出,不会把能过的请求误杀。
|
|
16
|
+
* 图片/文件按固定开销加字节折算,视觉 token 的真实计费未知时宁可高估。
|
|
17
|
+
*
|
|
18
|
+
* @module @dan-ai-studio/dshopencodego/context-fit
|
|
19
|
+
*/
|
|
20
|
+
import type { GenerateOptions } from '@deepseek-ai/dsh-llm';
|
|
21
|
+
/** 为分词器漂移和线上传输开销预留的窗口。 */
|
|
22
|
+
export declare const CONTEXT_FIT_RESERVE_TOKENS = 2048;
|
|
23
|
+
/** 收缩后仍值得发一次请求的最小输出。低于它就直接失败,逼宿主压缩。 */
|
|
24
|
+
export declare const CONTEXT_FIT_MIN_OUTPUT_TOKENS = 256;
|
|
25
|
+
/** 估算所需的请求子集:只读文本与附件元数据,不读字节。 */
|
|
26
|
+
export interface FittableRequest {
|
|
27
|
+
readonly messages: GenerateOptions['messages'];
|
|
28
|
+
readonly system?: GenerateOptions['system'];
|
|
29
|
+
readonly tools?: GenerateOptions['tools'];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 保守估算一次请求的输入 token 数(上界,非精确计数)。
|
|
33
|
+
* @param options - 本次请求的消息、系统提示与工具声明。
|
|
34
|
+
* @returns 估算的输入 token 数,至少为 0 的有限整数。
|
|
35
|
+
*/
|
|
36
|
+
export declare function estimateInputTokens(options: FittableRequest): number;
|
|
37
|
+
/** `resolveFittedMaxTokens` 的输入。 */
|
|
38
|
+
export interface FitRequest {
|
|
39
|
+
/** 展示给宿主看的模型 id,只用于报错文本。 */
|
|
40
|
+
readonly modelId: string;
|
|
41
|
+
/** 该模型的上下文窗口(含本次已应用的覆盖)。 */
|
|
42
|
+
readonly contextWindow: number;
|
|
43
|
+
/** 路由自身的输出上限(含覆盖),未知时传 undefined。 */
|
|
44
|
+
readonly routeMaxTokens?: number | undefined;
|
|
45
|
+
/** 调用方本次请求的输出上限,未指定时传 undefined。 */
|
|
46
|
+
readonly requestedMaxTokens?: number | undefined;
|
|
47
|
+
/** `estimateInputTokens` 的输出。 */
|
|
48
|
+
readonly estimatedInputTokens: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 按剩余窗口装配本次的 `maxTokens`。
|
|
52
|
+
* @param fit - 窗口、路由上限、调用方请求与输入估算。
|
|
53
|
+
* @returns 发往网关的 `maxTokens`:不需要收缩时与调用方请求一致
|
|
54
|
+
* (调用方未指定则保持 `undefined`,不断言网关默认值)。
|
|
55
|
+
* @throws {LlmError} `CONTEXT_WINDOW_EXCEEDED`:输入本身已超窗,或剩余
|
|
56
|
+
* 窗口连最小输出都放不下。调用方应据此走压缩/截断分支。
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolveFittedMaxTokens(fit: FitRequest): number | undefined;
|
|
@@ -91,6 +91,20 @@ export interface RequestLogEntry {
|
|
|
91
91
|
* reached the wire (rejected up front).
|
|
92
92
|
*/
|
|
93
93
|
readonly prepMs?: number;
|
|
94
|
+
/**
|
|
95
|
+
* Wall time from request start to the response headers' arrival, in
|
|
96
|
+
* milliseconds. Splits the first-token wait in two: up to here the
|
|
97
|
+
* gateway is queuing, after here the model is thinking. Absent when the
|
|
98
|
+
* response never arrived.
|
|
99
|
+
*/
|
|
100
|
+
readonly responseMs?: number;
|
|
101
|
+
/**
|
|
102
|
+
* Elapsed milliseconds of every tenth accepted token delta, capped.
|
|
103
|
+
* Cuts the streaming phase into visible blocks, so a stall mid-output
|
|
104
|
+
* reads as a gap rather than a uniformly slow bar. Absent when fewer
|
|
105
|
+
* than ten deltas arrived — then the output slice needs no subdivision.
|
|
106
|
+
*/
|
|
107
|
+
readonly streamMarksMs?: readonly number[];
|
|
94
108
|
/** Wall time from request start to terminal event, in milliseconds. */
|
|
95
109
|
readonly durationMs?: number;
|
|
96
110
|
/** Wall time from request start to the first token delta, in milliseconds. */
|
|
@@ -177,6 +191,13 @@ export interface RequestLogGates {
|
|
|
177
191
|
/** How many entries to keep; the ring trims to it on every append. */
|
|
178
192
|
readonly maxEntries: () => number;
|
|
179
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* How many streaming timestamps one row keeps at most. Past the cap the
|
|
196
|
+
* trail simply stops growing: the newest marks matter more than the oldest
|
|
197
|
+
* for reading a stall, and the oldest are still bracketed by the first
|
|
198
|
+
* token and the last one.
|
|
199
|
+
*/
|
|
200
|
+
export declare const MAX_STREAM_MARKS = 200;
|
|
180
201
|
/**
|
|
181
202
|
* Minimum content span for a meaningful rate, in milliseconds.
|
|
182
203
|
*
|
package/package.json
CHANGED