@goodandready/dsh-opencode-provider 0.5.27 → 0.5.28
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/CHANGELOG.md +6 -0
- package/README.md +3 -3
- package/README.ru.md +3 -3
- package/README.zh.md +3 -3
- package/lib/client.js +50 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.js +64 -14
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.28 — release 5: image policy and preparation timeout
|
|
4
|
+
|
|
5
|
+
- **#73 — image policy**: `maxImages`, `maxRequestImageBytes`, `requestImagePixelBudget` and `requestImageMaxBytes` are configurable in Settings; defaults preserve the previous 50 images / 24 MiB / 1568px / 1 MiB behavior. Count and pixel policies are covered by tests.
|
|
6
|
+
- **#78 — preparation timeout**: `requestPreparationTimeoutMs` (default 60s) bounds image resolution before dispatch, independently of the response-header timeout; caller aborts still win, and timeouts surface as `TIMEOUT`.
|
|
7
|
+
- 136 tests.
|
|
8
|
+
|
|
3
9
|
## 0.5.27 — release 4: catalog freshness
|
|
4
10
|
|
|
5
11
|
- **#86 — new-model badge**: the live catalog now keeps `release_date` (or `created`) metadata; Settings marks models released within the last seven UTC days with a NEW badge and date tooltip. Dates are dropped safely when the gateway omits or malforms them.
|
package/README.md
CHANGED
|
@@ -132,12 +132,12 @@ npm pack
|
|
|
132
132
|
Install the **packed tarball** into a profile:
|
|
133
133
|
|
|
134
134
|
```bash
|
|
135
|
-
dsh plugin --profile web add /absolute/path/to/goodandready-dsh-opencode-provider-0.5.
|
|
135
|
+
dsh plugin --profile web add /absolute/path/to/goodandready-dsh-opencode-provider-0.5.28.tgz
|
|
136
136
|
# DSH Desktop:
|
|
137
|
-
dsh plugin --profile desktop add /absolute/path/to/goodandready-dsh-opencode-provider-0.5.
|
|
137
|
+
dsh plugin --profile desktop add /absolute/path/to/goodandready-dsh-opencode-provider-0.5.28.tgz
|
|
138
138
|
|
|
139
139
|
# Or install the published package:
|
|
140
|
-
dsh plugin --profile web add @goodandready/dsh-opencode-provider@0.5.
|
|
140
|
+
dsh plugin --profile web add @goodandready/dsh-opencode-provider@0.5.28
|
|
141
141
|
```
|
|
142
142
|
|
|
143
143
|
Restart dsh (or DSH Desktop), then pick **OpenCode (plugin)** or **OpenCode Go (plugin)** in the model picker.
|
package/README.ru.md
CHANGED
|
@@ -131,12 +131,12 @@ npm pack
|
|
|
131
131
|
Установка из **упакованного tarball**:
|
|
132
132
|
|
|
133
133
|
```bash
|
|
134
|
-
dsh plugin --profile web add /absolute/path/to/goodandready-dsh-opencode-provider-0.5.
|
|
134
|
+
dsh plugin --profile web add /absolute/path/to/goodandready-dsh-opencode-provider-0.5.28.tgz
|
|
135
135
|
# DSH Desktop:
|
|
136
|
-
dsh plugin --profile desktop add /absolute/path/to/goodandready-dsh-opencode-provider-0.5.
|
|
136
|
+
dsh plugin --profile desktop add /absolute/path/to/goodandready-dsh-opencode-provider-0.5.28.tgz
|
|
137
137
|
|
|
138
138
|
# Либо установка опубликованного пакета из npm:
|
|
139
|
-
dsh plugin --profile web add @goodandready/dsh-opencode-provider@0.5.
|
|
139
|
+
dsh plugin --profile web add @goodandready/dsh-opencode-provider@0.5.28
|
|
140
140
|
```
|
|
141
141
|
|
|
142
142
|
После установки перезапустите dsh (или DSH Desktop) и выберите **OpenCode (plugin)** или **OpenCode Go (plugin)** в списке моделей.
|
package/README.zh.md
CHANGED
|
@@ -126,12 +126,12 @@ npm pack
|
|
|
126
126
|
通过**打包文件 (.tgz)**安装:
|
|
127
127
|
|
|
128
128
|
```bash
|
|
129
|
-
dsh plugin --profile web add /absolute/path/to/goodandready-dsh-opencode-provider-0.5.
|
|
129
|
+
dsh plugin --profile web add /absolute/path/to/goodandready-dsh-opencode-provider-0.5.28.tgz
|
|
130
130
|
# DSH 桌面端:
|
|
131
|
-
dsh plugin --profile desktop add /absolute/path/to/goodandready-dsh-opencode-provider-0.5.
|
|
131
|
+
dsh plugin --profile desktop add /absolute/path/to/goodandready-dsh-opencode-provider-0.5.28.tgz
|
|
132
132
|
|
|
133
133
|
# 或从 npm 安装已发布版本:
|
|
134
|
-
dsh plugin --profile web add @goodandready/dsh-opencode-provider@0.5.
|
|
134
|
+
dsh plugin --profile web add @goodandready/dsh-opencode-provider@0.5.28
|
|
135
135
|
```
|
|
136
136
|
|
|
137
137
|
安装完成后重启 dsh 或 DSH 桌面端,在模型选择器中选择 **OpenCode (plugin)** 或 **OpenCode Go (plugin)** 即可。
|
package/lib/client.js
CHANGED
|
@@ -181,6 +181,11 @@ window.__ModuleLoader__.load({
|
|
|
181
181
|
usageUrl: "Usage endpoint",
|
|
182
182
|
requestTimeoutMs: "Header timeout (ms)",
|
|
183
183
|
streamIdleTimeoutMs: "Stream idle timeout (ms)",
|
|
184
|
+
requestPreparationTimeoutMs: "Preparation timeout (ms)",
|
|
185
|
+
maxImages: "Max images per request",
|
|
186
|
+
maxRequestImageBytes: "Request image budget (bytes)",
|
|
187
|
+
requestImagePixelBudget: "Image pixel budget",
|
|
188
|
+
requestImageMaxBytes: "Per-image max bytes",
|
|
184
189
|
proxyUrl: "Proxy URL",
|
|
185
190
|
proxyUrlHint: "HTTP, HTTPS or SOCKS5 proxy for inference, catalog and usage. Empty disables it. Credentials are not supported.",
|
|
186
191
|
maxOutputTokens: "Output limit (empty = model default, 0 = omit)",
|
|
@@ -409,6 +414,11 @@ window.__ModuleLoader__.load({
|
|
|
409
414
|
usageUrl: "用量端点",
|
|
410
415
|
requestTimeoutMs: "请求头超时(毫秒)",
|
|
411
416
|
streamIdleTimeoutMs: "流空闲超时(毫秒)",
|
|
417
|
+
requestPreparationTimeoutMs: "准备超时(毫秒)",
|
|
418
|
+
maxImages: "每请求最大图片数",
|
|
419
|
+
maxRequestImageBytes: "请求图片预算(字节)",
|
|
420
|
+
requestImagePixelBudget: "图片像素预算",
|
|
421
|
+
requestImageMaxBytes: "单图最大字节数",
|
|
412
422
|
proxyUrl: "代理地址",
|
|
413
423
|
proxyUrlHint: "用于推理、目录和用量的 HTTP、HTTPS 或 SOCKS5 代理。留空则禁用。不支持代理认证。",
|
|
414
424
|
maxOutputTokens: "输出上限(空 = 模型默认,0 = 省略)",
|
|
@@ -1696,6 +1706,11 @@ window.__ModuleLoader__.load({
|
|
|
1696
1706
|
openCodeAuthEntry: state.config.openCodeAuthEntry,
|
|
1697
1707
|
requestTimeoutMs: String(state.config.requestTimeoutMs),
|
|
1698
1708
|
streamIdleTimeoutMs: String(state.config.streamIdleTimeoutMs),
|
|
1709
|
+
requestPreparationTimeoutMs: String(state.config.requestPreparationTimeoutMs),
|
|
1710
|
+
maxImages: String(state.config.maxImages),
|
|
1711
|
+
maxRequestImageBytes: String(state.config.maxRequestImageBytes),
|
|
1712
|
+
requestImagePixelBudget: String(state.config.requestImagePixelBudget),
|
|
1713
|
+
requestImageMaxBytes: String(state.config.requestImageMaxBytes),
|
|
1699
1714
|
proxyUrl: state.config.proxyUrl,
|
|
1700
1715
|
maxOutputTokens: state.config.maxOutputTokens === null ? "" : String(state.config.maxOutputTokens),
|
|
1701
1716
|
contextWindow: state.config.contextWindow === null ? "" : String(state.config.contextWindow),
|
|
@@ -1743,6 +1758,11 @@ window.__ModuleLoader__.load({
|
|
|
1743
1758
|
openCodeAuthEntry: draft.openCodeAuthEntry.trim(),
|
|
1744
1759
|
requestTimeoutMs: numberOrNull(draft.requestTimeoutMs) ?? 3e5,
|
|
1745
1760
|
streamIdleTimeoutMs: numberOrNull(draft.streamIdleTimeoutMs) ?? 3e5,
|
|
1761
|
+
requestPreparationTimeoutMs: numberOrNull(draft.requestPreparationTimeoutMs) ?? 6e4,
|
|
1762
|
+
maxImages: numberOrNull(draft.maxImages) ?? 50,
|
|
1763
|
+
maxRequestImageBytes: numberOrNull(draft.maxRequestImageBytes) ?? 25165824,
|
|
1764
|
+
requestImagePixelBudget: numberOrNull(draft.requestImagePixelBudget) ?? 2458624,
|
|
1765
|
+
requestImageMaxBytes: numberOrNull(draft.requestImageMaxBytes) ?? 1048576,
|
|
1746
1766
|
proxyUrl: draft.proxyUrl.trim(),
|
|
1747
1767
|
maxOutputTokens: numberOrNull(draft.maxOutputTokens),
|
|
1748
1768
|
contextWindow: numberOrNull(draft.contextWindow),
|
|
@@ -3148,6 +3168,36 @@ window.__ModuleLoader__.load({
|
|
|
3148
3168
|
value: draft.streamIdleTimeoutMs,
|
|
3149
3169
|
onChange: (value) => update({ streamIdleTimeoutMs: value })
|
|
3150
3170
|
}),
|
|
3171
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
3172
|
+
label: t("requestPreparationTimeoutMs"),
|
|
3173
|
+
type: "number",
|
|
3174
|
+
value: draft.requestPreparationTimeoutMs,
|
|
3175
|
+
onChange: (value) => update({ requestPreparationTimeoutMs: value })
|
|
3176
|
+
}),
|
|
3177
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
3178
|
+
label: t("maxImages"),
|
|
3179
|
+
type: "number",
|
|
3180
|
+
value: draft.maxImages,
|
|
3181
|
+
onChange: (value) => update({ maxImages: value })
|
|
3182
|
+
}),
|
|
3183
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
3184
|
+
label: t("maxRequestImageBytes"),
|
|
3185
|
+
type: "number",
|
|
3186
|
+
value: draft.maxRequestImageBytes,
|
|
3187
|
+
onChange: (value) => update({ maxRequestImageBytes: value })
|
|
3188
|
+
}),
|
|
3189
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
3190
|
+
label: t("requestImagePixelBudget"),
|
|
3191
|
+
type: "number",
|
|
3192
|
+
value: draft.requestImagePixelBudget,
|
|
3193
|
+
onChange: (value) => update({ requestImagePixelBudget: value })
|
|
3194
|
+
}),
|
|
3195
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
3196
|
+
label: t("requestImageMaxBytes"),
|
|
3197
|
+
type: "number",
|
|
3198
|
+
value: draft.requestImageMaxBytes,
|
|
3199
|
+
onChange: (value) => update({ requestImageMaxBytes: value })
|
|
3200
|
+
}),
|
|
3151
3201
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
3152
3202
|
label: t("proxyUrl"),
|
|
3153
3203
|
hint: t("proxyUrlHint"),
|
package/lib/index.d.ts
CHANGED
|
@@ -37,6 +37,16 @@ interface Config {
|
|
|
37
37
|
requestTimeoutMs?: number;
|
|
38
38
|
/** Milliseconds a stream may stall; defaults to 300s. */
|
|
39
39
|
streamIdleTimeoutMs?: number;
|
|
40
|
+
/** Milliseconds allowed for image resolution and request preparation. */
|
|
41
|
+
requestPreparationTimeoutMs?: number;
|
|
42
|
+
/** Request-wide image count cap; defaults to 50. */
|
|
43
|
+
maxImages?: number;
|
|
44
|
+
/** Request-wide base64 image budget; defaults to 24 MiB. */
|
|
45
|
+
maxRequestImageBytes?: number;
|
|
46
|
+
/** Total-pixel budget for one normalized image. */
|
|
47
|
+
requestImagePixelBudget?: number;
|
|
48
|
+
/** Raw encoded-byte target for one image before base64 expansion. */
|
|
49
|
+
requestImageMaxBytes?: number;
|
|
40
50
|
/** HTTP/HTTPS/SOCKS5 proxy for inference, catalog and usage requests. */
|
|
41
51
|
proxyUrl?: string;
|
|
42
52
|
/** Visible-model allowlist; an empty list means "show everything". */
|
|
@@ -85,6 +95,11 @@ interface ResolvedConfig {
|
|
|
85
95
|
openCodeAuthEntry: string;
|
|
86
96
|
requestTimeoutMs: number;
|
|
87
97
|
streamIdleTimeoutMs: number;
|
|
98
|
+
requestPreparationTimeoutMs: number;
|
|
99
|
+
maxImages: number;
|
|
100
|
+
maxRequestImageBytes: number;
|
|
101
|
+
requestImagePixelBudget: number;
|
|
102
|
+
requestImageMaxBytes: number;
|
|
88
103
|
proxyUrl: string;
|
|
89
104
|
visibleModels: readonly string[];
|
|
90
105
|
modelVisibility: Readonly<Record<string, boolean>>;
|
package/lib/index.js
CHANGED
|
@@ -81,10 +81,14 @@ const DEFAULT_GO_API_BASE = "https://opencode.ai/inference/go";
|
|
|
81
81
|
const DEFAULT_GO_ZEN_BASE = "https://opencode.ai/zen/go/v1";
|
|
82
82
|
const DEFAULT_USAGE_URL = "https://opencode.ai/zen/go/v1/usage";
|
|
83
83
|
const DEFAULT_AUTH_ENTRY = "opencode-go";
|
|
84
|
-
const DEFAULT_USER_AGENT = "dsh-opencode-provider/0.5.
|
|
84
|
+
const DEFAULT_USER_AGENT = "dsh-opencode-provider/0.5.28";
|
|
85
85
|
const DEFAULT_CONTEXT_WINDOW = 262144;
|
|
86
86
|
const DEFAULT_MAX_TOKENS = 32768;
|
|
87
87
|
const DEFAULT_GENERATE_MAX_TOKENS = 65536;
|
|
88
|
+
const DEFAULT_MAX_REQUEST_IMAGE_BYTES = 25165824;
|
|
89
|
+
const DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET = 2458624;
|
|
90
|
+
const DEFAULT_REQUEST_IMAGE_MAX_BYTES = 1048576;
|
|
91
|
+
const DEFAULT_REQUEST_PREPARATION_TIMEOUT_MS = 6e4;
|
|
88
92
|
function markVolatile(schema) {
|
|
89
93
|
const mark = schema.volatile;
|
|
90
94
|
return typeof mark === "function" ? mark.call(schema) : schema;
|
|
@@ -99,6 +103,11 @@ const Config = z.object({
|
|
|
99
103
|
openCodeAuthEntry: markVolatile(z.string().default(DEFAULT_AUTH_ENTRY)),
|
|
100
104
|
requestTimeoutMs: markVolatile(z.number().min(1).max(2147483647).default(3e5)),
|
|
101
105
|
streamIdleTimeoutMs: markVolatile(z.number().min(1).max(2147483647).default(3e5)),
|
|
106
|
+
requestPreparationTimeoutMs: markVolatile(z.number().min(1).max(2147483647).default(DEFAULT_REQUEST_PREPARATION_TIMEOUT_MS)),
|
|
107
|
+
maxImages: markVolatile(z.number().min(1).max(1e4).step(1).default(50)),
|
|
108
|
+
maxRequestImageBytes: markVolatile(z.number().min(1).max(1e9).step(1).default(DEFAULT_MAX_REQUEST_IMAGE_BYTES)),
|
|
109
|
+
requestImagePixelBudget: markVolatile(z.number().min(1).max(1e8).step(1).default(DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET)),
|
|
110
|
+
requestImageMaxBytes: markVolatile(z.number().min(1).max(1e8).step(1).default(DEFAULT_REQUEST_IMAGE_MAX_BYTES)),
|
|
102
111
|
proxyUrl: markVolatile(z.string().default("")),
|
|
103
112
|
visibleModels: markVolatile(z.array(z.string()).default([])),
|
|
104
113
|
modelVisibility: markVolatile(z.dict(z.boolean()).default({})),
|
|
@@ -212,6 +221,11 @@ function resolveConfig(config) {
|
|
|
212
221
|
openCodeAuthEntry: typeof config.openCodeAuthEntry === "string" && config.openCodeAuthEntry !== "" ? config.openCodeAuthEntry : DEFAULT_AUTH_ENTRY,
|
|
213
222
|
requestTimeoutMs: positiveInt(config.requestTimeoutMs, 3e5),
|
|
214
223
|
streamIdleTimeoutMs: positiveInt(config.streamIdleTimeoutMs, 3e5),
|
|
224
|
+
requestPreparationTimeoutMs: positiveInt(config.requestPreparationTimeoutMs, DEFAULT_REQUEST_PREPARATION_TIMEOUT_MS),
|
|
225
|
+
maxImages: positiveInt(config.maxImages, 50),
|
|
226
|
+
maxRequestImageBytes: positiveInt(config.maxRequestImageBytes, DEFAULT_MAX_REQUEST_IMAGE_BYTES),
|
|
227
|
+
requestImagePixelBudget: positiveInt(config.requestImagePixelBudget, DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET),
|
|
228
|
+
requestImageMaxBytes: positiveInt(config.requestImageMaxBytes, DEFAULT_REQUEST_IMAGE_MAX_BYTES),
|
|
215
229
|
proxyUrl: normalizeProxyUrl(config.proxyUrl),
|
|
216
230
|
visibleModels: Array.isArray(config.visibleModels) ? config.visibleModels.filter((id) => typeof id === "string" && id !== "") : [],
|
|
217
231
|
modelVisibility: booleanRecord(config.modelVisibility),
|
|
@@ -1292,16 +1306,21 @@ function classifyStreamError(value, status = 200) {
|
|
|
1292
1306
|
}
|
|
1293
1307
|
// src/images.ts
|
|
1294
1308
|
const MAX_LONG_EDGE = 1568;
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1309
|
+
function limitsOf(policy) {
|
|
1310
|
+
return {
|
|
1311
|
+
maxImages: policy?.maxImages ?? 50,
|
|
1312
|
+
maxRequestImageBytes: policy?.maxRequestImageBytes ?? 25165824,
|
|
1313
|
+
requestImagePixelBudget: policy?.requestImagePixelBudget ?? 2458624,
|
|
1314
|
+
requestImageMaxBytes: policy?.requestImageMaxBytes ?? 1048576
|
|
1315
|
+
};
|
|
1316
|
+
}
|
|
1299
1317
|
/**
|
|
1300
1318
|
* Keep the newest images under one request-wide budget. The oldest images are
|
|
1301
1319
|
* dropped first; the transports render them as an "image omitted" placeholder
|
|
1302
1320
|
* instead of failing the whole request.
|
|
1303
1321
|
*/
|
|
1304
|
-
function selectRequestImages(refs, occurrences) {
|
|
1322
|
+
function selectRequestImages(refs, occurrences, policy) {
|
|
1323
|
+
const limits = limitsOf(policy);
|
|
1305
1324
|
const unique = [];
|
|
1306
1325
|
const seen = /* @__PURE__ */ new Set();
|
|
1307
1326
|
for (const ref of refs) {
|
|
@@ -1314,7 +1333,7 @@ function selectRequestImages(refs, occurrences) {
|
|
|
1314
1333
|
let start = 0;
|
|
1315
1334
|
let totalImages = unique.reduce((sum, ref) => sum + countOf(ref), 0);
|
|
1316
1335
|
let bytes = unique.reduce((sum, ref) => sum + encoded(ref.bytes) * countOf(ref), 0);
|
|
1317
|
-
while (start < unique.length && (totalImages >
|
|
1336
|
+
while (start < unique.length && (totalImages > limits.maxImages || bytes > limits.maxRequestImageBytes)) {
|
|
1318
1337
|
const dropped = unique[start];
|
|
1319
1338
|
if (dropped !== void 0) {
|
|
1320
1339
|
const count = countOf(dropped);
|
|
@@ -1333,20 +1352,23 @@ function selectRequestImages(refs, occurrences) {
|
|
|
1333
1352
|
dropped: unique.slice(0, start)
|
|
1334
1353
|
};
|
|
1335
1354
|
}
|
|
1336
|
-
function targetOf(ref) {
|
|
1355
|
+
function targetOf(ref, policy) {
|
|
1356
|
+
const limits = limitsOf(policy);
|
|
1337
1357
|
const longEdge = Math.max(ref.width, ref.height);
|
|
1338
|
-
const
|
|
1358
|
+
const pixelEdge = Math.max(1, Math.floor(Math.sqrt(limits.requestImagePixelBudget)));
|
|
1359
|
+
const maxEdge = Math.min(MAX_LONG_EDGE, pixelEdge);
|
|
1360
|
+
const scale = longEdge > maxEdge ? maxEdge / longEdge : 1;
|
|
1339
1361
|
return {
|
|
1340
1362
|
width: Math.max(1, Math.round(ref.width * scale)),
|
|
1341
1363
|
height: Math.max(1, Math.round(ref.height * scale)),
|
|
1342
|
-
maxBytes:
|
|
1364
|
+
maxBytes: limits.requestImageMaxBytes
|
|
1343
1365
|
};
|
|
1344
1366
|
}
|
|
1345
1367
|
function hasImages(options) {
|
|
1346
1368
|
return options.messages.some((message) => message.content.some((block) => block.type === "image" && block.offloaded !== true));
|
|
1347
1369
|
}
|
|
1348
1370
|
/** Decode the distinct request images that fit the request-wide budget. */
|
|
1349
|
-
async function resolveImages(options, store, signal) {
|
|
1371
|
+
async function resolveImages(options, store, signal, policy) {
|
|
1350
1372
|
const refs = [];
|
|
1351
1373
|
const counts = /* @__PURE__ */ new Map();
|
|
1352
1374
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -1359,8 +1381,8 @@ async function resolveImages(options, store, signal) {
|
|
|
1359
1381
|
refs.push(ref);
|
|
1360
1382
|
}
|
|
1361
1383
|
const images = /* @__PURE__ */ new Map();
|
|
1362
|
-
for (const ref of selectRequestImages(refs, counts).kept) {
|
|
1363
|
-
const request = await store.readImageRequest(ref, targetOf(ref), signal);
|
|
1384
|
+
for (const ref of selectRequestImages(refs, counts, policy).kept) {
|
|
1385
|
+
const request = await store.readImageRequest(ref, targetOf(ref, policy), signal);
|
|
1364
1386
|
const base64 = Buffer.from(request.data).toString("base64");
|
|
1365
1387
|
images.set(ref.attachmentId, {
|
|
1366
1388
|
mediaType: request.mediaType,
|
|
@@ -3369,7 +3391,25 @@ var OpenCodeAdapter = class extends LlmAdapter {
|
|
|
3369
3391
|
if (hasImages(options)) {
|
|
3370
3392
|
const store = this.deps.resolveAttachments?.();
|
|
3371
3393
|
if (store === void 0) throw new LlmError("llm-opencode: image input requires the durable attachment service", "UNSUPPORTED_CONTENT");
|
|
3372
|
-
|
|
3394
|
+
const preparation = new AbortController();
|
|
3395
|
+
let timedOut = false;
|
|
3396
|
+
const onAbort = () => preparation.abort(options.signal?.reason);
|
|
3397
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
3398
|
+
const timer = setTimeout(() => {
|
|
3399
|
+
timedOut = true;
|
|
3400
|
+
preparation.abort();
|
|
3401
|
+
}, config.requestPreparationTimeoutMs);
|
|
3402
|
+
timer.unref?.();
|
|
3403
|
+
try {
|
|
3404
|
+
images = await resolveImages(options, store, preparation.signal, config);
|
|
3405
|
+
} catch (error) {
|
|
3406
|
+
if (options.signal?.aborted === true) throw options.signal.reason ?? error;
|
|
3407
|
+
if (timedOut) throw new LlmError(`OpenCode image preparation exceeded ${config.requestPreparationTimeoutMs}ms`, "TIMEOUT", { cause: error });
|
|
3408
|
+
throw error;
|
|
3409
|
+
} finally {
|
|
3410
|
+
clearTimeout(timer);
|
|
3411
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
3412
|
+
}
|
|
3373
3413
|
}
|
|
3374
3414
|
let bodyOptions = options;
|
|
3375
3415
|
if (options.tools !== void 0) {
|
|
@@ -4748,6 +4788,11 @@ function publicConfig(config) {
|
|
|
4748
4788
|
openCodeAuthEntry: config.openCodeAuthEntry,
|
|
4749
4789
|
requestTimeoutMs: config.requestTimeoutMs,
|
|
4750
4790
|
streamIdleTimeoutMs: config.streamIdleTimeoutMs,
|
|
4791
|
+
requestPreparationTimeoutMs: config.requestPreparationTimeoutMs,
|
|
4792
|
+
maxImages: config.maxImages,
|
|
4793
|
+
maxRequestImageBytes: config.maxRequestImageBytes,
|
|
4794
|
+
requestImagePixelBudget: config.requestImagePixelBudget,
|
|
4795
|
+
requestImageMaxBytes: config.requestImageMaxBytes,
|
|
4751
4796
|
proxyUrl: config.proxyUrl,
|
|
4752
4797
|
visibleModels: config.visibleModels,
|
|
4753
4798
|
modelVisibility: config.modelVisibility,
|
|
@@ -4944,6 +4989,11 @@ function configOps(patch) {
|
|
|
4944
4989
|
if ("openCodeAuthEntry" in patch) set("openCodeAuthEntry", patch.openCodeAuthEntry);
|
|
4945
4990
|
if ("requestTimeoutMs" in patch) set("requestTimeoutMs", patch.requestTimeoutMs);
|
|
4946
4991
|
if ("streamIdleTimeoutMs" in patch) set("streamIdleTimeoutMs", patch.streamIdleTimeoutMs);
|
|
4992
|
+
if ("requestPreparationTimeoutMs" in patch) set("requestPreparationTimeoutMs", patch.requestPreparationTimeoutMs);
|
|
4993
|
+
if ("maxImages" in patch) set("maxImages", patch.maxImages);
|
|
4994
|
+
if ("maxRequestImageBytes" in patch) set("maxRequestImageBytes", patch.maxRequestImageBytes);
|
|
4995
|
+
if ("requestImagePixelBudget" in patch) set("requestImagePixelBudget", patch.requestImagePixelBudget);
|
|
4996
|
+
if ("requestImageMaxBytes" in patch) set("requestImageMaxBytes", patch.requestImageMaxBytes);
|
|
4947
4997
|
if ("proxyUrl" in patch) set("proxyUrl", normalizeProxyUrl(typeof patch.proxyUrl === "string" ? patch.proxyUrl : ""));
|
|
4948
4998
|
if ("visibleModels" in patch) set("visibleModels", cleanStringArray(patch.visibleModels));
|
|
4949
4999
|
if ("modelVisibility" in patch) set("modelVisibility", cleanBooleanRecord(patch.modelVisibility));
|