mirror of
https://github.com/dtzp555-max/ocp.git
synced 2026-07-27 16:05:07 +00:00
a17b6c0ad2b4fcffbebe820da6799c473e270b56
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3dc023e596 |
feat(models): align maxTokens with the CLI registry (#195) (#208)
* feat(models): align maxTokens with the CLI registry (#195)
Every Opus entry and claude-sonnet-5 go 16384 -> 64000; claude-sonnet-4-6 and
claude-haiku-4-5 go to 32000 (haiku was 8192). These are the
max_output_tokens.default each model declares in the compiled CLI 2.1.220
registry, extracted id-anchored:
claude-opus-5 max_output_tokens:{default:64000,upper:128000}
claude-opus-4-8 max_output_tokens:{default:64000,upper:128000}
claude-opus-4-7 max_output_tokens:{default:64000,upper:128000}
claude-opus-4-6 max_output_tokens:{default:64000,upper:128000}
claude-sonnet-5 max_output_tokens:{default:64000,upper:128000}
claude-sonnet-4-6 max_output_tokens:{default:32000,upper:128000}
claude-haiku-4-5 max_output_tokens:{default:32000,upper:64000}
This is not cosmetic metadata. OCP itself never enforces maxTokens — server.mjs
does not read it — but it is propagated to OpenClaw (setup.mjs,
scripts/sync-openclaw.mjs), and OpenClaw CAPS the outbound request with it:
maxTokens = Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens)
with reasoning budgets of medium 8192 / high 16384, and a clamp
`if (maxTokens <= thinkingBudget) thinkingBudget = maxTokens - 1024`.
So at `high` reasoning against a model declared at 16384: maxTokens resolves to
16384, the clamp fires, thinking takes 15360, and roughly 1024 tokens are left
for the visible answer. That is what this repo shipped for every model until
now, and it is the actual harm — not the advertised-vs-real mismatch.
ocp-connect keeps its own family-prefix table (/v1/models does not expose
maxTokens, so it cannot derive them). Set to the family FLOOR — opus 64000,
sonnet 32000 because sonnet-4-6 is 32000 while sonnet-5 is 64000, haiku 32000 —
because prefixes cannot distinguish versions and under-advertising merely caps
a client lower than the model allows, whereas over-advertising would promise
capacity a family member does not have. Commented in place.
New test asserts the PRINCIPLE, not the numbers: every maxTokens must exceed
OpenClaw's `high` thinking budget so an answer still fits. A value-pinning test
would need editing on every model addition and would not explain itself.
Mutation-proven: reverting one entry to 16384 fails with
"claude-opus-5 declares maxTokens=16384 <= 16384: at OpenClaw's 'high'
reasoning level the thinking budget would consume all but ~1024 tokens".
Owner-approved decision (option: align with registry defaults). Tradeoff
recorded in CHANGELOG: longer answers, correspondingly higher per-request quota
burn on long generations.
Verified: bash -n on ocp-connect, and py_compile on its embedded python block
(lines 101-334) so the comment sits at a valid indentation.
Tests: 458 passed, 0 failed (457 + 1).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017gbqUZ8HfBZpjjbzQ85oH8
* fix(models): rewrite the maxTokens rationale — my justification was factually wrong
The numbers were right, the code was right, and the reason I gave for both was
wrong. Verified every part of the review's finding first-hand before rewriting.
WHAT I CLAIMED: OpenClaw caps outbound requests via
`maxTokens = Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens)`, so a
16384 declaration at `high` reasoning left ~1024 tokens for the visible answer,
and raising it would produce longer answers and higher quota burn.
WHY THAT CANNOT HAPPEN FOR OCP — three independent breaks, each confirmed here:
scripts/sync-openclaw.mjs:75 api: "openai-completions"
The clamp I cited lives behind `case "anthropic-messages"`; the
openai-completions transport has no thinkingBudget concept at all, so that code
never runs for a claude-local provider.
buildCliArgs pushes: --input-format, --disallowedTools, --allowedTools,
--dangerously-skip-permissions, --mcp-config
No output-token flag of any kind reaches the CLI. OCP cannot cap output even if
it wanted to.
grep max_completion_tokens server.mjs lib/ -> 0 occurrences
That is the field OpenClaw would send to a local openai-completions endpoint,
and this repo never reads it.
So "expect longer answers and higher per-request quota burn" was a promise that
would not have materialised. That is worse than a wrong number: a release note
that tells operators to expect a behavioural change which cannot occur.
The change still stands, on the honest reason: models.json is the SPOT (ADR
0003) and its values should be true. maxTokens is ADVERTISED metadata consumed
only by clients that choose to honour it. CHANGELOG and the test comment now
say exactly that, and say plainly that OCP behavior is unchanged.
Test replaced, not just re-worded. The old one asserted `maxTokens > 16384`,
which review showed lets every entry sit at 16385 and still call itself
"registry-aligned" — the actual claim had no coverage. Now pinned per model
against a recorded table of CLI 2.1.220 id-anchored values, with an explicit
failure for any model missing a row. Mutation-proven on both holes:
all entries at 16385 -> CAUGHT (the old test passed this)
sonnet-4-6 wrongly at 64000 -> CAUGHT
Also fixed ocp-connect's unknown-id fallback (8192 -> 32000). Review flagged it
as contradicting the invariant: 32000 is the LOWEST max_output_tokens.default
in the registry, so it is the safe floor and no longer sits below every family
in its own table. Unreachable today, wrong to leave inconsistent.
Verified: bash -n on ocp-connect and py_compile on its embedded python block.
Tests: 458 passed, 0 failed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017gbqUZ8HfBZpjjbzQ85oH8
* fix(ocp-connect): revert the unknown-id fallback to 8192 — 32000 over-advertised
The previous commit raised ocp-connect's unknown-id fallback from 8192 to 32000 on
the stated grounds that 32000 was "the LOWEST max_output_tokens.default in the CLI
2.1.220 registry". That is false, and the change it justified made this PR violate
its own thesis.
Pairing-free enumeration of the compiled registry (17 occurrences, no grep-window
artifacts):
7 max_output_tokens:{default:64000,upper:128000}
5 max_output_tokens:{default:32000,upper:64000}
2 max_output_tokens:{default:8192,upper:8192}
2 max_output_tokens:{default:32000,upper:32000}
1 max_output_tokens:{default:32000,upper:128000}
distinct defaults: 8192 / 32000 / 64000 GLOBAL MINIMUM: 8192
The floor is 8192, held by claude-3-5-haiku and claude-3-5-sonnet — and those are
exactly the ids that reach the fallback, since "claude-3-5-*" matches none of the
family prefixes. So the raise over-advertised the only two real models the branch
serves, by 4x, in a PR whose entire claim is that advertised metadata should be true.
Verified by exercising the real classifier (verbatim source slice, not a replica):
claude-3-5-haiku 8192 FALLBACK registry 8192 exact
claude-3-5-sonnet 8192 FALLBACK registry 8192 exact
claude-opus-5 64000 family registry 64000 exact
claude-sonnet-4-6 32000 family registry 32000 exact
claude-haiku-4-5-20251001 32000 family registry 32000 exact
claude-sonnet-5 32000 family registry 64000 under (safe)
Also in this commit:
- The family table's comment said "FAMILY FLOOR of the CLI registry". It is the floor
over each family's members CURRENTLY IN models.json, not over the registry family:
claude-opus-4-0 / -4-5 are opus-family at 32000, so the opus row would over-advertise
them 2x. Unreachable today (ocp-connect derives ids from /v1/models, i.e. models.json),
but the comment now states the real scope and what to do if a legacy opus is added.
- The test table keyed haiku on "claude-haiku-4-5-20251001" while telling the reader to
extract values id-anchored. That id has ZERO id-anchored hits: the registry record is
id:"claude-haiku-4-5" and the dated string appears only as its provider_ids.first_party
(10 bare-string hits). Following the instruction on that row returns nothing, which is
precisely what pushes a reader back to the bare-string search this test exists to
prevent. The row now carries the registry id.
Reviewer credit: the reviewer that found this also retracted its own earlier finding,
which is what produced the 32000 fallback in the first place. Both directions verified
independently here before acting.
server.mjs: unchanged by this commit (ALIGNMENT.md requires no cli.js citation).
Suite: 462 passed, 0 failed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017gbqUZ8HfBZpjjbzQ85oH8
* docs(ocp-connect): my unreachability reason was wrong — state the invariant that holds
Review of
|
||
|
|
fdd6dadf96 |
feat(models): add Claude Opus 5 and repoint the opus alias to it (#192)
* feat(models): add Claude Opus 5 and repoint the `opus` alias to it Adds `claude-opus-5` to models.json (the SPOT) and moves the `opus` alias from `claude-opus-4-8` to it. `/v1/models` goes 6 -> 7; OpenClaw picks the new entry up on the next `ocp update` via scripts/sync-openclaw.mjs. server.mjs is NOT modified by this PR — models.json is the single source of truth (ADR 0003) and every consumer (server.mjs MODEL_MAP, setup.mjs, sync-openclaw.mjs, ocp-connect) derives from it. ocp-connect needs no change either: its metadata table matches on the `claude-opus` FAMILY prefix, which `claude-opus-5` hits (the guard added in PR #152 review). Alignment evidence. The claim "the CLI itself defaults opus -> claude-opus-5" is verified from the compiled CLI binary 2.1.220 via `strings`, the same protocol used for #152/#168: latest_per_family:{fable:"claude-fable-5",opus:"claude-opus-5", sonnet:"claude-sonnet-5",haiku:"claude-haiku-4-5"} The same registry entry gives context:{window:1e6,native_1m:true}, max_output_tokens:{default:64000,upper:128000} and pricing:"tier_5_25" -- i.e. identical $5/$25 per MTok to Opus 4.8, so the alias repoint carries no cost change. Availability confirmed with a live subscription-pool completion (`claude -p --model claude-opus-5` -> "OK"). This mirrors #168 (sonnet -> sonnet-5), which established the precedent that following the CLI's own latest_per_family is the correct default behavior. contextWindow is deliberately 200000, not the native 1M: 1. MAX_PROMPT_CHARS is a SINGLE GLOBAL budget, not per-model. derivePromptCharBudget (lib/prompt.mjs) returns `max(floor, max(...contextWindows) * 3)` across ALL entries, so a 1M entry would lift the truncation ceiling to 3,000,000 chars for claude-haiku-4-5-20251001 as well -- genuinely a 200k-native model -- turning clean OCP-side truncation into an upstream API rejection. 2. OpenClaw scales its history budget linearly off this value: contextWindow * maxHistoryShare * SAFETY_MARGIN (= x0.6), plus an oversized-message threshold at x0.5 (compaction-planning, OpenClaw 2026.7.1). Its own bundled registry hardcodes 200000 for Claude models, and the upstream request to raise it to 1M (openclaw#22979) was closed "not planned" -- 1M needs a beta header its compaction path omits. Raising the window for real requires per-model budgets and is ADR-level; a new regression test pins the invariant so that change has to be deliberate. Tests: 452 passed, 0 failed. Three mutations verified to bite: - revert aliases.opus -> 4-8 => 1 failure (opus-alias SPOT) - delete the claude-opus-5 entry => 2 failures (presence + dangling alias) - set its contextWindow to 1000000 => 2 failures (invariant + budget SPOT) E2E on an isolated port (:3999, prod on :3456 untouched and verified so): /v1/models returns 7 ids with claude-opus-5 first; a request with model:"opus" logs event=claude_spawned model=claude-opus-5 tier=opus and returns a real completion. Derived MAX_PROMPT_CHARS stays 600000. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbqUZ8HfBZpjjbzQ85oH8 * fix(docs,test): restore the dropped Opus 4.8 line; assert the window CEILING Two review findings from the independent Iron-Rule-10 reviewer, both confirmed before applying: 1. docs/lan-mode.md: the sample `ocp update` output lost `ocp/claude-opus-4-8` entirely — the edit substituted the id instead of inserting the new one, so the block listed 6 bullets while line 219 of the same document claims "7 models available". Self-contradictory. Restored; the block is 7 again. 2. test-features.mjs: "every contextWindow is 200000" was too rigid and contradicted ADR 0009, which states the budget "scales automatically — no code change". Asserting every entry turned that documented no-code-change path into a must-edit-tests path, and would have failed on a future entry with a legitimately SMALLER window. Now asserts the MAX instead: raising the ceiling (the actual hazard, since the budget is global) still fails, while a smaller-window model stays legal. Verified the reformulation is strictly better, not just different: - raise a window to 1000000 -> 2 failures (ceiling + derivePromptCharBudget SPOT) - add a legitimate 128k model -> 452 passed, 0 failed (old test would have failed here) Tests: 452 passed, 0 failed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbqUZ8HfBZpjjbzQ85oH8 --------- Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
0c3e42b2e4 |
feat(models): repoint default sonnet alias to claude-sonnet-5 (#168)
* feat(models): add Claude Sonnet 5 to models.json SPOT Adds `claude-sonnet-5` (the latest Sonnet, supported by claude CLI >= 2.1.206) to models.json — the single source of truth (ADR 0003). Both the /v1/models endpoint and setup.mjs OpenClaw registration derive from it automatically. - New model entry `claude-sonnet-5` (reasoning, 200k ctx, 16k max tokens), mirroring the existing Sonnet entry shape. - Point the `sonnet` alias at `claude-sonnet-5` (newest Sonnet), consistent with `opus` -> `claude-opus-4-8`. Previous `claude-sonnet-4-6` is retained for pinning. - README "Available Models" table updated (release-kit 5.3). - Update the aliases.sonnet SPOT test to the new default. Endpoint class: B.1 (/v1/models), data-only via the models.json SPOT. Authorized by ADR 0006 (OpenAI shim scope) + ADR 0003 (models.json SPOT). Verified: `claude --model claude-sonnet-5 -p` returns a valid response on a current subscription CLI (2.1.206); npm test green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(models): make PR #152 purely additive + close ocp-connect drift + real SPOT test Addresses the maintainer's review. Rescopes this PR to the additive change only — adding claude-sonnet-5 to models.json — and defers the `sonnet` alias repoint to its own PR per Iron Rule 11 (the alias is the default for every request that omits `model`; repointing it is a behavior change that deserves separate review + a CHANGELOG entry). No server.mjs change, so no cli.js citation required. Metadata confirmed unchanged: contextWindow 200000 / maxTokens 16384 stay, per the maintainer's correction (OCP truncates at MAX_PROMPT_CHARS, and contextWindow feeds OpenClaw's compaction budget — advertising a larger window than OCP delivers just makes OpenClaw overshoot). Fixes vs review: 1. Reverted `aliases.sonnet` back to claude-sonnet-4-6 — this PR only *adds* the model; the repoint ships separately. README updated to match (5 is available by full ID; 4-6 remains the alias default). 2. Replaced the tautological SPOT test. The old assertion read a literal out of models.json and asserted it equalled the same literal — it passed even with a dangling alias. Added referential-integrity tests: every aliases/legacyAliases value must resolve to a real models[].id, plus an explicit assertion that claude-sonnet-5 exists in models[]. This is the guard that actually catches an alias pointing at a non-existent model (VALID_MODELS keys on alias names, never targets, so nothing else checks this). 3. Fixed ocp-connect classification drift. Its prefix table pinned "claude-sonnet-4", which misses "claude-sonnet-5" and falls through to the non-reasoning / 8k-output default. Broadened both the model_meta and alias_prefixes tables to family prefixes (claude-opus / claude-sonnet / claude-haiku) so any future versioned ID classifies correctly with no per-model edit. /v1/models does not expose reasoning/maxTokens (OpenAI /v1/models schema has no such fields — adding them would be a Rule 2 invention), so family classification stays in ocp-connect. primary_model stays claude-sonnet-4-6, matching the (unchanged) sonnet alias — it moves with the alias in the repoint PR. Tests: 266 passed, 0 failed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(models): repoint default `sonnet` alias to claude-sonnet-5 Split out from #152 per Iron Rule 11: the additive model entry (#152) lands the claude-sonnet-5 metadata; this PR makes the behavior change — moving the default `sonnet` alias from claude-sonnet-4-6 to claude-sonnet-5. `aliases.sonnet` is the model used for every /v1/chat/completions request that omits `model` (server.mjs default) and, via ocp-connect, OpenClaw's OCP primary. Repointing it changes behavior for every such client, so it gets its own PR + CHANGELOG entry separate from the additive entry. - models.json: aliases.sonnet -> claude-sonnet-5 (claude-sonnet-4-6 kept by full ID for pinning). Both are pricing tier_3_15 — no cost regression. - ocp-connect: primary_model now prefers claude-sonnet-5 (falls back to 4-6, then first model), tracking the alias default so OpenClaw's primary matches. - README: swap the "default for sonnet alias" annotation onto claude-sonnet-5. - CHANGELOG: Unreleased § Changed entry documenting the default change + how to pin. - test: SPOT assertion updated to claude-sonnet-5; referential-integrity tests from #152 continue to guard that the alias target actually exists in models[]. No server.mjs change, so no cli.js citation required. Depends on #152 (needs the claude-sonnet-5 models[] entry to exist, else the referential-integrity test fails). Rebase/merge after #152 lands. Tests: 266 passed, 0 failed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: vvlasy-openclaw <vvlasy@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: dtzp555 <dtzp555@gmail.com> |
||
|
|
27216646c8 |
feat(models): add Claude Sonnet 5 to models.json SPOT (#152)
* feat(models): add Claude Sonnet 5 to models.json SPOT Adds `claude-sonnet-5` (the latest Sonnet, supported by claude CLI >= 2.1.206) to models.json — the single source of truth (ADR 0003). Both the /v1/models endpoint and setup.mjs OpenClaw registration derive from it automatically. - New model entry `claude-sonnet-5` (reasoning, 200k ctx, 16k max tokens), mirroring the existing Sonnet entry shape. - Point the `sonnet` alias at `claude-sonnet-5` (newest Sonnet), consistent with `opus` -> `claude-opus-4-8`. Previous `claude-sonnet-4-6` is retained for pinning. - README "Available Models" table updated (release-kit 5.3). - Update the aliases.sonnet SPOT test to the new default. Endpoint class: B.1 (/v1/models), data-only via the models.json SPOT. Authorized by ADR 0006 (OpenAI shim scope) + ADR 0003 (models.json SPOT). Verified: `claude --model claude-sonnet-5 -p` returns a valid response on a current subscription CLI (2.1.206); npm test green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(models): make PR #152 purely additive + close ocp-connect drift + real SPOT test Addresses the maintainer's review. Rescopes this PR to the additive change only — adding claude-sonnet-5 to models.json — and defers the `sonnet` alias repoint to its own PR per Iron Rule 11 (the alias is the default for every request that omits `model`; repointing it is a behavior change that deserves separate review + a CHANGELOG entry). No server.mjs change, so no cli.js citation required. Metadata confirmed unchanged: contextWindow 200000 / maxTokens 16384 stay, per the maintainer's correction (OCP truncates at MAX_PROMPT_CHARS, and contextWindow feeds OpenClaw's compaction budget — advertising a larger window than OCP delivers just makes OpenClaw overshoot). Fixes vs review: 1. Reverted `aliases.sonnet` back to claude-sonnet-4-6 — this PR only *adds* the model; the repoint ships separately. README updated to match (5 is available by full ID; 4-6 remains the alias default). 2. Replaced the tautological SPOT test. The old assertion read a literal out of models.json and asserted it equalled the same literal — it passed even with a dangling alias. Added referential-integrity tests: every aliases/legacyAliases value must resolve to a real models[].id, plus an explicit assertion that claude-sonnet-5 exists in models[]. This is the guard that actually catches an alias pointing at a non-existent model (VALID_MODELS keys on alias names, never targets, so nothing else checks this). 3. Fixed ocp-connect classification drift. Its prefix table pinned "claude-sonnet-4", which misses "claude-sonnet-5" and falls through to the non-reasoning / 8k-output default. Broadened both the model_meta and alias_prefixes tables to family prefixes (claude-opus / claude-sonnet / claude-haiku) so any future versioned ID classifies correctly with no per-model edit. /v1/models does not expose reasoning/maxTokens (OpenAI /v1/models schema has no such fields — adding them would be a Rule 2 invention), so family classification stays in ocp-connect. primary_model stays claude-sonnet-4-6, matching the (unchanged) sonnet alias — it moves with the alias in the repoint PR. Tests: 266 passed, 0 failed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: vvlasy-openclaw <vvlasy@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
885f62addf |
feat: Phase 6c — claude stream-json port + --system-prompt + opus 4.8 (#103)
* wip(rescue): OCP Phase 6c stream-json port + opus 4.8 (uncommitted /tmp work) Rescue commit — preserves the subagent-produced Phase 6c port (claude -p → stream-json + --system-prompt + NDJSON parser) and opus 4.8 model addition done 2026-05-30 in a /tmp clone (volatile). NOT reviewed-for-merge; this is preservation only on a WIP branch so a /tmp reboot does not lose the work. Strategy context: OCP is being made the first-mover for TUI-mode (users are on OCP). Phase 6c here is the DEFAULT-path foundation (stream-json = sdk-cli = the "Max-user stable mode" fallback). TUI-mode (cc_entrypoint=cli subscription bridge) lands on top as an opt-in. Re-review before merging to main. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(phase6c): fold review findings — scrub hostname, README prose, parser tests, version citation P3-1 (binding): scrub private hostname "PI231" from server.mjs comment; replace with role-based term "the test server". Repo is public — no machine-specific hostnames may appear. P3-2: update README.md "How It Works" diagram and prose from stale "claude -p" to "claude --output-format stream-json", matching the Phase 6c spawn change already in server.mjs and CHANGELOG. P2-2: update all five authority citations in server.mjs from bare "claude CLI v2.1.104" to "claude CLI § <flag> (ported from OLP, verified v2.1.104; behavior stable through v2.1.158)" — honest about OLP provenance and version range, without inventing new facts. P2-1: add "Stream-JSON parsers" suite to test-features.mjs (17 new tests, 84 → 101 total). Copies parseStreamJsonLines and parseStreamJsonEvent verbatim from server.mjs with a MIRRORS header comment; logEvent stubbed to avoid live-server side-effects. Covers: content_block_delta deltas, assistant-aggregate fallback, no-double-count guard, aggregate-only short responses, partial-line buffering across two chunks, is_error result variants, malformed/non-JSON lines, system/user/unknown event types. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
c6f7850e89 |
refactor(models): extract models.json as single source of truth (#30)
Pure refactor. No API surface change. MODEL_MAP and MODELS in server.mjs are now derived from models.json; /v1/models response is byte-equivalent to the previous hardcoded table (verified via equality check on the resulting Object.entries sorted). setup.mjs MODEL_ID_MAP / MODELS / MODEL_ALIASES also derived from models.json, fixing a latent drift where setup.mjs still listed claude-opus-4-6 / claude-haiku-4 (v3.0-era) while server.mjs had already moved to opus-4-7 + haiku-4-5-20251001 in v3.10.0. server.mjs change scope: no network/endpoint surface modified. No new env vars, headers, or routes. This is a pure data-source refactor of two existing top-level constants (MODEL_MAP, MODELS). No cli.js operation is being added or changed, so per ALIGNMENT.md Rule 2 this requires no cli.js:NNNN citation — the change does not touch the Claude-CLI-call boundary. Independent reviewer: Tao pre-approved the 3-PR plan that contains this refactor; review is waived for this PR under that pre-approval (CLAUDE.md Iron Rule 10 exception, task-scoped). Unblocks PR B (scripts/sync-openclaw.mjs), which needs a single source of truth to reconcile with on `ocp update`. Co-authored-by: Tao Deng <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |