@dan-ai-studio/dshopencodego 0.1.33 → 0.1.35

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
@@ -161,7 +161,7 @@ The "OpenCode Go" section shows the live gateway catalog (the count follows the
161
161
  - any mismatch → **that plugin row is disabled with a printed reason** (`Plugin … is incompatible with dsh …`), leaving other plugins untouched;
162
162
  - to take the risk anyway, grant an **exact-version exemption**: `dsh plugin --profile <profile> allow-version <pkg>@<version> --dsh-version <exact> --accept-risk` (applies only to that package and that exact runtime version); `dsh plugin --profile <profile> version-exemptions` lists what a profile holds.
163
163
 
164
- The `engines.dsh` field is informational for readers and package managers; **DSH's compatibility gate reads only `peerDependencies`**. `@deepseek-ai/cordis` is declared separately as `4.0.2 || 4.0.3 || 4.0.4`.
164
+ The `engines.dsh` field is informational for readers and package managers; **DSH's compatibility gate reads only `peerDependencies`**. `@deepseek-ai/cordis` is declared separately as `4.0.2 || 4.0.3 || 4.0.4 || 4.0.5-alpha.1 || 4.0.5-alpha.2` (the latter two cover the runtime DSH `0.2.1-alpha.3` and later use).
165
165
 
166
166
  **Outside the declared range**: releases before `0.1.7-alpha.1`, the never-published gap `>=0.1.8 <0.2.0-rc.1`, and `0.3.0+` are refused. If the seam is compatible, widen the peer range in your own build (never in DSH core), or wait for a plugin release.
167
167
 
@@ -170,11 +170,11 @@ The `engines.dsh` field is informational for readers and package managers; **DSH
170
170
  | Binding layer | Declared | Enforced by |
171
171
  | --- | --- | --- |
172
172
  | `peerDependencies` (17 `@deepseek-ai/dsh-*` packages) | all `>=0.1.7-alpha.1 <0.2.0 \|\| >=0.2.0-rc.1 <0.3.0` | **DSH's gate, at plugin load time** |
173
- | `@deepseek-ai/cordis` | `4.0.2 \|\| 4.0.3 \|\| 4.0.4` | the same gate |
174
- | `engines.dsh` | `>=0.1.7-alpha.1 <0.2.0 \|\| >=0.2.0-rc.1 <0.3.0` | informational only; DSH never reads it |
173
+ | `@deepseek-ai/cordis` | `4.0.2 \|\| 4.0.3 \|\| 4.0.4 \|\| 4.0.5-alpha.1 \|\| 4.0.5-alpha.2` | the same gate |
174
+ | `engines.dsh` | `>=0.1.7-alpha.1 <0.2.0 \|\| >=0.2.0-rc.1 <0.2.1 \|\| >=0.2.1-alpha.1 <0.3.0` | informational only; DSH never reads it |
175
175
  | `engines.node` | `^22.19.0 \|\| >=24.0.0` | the package manager |
176
- | bundled `@earendil-works/pi-ai` | pinned to exactly `0.87.1` | an independent coupling: a change in pi-ai's request construction changes this plugin's wire behaviour |
177
- | bundled `@deepseek-ai/schemastery` | `^3.18.3` | ordinary semver |
176
+ | bundled `@earendil-works/pi-ai` | patch-level range `~1.3.0` (within 1.3.x) | an independent coupling: a change in pi-ai's request construction changes this plugin's wire behaviour, and its builtin catalog is this plugin's fallback data |
177
+ | bundled `@deepseek-ai/schemastery` | `~3.18.5-alpha.2` | kept in step with `dsh-settings`'s peer |
178
178
 
179
179
  Things to keep in mind when maintaining this:
180
180
 
@@ -196,7 +196,7 @@ Things to keep in mind when maintaining this:
196
196
  | "The settings write was rejected" | Usually a concurrent writer (another window or process) holding the same profile. The plugin retries once automatically; if it still fails the view has reloaded — click again. |
197
197
  | The usage button shows "unavailable" | An endpoint or credential change invalidated the previous reading. Fix the configuration and press Retry. It never shows `0` in place of a missing reading. |
198
198
  | npm publish fails with `ENEEDAUTH` | OIDC did not match: check the Trusted Publisher's **workflow filename** (must be exactly `publish-npm.yml`, case-sensitive) and the organization/repository fields; run on GitHub-hosted runners with `id-token: write`. A `repository.url` that does not match the GitHub repository is rejected as well. |
199
- | The whole DSH process stalls during ultra-long tool calls (multi-MB arguments) | Inherent to pi-ai 0.87.1's per-delta re-parsing (issue #9265 / PR #9461). This plugin does not port DSH's consumer-side patch (ADR-0005); the fix arrives with an upstream release and a pi-ai upgrade. |
199
+ | The whole DSH process stalls during ultra-long tool calls (multi-MB arguments) | Observed on pi-ai `0.87.1`: per-delta re-parsing of the accumulated arguments (issue #9265 / PR #9461). This plugin does not port DSH's consumer-side patch (ADR-0005); the bundled dependency is now `~1.3.0`, so a recurrence would be upstream behaviour and would be fixed by an upstream release. |
200
200
 
201
201
  ## Development
202
202
 
package/README.md CHANGED
@@ -161,7 +161,7 @@ API Key 通过 Harness 凭证库提供(引用名 `OPENCODE_GO_API_KEY`),
161
161
  - 任一不满足 → **该插件行被禁用并打印原因**(`Plugin … is incompatible with dsh …`),其他插件不受影响;
162
162
  - 需要冒险时可用**精确版本豁免**:`dsh plugin --profile <profile> allow-version <包>@<版本> --dsh-version <精确版本> --accept-risk`(只对该包与该精确版本生效);`dsh plugin --profile <profile> version-exemptions` 可列出当前 profile 的豁免。
163
163
 
164
- `package.json` 里的 `engines.dsh` 是本插件为读者/包管理器写的信息字段;**DSH 的兼容门禁只读 `peerDependencies`**,请以它为准。`@deepseek-ai/cordis` 单独声明为 `4.0.2 || 4.0.3 || 4.0.4`。
164
+ `package.json` 里的 `engines.dsh` 是本插件为读者/包管理器写的信息字段;**DSH 的兼容门禁只读 `peerDependencies`**,请以它为准。`@deepseek-ai/cordis` 单独声明为 `4.0.2 || 4.0.3 || 4.0.4 || 4.0.5-alpha.1 || 4.0.5-alpha.2`(后两个分支对应 DSH `0.2.1-alpha.3` 及之后所用的运行时)。
165
165
 
166
166
  **声明范围之外**:`0.1.7-alpha.1` 之前、`0.1.8`–`0.2.0-rc.1` 之间的空白带、以及 `0.3.0+` 会被拒绝加载。如果 DSH 侧接口兼容,可自行放宽该插件的 peer 范围并重新构建(不改 DSH 核心);否则请等插件跟进发版。
167
167
 
@@ -170,11 +170,11 @@ API Key 通过 Harness 凭证库提供(引用名 `OPENCODE_GO_API_KEY`),
170
170
  | 绑定层 | 声明 | 谁在把关 |
171
171
  | --- | --- | --- |
172
172
  | `peerDependencies`(17 个 `@deepseek-ai/dsh-*`) | 均为 `>=0.1.7-alpha.1 <0.2.0 \|\| >=0.2.0-rc.1 <0.3.0` | **DSH 加载时的真门禁** |
173
- | `@deepseek-ai/cordis` | `4.0.2 \|\| 4.0.3 \|\| 4.0.4` | 同一门禁 |
174
- | `engines.dsh` | `>=0.1.7-alpha.1 <0.2.0 \|\| >=0.2.0-rc.1 <0.3.0` | 仅信息字段,DSH 不读 |
173
+ | `@deepseek-ai/cordis` | `4.0.2 \|\| 4.0.3 \|\| 4.0.4 \|\| 4.0.5-alpha.1 \|\| 4.0.5-alpha.2` | 同一门禁 |
174
+ | `engines.dsh` | `>=0.1.7-alpha.1 <0.2.0 \|\| >=0.2.0-rc.1 <0.2.1 \|\| >=0.2.1-alpha.1 <0.3.0` | 仅信息字段,DSH 不读 |
175
175
  | `engines.node` | `^22.19.0 \|\| >=24.0.0` | 包管理器 |
176
- | 自带依赖 `@earendil-works/pi-ai` | 精确锁 `0.87.1` | 独立耦合:pi-ai 改请求构造即影响本插件的线上行为 |
177
- | 自带依赖 `@deepseek-ai/schemastery` | `^3.18.3` | 常规 semver |
176
+ | 自带依赖 `@earendil-works/pi-ai` | 补丁级范围 `~1.3.0`(1.3.x 内) | 独立耦合:pi-ai 改请求构造即影响本插件的线上行为;其内置目录同时是本插件的打底数据 |
177
+ | 自带依赖 `@deepseek-ai/schemastery` | `~3.18.5-alpha.2` | 与 `dsh-settings` 的 peer 保持一致 |
178
178
 
179
179
  维护时需要注意:
180
180
 
@@ -196,7 +196,7 @@ API Key 通过 Harness 凭证库提供(引用名 `OPENCODE_GO_API_KEY`),
196
196
  | 设置页出现「设置写入被拒绝」 | 通常是与另一个窗口/进程并发写同一 profile;插件会自动重试一次,仍失败时界面已重载最新状态,再点一次即可。 |
197
197
  | 用量按钮显示「不可用」 | 端点或凭证变化导致旧读数作废;配置正确后点「重试」。数值不会以 0 冒充。 |
198
198
  | npm 发布报 `ENEEDAUTH` | OIDC 没匹配上:核对包设置里 Trusted Publisher 的 **workflow 文件名**(必须恰为 `publish-npm.yml`、大小写敏感)与组织/仓库字段;确认跑在 GitHub 托管 runner 上且工作流带 `id-token: write`。`package.json` 的 `repository.url` 与仓库不符也会被拒。 |
199
- | 超长工具调用(多 MB 参数)期间整个 DSH 进程卡顿 | 上游 pi-ai 0.87.1 逐 delta 重解析的固有开销(issue #9265 / PR #9461)。本插件不移植 DSH 的消费者侧补丁(ADR-0005);修复随上游发布后升级 pi-ai 解决。 |
199
+ | 超长工具调用(多 MB 参数)期间整个 DSH 进程卡顿 | 曾在 pi-ai `0.87.1` 上观测到逐 delta 重解析的固有开销(issue #9265 / PR #9461)。本插件不移植 DSH 的消费者侧补丁(ADR-0005);当前自带依赖已是 `~1.3.0`,若仍复现则属上游行为,随其发版解决。 |
200
200
 
201
201
  ## 开发
202
202
 
package/lib/client.js CHANGED
@@ -562,7 +562,7 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id) + "]")
562
562
  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)}";
563
563
  document.head.appendChild(style);
564
564
  }
565
- var section_default = { "title": "d7lz0W_title", "input": "d7lz0W_input", "root": "d7lz0W_root", "select": "d7lz0W_select", "button": "d7lz0W_button", "block": "d7lz0W_block", "hint": "d7lz0W_hint", "list": "d7lz0W_list", "item": "d7lz0W_item", "ok": "d7lz0W_ok", "itemMain": "d7lz0W_itemMain", "itemBody": "d7lz0W_itemBody", "name": "d7lz0W_name", "badge": "d7lz0W_badge", "itemModalities": "d7lz0W_itemModalities", "warn": "d7lz0W_warn", "number": "d7lz0W_number", "mono": "d7lz0W_mono", "itemMeta": "d7lz0W_itemMeta", "row": "d7lz0W_row" };
565
+ var section_default = { "itemMain": "d7lz0W_itemMain", "warn": "d7lz0W_warn", "select": "d7lz0W_select", "mono": "d7lz0W_mono", "title": "d7lz0W_title", "block": "d7lz0W_block", "hint": "d7lz0W_hint", "row": "d7lz0W_row", "itemModalities": "d7lz0W_itemModalities", "button": "d7lz0W_button", "ok": "d7lz0W_ok", "number": "d7lz0W_number", "list": "d7lz0W_list", "item": "d7lz0W_item", "itemBody": "d7lz0W_itemBody", "root": "d7lz0W_root", "input": "d7lz0W_input", "itemMeta": "d7lz0W_itemMeta", "name": "d7lz0W_name", "badge": "d7lz0W_badge" };
566
566
 
567
567
  // src/client/Section.tsx
568
568
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -1335,7 +1335,7 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]"
1335
1335
  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}";
1336
1336
  document.head.appendChild(style);
1337
1337
  }
1338
- var pill_default = { "limited": "mMNkkW_limited", "warning": "mMNkkW_warning", "root": "mMNkkW_root", "window": "mMNkkW_window", "progress": "mMNkkW_progress", "panel": "mMNkkW_panel", "row": "mMNkkW_row", "hint": "mMNkkW_hint", "trigger": "mMNkkW_trigger", "retry": "mMNkkW_retry", "local": "mMNkkW_local" };
1338
+ var pill_default = { "warning": "mMNkkW_warning", "local": "mMNkkW_local", "retry": "mMNkkW_retry", "trigger": "mMNkkW_trigger", "root": "mMNkkW_root", "panel": "mMNkkW_panel", "window": "mMNkkW_window", "hint": "mMNkkW_hint", "row": "mMNkkW_row", "progress": "mMNkkW_progress", "limited": "mMNkkW_limited" };
1339
1339
 
1340
1340
  // src/client/UsagePill.tsx
1341
1341
  var import_jsx_runtime2 = require("react/jsx-runtime");
@@ -1515,6 +1515,9 @@ function apply(ctx) {
1515
1515
  });
1516
1516
  scope.inject(["remote.pluginManager"], (managerScope) => {
1517
1517
  pluginManager.current = managerScope.remote.pluginManager;
1518
+ return () => {
1519
+ pluginManager.current = void 0;
1520
+ };
1518
1521
  });
1519
1522
  const translate = scope.locale.bind(NS);
1520
1523
  scope.effect(() => () => {
package/lib/index.js CHANGED
@@ -421,7 +421,13 @@ function readOnlineMetadata(body, sources) {
421
421
  throw new Error(`configured protocol "${sources.overrides[id]}" is not one of anthropic-messages, openai-completions, openai-responses`);
422
422
  }
423
423
  const decision = decideProtocol(id, {
424
- ...exact?.api === void 0 ? {} : { builtin: exact.api },
424
+ // Guarded, not asserted: pi-ai's builtin catalog is wider than this
425
+ // plugin's three protocols — 1.3.0 labels `gemini-4-argon-contributor`
426
+ // as `google-generative-ai`. Casting it straight to `WireProtocol`
427
+ // let an unimplementable protocol enter as `builtin`, the most
428
+ // trustworthy source, and the model then failed only once a stream
429
+ // was attempted.
430
+ ...asWireProtocol(exact?.api) === void 0 ? {} : { builtin: asWireProtocol(exact?.api) },
425
431
  ...protocolOfNpm(metadata["provider"] === void 0 ? providerNpm : record(metadata["provider"])["npm"] ?? providerNpm) === void 0 ? {} : { online: protocolOfNpm(record(metadata["provider"])["npm"] ?? providerNpm) },
426
432
  ...override === void 0 ? {} : { override }
427
433
  });
@@ -511,6 +517,9 @@ function harnessApiKeyAuth() {
511
517
  }
512
518
  };
513
519
  }
520
+ function unsupportedBuiltinApi(api) {
521
+ return api === void 0 || asWireProtocol(api) !== void 0 ? void 0 : api;
522
+ }
514
523
  function buildProvider(baseURL, models) {
515
524
  return createProvider({
516
525
  id: PROVIDER_ID,
@@ -638,6 +647,11 @@ var OpencodeGoCatalog = class {
638
647
  unavailable.set(id, reason);
639
648
  continue;
640
649
  }
650
+ const unsupported = unsupportedBuiltinApi(builtin.get(id)?.api);
651
+ if (unsupported !== void 0) {
652
+ unavailable.set(id, `its wire protocol "${unsupported}" is not implemented by this plugin`);
653
+ continue;
654
+ }
641
655
  facts.set(id, this.withDocumentedProtocol(this.inferredFacts(id, builtin)));
642
656
  }
643
657
  if (unavailable.size > 0) {
@@ -675,14 +689,15 @@ var OpencodeGoCatalog = class {
675
689
  /** Facts for an id no source describes, from the ladder and the route defaults. */
676
690
  inferredFacts(id, builtin) {
677
691
  const exact = builtin.get(id);
678
- const api = exact?.api ?? inferFamily(id);
692
+ const builtinApi = asWireProtocol(exact?.api);
693
+ const api = builtinApi ?? inferFamily(id);
679
694
  const contextWindow = exact !== void 0 ? exact.contextWindow : this.options.defaults.contextWindow;
680
695
  const maxTokens = exact !== void 0 ? exact.maxTokens : this.options.defaults.maxTokens;
681
696
  return {
682
697
  id,
683
698
  name: exact?.name ?? id,
684
699
  api,
685
- protocolSource: exact === void 0 ? "inferred" : "builtin",
700
+ protocolSource: builtinApi === void 0 ? "inferred" : "builtin",
686
701
  contextWindow,
687
702
  maxInputTokens: void 0,
688
703
  maxTokens,
@@ -2083,7 +2098,7 @@ function createUpdateChecker(deps) {
2083
2098
  }
2084
2099
 
2085
2100
  // src/update/version.ts
2086
- var PLUGIN_VERSION = true ? "0.1.33" : "0.0.0-dev";
2101
+ var PLUGIN_VERSION = true ? "0.1.35" : "0.0.0-dev";
2087
2102
 
2088
2103
  // src/update/service.ts
2089
2104
  import { TypertRemoteService as TypertRemoteService2 } from "@deepseek-ai/dsh-typert-protocol";
@@ -29,6 +29,7 @@ import { fetchModelIds } from "./gateway.js";
29
29
  import { fetchGoDocument, GO_DOC_URLS } from "./go-doc.js";
30
30
  import { readBoundedJson } from "./json-response.js";
31
31
  import { readOnlineMetadata, toPiModel } from "./metadata.js";
32
+ import { asWireProtocol } from "./protocol.js";
32
33
  export { PROVIDER_ID, DISPLAY_NAME, DEFAULT_BASE_URL, CONSOLE_BASE_URL } from "./constants.js";
33
34
  export { readModelIds, fetchModelIds } from "./gateway.js";
34
35
  export { readOnlineMetadata, toPiModel, modelBaseURL } from "./metadata.js";
@@ -59,6 +60,18 @@ function harnessApiKeyAuth() {
59
60
  },
60
61
  };
61
62
  }
63
+ /**
64
+ * The installed catalog's protocol, when this plugin cannot serve it.
65
+ *
66
+ * `Model<Api>['api']` is pi-ai's wider union; this plugin mounts exactly the
67
+ * three in `WIRE_PROTOCOLS`. The check exists because the catalog is wider
68
+ * than the plugin and grows on its own release cadence.
69
+ * @param api - the raw `api` string the installed catalog states.
70
+ * @returns the unusable protocol, or undefined when there is nothing to refuse.
71
+ */
72
+ function unsupportedBuiltinApi(api) {
73
+ return api === undefined || asWireProtocol(api) !== undefined ? undefined : api;
74
+ }
62
75
  function buildProvider(baseURL, models) {
63
76
  return createProvider({
64
77
  id: PROVIDER_ID,
@@ -205,6 +218,18 @@ export class OpencodeGoCatalog {
205
218
  unavailable.set(id, reason);
206
219
  continue;
207
220
  }
221
+ // The installed catalog may name a protocol this plugin cannot mount.
222
+ // pi-ai 1.3.0 labels `gemini-4-argon-contributor` as
223
+ // `google-generative-ai`, which `buildProvider` has no entry for, and
224
+ // the string used to reach the model list through an unchecked cast.
225
+ // Listing it as usable would defer the failure to the first stream —
226
+ // the one outcome this plugin refuses to ship — so it is refused here,
227
+ // exactly like a malformed record.
228
+ const unsupported = unsupportedBuiltinApi(builtin.get(id)?.api);
229
+ if (unsupported !== undefined) {
230
+ unavailable.set(id, `its wire protocol "${unsupported}" is not implemented by this plugin`);
231
+ continue;
232
+ }
208
233
  // No source describes this id. The gateway's own provider default
209
234
  // (`@ai-sdk/openai-compatible`) makes Chat Completions the best available
210
235
  // guess, and the route defaults size it; the settings surface marks it as
@@ -245,14 +270,17 @@ export class OpencodeGoCatalog {
245
270
  /** Facts for an id no source describes, from the ladder and the route defaults. */
246
271
  inferredFacts(id, builtin) {
247
272
  const exact = builtin.get(id);
248
- const api = exact?.api ?? inferFamily(id);
273
+ // Guarded for the same reason `assemble` refuses these ids up front: the
274
+ // installed catalog states protocols this plugin cannot mount.
275
+ const builtinApi = asWireProtocol(exact?.api);
276
+ const api = builtinApi ?? inferFamily(id);
249
277
  const contextWindow = exact !== undefined ? exact.contextWindow : this.options.defaults.contextWindow;
250
278
  const maxTokens = exact !== undefined ? exact.maxTokens : this.options.defaults.maxTokens;
251
279
  return {
252
280
  id,
253
281
  name: exact?.name ?? id,
254
282
  api,
255
- protocolSource: exact === undefined ? 'inferred' : 'builtin',
283
+ protocolSource: builtinApi === undefined ? 'inferred' : 'builtin',
256
284
  contextWindow,
257
285
  maxInputTokens: undefined,
258
286
  maxTokens,
@@ -188,7 +188,13 @@ export function readOnlineMetadata(body, sources) {
188
188
  throw new Error(`configured protocol "${sources.overrides[id]}" is not one of anthropic-messages, openai-completions, openai-responses`);
189
189
  }
190
190
  const decision = decideProtocol(id, {
191
- ...exact?.api === undefined ? {} : { builtin: exact.api },
191
+ // Guarded, not asserted: pi-ai's builtin catalog is wider than this
192
+ // plugin's three protocols — 1.3.0 labels `gemini-4-argon-contributor`
193
+ // as `google-generative-ai`. Casting it straight to `WireProtocol`
194
+ // let an unimplementable protocol enter as `builtin`, the most
195
+ // trustworthy source, and the model then failed only once a stream
196
+ // was attempted.
197
+ ...asWireProtocol(exact?.api) === undefined ? {} : { builtin: asWireProtocol(exact?.api) },
192
198
  ...protocolOfNpm(metadata['provider'] === undefined ? providerNpm : record(metadata['provider'])['npm'] ?? providerNpm) === undefined
193
199
  ? {}
194
200
  : { online: protocolOfNpm(record(metadata['provider'])['npm'] ?? providerNpm) },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dan-ai-studio/dshopencodego",
3
- "version": "0.1.33",
3
+ "version": "0.1.35",
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",
@@ -68,7 +68,7 @@
68
68
  },
69
69
  "dependencies": {
70
70
  "@deepseek-ai/schemastery": "~3.18.5-alpha.2",
71
- "@earendil-works/pi-ai": "~1.0.2"
71
+ "@earendil-works/pi-ai": "~1.3.0"
72
72
  },
73
73
  "peerDependencies": {
74
74
  "@deepseek-ai/cordis": "4.0.2 || 4.0.3 || 4.0.4 || 4.0.5-alpha.1 || 4.0.5-alpha.2",
@@ -112,27 +112,27 @@
112
112
  },
113
113
  "devDependencies": {
114
114
  "@deepseek-ai/cordis": "4.0.5-alpha.2",
115
- "@deepseek-ai/dsh-api-remotes": "0.2.1-alpha.4",
116
- "@deepseek-ai/dsh-attachment": "0.2.1-alpha.4",
117
- "@deepseek-ai/dsh-brand": "0.2.1-alpha.4",
118
- "@deepseek-ai/dsh-client-locale": "0.2.1-alpha.4",
119
- "@deepseek-ai/dsh-client-store": "0.2.1-alpha.4",
120
- "@deepseek-ai/dsh-client-ui-conversation": "0.2.1-alpha.4",
121
- "@deepseek-ai/dsh-client-ui-model-selection": "0.2.1-alpha.4",
122
- "@deepseek-ai/dsh-client-ui-renderer": "0.2.1-alpha.4",
123
- "@deepseek-ai/dsh-client-ui-settings": "0.2.1-alpha.4",
124
- "@deepseek-ai/dsh-client-ui-slots": "0.2.1-alpha.4",
125
- "@deepseek-ai/dsh-credentials": "0.2.1-alpha.4",
126
- "@deepseek-ai/dsh-fs": "0.2.1-alpha.4",
127
- "@deepseek-ai/dsh-launch-environment": "0.2.1-alpha.4",
128
- "@deepseek-ai/dsh-llm": "0.2.1-alpha.4",
129
- "@deepseek-ai/dsh-sandbox": "0.2.1-alpha.4",
130
- "@deepseek-ai/dsh-scope": "0.2.1-alpha.4",
131
- "@deepseek-ai/dsh-session": "0.2.1-alpha.4",
132
- "@deepseek-ai/dsh-settings": "0.2.1-alpha.4",
133
- "@deepseek-ai/dsh-timeout": "0.2.1-alpha.4",
134
- "@deepseek-ai/dsh-typert-protocol": "0.2.1-alpha.4",
135
- "@deepseek-ai/dsh-typert-registry": "0.2.1-alpha.4",
115
+ "@deepseek-ai/dsh-api-remotes": "0.2.1-alpha.5",
116
+ "@deepseek-ai/dsh-attachment": "0.2.1-alpha.5",
117
+ "@deepseek-ai/dsh-brand": "0.2.1-alpha.5",
118
+ "@deepseek-ai/dsh-client-locale": "0.2.1-alpha.5",
119
+ "@deepseek-ai/dsh-client-store": "0.2.1-alpha.5",
120
+ "@deepseek-ai/dsh-client-ui-conversation": "0.2.1-alpha.5",
121
+ "@deepseek-ai/dsh-client-ui-model-selection": "0.2.1-alpha.5",
122
+ "@deepseek-ai/dsh-client-ui-renderer": "0.2.1-alpha.5",
123
+ "@deepseek-ai/dsh-client-ui-settings": "0.2.1-alpha.5",
124
+ "@deepseek-ai/dsh-client-ui-slots": "0.2.1-alpha.5",
125
+ "@deepseek-ai/dsh-credentials": "0.2.1-alpha.5",
126
+ "@deepseek-ai/dsh-fs": "0.2.1-alpha.5",
127
+ "@deepseek-ai/dsh-launch-environment": "0.2.1-alpha.5",
128
+ "@deepseek-ai/dsh-llm": "0.2.1-alpha.5",
129
+ "@deepseek-ai/dsh-sandbox": "0.2.1-alpha.5",
130
+ "@deepseek-ai/dsh-scope": "0.2.1-alpha.5",
131
+ "@deepseek-ai/dsh-session": "0.2.1-alpha.5",
132
+ "@deepseek-ai/dsh-settings": "0.2.1-alpha.5",
133
+ "@deepseek-ai/dsh-timeout": "0.2.1-alpha.5",
134
+ "@deepseek-ai/dsh-typert-protocol": "0.2.1-alpha.5",
135
+ "@deepseek-ai/dsh-typert-registry": "0.2.1-alpha.5",
136
136
  "@testing-library/dom": "^10.4.1",
137
137
  "@testing-library/react": "^16.3.0",
138
138
  "@types/node": "^22.20.0",