dsh-opencode-go 0.1.9 → 0.1.10
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 +5 -3
- package/README.md +5 -3
- package/docs/verification.md +18 -0
- package/lib/client.js +2 -2
- package/lib/index.js +61 -3
- package/lib/types/json-response.d.ts +2 -0
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -33,7 +33,7 @@ If your DSH version does not have an **Add plugin** entry, use the command-line
|
|
|
33
33
|
### Command-line installation (alternative)
|
|
34
34
|
|
|
35
35
|
```sh
|
|
36
|
-
dsh plugin --profile web add dsh-opencode-go@0.1.
|
|
36
|
+
dsh plugin --profile web add dsh-opencode-go@0.1.10
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
Start or restart `dsh web`, then:
|
|
@@ -47,7 +47,7 @@ Start or restart `dsh web`, then:
|
|
|
47
47
|
Install the plugin into the Headless profile:
|
|
48
48
|
|
|
49
49
|
```sh
|
|
50
|
-
dsh plugin --profile headless add dsh-opencode-go@0.1.
|
|
50
|
+
dsh plugin --profile headless add dsh-opencode-go@0.1.10
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
Save the following as `headless.patch.yml` to select a default model:
|
|
@@ -74,7 +74,7 @@ To build from source and install a local package:
|
|
|
74
74
|
```sh
|
|
75
75
|
npm ci --legacy-peer-deps
|
|
76
76
|
npm pack
|
|
77
|
-
dsh plugin --profile web add ./dsh-opencode-go-0.1.
|
|
77
|
+
dsh plugin --profile web add ./dsh-opencode-go-0.1.10.tgz
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
The development dependencies include real test packages from multiple DSH generations, so installation requires `--legacy-peer-deps`. For Headless, replace `web` with `headless`.
|
|
@@ -109,6 +109,8 @@ A gateway model ID with no usable protocol or capability configuration is shown
|
|
|
109
109
|
|
|
110
110
|
A reasoning-capable model without adjustable reasoning levels (for example, `union-alpha`) remains selectable and usable; it simply has no reasoning-strength control.
|
|
111
111
|
|
|
112
|
+
A model that does offer adjustable levels also declares a default effort (`high` when the model offers it, otherwise the highest level it offers) whenever its transport would answer an unset effort with an explicit disable (`deepseek`, `zai`, `qwen`, `qwen-chat-template`). DSH uses that default when no level has been chosen, so leaving the control unset still sends a reasoning level instead of turning thinking off. Transports that leave the choice to the provider declare no default and are unchanged, and an explicitly chosen level always wins.
|
|
113
|
+
|
|
112
114
|
If the online configuration is temporarily unavailable, the plugin prefers a configuration fetched successfully earlier in the process and falls back to pi-ai's built-in metadata. If the gateway catalog is unavailable, existing requests can use the last catalog; a Settings refresh reports the failure instead of presenting stale data as current. `refreshMinutes` controls the cache lifetime for ongoing model requests, but does not prevent an explicit model-list read from fetching fresh data.
|
|
113
115
|
|
|
114
116
|
## Uninstall
|
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
### 命令行安装(备选)
|
|
35
35
|
|
|
36
36
|
```sh
|
|
37
|
-
dsh plugin --profile web add dsh-opencode-go@0.1.
|
|
37
|
+
dsh plugin --profile web add dsh-opencode-go@0.1.10
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
安装后启动或重启 `dsh web`,然后:
|
|
@@ -48,7 +48,7 @@ dsh plugin --profile web add dsh-opencode-go@0.1.9
|
|
|
48
48
|
安装到 Headless profile:
|
|
49
49
|
|
|
50
50
|
```sh
|
|
51
|
-
dsh plugin --profile headless add dsh-opencode-go@0.1.
|
|
51
|
+
dsh plugin --profile headless add dsh-opencode-go@0.1.10
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
将以下内容保存为 `headless.patch.yml`,选择默认模型:
|
|
@@ -75,7 +75,7 @@ dsh --profile headless --patch ./headless.patch.yml "你好"
|
|
|
75
75
|
```sh
|
|
76
76
|
npm ci --legacy-peer-deps
|
|
77
77
|
npm pack
|
|
78
|
-
dsh plugin --profile web add ./dsh-opencode-go-0.1.
|
|
78
|
+
dsh plugin --profile web add ./dsh-opencode-go-0.1.10.tgz
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
开发依赖包含多代 DSH 的真实测试包,安装时需要 `--legacy-peer-deps`。Headless 用户将 `web` 换成 `headless`。
|
|
@@ -110,6 +110,8 @@ dsh plugin --profile web update dsh-opencode-go --latest
|
|
|
110
110
|
|
|
111
111
|
模型具有推理能力但没有可调节的推理档位时(如 `union-alpha`),仍可正常选择和使用,只是不显示推理强度选项。
|
|
112
112
|
|
|
113
|
+
提供可调节档位的模型,如果其传输协议在未选择档位时会显式关闭思考(`deepseek`、`zai`、`qwen`、`qwen-chat-template`),还会声明一个默认档位(模型支持 `high` 时用 `high`,否则用它提供的最高档位)。用户未选择档位时 DSH 使用该默认值,因此留空也会带上推理档位,而不是关闭思考。由服务商自行决定的协议不声明默认值,行为不变;显式选择的档位始终优先。
|
|
114
|
+
|
|
113
115
|
在线配置暂时不可达时,优先复用本次运行中成功获取的配置,以 pi-ai 内置配置作为备用。网关目录不可达时,已有请求可以使用上次目录;设置页刷新会显示失败,避免把旧目录误认为最新结果。`refreshMinutes` 只控制已有模型请求的缓存时长,不阻止主动读取列表获取新模型。
|
|
114
116
|
|
|
115
117
|
## 卸载
|
package/docs/verification.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Verification
|
|
2
2
|
|
|
3
|
+
## Default reasoning effort (plugin 0.1.10, 2026-09-23)
|
|
4
|
+
|
|
5
|
+
PR #6 declares a default effort for the pi-ai transports that explicitly disable thinking when the effort is unset: `deepseek`, `zai`, `qwen`, and `qwen-chat-template`. Models offering `high` default to it; otherwise the highest supported non-`off` effort is selected. Explicit choices, including `off`, still take precedence. Other transports and models without adjustable efforts retain their existing behavior.
|
|
6
|
+
|
|
7
|
+
Review found that the original fallback selected the first non-`off` effort from pi-ai's ascending list. End-to-end regressions failed with `low` in the outgoing request for models offering `low/medium` or `low/max`, then passed after selecting the last supported effort. The same cases cover `low` alone and the preference for `high` over `max` when both are offered.
|
|
8
|
+
|
|
9
|
+
Host/Client type checks, the build, and all **233 tests in 18 files** pass on macOS / Node.js 24.14.1 using the existing installed dependencies. Permanent compatibility coverage adds 42 local HTTP requests through the built plugin and all six supported DSH runtimes, verifying default effort resolution, explicit `low` and `off`, Qwen's thinking switch, provider-decides models, and reasoning/text stream conversion. Published UI primitives still emit missing-source-map warnings; all assertions pass. Completion requests use local fixtures and test credentials, with no paid model calls or manual Web/Desktop verification.
|
|
10
|
+
|
|
11
|
+
This release also includes PR #5's bounded compressed-response recovery described below, which was merged after the 0.1.9 release.
|
|
12
|
+
|
|
13
|
+
## Bounded model discovery responses (2026-09-23)
|
|
14
|
+
|
|
15
|
+
Model discovery accepts ordinary JSON and Brotli, gzip, or deflate JSON whose `Content-Encoding` header is missing. Correctly labeled responses continue through Fetch's automatic decoding. The shared reader counts actual streamed bytes and cancels oversized bodies; fallback decoders run asynchronously with `maxOutputLength`. Both delivered bytes and fallback output are limited to 1 MiB for the gateway listing and 16 MiB for models.dev metadata. These are payload limits, not total process-memory or CPU-time budgets. Failed recovery preserves the original JSON error and each decoder's cause.
|
|
16
|
+
|
|
17
|
+
Host/Client type checks and the build passed, followed by all **222 tests in 18 files**, on macOS / Node.js 24.14.1 using the existing installed dependencies. Ten new resource-limit and diagnostic tests failed against the original parser before passing with the bounded reader. Real local HTTP tests cover both discovery sources, correctly labeled and unlabeled compression, corruption, cached fallback, and each source's limit exceeded by exactly one byte. The upstream UI primitives packages still emit missing-source-map warnings; all assertions pass.
|
|
18
|
+
|
|
19
|
+
The missing-header failure is reproduced with controlled HTTP fixtures. A read-only direct check of the two public endpoints returned HTTP 200 with correct `Content-Encoding: br` headers and valid JSON after Node's automatic decoding; models.dev was approximately 4.6 MiB decoded. This does not establish why the original reporter's proxy environment failed: response headers, a raw response sample, and the relevant proxy/runtime configuration are still needed. Curl's automatic decoding also relies on `Content-Encoding`, so successful curl access alone does not establish the reported root cause. Usage fetching is outside this change.
|
|
20
|
+
|
|
3
21
|
## DSH 0.1.7-alpha.2 compatibility (plugin 0.1.9, 2026-09-23)
|
|
4
22
|
|
|
5
23
|
The package now declares DSH `0.1.7-alpha.2` and Cordis `4.0.4` support while retaining the five previously supported hosts. Before the change, the SemVer regression rejected the new host in `engines.dsh`; the DSH and Cordis peer ranges also excluded its published versions. `engines.dsh` is declarative in the current upstream installer, so it must not be confused with an enforced loader check. The peer ranges affect dependency resolution. Unverified future prereleases remain outside the declared range.
|
package/lib/client.js
CHANGED
|
@@ -103,7 +103,7 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id) + "]")
|
|
|
103
103
|
style.textContent = '.BtKYva_page{flex-direction:column;min-width:0;height:100%;min-height:0;display:flex;container-type:size}.BtKYva_pageBody{scrollbar-gutter:stable;flex:1;min-height:0;padding-right:4px;overflow-y:auto}.BtKYva_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.BtKYva_field+.BtKYva_field{border-top:.5px solid var(--dsw-alias-border-l2)}.BtKYva_head{align-items:center;gap:8px;display:flex}.BtKYva_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.BtKYva_badges{align-items:center;gap:8px;display:inline-flex}.BtKYva_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.BtKYva_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.BtKYva_reset:disabled{cursor:default}.BtKYva_reset:focus-visible,.BtKYva_disclosure:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px}.BtKYva_input{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.BtKYva_input:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px;border-color:var(--dsw-alias-brand-primary)}.BtKYva_input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.BtKYva_inputInvalid{border-color:var(--dsw-alias-label-error);}.BtKYva_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.BtKYva_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.BtKYva_intro{color:var(--dsw-alias-label-secondary);margin:0 0 8px;font-size:13px;line-height:1.5}.BtKYva_disclosure{font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;margin:0;padding:0;display:flex}.BtKYva_disclosure:hover .BtKYva_label{color:var(--dsw-alias-brand-primary)}.BtKYva_chevron,.BtKYva_chevronOpen{width:14px;height:14px;color:var(--dsw-alias-label-tertiary);flex:none}.BtKYva_chevron{transform:rotate(-90deg)}.BtKYva_advanced{flex-direction:column;gap:4px;padding:4px 0 0 22px;display:flex}.BtKYva_advanced .BtKYva_field+.BtKYva_field{border-top:none}.BtKYva_chips{flex-wrap:wrap;gap:6px;display:flex}.BtKYva_limitsEditor{flex-direction:column;gap:10px;padding-top:4px;display:flex}.BtKYva_limitsToolbar{grid-template-columns:minmax(0,1fr) auto;align-items:end;gap:6px 10px;display:grid}.BtKYva_limitsFilterLabel{color:var(--dsw-alias-label-secondary);grid-column:1/-1;font-size:12px;font-weight:500;line-height:1.5}.BtKYva_limitsSummary{color:var(--dsw-alias-label-tertiary);white-space:nowrap;padding-bottom:8px;font-size:12px;line-height:1.5}.BtKYva_limitsId,.BtKYva_limitsModelId{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.BtKYva_limitsId{color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.4}.BtKYva_limitsModelId{color:var(--dsw-alias-label-tertiary);margin-top:2px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;line-height:1.4}.BtKYva_visuallyHidden{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}@media (width<=560px){.BtKYva_limitsToolbar{grid-template-columns:1fr}.BtKYva_limitsSummary{padding-bottom:0}}.BtKYva_actions{border-top:.5px solid var(--dsw-alias-border-l2);flex-wrap:wrap;flex:none;align-items:center;gap:8px;padding:12px 0;display:flex}.BtKYva_failedNote{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.BtKYva_pageTop{align-items:flex-start;gap:16px;display:flex}.BtKYva_pageTop .BtKYva_intro{flex:1}.BtKYva_advancedTrigger{flex-shrink:0;margin-left:auto;}.BtKYva_advancedTrigger .BtKYva_label{color:var(--dsw-alias-label-tertiary);font-size:12px}.BtKYva_filters{flex-wrap:wrap;gap:6px;display:flex}.BtKYva_filter{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:6px;padding:6px 9px;font-size:12px}.BtKYva_filter[aria-pressed=true]{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3)}.BtKYva_filter span{color:var(--dsw-alias-label-tertiary);margin-left:4px}.BtKYva_modelLayout{border:.5px solid var(--dsw-alias-border-l4);border-radius:10px;grid-template-columns:minmax(0,43fr) minmax(0,57fr);height:clamp(240px,100cqh - 460px,480px);display:grid;overflow:hidden}.BtKYva_modelList{border-right:.5px solid var(--dsw-alias-border-l2);min-height:0;padding:6px;overflow-y:auto}.BtKYva_modelChoice{text-align:left;width:100%;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:0;border-radius:6px;padding:12px 9px;display:block}.BtKYva_modelChoice[aria-pressed=true],.BtKYva_modelChoice:hover{background:var(--dsw-alias-bg-layer-3)}.BtKYva_modelName{overflow-wrap:anywhere;flex-wrap:wrap;align-items:center;gap:5px;font-size:13px;display:flex}.BtKYva_modelDetails{flex-direction:column;align-items:stretch;gap:10px;min-width:0;padding:18px;display:flex;overflow-y:auto}.BtKYva_modelDetails h3{overflow-wrap:anywhere;margin:0;font-size:16px}.BtKYva_modelHeading{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.BtKYva_modelDetails .BtKYva_field{border:0;padding:8px 0}.BtKYva_modelDetails .BtKYva_input{box-sizing:border-box;width:100%;min-width:0}.BtKYva_modelDetails .BtKYva_reset{align-self:flex-start}.BtKYva_newBadge{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);border:.5px solid var(--dsw-alias-border-l4);border-radius:4px;padding:2px 4px;font-size:9px}.BtKYva_releaseDate{color:var(--dsw-alias-label-tertiary);margin-top:4px;font-size:10px;display:block}.BtKYva_modelChoice:focus-visible,.BtKYva_filter:focus-visible,.BtKYva_advancedTrigger:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}@container (width<=440px){.BtKYva_pageTop{flex-wrap:wrap}.BtKYva_modelLayout{grid-template-columns:minmax(0,1fr);height:auto}.BtKYva_modelList{border-right:0;border-bottom:.5px solid var(--dsw-alias-border-l2);max-height:240px}.BtKYva_modelDetails{max-height:460px}}.BtKYva_keySection{border-top:.5px solid var(--dsw-alias-border-l2);padding:12px 0}.BtKYva_keySection summary{cursor:pointer;list-style:none}.BtKYva_keySection summary:after{content:"\u2304";color:var(--dsw-alias-label-tertiary)}.BtKYva_keySection summary::-webkit-details-marker{display:none}.BtKYva_keySection>.BtKYva_input{box-sizing:border-box;width:100%;margin:10px 0 6px}.BtKYva_keySection summary:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}';
|
|
104
104
|
document.head.appendChild(style);
|
|
105
105
|
}
|
|
106
|
-
var Section_default = { "
|
|
106
|
+
var Section_default = { "pageTop": "BtKYva_pageTop", "invalid": "BtKYva_invalid", "limitsModelId": "BtKYva_limitsModelId", "limitsToolbar": "BtKYva_limitsToolbar", "modelList": "BtKYva_modelList", "field": "BtKYva_field", "inputInvalid": "BtKYva_inputInvalid BtKYva_input", "label": "BtKYva_label", "modelDetails": "BtKYva_modelDetails", "page": "BtKYva_page", "failedNote": "BtKYva_failedNote", "limitsEditor": "BtKYva_limitsEditor", "modelChoice": "BtKYva_modelChoice", "hint": "BtKYva_hint", "chips": "BtKYva_chips", "modelName": "BtKYva_modelName", "chevronOpen": "BtKYva_chevronOpen", "modelHeading": "BtKYva_modelHeading", "releaseDate": "BtKYva_releaseDate", "advancedTrigger": "BtKYva_advancedTrigger BtKYva_disclosure", "keySection": "BtKYva_keySection", "badges": "BtKYva_badges", "disclosure": "BtKYva_disclosure", "visuallyHidden": "BtKYva_visuallyHidden", "head": "BtKYva_head", "filter": "BtKYva_filter", "actions": "BtKYva_actions", "limitsId": "BtKYva_limitsId", "pageBody": "BtKYva_pageBody", "intro": "BtKYva_intro", "modelLayout": "BtKYva_modelLayout", "input": "BtKYva_input", "advanced": "BtKYva_advanced", "newBadge": "BtKYva_newBadge", "limitsFilterLabel": "BtKYva_limitsFilterLabel", "limitsSummary": "BtKYva_limitsSummary", "reset": "BtKYva_reset", "chevron": "BtKYva_chevron", "filters": "BtKYva_filters" };
|
|
107
107
|
|
|
108
108
|
// src/client/ModelEditor.tsx
|
|
109
109
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -1331,7 +1331,7 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]"
|
|
|
1331
1331
|
style.textContent = ".dmPm3q_root{min-width:0;display:inline-flex;position:relative}.dmPm3q_trigger{color:inherit;opacity:.75;font:inherit;cursor:pointer;white-space:nowrap;background:0 0;border:0;border-radius:6px;padding:4px 6px;font-size:12px}.dmPm3q_trigger:hover,.dmPm3q_trigger:focus-visible{opacity:1;background:color-mix(in srgb, currentColor 8%, transparent)}.dmPm3q_panel{z-index:100;border:1px solid color-mix(in srgb, currentColor 18%, transparent);width:280px;max-width:calc(100vw - 32px);color:var(--dsw-alias-label-primary,CanvasText);background:var(--dsw-specific-menu,Canvas);border-radius:12px;padding:16px;font-size:12px;position:absolute;bottom:calc(100% + 12px);right:0;box-shadow:0 8px 30px #0002}.dmPm3q_hint{opacity:.65;font-size:11px;line-height:1.6}.dmPm3q_window{margin-top:14px}.dmPm3q_row{justify-content:space-between;margin-bottom:5px;display:flex}.dmPm3q_window progress{accent-color:#39a878;width:100%;height:5px;margin-bottom:5px;display:block}.dmPm3q_window progress::-webkit-progress-bar{background:color-mix(in srgb, currentColor 15%, transparent);border-radius:4px}.dmPm3q_window progress::-webkit-progress-value{background:#39a878;border-radius:4px}.dmPm3q_window progress::-moz-progress-bar{background:#39a878;border-radius:4px}";
|
|
1332
1332
|
document.head.appendChild(style);
|
|
1333
1333
|
}
|
|
1334
|
-
var UsagePill_default = { "
|
|
1334
|
+
var UsagePill_default = { "row": "dmPm3q_row", "trigger": "dmPm3q_trigger", "panel": "dmPm3q_panel", "root": "dmPm3q_root", "hint": "dmPm3q_hint", "window": "dmPm3q_window" };
|
|
1335
1335
|
|
|
1336
1336
|
// src/client/UsagePill.tsx
|
|
1337
1337
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
package/lib/index.js
CHANGED
|
@@ -858,11 +858,65 @@ function readModelMetadata(body, baseURL, builtin) {
|
|
|
858
858
|
return { models, errors, details };
|
|
859
859
|
}
|
|
860
860
|
|
|
861
|
+
// src/json-response.ts
|
|
862
|
+
import { promisify } from "node:util";
|
|
863
|
+
import { brotliDecompress, gunzip, inflate } from "node:zlib";
|
|
864
|
+
var decoders = [
|
|
865
|
+
{ name: "Brotli", decode: promisify(brotliDecompress) },
|
|
866
|
+
{ name: "gzip", decode: promisify(gunzip) },
|
|
867
|
+
{ name: "deflate", decode: promisify(inflate) }
|
|
868
|
+
];
|
|
869
|
+
async function readBoundedBody(response, maxBytes) {
|
|
870
|
+
if (response.body === null) return Buffer.alloc(0);
|
|
871
|
+
const reader = response.body.getReader();
|
|
872
|
+
const chunks = [];
|
|
873
|
+
let size = 0;
|
|
874
|
+
try {
|
|
875
|
+
while (true) {
|
|
876
|
+
const { done, value } = await reader.read();
|
|
877
|
+
if (done) return Buffer.concat(chunks, size);
|
|
878
|
+
if (value.byteLength > maxBytes - size) {
|
|
879
|
+
const error = new RangeError(`Response body exceeds ${maxBytes} byte limit`);
|
|
880
|
+
await reader.cancel(error).catch(() => {
|
|
881
|
+
});
|
|
882
|
+
throw error;
|
|
883
|
+
}
|
|
884
|
+
size += value.byteLength;
|
|
885
|
+
chunks.push(value);
|
|
886
|
+
}
|
|
887
|
+
} finally {
|
|
888
|
+
reader.releaseLock();
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
async function readJsonResponse(response, maxBytes) {
|
|
892
|
+
const bytes = await readBoundedBody(response, maxBytes);
|
|
893
|
+
const parse = (data) => JSON.parse(new TextDecoder().decode(data));
|
|
894
|
+
const errors = [];
|
|
895
|
+
try {
|
|
896
|
+
return parse(bytes);
|
|
897
|
+
} catch (error) {
|
|
898
|
+
errors.push(error);
|
|
899
|
+
}
|
|
900
|
+
for (const { name: name2, decode } of decoders) {
|
|
901
|
+
try {
|
|
902
|
+
return parse(await decode(bytes, { maxOutputLength: maxBytes }));
|
|
903
|
+
} catch (error) {
|
|
904
|
+
if (error instanceof Error && "code" in error && error.code === "ERR_BUFFER_TOO_LARGE") {
|
|
905
|
+
throw new RangeError(`${name2} decoded response exceeds ${maxBytes} byte limit`, { cause: error });
|
|
906
|
+
}
|
|
907
|
+
errors.push(new Error(`${name2} response decoding or JSON parsing failed`, { cause: error }));
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
throw new AggregateError(errors, "Response is not valid JSON, including after Brotli, gzip, or deflate decoding");
|
|
911
|
+
}
|
|
912
|
+
|
|
861
913
|
// src/catalog.ts
|
|
862
914
|
var PROVIDER_ID = "opencode-go";
|
|
863
915
|
var DISPLAY_NAME = "OpenCode Go";
|
|
864
916
|
var DEFAULT_BASE_URL = "https://opencode.ai/zen/go/v1";
|
|
865
917
|
var MODELS_FETCH_TIMEOUT_MS = 1e4;
|
|
918
|
+
var MODEL_LISTING_MAX_BYTES = 1024 * 1024;
|
|
919
|
+
var MODEL_METADATA_MAX_BYTES = 16 * 1024 * 1024;
|
|
866
920
|
function builtinModels(baseURL) {
|
|
867
921
|
return new Map(getBuiltinModels("opencode-go").map((model) => [model.id, {
|
|
868
922
|
...model,
|
|
@@ -894,7 +948,7 @@ async function fetchLiveModelIds(baseURL) {
|
|
|
894
948
|
throw new LlmError5(`could not reach ${url}`, "DISCOVERY_FAILED", { cause: error });
|
|
895
949
|
}
|
|
896
950
|
if (!response.ok) throw new LlmError5(`${url} answered ${response.status}`, "DISCOVERY_FAILED");
|
|
897
|
-
return readLiveModelIds(await response
|
|
951
|
+
return readLiveModelIds(await readJsonResponse(response, MODEL_LISTING_MAX_BYTES));
|
|
898
952
|
}
|
|
899
953
|
function harnessApiKeyAuth() {
|
|
900
954
|
return { apiKey: {
|
|
@@ -952,7 +1006,7 @@ var OpencodeGoCatalog = class {
|
|
|
952
1006
|
});
|
|
953
1007
|
if (response.status === 304 && this.metadata !== void 0) return this.metadata;
|
|
954
1008
|
if (!response.ok) throw new Error(`models.dev answered ${response.status}`);
|
|
955
|
-
const metadata = readModelMetadata(await response
|
|
1009
|
+
const metadata = readModelMetadata(await readJsonResponse(response, MODEL_METADATA_MAX_BYTES), this.baseURL, builtin);
|
|
956
1010
|
this.metadata = metadata;
|
|
957
1011
|
this.metadataETag = response.headers.get("etag") ?? void 0;
|
|
958
1012
|
return metadata;
|
|
@@ -1088,6 +1142,7 @@ function assertBaseURL(raw) {
|
|
|
1088
1142
|
}
|
|
1089
1143
|
|
|
1090
1144
|
// src/adapter.ts
|
|
1145
|
+
var DISABLES_THINKING_WHEN_UNSET = /* @__PURE__ */ new Set(["deepseek", "zai", "qwen", "qwen-chat-template"]);
|
|
1091
1146
|
function withModelLimit(model, limits) {
|
|
1092
1147
|
const limit = limits[model.id];
|
|
1093
1148
|
if (limit == null) return model;
|
|
@@ -1165,11 +1220,14 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
1165
1220
|
const reasoning = {};
|
|
1166
1221
|
const levels = model.reasoning ? getSupportedThinkingLevels(model) : [];
|
|
1167
1222
|
if (levels.length > 0) {
|
|
1223
|
+
const format = model.compat?.thinkingFormat;
|
|
1224
|
+
const fallback = format !== void 0 && DISABLES_THINKING_WHEN_UNSET.has(format) ? levels.includes("high") ? "high" : levels.findLast((level) => level !== "off") : void 0;
|
|
1168
1225
|
reasoning.reasoning = {
|
|
1169
1226
|
efforts: levels.map((level) => ({
|
|
1170
1227
|
id: ReasoningEffortId(level),
|
|
1171
1228
|
name: `${level.charAt(0).toUpperCase()}${level.slice(1)}`
|
|
1172
|
-
}))
|
|
1229
|
+
})),
|
|
1230
|
+
...fallback === void 0 ? {} : { defaultEffort: ReasoningEffortId(fallback) }
|
|
1173
1231
|
};
|
|
1174
1232
|
}
|
|
1175
1233
|
return {
|