mirror of
https://github.com/dtzp555-max/ocp.git
synced 2026-07-26 23:45:08 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62c21d883a |
@@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **`maxTokens` now matches the CLI registry instead of a uniform 16384 (#195).** Every Opus entry and `claude-sonnet-5` go to **64000**, `claude-sonnet-4-6` and `claude-haiku-4-5` to **32000** — the `max_output_tokens.default` each model actually declares in the compiled CLI 2.1.220 registry. OCP never enforced this value; it is propagated to OpenClaw, where it **caps the outbound request**: `maxTokens = Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens)`. OpenClaw's reasoning budgets are medium 8192 / high 16384, and when `maxTokens <= thinkingBudget` it clamps thinking to `maxTokens - 1024` — so a model declared at 16384 running at **high** reasoning spent ~15360 on thinking and left **~1024 tokens for the actual answer**. `ocp-connect`'s independent family table moves to the family floor (opus 64000, sonnet 32000, haiku 32000) since prefixes cannot distinguish versions. Expect longer answers and correspondingly higher per-request quota burn on long generations.
|
||||||
|
|
||||||
## v3.25.0 — 2026-07-27
|
## v3.25.0 — 2026-07-27
|
||||||
|
|
||||||
Minor release. Headline: **Claude Opus 5** joins the model list and the `opus` alias now resolves to it. Alongside it, two `server.mjs` correctness fixes found by review rather than by users — a monotonic in-flight-counter leak, and cache keys that were hashing the alias string instead of the model it resolves to. The three TUI/prompt fixes that landed after v3.24.0 are included here too.
|
Minor release. Headline: **Claude Opus 5** joins the model list and the `opus` alias now resolves to it. Alongside it, two `server.mjs` correctness fixes found by review rather than by users — a monotonic in-flight-counter leak, and cache keys that were hashing the alias string instead of the model it resolves to. The three TUI/prompt fixes that landed after v3.24.0 are included here too.
|
||||||
|
|||||||
+7
-7
@@ -8,7 +8,7 @@
|
|||||||
"openclawName": "Claude Opus 5 (via CLI)",
|
"openclawName": "Claude Opus 5 (via CLI)",
|
||||||
"reasoning": true,
|
"reasoning": true,
|
||||||
"contextWindow": 200000,
|
"contextWindow": 200000,
|
||||||
"maxTokens": 16384
|
"maxTokens": 64000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "claude-opus-4-8",
|
"id": "claude-opus-4-8",
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
"openclawName": "Claude Opus 4.8 (via CLI)",
|
"openclawName": "Claude Opus 4.8 (via CLI)",
|
||||||
"reasoning": true,
|
"reasoning": true,
|
||||||
"contextWindow": 200000,
|
"contextWindow": 200000,
|
||||||
"maxTokens": 16384
|
"maxTokens": 64000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "claude-opus-4-7",
|
"id": "claude-opus-4-7",
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
"openclawName": "Claude Opus 4.7 (via CLI)",
|
"openclawName": "Claude Opus 4.7 (via CLI)",
|
||||||
"reasoning": true,
|
"reasoning": true,
|
||||||
"contextWindow": 200000,
|
"contextWindow": 200000,
|
||||||
"maxTokens": 16384
|
"maxTokens": 64000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "claude-opus-4-6",
|
"id": "claude-opus-4-6",
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
"openclawName": "Claude Opus 4.6 (via CLI)",
|
"openclawName": "Claude Opus 4.6 (via CLI)",
|
||||||
"reasoning": true,
|
"reasoning": true,
|
||||||
"contextWindow": 200000,
|
"contextWindow": 200000,
|
||||||
"maxTokens": 16384
|
"maxTokens": 64000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "claude-sonnet-5",
|
"id": "claude-sonnet-5",
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
"openclawName": "Claude Sonnet 5 (via CLI)",
|
"openclawName": "Claude Sonnet 5 (via CLI)",
|
||||||
"reasoning": true,
|
"reasoning": true,
|
||||||
"contextWindow": 200000,
|
"contextWindow": 200000,
|
||||||
"maxTokens": 16384
|
"maxTokens": 64000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "claude-sonnet-4-6",
|
"id": "claude-sonnet-4-6",
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
"openclawName": "Claude Sonnet 4.6 (via CLI)",
|
"openclawName": "Claude Sonnet 4.6 (via CLI)",
|
||||||
"reasoning": true,
|
"reasoning": true,
|
||||||
"contextWindow": 200000,
|
"contextWindow": 200000,
|
||||||
"maxTokens": 16384
|
"maxTokens": 32000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "claude-haiku-4-5-20251001",
|
"id": "claude-haiku-4-5-20251001",
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
"openclawName": "Claude Haiku 4.5 (via CLI)",
|
"openclawName": "Claude Haiku 4.5 (via CLI)",
|
||||||
"reasoning": false,
|
"reasoning": false,
|
||||||
"contextWindow": 200000,
|
"contextWindow": 200000,
|
||||||
"maxTokens": 8192
|
"maxTokens": 32000
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"aliases": {
|
"aliases": {
|
||||||
|
|||||||
+10
-3
@@ -129,10 +129,17 @@ provider = {
|
|||||||
# re-trip it. Family prefixes classify any versioned ID correctly with no per-model
|
# re-trip it. Family prefixes classify any versioned ID correctly with no per-model
|
||||||
# edit. (ADR 0003: models.json is the SPOT for model existence; /v1/models does not
|
# edit. (ADR 0003: models.json is the SPOT for model existence; /v1/models does not
|
||||||
# expose reasoning/maxTokens, so family classification stays here.)
|
# expose reasoning/maxTokens, so family classification stays here.)
|
||||||
|
# maxTokens values are the FAMILY FLOOR of the CLI registry max_output_tokens.default
|
||||||
|
# (opus family 64000; sonnet 32000 because sonnet-4-6 is 32000 while sonnet-5 is 64000;
|
||||||
|
# haiku 32000). Family prefixes cannot distinguish versions, so the floor is used
|
||||||
|
# deliberately: under-advertising caps a client lower than the model allows, which is safe,
|
||||||
|
# whereas over-advertising would promise capacity a member of the family does not have.
|
||||||
|
# models.json is authoritative per ADR 0003; this table only exists because /v1/models does
|
||||||
|
# not expose maxTokens.
|
||||||
model_meta = {
|
model_meta = {
|
||||||
"claude-opus": {"name": "Claude Opus (OCP)", "reasoning": True, "maxTokens": 16384},
|
"claude-opus": {"name": "Claude Opus (OCP)", "reasoning": True, "maxTokens": 64000},
|
||||||
"claude-sonnet": {"name": "Claude Sonnet (OCP)", "reasoning": True, "maxTokens": 16384},
|
"claude-sonnet": {"name": "Claude Sonnet (OCP)", "reasoning": True, "maxTokens": 32000},
|
||||||
"claude-haiku": {"name": "Claude Haiku (OCP)", "reasoning": False, "maxTokens": 8192},
|
"claude-haiku": {"name": "Claude Haiku (OCP)", "reasoning": False, "maxTokens": 32000},
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_model_meta(mid):
|
def get_model_meta(mid):
|
||||||
|
|||||||
@@ -4299,6 +4299,24 @@ test("models.json: every aliases value resolves to a real models[].id (referenti
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// maxTokens must leave room for a visible answer once a client's thinking budget is taken out
|
||||||
|
// (#195). OCP never enforces maxTokens itself — it is propagated to OpenClaw (setup.mjs,
|
||||||
|
// scripts/sync-openclaw.mjs) where it CAPS the outbound request:
|
||||||
|
// maxTokens = Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens)
|
||||||
|
// OpenClaw's reasoning budgets are medium 8192 / high 16384, and when maxTokens <= thinkingBudget
|
||||||
|
// it clamps thinking to maxTokens - 1024. So a model declared at 16384 running at `high` spent
|
||||||
|
// ~15360 on thinking and left ~1024 for the actual answer — which is what this repo shipped until
|
||||||
|
// v3.25.0. Asserting the PRINCIPLE rather than pinning per-model numbers: a value test would need
|
||||||
|
// editing every time a model is added, and would not say why.
|
||||||
|
const _spotHighThinkingBudget = 16384; // OpenClaw's `high` reasoning budget
|
||||||
|
test("models.json: every maxTokens exceeds the high thinking budget, leaving room for output (#195)", () => {
|
||||||
|
for (const m of _spotModels.models) {
|
||||||
|
assert.ok(m.maxTokens > _spotHighThinkingBudget,
|
||||||
|
`${m.id} declares maxTokens=${m.maxTokens} <= ${_spotHighThinkingBudget}: at OpenClaw's 'high' reasoning ` +
|
||||||
|
`level the thinking budget would consume all but ~1024 tokens of the response`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test("models.json: every legacyAliases value resolves to a real models[].id (referential integrity)", () => {
|
test("models.json: every legacyAliases value resolves to a real models[].id (referential integrity)", () => {
|
||||||
for (const [name, target] of Object.entries(_spotModels.legacyAliases || {})) {
|
for (const [name, target] of Object.entries(_spotModels.legacyAliases || {})) {
|
||||||
assert.ok(_spotModelIds.has(target), `legacyAliases.${name} -> '${target}' is a dangling alias (no matching models[].id)`);
|
assert.ok(_spotModelIds.has(target), `legacyAliases.${name} -> '${target}' is a dangling alias (no matching models[].id)`);
|
||||||
|
|||||||
Reference in New Issue
Block a user