@dan-ai-studio/dshopencodego 0.1.13 → 0.1.15

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 CHANGED
@@ -120,11 +120,10 @@ The gateway's `/v1/models` answers only *which* models exist, never *how* to cal
120
120
 
121
121
  ## The model list in the settings page
122
122
 
123
- The "OpenCode Go" section shows the live gateway catalog (42+ models) with, per model:
123
+ The "OpenCode Go" section shows the live gateway catalog (the count follows the gateway) with, per model:
124
124
 
125
125
  - **context / max input / max output**, **release date**, **price per 1M tokens** (from models.dev), and **Go allowance**;
126
126
  - **Go allowance** comes from OpenCode's own documentation (the "usage limits / estimated requests" tables) — **no API exposes it**. It is a transcribed table (source URL and date in the `src/go-limits.ts` header); pricing or promotion changes require updating it and shipping a release;
127
- - **Capability marks**: badges on each row label **structured output / temperature control / open weights** exactly as models.dev declares them. Only a declared "yes" is marked — an unstated or declared "no" stays unmarked, the same rule the reasoning levels follow.
128
127
  - **Input modalities**: a separate line lists the input modes models.dev declares (text / image / audio / video / PDF). These are the **model's own metadata**, not what the Harness can forward — the Harness sends text and images natively; audio/video/PDF travel as attachments and tool reads. The line is absent when the document declares none.
129
128
  - filtering (by name/id, enabled-only, show-deprecated — **deprecated hidden by default**), sorting (newest first, monthly requests, input price, context, name, enabled first); the list is the only view, one model per row.
130
129
 
@@ -153,7 +152,7 @@ The `engines.dsh` field is informational for readers and package managers; **DSH
153
152
 
154
153
  | Binding layer | Declared | Enforced by |
155
154
  | --- | --- | --- |
156
- | `peerDependencies` (15 `@deepseek-ai/dsh-*` packages) | all `>=0.1.7-alpha.1 <0.1.8` | **DSH's gate, at plugin load time** |
155
+ | `peerDependencies` (17 `@deepseek-ai/dsh-*` packages) | all `>=0.1.7-alpha.1 <0.1.8` | **DSH's gate, at plugin load time** |
157
156
  | `@deepseek-ai/cordis` | `4.0.2 \|\| 4.0.3 \|\| 4.0.4` | the same gate |
158
157
  | `engines.dsh` | `>=0.1.7-alpha.1 <0.1.8` | informational only; DSH never reads it |
159
158
  | `engines.node` | `^22.19.0 \|\| >=24.0.0` | the package manager |
@@ -162,7 +161,7 @@ The `engines.dsh` field is informational for readers and package managers; **DSH
162
161
 
163
162
  Things to keep in mind when maintaining this:
164
163
 
165
- - **Required versus optional peers**: six of the fifteen are marked `optional` (`dsh-api-remotes`, `dsh-client-locale`, `dsh-client-store`, `dsh-client-ui-model-selection`, `dsh-client-ui-settings`, `dsh-client-ui-slots`). The nine that actually block loading are `dsh-llm`, `dsh-typert-protocol`, `dsh-attachment`, `dsh-brand`, `dsh-credentials`, `dsh-fs`, `dsh-launch-environment`, `dsh-settings`, and `dsh-timeout`. `dsh-llm` is the heaviest coupling — more than twenty imports across the source.
164
+ - **Required versus optional peers**: six of the eighteen are marked `optional` (`dsh-api-remotes`, `dsh-client-locale`, `dsh-client-store`, `dsh-client-ui-model-selection`, `dsh-client-ui-settings`, `dsh-client-ui-slots`). The twelve that actually block loading are `cordis`, `dsh-attachment`, `dsh-brand`, `dsh-client-ui-conversation`, `dsh-client-ui-renderer`, `dsh-credentials`, `dsh-fs`, `dsh-launch-environment`, `dsh-llm`, `dsh-timeout`, `dsh-typert-protocol`, and `dsh-typert-registry`. `dsh-llm` is the heaviest coupling — more than twenty imports across the source.
166
165
  - **Declared range ≠ verified range**: `0.1.7-alpha.1` and `alpha.2` fall inside the declaration but were never verified here. What was verified is `0.1.7-rc.1` (the dev-dependency baseline) and `0.1.7-rc.2` (daily use).
167
166
  - **The upper bound is a tracking line**: `<0.1.8` means that the moment DSH ships `0.1.8`, this plugin must ship a new release in the same window or every user loses the plugin. After changing a range, `npm test` is the verification (local mock gateway, no network, no tokens) — ranges follow what the interfaces declare, and are never "measured" with live probes.
168
167
  - **Peer coverage is now guarded both ways**: `dsh-typert-registry`, `dsh-client-ui-conversation`, and `dsh-client-ui-renderer` were imported by the source but absent from `peerDependencies`, invisible to the gate; they are declared now, and `tests/peer-coverage.spec.ts` asserts both directions — anything the source imports must be declared, and anything declared but unreached must be removed (`dsh-settings` went that way: the settings form is actually provided by `dsh-client-ui-settings`).
package/README.md CHANGED
@@ -120,11 +120,10 @@ API Key 通过 Harness 凭证库提供(引用名 `OPENCODE_GO_API_KEY`),
120
120
 
121
121
  ## 设置页里的模型列表
122
122
 
123
- 设置页的「OpenCode Go」分区展示网关实时目录(42 个起),并对每个模型给出:
123
+ 设置页的「OpenCode Go」分区展示网关实时目录(数量随网关发布变化),并对每个模型给出:
124
124
 
125
125
  - **上下文 / 输入 / 输出**(最大输入只有部分模型有官方数据)、**发布时间**、**单价 /1M**(来自 models.dev)、**Go 额度**;
126
126
  - **Go 额度**来自 OpenCode 官方文档的「使用限制 / 预估请求数」表,**没有接口提供**,是本插件转写的数据表(见 `src/go-limits.ts` 的注释:来源 URL 与转写日期);文档调整价格或促销时需要更新该表并随发版发布。
127
- - **能力标记**:按 models.dev 的声明给每个模型加**结构化输出 / 温度控制 / 开源权重**徽标。只标注声明为"支持"的项——**未声明或声明不支持都不加标记**,与推理档位同一口径:不替文档下结论。
128
127
  - **输入模态**:单独一行列出 models.dev 声明的输入方式(文本 / 图像 / 音频 / 视频 / PDF)。这是**模型自身的元数据**,不等于 DSH 能直传:DSH 的模型输入只原生支持文本与图像,音视频/PDF 走附件与工具读取路径;文档未声明时该行不显示。
129
128
  - 筛选(按名称/ID、仅已启用、显示已弃用——**默认隐藏已弃用**)、排序(新发布优先 / 每月预估次数 / 输入单价 / 上下文 / 名称 / 已启用优先);列表是唯一视图,逐模型纵向排列。
130
129
 
@@ -153,7 +152,7 @@ API Key 通过 Harness 凭证库提供(引用名 `OPENCODE_GO_API_KEY`),
153
152
 
154
153
  | 绑定层 | 声明 | 谁在把关 |
155
154
  | --- | --- | --- |
156
- | `peerDependencies`(15 个 `@deepseek-ai/dsh-*`) | 均为 `>=0.1.7-alpha.1 <0.1.8` | **DSH 加载时的真门禁** |
155
+ | `peerDependencies`(17 个 `@deepseek-ai/dsh-*`) | 均为 `>=0.1.7-alpha.1 <0.1.8` | **DSH 加载时的真门禁** |
157
156
  | `@deepseek-ai/cordis` | `4.0.2 \|\| 4.0.3 \|\| 4.0.4` | 同一门禁 |
158
157
  | `engines.dsh` | `>=0.1.7-alpha.1 <0.1.8` | 仅信息字段,DSH 不读 |
159
158
  | `engines.node` | `^22.19.0 \|\| >=24.0.0` | 包管理器 |
@@ -162,7 +161,7 @@ API Key 通过 Harness 凭证库提供(引用名 `OPENCODE_GO_API_KEY`),
162
161
 
163
162
  维护时需要注意:
164
163
 
165
- - **必选与可选之分**:15 个 peer 中 6 个标了 `optional`(`dsh-api-remotes`、`dsh-client-locale`、`dsh-client-store`、`dsh-client-ui-model-selection`、`dsh-client-ui-settings`、`dsh-client-ui-slots`);真正卡住加载的是 9 个——`dsh-llm`、`dsh-typert-protocol`、`dsh-attachment`、`dsh-brand`、`dsh-credentials`、`dsh-fs`、`dsh-launch-environment`、`dsh-settings`、`dsh-timeout`。其中 `dsh-llm` 是最重的一处耦合(源码 import 二十余处)。
164
+ - **必选与可选之分**:18 个 peer(17 个 `dsh-*` 加框架 `cordis`)中 6 个标了 `optional`(`dsh-api-remotes`、`dsh-client-locale`、`dsh-client-store`、`dsh-client-ui-model-selection`、`dsh-client-ui-settings`、`dsh-client-ui-slots`);真正卡住加载的是 12 个——`cordis`、`dsh-attachment`、`dsh-brand`、`dsh-client-ui-conversation`、`dsh-client-ui-renderer`、`dsh-credentials`、`dsh-fs`、`dsh-launch-environment`、`dsh-llm`、`dsh-timeout`、`dsh-typert-protocol`、`dsh-typert-registry`。其中 `dsh-llm` 是最重的一处耦合(源码 import 二十余处)。
166
165
  - **名义范围 ≠ 实测范围**:`0.1.7-alpha.1`、`alpha.2` 落在声明范围内,但本项目没有验证过;实际验证过的是 `0.1.7-rc.1`(开发依赖基线)与 `0.1.7-rc.2`(日常使用)。
167
166
  - **上界就是跟版线**:`<0.1.8` 意味着 DSH 一旦发布 `0.1.8`,本插件必须同批发新版,否则所有用户加载失败。调整范围后用 `npm test` 验证即可(本地 mock 网关,零网络零 token)——范围以接口声明为准,不要用线上探测来"测"出一个范围。
168
167
  - **peer 覆盖已双向守住**:`dsh-typert-registry`、`dsh-client-ui-conversation`、`dsh-client-ui-renderer` 曾被源码 import 却未声明、门禁管不到,现已补进 `peerDependencies`;`tests/peer-coverage.spec.ts` 双向断言——源码用到的必须声明,声明了却没人用的必须删(`dsh-settings` 就这样被移除:设置表单实际由 `dsh-client-ui-settings` 提供)。
package/lib/client.js CHANGED
@@ -87,9 +87,6 @@ function parseModel(value) {
87
87
  ...row["protocolSource"] === "builtin" || row["protocolSource"] === "online" || row["protocolSource"] === "inferred" || row["protocolSource"] === "override" ? { protocolSource: row["protocolSource"] } : {},
88
88
  ...typeof row["assumedLimits"] === "boolean" ? { assumedLimits: row["assumedLimits"] } : {},
89
89
  ...parseModalities(row["inputModalities"]),
90
- ...typeof row["structuredOutput"] === "boolean" ? { structuredOutput: row["structuredOutput"] } : {},
91
- ...typeof row["temperature"] === "boolean" ? { temperature: row["temperature"] } : {},
92
- ...typeof row["openWeights"] === "boolean" ? { openWeights: row["openWeights"] } : {},
93
90
  ...typeof row["configurationMissing"] === "string" ? { configurationMissing: row["configurationMissing"] } : {}
94
91
  };
95
92
  }
@@ -278,9 +275,6 @@ var en = {
278
275
  modalityAudio: "Audio",
279
276
  modalityVideo: "Video",
280
277
  modalityPdf: "PDF",
281
- capStructured: "Structured",
282
- capTemperature: "Temp",
283
- capOpenWeights: "Open",
284
278
  iosInput: "in",
285
279
  iosOutput: "out",
286
280
  iosContext: "ctx",
@@ -347,9 +341,6 @@ var zh = {
347
341
  modalityAudio: "\u97F3\u9891",
348
342
  modalityVideo: "\u89C6\u9891",
349
343
  modalityPdf: "PDF",
350
- capStructured: "\u7ED3\u6784\u5316",
351
- capTemperature: "\u6E29\u5EA6",
352
- capOpenWeights: "\u5F00\u6E90",
353
344
  iosInput: "\u5165",
354
345
  iosOutput: "\u51FA",
355
346
  iosContext: "\u4E0A\u4E0B\u6587",
@@ -443,13 +434,6 @@ function visibleModels(models, filter, visibility, locale) {
443
434
  });
444
435
  return sortRows(rows, filter.sort, visibility, locale);
445
436
  }
446
- function capabilityLabels(model, t) {
447
- const labels = [];
448
- if (model.structuredOutput === true) labels.push(t("capStructured"));
449
- if (model.temperature === true) labels.push(t("capTemperature"));
450
- if (model.openWeights === true) labels.push(t("capOpenWeights"));
451
- return labels;
452
- }
453
437
  var MODALITY_KEYS = {
454
438
  text: "modalityText",
455
439
  image: "modalityImage",
@@ -470,7 +454,7 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id) + "]")
470
454
  style.textContent = ".d7lz0W_root{color:var(--dsw-alias-label-primary);flex-direction:column;gap:1.25rem;display:flex}.d7lz0W_title{margin:0;font-size:1.05rem}.d7lz0W_hint{color:var(--dsw-alias-label-secondary);margin:0;font-size:.8rem}.d7lz0W_warn{color:var(--dsw-alias-state-warn-primary);margin:0;font-size:.8rem}.d7lz0W_ok{color:var(--dsw-alias-state-success-primary);font-size:.8rem}.d7lz0W_block{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:.6rem;flex-direction:column;gap:.5rem;padding:.85rem;display:flex}.d7lz0W_row{flex-wrap:wrap;align-items:center;gap:.5rem;display:flex}.d7lz0W_row>strong{margin-right:auto}.d7lz0W_input{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);min-width:10rem;color:var(--dsw-alias-label-primary);font:inherit;border-radius:.35rem;flex:14rem;padding:.35rem .5rem;font-size:.85rem}.d7lz0W_button{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:.35rem;padding:.35rem .7rem;font-size:.8rem}.d7lz0W_button:disabled{color:var(--dsw-alias-state-idle-primary);cursor:default}.d7lz0W_number{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:5rem;color:var(--dsw-alias-label-primary);font:inherit;border-radius:.35rem;padding:.25rem .4rem;font-size:.8rem}.d7lz0W_select{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:auto;max-width:100%;color:var(--dsw-alias-label-primary);font:inherit;border-radius:.35rem;padding:.25rem .4rem;font-size:.8rem}.d7lz0W_list{flex-direction:column;display:flex}.d7lz0W_item{border-top:1px solid var(--dsw-alias-border-l1);align-items:flex-start;gap:.5rem;padding:.45rem .15rem;display:flex}.d7lz0W_item input[type=checkbox]{accent-color:var(--dsw-alias-brand-primary);margin-top:.15rem}.d7lz0W_itemBody{flex-direction:column;gap:.15rem;min-width:0;display:flex}.d7lz0W_itemMain{flex-wrap:wrap;align-items:baseline;gap:.6rem;display:flex}.d7lz0W_itemMeta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:.75rem;font-size:.75rem;display:flex}.d7lz0W_itemModalities{color:var(--dsw-alias-label-secondary);font-size:.75rem}.d7lz0W_name{color:var(--dsw-alias-label-primary)}.d7lz0W_mono{color:var(--dsw-alias-label-secondary);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.d7lz0W_badge{color:var(--dsw-alias-brand-primary)}";
471
455
  document.head.appendChild(style);
472
456
  }
473
- var section_default = { "title": "d7lz0W_title", "root": "d7lz0W_root", "block": "d7lz0W_block", "name": "d7lz0W_name", "number": "d7lz0W_number", "select": "d7lz0W_select", "badge": "d7lz0W_badge", "itemModalities": "d7lz0W_itemModalities", "hint": "d7lz0W_hint", "mono": "d7lz0W_mono", "warn": "d7lz0W_warn", "row": "d7lz0W_row", "ok": "d7lz0W_ok", "input": "d7lz0W_input", "list": "d7lz0W_list", "button": "d7lz0W_button", "itemMain": "d7lz0W_itemMain", "itemBody": "d7lz0W_itemBody", "itemMeta": "d7lz0W_itemMeta", "item": "d7lz0W_item" };
457
+ var section_default = { "warn": "d7lz0W_warn", "itemMeta": "d7lz0W_itemMeta", "hint": "d7lz0W_hint", "input": "d7lz0W_input", "badge": "d7lz0W_badge", "name": "d7lz0W_name", "itemBody": "d7lz0W_itemBody", "itemMain": "d7lz0W_itemMain", "mono": "d7lz0W_mono", "button": "d7lz0W_button", "row": "d7lz0W_row", "root": "d7lz0W_root", "list": "d7lz0W_list", "title": "d7lz0W_title", "item": "d7lz0W_item", "itemModalities": "d7lz0W_itemModalities", "ok": "d7lz0W_ok", "select": "d7lz0W_select", "block": "d7lz0W_block", "number": "d7lz0W_number" };
474
458
 
475
459
  // src/client/Section.tsx
476
460
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -651,7 +635,7 @@ var SectionController = class {
651
635
  this.set({ saving: false });
652
636
  }
653
637
  }
654
- /** Narrow or reorder the model table; a view preference, never a write. */
638
+ /** Narrow or reorder the model list; a view preference, never a write. */
655
639
  setFilter(patch) {
656
640
  this.set({ filter: { ...this.state.filter, ...patch } });
657
641
  }
@@ -918,7 +902,6 @@ function Section({ controller, t, getLocale }) {
918
902
  ] }),
919
903
  reading !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: section_default.list, children: rows.map((model) => {
920
904
  const badge = badgeFor(model, t);
921
- const capabilities = capabilityLabels(model, t).join(" \xB7 ");
922
905
  const modalities = inputModalityLabels(model, t).join(" \xB7 ");
923
906
  const offered = isOffered(model, visibility);
924
907
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.item, children: [
@@ -939,7 +922,6 @@ function Section({ controller, t, getLocale }) {
939
922
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.name, children: model.name }),
940
923
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.mono, children: model.id }),
941
924
  model.releaseDate !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.hint, children: model.releaseDate }),
942
- capabilities.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.badge, children: capabilities }),
943
925
  badge.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.badge, children: badge })
944
926
  ] }),
945
927
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.itemMeta, children: [
@@ -968,7 +950,7 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]"
968
950
  style.textContent = ".mMNkkW_root{align-items:center;display:inline-flex;position:relative}.mMNkkW_trigger{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;white-space:nowrap;border-radius:999px;padding:.35rem .6rem;font-size:.8rem;line-height:1}.mMNkkW_trigger:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2)}.mMNkkW_panel{z-index:20;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-overlay);width:18rem;color:var(--dsw-alias-label-primary);border-radius:.6rem;flex-direction:column;gap:.6rem;padding:.75rem .85rem;display:flex;position:absolute;bottom:calc(100% + .5rem);right:0;box-shadow:0 8px 24px #0000002e}.mMNkkW_window{flex-direction:column;gap:.25rem;display:flex}.mMNkkW_row{justify-content:space-between;gap:.5rem;font-size:.85rem;display:flex}.mMNkkW_hint{color:var(--dsw-alias-label-secondary);margin:0;font-size:.75rem}.mMNkkW_progress{width:100%;height:.35rem;accent-color:var(--dsw-alias-brand-primary)}.mMNkkW_limited{color:var(--dsw-alias-state-warn-primary);font-size:.75rem}.mMNkkW_warning{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-label-primary);border-radius:.4rem;padding:.4rem .5rem;font-size:.75rem}.mMNkkW_retry{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:.35rem;align-self:flex-start;padding:.25rem .5rem;font-size:.75rem}.mMNkkW_local{border-top:1px solid var(--dsw-alias-border-l1);flex-direction:column;gap:.2rem;padding-top:.5rem;display:flex}";
969
951
  document.head.appendChild(style);
970
952
  }
971
- var pill_default = { "progress": "mMNkkW_progress", "root": "mMNkkW_root", "limited": "mMNkkW_limited", "local": "mMNkkW_local", "panel": "mMNkkW_panel", "row": "mMNkkW_row", "retry": "mMNkkW_retry", "trigger": "mMNkkW_trigger", "warning": "mMNkkW_warning", "hint": "mMNkkW_hint", "window": "mMNkkW_window" };
953
+ var pill_default = { "progress": "mMNkkW_progress", "window": "mMNkkW_window", "limited": "mMNkkW_limited", "retry": "mMNkkW_retry", "panel": "mMNkkW_panel", "local": "mMNkkW_local", "hint": "mMNkkW_hint", "warning": "mMNkkW_warning", "trigger": "mMNkkW_trigger", "root": "mMNkkW_root", "row": "mMNkkW_row" };
972
954
 
973
955
  // src/client/UsagePill.tsx
974
956
  var import_jsx_runtime2 = require("react/jsx-runtime");
@@ -1151,7 +1133,11 @@ function apply(ctx) {
1151
1133
  scope.slots.inject("settings.section", () => scope.slots.register({
1152
1134
  name: "settings.section",
1153
1135
  id: "dshopencodego",
1154
- order: 20,
1136
+ // After the product rows. The built-ins run -10 (account) through 20
1137
+ // (agent presets); sharing 20 with `agent-presets` left the pair ordered
1138
+ // by registration timing, which drifts between boots. The host's own
1139
+ // tests use 1000 for "last".
1140
+ order: 1e3,
1155
1141
  label: () => translate("nav"),
1156
1142
  inject: () => ({
1157
1143
  controller,
package/lib/index.js CHANGED
@@ -213,9 +213,6 @@ function positiveInteger(value) {
213
213
  function nonEmptyString(value) {
214
214
  return typeof value === "string" && value.length > 0 ? value : void 0;
215
215
  }
216
- function declaredBoolean(value) {
217
- return typeof value === "boolean" ? value : void 0;
218
- }
219
216
  function readInputModalities(metadata) {
220
217
  const declared = record(metadata["modalities"])["input"];
221
218
  if (!Array.isArray(declared)) return void 0;
@@ -354,9 +351,6 @@ function readOnlineMetadata(body, sources) {
354
351
  inputModalities: readInputModalities(metadata),
355
352
  reasoning,
356
353
  thinkingLevelMap: reasoning ? thinkingLevels(metadata, exact?.api === api ? exact : sibling) : void 0,
357
- structuredOutput: declaredBoolean(metadata["structured_output"]),
358
- temperature: declaredBoolean(metadata["temperature"]),
359
- openWeights: declaredBoolean(metadata["open_weights"]),
360
354
  compat: compatFor(api, metadata, exact, sibling),
361
355
  cost,
362
356
  deprecated: metadata["status"] === "deprecated",
@@ -551,11 +545,6 @@ var OpencodeGoCatalog = class {
551
545
  inputModalities: void 0,
552
546
  reasoning: exact?.reasoning ?? false,
553
547
  thinkingLevelMap: exact?.thinkingLevelMap,
554
- // No source describes these, so the page says nothing instead of
555
- // guessing: the installed catalog knows wire shapes, not capabilities.
556
- structuredOutput: void 0,
557
- temperature: void 0,
558
- openWeights: void 0,
559
548
  compat: exact?.compat ?? {},
560
549
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
561
550
  deprecated: false,
@@ -1539,9 +1528,6 @@ function parseModel(value) {
1539
1528
  ...row["protocolSource"] === "builtin" || row["protocolSource"] === "online" || row["protocolSource"] === "inferred" || row["protocolSource"] === "override" ? { protocolSource: row["protocolSource"] } : {},
1540
1529
  ...typeof row["assumedLimits"] === "boolean" ? { assumedLimits: row["assumedLimits"] } : {},
1541
1530
  ...parseModalities(row["inputModalities"]),
1542
- ...typeof row["structuredOutput"] === "boolean" ? { structuredOutput: row["structuredOutput"] } : {},
1543
- ...typeof row["temperature"] === "boolean" ? { temperature: row["temperature"] } : {},
1544
- ...typeof row["openWeights"] === "boolean" ? { openWeights: row["openWeights"] } : {},
1545
1531
  ...typeof row["configurationMissing"] === "string" ? { configurationMissing: row["configurationMissing"] } : {}
1546
1532
  };
1547
1533
  }
@@ -1732,10 +1718,7 @@ function catalogReading(snapshot, visibility, listingFailure) {
1732
1718
  },
1733
1719
  protocolSource: fact.protocolSource,
1734
1720
  assumedLimits: fact.assumedLimits,
1735
- ...fact.structuredOutput === void 0 ? {} : { structuredOutput: fact.structuredOutput },
1736
- ...fact.inputModalities === void 0 ? {} : { inputModalities: fact.inputModalities },
1737
- ...fact.temperature === void 0 ? {} : { temperature: fact.temperature },
1738
- ...fact.openWeights === void 0 ? {} : { openWeights: fact.openWeights }
1721
+ ...fact.inputModalities === void 0 ? {} : { inputModalities: fact.inputModalities }
1739
1722
  };
1740
1723
  }),
1741
1724
  ...[...snapshot.unavailable].map(([id, reason]) => ({ id, name: id, configurationMissing: reason }))
@@ -73,9 +73,6 @@ function parseModel(value) {
73
73
  ? { protocolSource: row['protocolSource'] } : {},
74
74
  ...typeof row['assumedLimits'] === 'boolean' ? { assumedLimits: row['assumedLimits'] } : {},
75
75
  ...parseModalities(row['inputModalities']),
76
- ...typeof row['structuredOutput'] === 'boolean' ? { structuredOutput: row['structuredOutput'] } : {},
77
- ...typeof row['temperature'] === 'boolean' ? { temperature: row['temperature'] } : {},
78
- ...typeof row['openWeights'] === 'boolean' ? { openWeights: row['openWeights'] } : {},
79
76
  ...typeof row['configurationMissing'] === 'string' ? { configurationMissing: row['configurationMissing'] } : {},
80
77
  };
81
78
  }
@@ -209,11 +209,6 @@ export class OpencodeGoCatalog {
209
209
  inputModalities: undefined,
210
210
  reasoning: exact?.reasoning ?? false,
211
211
  thinkingLevelMap: exact?.thinkingLevelMap,
212
- // No source describes these, so the page says nothing instead of
213
- // guessing: the installed catalog knows wire shapes, not capabilities.
214
- structuredOutput: undefined,
215
- temperature: undefined,
216
- openWeights: undefined,
217
212
  compat: exact?.compat ?? {},
218
213
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
219
214
  deprecated: false,
@@ -44,14 +44,6 @@ export interface ModelFacts {
44
44
  readonly inputModalities: readonly InputModality[] | undefined;
45
45
  readonly reasoning: boolean;
46
46
  readonly thinkingLevelMap: ThinkingLevelMap | undefined;
47
- /**
48
- * Declared capability facts, exactly as models.dev states them. `undefined`
49
- * means the document says nothing about the capability, which is not the
50
- * same answer as `false` and must never be rendered as "unsupported".
51
- */
52
- readonly structuredOutput: boolean | undefined;
53
- readonly temperature: boolean | undefined;
54
- readonly openWeights: boolean | undefined;
55
47
  readonly compat: Model<Api>['compat'];
56
48
  readonly cost: ModelCost;
57
49
  readonly deprecated: boolean;
@@ -29,10 +29,6 @@ function positiveInteger(value) {
29
29
  function nonEmptyString(value) {
30
30
  return typeof value === 'string' && value.length > 0 ? value : undefined;
31
31
  }
32
- /** A capability the document states as yes or no; silence stays silence. */
33
- function declaredBoolean(value) {
34
- return typeof value === 'boolean' ? value : undefined;
35
- }
36
32
  /**
37
33
  * Input modalities exactly as the document declares them, in display order.
38
34
  *
@@ -245,9 +241,6 @@ export function readOnlineMetadata(body, sources) {
245
241
  inputModalities: readInputModalities(metadata),
246
242
  reasoning,
247
243
  thinkingLevelMap: reasoning ? thinkingLevels(metadata, exact?.api === api ? exact : sibling) : undefined,
248
- structuredOutput: declaredBoolean(metadata['structured_output']),
249
- temperature: declaredBoolean(metadata['temperature']),
250
- openWeights: declaredBoolean(metadata['open_weights']),
251
244
  compat: compatFor(api, metadata, exact, sibling),
252
245
  cost,
253
246
  deprecated: metadata['status'] === 'deprecated',
@@ -43,10 +43,7 @@ export function catalogReading(snapshot, visibility, listingFailure) {
43
43
  },
44
44
  protocolSource: fact.protocolSource,
45
45
  assumedLimits: fact.assumedLimits,
46
- ...fact.structuredOutput === undefined ? {} : { structuredOutput: fact.structuredOutput },
47
46
  ...fact.inputModalities === undefined ? {} : { inputModalities: fact.inputModalities },
48
- ...fact.temperature === undefined ? {} : { temperature: fact.temperature },
49
- ...fact.openWeights === undefined ? {} : { openWeights: fact.openWeights },
50
47
  };
51
48
  }),
52
49
  ...[...snapshot.unavailable].map(([id, reason]) => ({ id, name: id, configurationMissing: reason })),
@@ -77,8 +77,13 @@ export interface OpencodeGoConfig {
77
77
  */
78
78
  retryPolicy?: RetryPolicyConfig;
79
79
  }
80
- /** Plain resolved values used by the adapter. */
81
- export declare const PlainConfig: z<OpencodeGoConfig>;
80
+ /**
81
+ * Plain resolved values used by the adapter.
82
+ *
83
+ * The input side is a partial on purpose: a profile writes only the fields it
84
+ * overrides, and the schema's own defaults fill the rest.
85
+ */
86
+ export declare const PlainConfig: z<Partial<OpencodeGoConfig>, OpencodeGoConfig>;
82
87
  /** 0.1.7's Loader retains these references when profile fields change. */
83
88
  export type LiveConfig = {
84
89
  [K in keyof OpencodeGoConfig]-?: {
@@ -44,7 +44,12 @@ const fields = {
44
44
  modelProtocols: z.dict(z.string()).default({}),
45
45
  retryPolicy: RetryPolicySchema,
46
46
  };
47
- /** Plain resolved values used by the adapter. */
47
+ /**
48
+ * Plain resolved values used by the adapter.
49
+ *
50
+ * The input side is a partial on purpose: a profile writes only the fields it
51
+ * overrides, and the schema's own defaults fill the rest.
52
+ */
48
53
  export const PlainConfig = z.object(fields);
49
54
  /** Runtime schema for {@link OpencodeGoConfig}; every field stays live. */
50
55
  export const Config = z.object(Object.fromEntries(Object.entries(fields).map(([key, schema]) => [key, schema.volatile()])));
@@ -42,14 +42,6 @@ export interface ModelSummary {
42
42
  * document declares none this build can name.
43
43
  */
44
44
  readonly inputModalities?: readonly InputModality[];
45
- /**
46
- * Capabilities models.dev declares, in its own words. Each is absent when the
47
- * document is silent about it — absence is "unstated", never "unsupported",
48
- * so the page leaves the cell empty instead of showing a negative.
49
- */
50
- readonly structuredOutput?: boolean;
51
- readonly temperature?: boolean;
52
- readonly openWeights?: boolean;
53
45
  /** True when a capacity came from the route default rather than a source. */
54
46
  readonly assumedLimits?: boolean;
55
47
  /** Advertised by the gateway but not configurable, with the reason. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dan-ai-studio/dshopencodego",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "OpenCode Go provider for DeepSeek Harness: live gateway catalog, per-conversation session header, usage",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -55,8 +55,9 @@
55
55
  },
56
56
  "scripts": {
57
57
  "build": "node scripts/build.mjs",
58
- "typecheck": "tsc -p tsconfig.host.json --noEmit && tsc -p tsconfig.client.json --noEmit",
58
+ "typecheck": "tsc -p tsconfig.host.json --noEmit && tsc -p tsconfig.client.json --noEmit && tsc -p tsconfig.tests.json --noEmit",
59
59
  "test": "vitest run",
60
+ "test:coverage": "vitest run --coverage",
60
61
  "test:watch": "vitest",
61
62
  "prepare": "npm run build",
62
63
  "prepack": "npm run build"
@@ -130,6 +131,7 @@
130
131
  "@types/node": "^22.20.0",
131
132
  "@types/react": "~18.3.1",
132
133
  "@types/react-dom": "~18.3.0",
134
+ "@vitest/coverage-v8": "^4.1.11",
133
135
  "esbuild": "^0.28.2",
134
136
  "jsdom": "^29.0.0",
135
137
  "lightningcss": "^1.32.0",