openzoo 0.49.17 → 0.49.18

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.
Files changed (2) hide show
  1. package/lib/openclaw.js +38 -5
  2. package/package.json +1 -1
package/lib/openclaw.js CHANGED
@@ -133,7 +133,13 @@ async function fetchCatalogRows() {
133
133
  const r = await fetchHeaders(`${config.apiBase}/v1/models`);
134
134
  if (!r.ok) throw new Error(`model catalog fetch failed: HTTP ${r.status}`);
135
135
  const d = await r.json();
136
- return quoteableRows(d.data).filter((m) => !isAutoModel(m.id));
136
+ // AUTO STAYS IN THE CATALOG. It used to be stripped here, which made it
137
+ // unreachable by EVERY route — `--models openzoo/auto` failed with "not in
138
+ // the live catalog", and OpenClaw refused a hand-edited config with
139
+ // `model not allowed: openzoo/auto`. The price objection below is about the
140
+ // cost BLOCK, and the answer to that is to quote a ceiling, not to delete
141
+ // the router we tell people to use.
142
+ return quoteableRows(d.data);
137
143
  }
138
144
 
139
145
  function pickRows(rows, { all, wanted }) {
@@ -146,10 +152,25 @@ function pickRows(rows, { all, wanted }) {
146
152
  return wanted.map((id) => byId.get(id));
147
153
  }
148
154
  if (all) return rows;
149
- // Short honest default: same flagship picker Claude Code gets, minus Auto
150
- // (Auto's price varies per route — a fixed cost block would be a lie).
151
- const picked = pickClaudePickerRows(rows).filter((m) => !isAutoModel(m.id));
152
- return picked.length ? picked : rows.slice(0, 8);
155
+ // Same flagship picker Claude Code gets, WITH Auto pinned first.
156
+ //
157
+ // Auto's price genuinely varies per route, so no fixed cost block is exact.
158
+ // But omitting it entirely is the worse lie: it tells the harness the router
159
+ // does not exist. The command already prints "prices are the CEILING
160
+ // (openrouter-direct)" over every row it writes, and a ceiling is precisely
161
+ // what an upper bound across the picked set is — see the cost fix-up in
162
+ // setupOpenClaw.
163
+ const picked = pickClaudePickerRows(rows);
164
+ const withoutAuto = picked.filter((m) => !isAutoModel(m.id));
165
+ // PREFER THE BARE `auto` ID. The catalog offers `auto`, `openzoo/auto` and
166
+ // `openzoo-auto` for the same router. OpenClaw renders a model as
167
+ // `<provider>/<id>` and our provider key is already `openzoo`, so taking the
168
+ // prefixed row writes `openzoo/openzoo/auto` — which is not the string the
169
+ // user types and OpenClaw rejects it as "model not allowed".
170
+ const autos = rows.filter((m) => isAutoModel(m.id));
171
+ const auto = autos.find((m) => m.id === "auto") ?? autos[0];
172
+ const ordered = auto ? [auto, ...withoutAuto] : withoutAuto;
173
+ return ordered.length ? ordered : rows.slice(0, 8);
153
174
  }
154
175
 
155
176
  /**
@@ -170,6 +191,18 @@ export async function setupOpenClaw(argv = []) {
170
191
  const rows = pickRows(await fetchCatalogRows(), opt);
171
192
  if (!rows.length) throw new Error('live catalog returned no quoteable models');
172
193
  const entries = rows.map(openclawModelEntry);
194
+ // AUTO IS PRICED AT THE CEILING OF WHAT IT CAN ROUTE TO. Its own catalog row
195
+ // carries no usable price (the route is chosen per request), and a zero there
196
+ // reads to a budgeting harness as "free", which is the one number guaranteed
197
+ // wrong. The max across everything written alongside it cannot be exceeded by
198
+ // any route Auto picks from that set, so it over-states and never under-states.
199
+ const autoEntry = entries.find((e) => isAutoModel(e.id));
200
+ if (autoEntry) {
201
+ const others = entries.filter((e) => e !== autoEntry);
202
+ const ceil = (k) => others.reduce((m, e) => Math.max(m, Number(e.cost?.[k]) || 0), 0);
203
+ autoEntry.cost = { input: ceil("input"), output: ceil("output"), cacheRead: 0, cacheWrite: 0 };
204
+ }
205
+ // Auto is written first, so it is also the default unless overridden.
173
206
  const defaultId = opt.defaultId || entries[0].id;
174
207
  if (!entries.some((e) => e.id === defaultId)) {
175
208
  throw new Error(`--default ${defaultId} is not among the written models (add it via --models)`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openzoo",
3
- "version": "0.49.17",
3
+ "version": "0.49.18",
4
4
  "description": "Local x402-paying proxy + MCP server for openzoo.fun \u2014 point any OpenAI-compatible harness (Cursor, Claude Code, aider, SDKs) at localhost and it pays per call from a local burner wallet. Solana and Base rails live; Robinhood experimental.",
5
5
  "license": "MIT",
6
6
  "type": "module",