dsh-agy-link 0.4.18 → 0.4.19

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.19 (2026-08-26)
4
+
5
+ - **Fixed: Antigravity Models Missing From the Model Picker (登录成功、额度正常但模型列表为空 — issue #1).**
6
+ - **Root cause**: when `agy models` lists a bare Gemini base alongside its effort variants (the agy 1.1.13 output shape, e.g. `gemini-3.7-flash` + `gemini-3.7-flash-medium`), `foldEfforts` emitted the base id TWICE — once as the folded base entry and once as a verbatim row. DSH's `llm.listModels` contract throws `INVALID_CATALOG` on any duplicate model id, and the host's model-catalog builder then drops the ENTIRE Antigravity provider group from the picker — so login and quota panels looked perfectly healthy while no Antigravity model could be selected.
7
+ - **Fix (three layers)**: (1) `foldEfforts` now absorbs the bare base into its folded entry instead of duplicating it; (2) `parseModelsOutput` dedupes repeated raw slugs (first occurrence wins); (3) `AgyAdapter.listModels` dedupes ids as a final guard, so even a user-configured `fallbackModels` list containing repeats can never nuke the whole group.
8
+ - Regression tests pin both bare-base-plus-variants shapes and the duplicate-slug parse, plus an adapter-level uniqueness guard test.
9
+ - **Observability**: when the adapter-level guard drops duplicate ids it now logs which ids were removed (`model catalog contained duplicate ids [...]`) so field instances surface in DSH server logs instead of being silently masked. When reporting picker issues, attach the `/agy doctor` report (`~/.dsh/agy-link/diagnostics/doctor-*.md`) and the raw `agy models` output.
10
+
3
11
  ## 0.4.18 (2026-08-25)
4
12
 
5
13
  - **Quota Fallback Never Clobbers Good Data (5h=100%/weekly-missing 根因).**
package/dist/index.js CHANGED
@@ -1074,7 +1074,7 @@ function parseModelsOutput(stdout) {
1074
1074
  if (text === "") return [];
1075
1075
  try {
1076
1076
  const list = extractModelList(JSON.parse(text));
1077
- if (list) return list;
1077
+ if (list) return dedupeBySlug(list);
1078
1078
  } catch {}
1079
1079
  const out = [];
1080
1080
  for (const line of text.split(/\n/)) {
@@ -1090,6 +1090,17 @@ function parseModelsOutput(stdout) {
1090
1090
  label: t
1091
1091
  });
1092
1092
  }
1093
+ return dedupeBySlug(out);
1094
+ }
1095
+ /** First occurrence wins: duplicate raw slugs would become duplicate catalog ids. */
1096
+ function dedupeBySlug(raw) {
1097
+ const seen = /* @__PURE__ */ new Set();
1098
+ const out = [];
1099
+ for (const r of raw) {
1100
+ if (seen.has(r.slug)) continue;
1101
+ seen.add(r.slug);
1102
+ out.push(r);
1103
+ }
1093
1104
  return out;
1094
1105
  }
1095
1106
  function extractModelList(parsed) {
@@ -1189,7 +1200,7 @@ function foldEfforts(raw) {
1189
1200
  };
1190
1201
  folded.sort((a, b) => rank(a) - rank(b));
1191
1202
  verbatim.sort((a, b) => rank(a) - rank(b));
1192
- return [...folded, ...verbatim];
1203
+ return [...folded, ...verbatim.filter((e) => !bases.has(e.id))];
1193
1204
  }
1194
1205
  function stripEffortLabel(label, eff) {
1195
1206
  const re = new RegExp("\\s*\\(?" + eff + "\\)?\\s*$", "i");
@@ -2071,12 +2082,25 @@ var AgyAdapter = class extends LlmAdapter {
2071
2082
  }
2072
2083
  async listModels(_provider) {
2073
2084
  this.deps.catalog.refreshIfNeeded();
2074
- return this.deps.catalog.get().models.map((m) => ({
2075
- provider: PROVIDER_ID,
2076
- id: m.id,
2077
- name: m.name,
2078
- inputModalities: ["text", "image"]
2079
- }));
2085
+ const cat = this.deps.catalog.get();
2086
+ const seen = /* @__PURE__ */ new Set();
2087
+ const models = [];
2088
+ const dropped = [];
2089
+ for (const m of cat.models) {
2090
+ if (seen.has(m.id)) {
2091
+ dropped.push(m.id);
2092
+ continue;
2093
+ }
2094
+ seen.add(m.id);
2095
+ models.push({
2096
+ provider: PROVIDER_ID,
2097
+ id: m.id,
2098
+ name: m.name,
2099
+ inputModalities: ["text", "image"]
2100
+ });
2101
+ }
2102
+ if (dropped.length > 0) this.warnOnce("catalog-dupes", "model catalog contained duplicate ids [" + dropped.join(", ") + "] — kept first occurrence so DSH does not drop the whole provider group (INVALID_CATALOG)");
2103
+ return models;
2080
2104
  }
2081
2105
  async resolveModel(_provider, model, _signal) {
2082
2106
  const cfg = this.deps.getConfig();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-agy-link",
3
- "version": "0.4.18",
3
+ "version": "0.4.19",
4
4
  "description": "Google Antigravity (agy CLI) models for DeepSeek Harness — stream Gemini/Claude/GPT-OSS subscriptions into DSH with thinking, tool activity, token usage and in-GUI Google OAuth login.",
5
5
  "type": "module",
6
6
  "license": "MIT",