diff --git a/docs/cloudflare-containers.md b/docs/cloudflare-containers.md index 265c6704..dbeb2bc3 100644 --- a/docs/cloudflare-containers.md +++ b/docs/cloudflare-containers.md @@ -42,15 +42,15 @@ Wrangler `vars` in `wrangler.jsonc` already set: - `SERVER_PORT=8080` - `APP_NAME=MultiLLM Proxy` -`RUNTIME_FEATURE_FLAGS` groups nine nonsecret settings into one JSON binding to +`RUNTIME_FEATURE_FLAGS` groups seven nonsecret settings into one JSON binding to leave room for provider secrets. Worker vars and secrets share a limit of 128 text bindings, and Cloudflare rejects an upload that exceeds it. The Container, usage ledger, roleplay settings and roleplay session read these grouped settings. An individual binding with the same setting name takes precedence, including an explicit disabled value. Keep credentials in separate Worker -secrets; the grouped binding accepts only the nine names committed in -`wrangler.jsonc`. Add a new nonsecret setting to the group rather than as a -separate var. +secrets; the grouped binding accepts only the nine names listed in +`worker/runtime-feature-flags.mjs`. Add a new nonsecret setting to the group +rather than as a separate var. Public HTTP requests receive a `308` redirect to the same HTTPS URL before any route or container work. For Container requests, the Worker overwrites diff --git a/docs/roleplay.md b/docs/roleplay.md index 5a341ef2..9960e2df 100644 --- a/docs/roleplay.md +++ b/docs/roleplay.md @@ -152,8 +152,8 @@ variants. `roleplay:intelligence` mirrors the `auto:intelligence` chat route. It tries a fixed list strictly in order across providers, without adaptive reordering: -MiMo-V2.6-Pro on NanoGPT, then on ClinePass; then GLM-5.3-Flash, GLM-5.3 and -GLM-5.2, each on NanoGPT, ClinePass (no GLM-5.2), OpenCode Go and NavyAI. +GLM-5.3, GLM-5.3-Flash and GLM-5.2, each on NanoGPT, ClinePass (no GLM-5.2), +OpenCode Go and NavyAI; then MiMo-V2.6-Pro on NanoGPT, then on ClinePass. Pay-as-you-go gateways (OpenRouter, LinkAPI) are not in the default list. Entries whose provider has no key are skipped, a cooling-down entry moves out of the way, and NanoGPT keys rotate within an entry before the next one. The @@ -162,18 +162,33 @@ usual safe-fallback statuses advance to the next entry. Set `provider:model` entries to replace the list. ClinePass uses `CLINE_API_KEY` and Cline's `reasoning.effort` field, up to `xhigh`. -Production sets it (`wrangler.jsonc`, 2026-10-25) to DeepSeek V4.1 Flash, GLM-5.3 and -MiMo-V2.6-Pro on OpenCode Go, then GLM-5.3 on ClinePass, then MiMo-V2.6-Pro, GLM-5.3, -GLM-5.3-Flash and GLM-5.2 on NanoGPT, then GLM-5.3-Flash and MiMo-V2.6-Pro on ClinePass. -In 24 test turns on OpenCode Go (scene continuation, conflict, out-of-character recall and -a 20k-token lorebook lookup) every model answered and kept to the card. DeepSeek V4.1 Flash -was fastest (median 5.2 s a turn), wrote nearly as well as GLM-5.3 and used about a -thirtieth of GLM's allowance per turn, so it leads. GLM-5.3 wrote the strongest scenes -(8.3 s). MiMo-V2.6-Pro was slowest (13.5 s), with the shortest replies and some -point-of-view slips. Go meters each model against its own monthly allowance. ClinePass GLM-5.3 gave its first words in about 4 s; MiMo on NanoGPT -took 59 s, and 152 s on an adult turn, so a turn that falls back to it is slow. OpenCode Go -refused every request on 2026-10-05; the key it used then has since expired. NavyAI's free plan was -refusing every request, so it is left out. +Production sets it (`wrangler.jsonc`, 2026-10-29) to GLM-5.3 on OpenCode Go, ClinePass +and NanoGPT, then DeepSeek V4.1 Flash on OpenCode Go, then GLM-5.3-Flash and GLM-5.2 on +NanoGPT and GLM-5.3-Flash on ClinePass, then MiMo-V2.6-Pro on OpenCode Go, NanoGPT and +ClinePass. GLM-5.3 is the recommended model for `roleplay:auto`. + +The order follows a test on 2026-10-29: three multi-turn roleplays with planted card +rules (a heist whose characters each have a fixed rule, a secret that must stay hidden +until proof is shown, and an out-of-character time skip with a status block to update), +two runs each on OpenCode Go, every reply read and scored out of 5. GLM-5.3 averaged 4.33 +with no hard rule breaks and took 21 to 41 s a reply. DeepSeek V4.1 Flash, which led the +chain from 2026-10-25, averaged 3.25: it answered in 6 to 10 s but reasoned far less +(0.7k to 3k characters against GLM-5.3's 11k to 30k), broke a character rule and came +close to confessing the secret. GLM-5.3-Flash averaged 3.92 with three hard rule breaks, +and MiMo-V2.6-Pro 2.83: among other faults it wrote a line for the user, so it is last. +Kimi K3.1 Pro scored highest (4.67) but took 72 to 143 s a reply and is not in the chain. +One reader scored two runs per scenario, so the sample is small. + +The cost is OpenCode Go usage. In a test on 2026-10-25 a GLM-5.3 turn used about 30 +times as much of the Go allowance as a DeepSeek V4.1 Flash turn, so leading with GLM-5.3 +reaches Go's [usage limits](opencode-go.md#subscription-and-upstream-limits) much +sooner. When Go refuses GLM-5.3, the turn moves to GLM-5.3 on ClinePass and NanoGPT, then +to DeepSeek V4.1 Flash. On 2026-10-29 only OpenCode Go answered: ClinePass returned 403 +`ENTITLEMENT_ERROR` for every model and NanoGPT returned 429 `model_cooldown`. Both +statuses advance to the next entry and pause that entry for the session (5 minutes after a +403, 1 minute after a 429). When it works, ClinePass GLM-5.3 gives its first words in about +4 s; MiMo on NanoGPT took 59 s, and 152 s on an adult turn, so a turn that falls back to it +is slow. NavyAI's free plan was refusing every request, so it is left out. With `ROLEPLAY_AUTO_ROUTE=intelligence`, plain `roleplay:auto` turns (and requests without a roleplay model) use the same chain. Turns that set `routing.mode` or @@ -184,10 +199,12 @@ configured key. Leave the variable unset for the adaptive behaviour above. `ROLEPLAY_HANDOFF_FROM` names chain entries that may pass a turn on, and `ROLEPLAY_HANDOFF_TO` the entries that take it; both use the -`ROLEPLAY_INTELLIGENCE_MODELS` format and are unset by default. Production sets -both inside `RUNTIME_FEATURE_FLAGS`; a separate var of the same name takes -precedence. Production lets DeepSeek V4.1 Flash on OpenCode Go hand off to -GLM-5.3 on OpenCode Go, then on ClinePass. A source request carries one internal function, `multillm_hand_off_turn`, +`ROLEPLAY_INTELLIGENCE_MODELS` format and are unset by default. Set them inside +`RUNTIME_FEATURE_FLAGS`; a separate var of the same name takes precedence. A +source hands off only to targets that come after it in the chain. Production +let DeepSeek V4.1 Flash hand off to GLM-5.3 from 2026-10-25 to 2026-10-29, while +DeepSeek led the chain. Now that GLM-5.3 comes first, no target follows DeepSeek, +so production sets neither. A source request carries one internal function, `multillm_hand_off_turn`, whose arguments are a reason (`deeper_reasoning` or `stronger_prose`), short notes and an optional draft. When the source calls it instead of writing, the Worker discards that attempt (its frames are held until visible text appears, so nothing @@ -629,7 +646,7 @@ Non-secret tuning variables: | `ROLEPLAY_PROVIDER_MODELS` | `{}` | JSON provider-specific Kimi/GLM ID or ordered fallback IDs | | `ROLEPLAY_PROVIDER_FAMILIES` | `{}` | JSON provider-to-family allowlists; an empty list disables that provider | | `ROLEPLAY_AUTO_ROUTE` | `adaptive` | `intelligence` sends plain `roleplay:auto` turns through the `roleplay:intelligence` chain | -| `ROLEPLAY_INTELLIGENCE_MODELS` | MiMo-V2.6-Pro, then GLM-5.3-Flash, GLM-5.3 and GLM-5.2 | Ordered `provider:model` list for `roleplay:intelligence`; providers `nanogpt`, `cline-pass`, `opencode`, `navyai`, `linkapi`, `openrouter` | +| `ROLEPLAY_INTELLIGENCE_MODELS` | GLM-5.3, then GLM-5.3-Flash and GLM-5.2, then MiMo-V2.6-Pro | Ordered `provider:model` list for `roleplay:intelligence`; providers `nanogpt`, `cline-pass`, `opencode`, `navyai`, `linkapi`, `openrouter` | | `ROLEPLAY_PROVIDER_LIMITS` | `{}` | JSON provider/family context and output overrides | | `ROLEPLAY_QUALITY_LATENCY_PREMIUM_PERCENT` | `20` | Largest allowed full GLM-5.3 p95 TTFB and total-latency premium over Flash | | `ROLEPLAY_QUALITY_MIN_SAMPLES` | `3` | Successful samples required for both full and Flash before promotion | @@ -651,8 +668,8 @@ Non-secret tuning variables: | `ROLEPLAY_UPSTREAM_HEADER_TIMEOUT_MS` | `90000` | Maximum wait for provider response headers before advancing to the next tier | | `ROLEPLAY_PRE_RESPONSE_FALLBACK_ENABLED` | `true` | Advance after a provider transport rejection or header timeout; client aborts never advance | | `ROLEPLAY_PROVIDER_ERROR_FALLBACK_ENABLED` | `true` | Advance only when a 500/502/504 JSON response explicitly identifies both its error code and type as `provider_error`; unknown 5xx responses remain fail-closed | -| `ROLEPLAY_HANDOFF_FROM` | unset | Chain entries offered `multillm_hand_off_turn`; production uses `opencode:deepseek-v4.1-flash` | -| `ROLEPLAY_HANDOFF_TO` | unset | Chain entries that take a handed-off turn, in chain order; production uses GLM-5.3 on OpenCode Go and ClinePass | +| `ROLEPLAY_HANDOFF_FROM` | unset | Chain entries offered `multillm_hand_off_turn`; production sets none | +| `ROLEPLAY_HANDOFF_TO` | unset | Chain entries after the source that take a handed-off turn, in chain order; production sets none | | `ROLEPLAY_HANDOFF_MIN_TURNS` | `2` | At most one handoff per this many turns in a session; `0` or `1` lifts the cap | | `ROLEPLAY_EMPTY_REPLY_FALLBACK_ENABLED` | `true` | Start a reply with no visible text over on the next candidate, at most twice | | `ROLEPLAY_REFUSAL_FALLBACK_ENABLED` | `true` | Privately regenerate an exact GLM-5.3 Flash refusal trigger with the configured Uncensored Flash candidate; rejected output is neither streamed nor stored | diff --git a/tests/outbound_inventory.json b/tests/outbound_inventory.json index 9023caa0..4eed1915 100644 --- a/tests/outbound_inventory.json +++ b/tests/outbound_inventory.json @@ -2127,7 +2127,7 @@ "worker/roleplay/config.mjs": { "kind": "non-provider", "reason": "Runtime module pinned independently of HTTP client spelling; network attempts require runtime admission.", - "sha256": "5998981bc7e5e7f026da9e49ed80d8de3212023e970db84549cb9976ba37c777" + "sha256": "bf7bd2fa10ad817990ceeafd538424a22eccb45166e52d8b6a0a65c1a7aa608a" }, "worker/roleplay/continuation.mjs": { "kind": "non-provider", @@ -2187,7 +2187,7 @@ "worker/roleplay/model-selection.mjs": { "kind": "non-provider", "reason": "Runtime module pinned independently of HTTP client spelling; network attempts require runtime admission.", - "sha256": "87e782e35c4ad4ee6e5df2c0264e9cb9b8118298bc8be0f418c270385b7ee576" + "sha256": "403fd6d2b7d1e7e467d7f2227c8cdb4ba9dd38c86a2fe79e783666d4e372c425" }, "worker/roleplay/nonstream-repair.mjs": { "kind": "non-provider", diff --git a/tests/test_roleplay_config_worker.mjs b/tests/test_roleplay_config_worker.mjs index 6181b6f2..af18bfc8 100644 --- a/tests/test_roleplay_config_worker.mjs +++ b/tests/test_roleplay_config_worker.mjs @@ -246,24 +246,24 @@ test("deployment defaults roleplay generation to high reasoning", async () => { assert.equal(config.vars?.ROLEPLAY_DEFAULT_REASONING_EFFORT, "high"); }); -test("deployment starts roleplay on OpenCode Go, then Cline Pass, and keeps NanoGPT on the subscription", async () => { +test("deployment starts roleplay on GLM 5.3 and keeps NanoGPT on the subscription", async () => { const configUrl = new URL("../wrangler.jsonc", import.meta.url); const config = JSON.parse(await readFile(configUrl, "utf8")); - // Measured 2026-10-25 on OpenCode Go (24 roleplay turns, every one answered): DeepSeek V4.1 Flash - // was fastest (median 5.2 s) and wrote nearly as well as GLM 5.3 for about a thirtieth of its - // allowance, so it leads; GLM 5.3 (8.3 s, the strongest scenes) is next, then MiMo-V2.6-Pro - // (13.5 s, the shortest replies). Cline Pass GLM 5.3 follows them; MiMo on NanoGPT is next. + // Scored 2026-10-29 on OpenCode Go (3 multi-turn roleplays with planted card rules, 2 runs each): + // GLM 5.3 averaged 4.33 of 5 with no hard rule breaks, DeepSeek V4.1 Flash 3.25 (it broke a + // character rule and nearly confessed a secret) and MiMo-V2.6-Pro 2.83 (it wrote the user's + // lines). GLM 5.3 leads on every provider; DeepSeek follows it, and MiMo is last. assert.deepEqual(config.vars?.ROLEPLAY_INTELLIGENCE_MODELS.split(","), [ - "opencode:deepseek-v4.1-flash", "opencode:glm-5.3", - "opencode:mimo-v2.6-pro", "cline-pass:cline-pass/glm-5.3", - "nanogpt:xiaomi/mimo-v2.6-pro", "nanogpt:z-ai/glm-5.3", + "opencode:deepseek-v4.1-flash", "nanogpt:z-ai/glm-5.3-flash", "nanogpt:z-ai/glm-5.2", "cline-pass:cline-pass/glm-5.3-flash", + "opencode:mimo-v2.6-pro", + "nanogpt:xiaomi/mimo-v2.6-pro", "cline-pass:cline-pass/mimo-v2.6-pro", ]); // The subscription-only key cannot pay for :fast, so NanoGPT requests stay on the subscription. @@ -272,31 +272,21 @@ test("deployment starts roleplay on OpenCode Go, then Cline Pass, and keeps Nano assert.equal(config.vars?.NANOGPT_SPEED_ROUTING, ""); }); -test("deployment lets DeepSeek hand pivotal turns to GLM 5.3, at most every other turn", async () => { +test("deployment offers no handoff now that GLM 5.3 leads", async () => { const configUrl = new URL("../wrangler.jsonc", import.meta.url); const config = JSON.parse(await readFile(configUrl, "utf8")); - // Measured 2026-10-25: with the tool offered, DeepSeek V4.1 Flash wrote all 12 ordinary turns - // itself and handed off 4 of 6 climax and multi-faction planning turns, each with a full draft. - // Grouped in RUNTIME_FEATURE_FLAGS: the Worker is at its limit of 128 text bindings. + // A source hands off only to targets later in the chain. DeepSeek V4.1 Flash now follows every + // GLM 5.3 entry, so a DeepSeek handoff could never reach one. A separate var would take + // precedence over RUNTIME_FEATURE_FLAGS, so neither setting may exist in either place. const flags = config.vars?.RUNTIME_FEATURE_FLAGS; - assert.equal(config.vars?.ROLEPLAY_HANDOFF_FROM, undefined); - assert.equal(config.vars?.ROLEPLAY_HANDOFF_TO, undefined); - assert.equal(flags?.ROLEPLAY_HANDOFF_FROM, "opencode:deepseek-v4.1-flash"); - assert.deepEqual(flags?.ROLEPLAY_HANDOFF_TO.split(","), [ - "opencode:glm-5.3", - "cline-pass:cline-pass/glm-5.3", - ]); - // ROLEPLAY_HANDOFF_MIN_TURNS keeps its default of 2. - assert.equal(config.vars?.ROLEPLAY_HANDOFF_MIN_TURNS, undefined); - const chain = config.vars?.ROLEPLAY_INTELLIGENCE_MODELS.split(","); - for (const target of flags.ROLEPLAY_HANDOFF_TO.split(",")) { - assert.ok(chain.indexOf(target) > chain.indexOf(flags.ROLEPLAY_HANDOFF_FROM), target); + for (const name of ["ROLEPLAY_HANDOFF_FROM", "ROLEPLAY_HANDOFF_TO"]) { + assert.equal(config.vars?.[name], undefined, name); + assert.equal(flags?.[name], undefined, name); } const settings = getRoleplaySettings(config.vars); - assert.deepEqual([...settings.handoffSources], ["opencode:deepseek-v4.1-flash"]); - assert.deepEqual([...settings.handoffTargets], ["opencode:glm-5.3", "cline-pass:cline-pass/glm-5.3"]); - assert.equal(settings.handoffMinTurns, 2); + assert.equal(settings.handoffSources.size, 0); + assert.equal(settings.handoffTargets.size, 0); }); test("deployment routes GLM through LinkAPI before NavyAI", async () => { diff --git a/tests/test_roleplay_intelligence_worker.mjs b/tests/test_roleplay_intelligence_worker.mjs index 07296108..7ba68b8c 100644 --- a/tests/test_roleplay_intelligence_worker.mjs +++ b/tests/test_roleplay_intelligence_worker.mjs @@ -45,32 +45,32 @@ test("roleplay:intelligence selects the fixed-order preference", () => { }); assert.equal(parsed.modelPreference, "intelligence"); - assert.match(ROLEPLAY_PUBLIC_MODEL_ALIASES["roleplay:intelligence"], /MiMo-V2\.6-Pro/); + assert.match(ROLEPLAY_PUBLIC_MODEL_ALIASES["roleplay:intelligence"], /^fixed order: GLM-5\.3,/); }); -test("the default chain is MiMo first, then GLM-5.3-Flash, 5.3 and 5.2", () => { +test("the default chain is GLM-5.3 first, then GLM-5.3-Flash and 5.2, then MiMo", () => { assert.deepEqual(order(chain(KEYS)), [ - "nanogpt:xiaomi/mimo-v2.6-pro", - "cline-pass:cline-pass/mimo-v2.6-pro", - "nanogpt:z-ai/glm-5.3-flash", - "cline-pass:cline-pass/glm-5.3-flash", - "opencode:glm-5.3-flash", - "navyai:glm-5.3-flash", "nanogpt:z-ai/glm-5.3", "cline-pass:cline-pass/glm-5.3", "opencode:glm-5.3", "navyai:glm-5.3", + "nanogpt:z-ai/glm-5.3-flash", + "cline-pass:cline-pass/glm-5.3-flash", + "opencode:glm-5.3-flash", + "navyai:glm-5.3-flash", "nanogpt:z-ai/glm-5.2", "opencode:glm-5.2", "navyai:glm-5.2", + "nanogpt:xiaomi/mimo-v2.6-pro", + "cline-pass:cline-pass/mimo-v2.6-pro", ]); }); test("chain entries without a provider key are skipped", () => { assert.deepEqual(order(chain({ CLINE_API_KEY: "cline-key" })), [ - "cline-pass:cline-pass/mimo-v2.6-pro", - "cline-pass:cline-pass/glm-5.3-flash", "cline-pass:cline-pass/glm-5.3", + "cline-pass:cline-pass/glm-5.3-flash", + "cline-pass:cline-pass/mimo-v2.6-pro", ]); }); @@ -115,14 +115,14 @@ test("a cooling chain entry moves behind the available ones", () => { const now = 1_000; const ranked = rankRoleplayCandidates( candidates, - { "nanogpt:xiaomi/mimo-v2.6-pro": { cooldownUntil: now + 60_000 } }, + { "nanogpt:z-ai/glm-5.3": { cooldownUntil: now + 60_000 } }, "intelligence", now, ); - assert.equal(ranked[0].model, "cline-pass/mimo-v2.6-pro"); - assert.ok(!ranked.some((candidate) => candidate.model === "xiaomi/mimo-v2.6-pro")); - assert.equal(ranked[0].key, "cline-pass:cline-pass/mimo-v2.6-pro"); + assert.equal(ranked[0].model, "cline-pass/glm-5.3"); + assert.ok(!ranked.some((candidate) => candidate.model === "z-ai/glm-5.3")); + assert.equal(ranked[0].key, "cline-pass:cline-pass/glm-5.3"); }); test("other roleplay aliases never use the intelligence chain", () => { @@ -197,7 +197,7 @@ test("Cline's non-streaming envelope is unwrapped and streams pass through", asy assert.equal(await unwrapClineEnvelope(failure), failure); }); -test("a roleplay:intelligence turn falls back from NanoGPT MiMo to ClinePass MiMo", async () => { +test("a roleplay:intelligence turn falls back from NanoGPT GLM-5.3 to ClinePass GLM-5.3", async () => { const fixture = makeRoleplayEnv({ NANOGPT_API_KEY: "nano-key", CLINE_API_KEY: "cline-key", @@ -219,7 +219,7 @@ test("a roleplay:intelligence turn falls back from NanoGPT MiMo to ClinePass MiM headers: { "Content-Type": "application/json" }, }); } - const completion = await completionResponse(payload.model, "MiMo answers.").json(); + const completion = await completionResponse(payload.model, "GLM answers.").json(); return new Response(JSON.stringify({ data: completion, success: true }), { headers: { "Content-Type": "application/json" }, }); @@ -238,13 +238,13 @@ test("a roleplay:intelligence turn falls back from NanoGPT MiMo to ClinePass MiM assert.equal(response.status, 200); const body = await response.json(); - assert.equal(body.choices[0].message.content, "MiMo answers."); + assert.equal(body.choices[0].message.content, "GLM answers."); assert.equal(response.headers.get("X-Roleplay-Provider"), "cline-pass"); - assert.equal(response.headers.get("X-Roleplay-Model"), "cline-pass/mimo-v2.6-pro"); + assert.equal(response.headers.get("X-Roleplay-Model"), "cline-pass/glm-5.3"); assert.equal(response.headers.get("X-Roleplay-Fallback-Count"), "1"); assert.deepEqual( calls.map((call) => call.model), - ["xiaomi/mimo-v2.6-pro", "cline-pass/mimo-v2.6-pro"], + ["z-ai/glm-5.3", "cline-pass/glm-5.3"], ); assert.equal(calls[1].url, "https://api.cline.bot/api/v1/chat/completions"); assert.equal(calls[1].authorization, "Bearer cline-key"); @@ -297,15 +297,15 @@ async function autoTurn(env, sessionId) { return { response, calls }; } -test("roleplay:auto starts with MiMo when ROLEPLAY_AUTO_ROUTE=intelligence", async () => { +test("roleplay:auto starts with GLM-5.3 when ROLEPLAY_AUTO_ROUTE=intelligence", async () => { const { response, calls } = await autoTurn( { NANOGPT_API_KEY: "nano-key", CLINE_API_KEY: "cline-key", ROLEPLAY_AUTO_ROUTE: "intelligence" }, "session-auto-intelligence", ); assert.equal(response.status, 200); - assert.deepEqual(calls, ["xiaomi/mimo-v2.6-pro"]); - assert.equal(response.headers.get("X-Roleplay-Model"), "xiaomi/mimo-v2.6-pro"); + assert.deepEqual(calls, ["z-ai/glm-5.3"]); + assert.equal(response.headers.get("X-Roleplay-Model"), "z-ai/glm-5.3"); }); test("roleplay:auto keeps the adaptive pool without the switch", async () => { @@ -315,7 +315,7 @@ test("roleplay:auto keeps the adaptive pool without the switch", async () => { ); assert.equal(response.status, 200); - assert.notEqual(calls[0], "xiaomi/mimo-v2.6-pro"); + assert.notEqual(calls[0], "z-ai/glm-5.3"); }); test("roleplay:auto falls back to the adaptive pool when the chain has no key", async () => { diff --git a/tests/test_runtime_feature_flags_worker.mjs b/tests/test_runtime_feature_flags_worker.mjs index 5c05574f..3c1cc32a 100644 --- a/tests/test_runtime_feature_flags_worker.mjs +++ b/tests/test_runtime_feature_flags_worker.mjs @@ -10,7 +10,7 @@ const config = JSON.parse(await readFile(new URL("../wrangler.jsonc", import.met const { MultiLLMProxyContainer } = await loadWorkerModule(); test("deployment groups feature settings while preserving Container flags and secrets", () => { - assert.equal(Object.keys(config.vars.RUNTIME_FEATURE_FLAGS).length, 9); + assert.equal(Object.keys(config.vars.RUNTIME_FEATURE_FLAGS).length, 7); // Vars and secrets share the Worker's limit of 128 text bindings, and the release has 127. // Put a new nonsecret setting in RUNTIME_FEATURE_FLAGS instead of raising this count. assert.equal(Object.keys(config.vars).length, 65); @@ -26,7 +26,6 @@ test("deployment groups feature settings while preserving Container flags and se assert.equal(container.envVars.RUNTIME_FEATURE_FLAGS, undefined); assert.equal(usageBucketsEnabled(source), true); assert.equal(runtimeFeatureValue(source, "ROLEPLAY_CANDIDATE_CONTEXT_REFIT"), "window"); - assert.equal(runtimeFeatureValue(source, "ROLEPLAY_HANDOFF_FROM"), "opencode:deepseek-v4.1-flash"); }); test("individual settings retain disabled values and precedence without mutating bindings", () => { diff --git a/worker/roleplay/config.mjs b/worker/roleplay/config.mjs index 18686506..49434d07 100644 --- a/worker/roleplay/config.mjs +++ b/worker/roleplay/config.mjs @@ -94,23 +94,23 @@ const REASONING_EFFORTS = new Set([ ]); const MAX_PROVIDER_MODELS_PER_FAMILY = 8; const MAX_INTELLIGENCE_CHAIN_ENTRIES = 32; -// roleplay:intelligence tries these strictly in order: MiMo-V2.6-Pro on NanoGPT -// then ClinePass, then GLM-5.3-Flash, GLM-5.3 and GLM-5.2 on every subscription -// or allowance provider. ROLEPLAY_INTELLIGENCE_MODELS replaces the list. +// roleplay:intelligence tries these strictly in order: GLM-5.3, GLM-5.3-Flash and +// GLM-5.2 on every subscription or allowance provider, then MiMo-V2.6-Pro on +// NanoGPT and ClinePass. ROLEPLAY_INTELLIGENCE_MODELS replaces the list. const DEFAULT_INTELLIGENCE_CHAIN = [ - "nanogpt:xiaomi/mimo-v2.6-pro", - "cline-pass:cline-pass/mimo-v2.6-pro", - "nanogpt:z-ai/glm-5.3-flash", - "cline-pass:cline-pass/glm-5.3-flash", - "opencode:glm-5.3-flash", - "navyai:glm-5.3-flash", "nanogpt:z-ai/glm-5.3", "cline-pass:cline-pass/glm-5.3", "opencode:glm-5.3", "navyai:glm-5.3", + "nanogpt:z-ai/glm-5.3-flash", + "cline-pass:cline-pass/glm-5.3-flash", + "opencode:glm-5.3-flash", + "navyai:glm-5.3-flash", "nanogpt:z-ai/glm-5.2", "opencode:glm-5.2", "navyai:glm-5.2", + "nanogpt:xiaomi/mimo-v2.6-pro", + "cline-pass:cline-pass/mimo-v2.6-pro", ]; const DEFAULT_MODELS = { kimi: "kimi-k2.6", diff --git a/worker/roleplay/model-selection.mjs b/worker/roleplay/model-selection.mjs index 11d04695..ce56ecec 100644 --- a/worker/roleplay/model-selection.mjs +++ b/worker/roleplay/model-selection.mjs @@ -57,7 +57,7 @@ export const ROLEPLAY_PUBLIC_MODEL_ALIASES = Object.freeze({ "roleplay:5.3": "full GLM-5.3 only", "roleplay:5.2": "GLM-5.2 only", "roleplay:uncensored": "uncensored GLM route with GLM-5.2 Venice fallback", - "roleplay:intelligence": "fixed order: MiMo-V2.6-Pro (NanoGPT, ClinePass), then GLM-5.3-Flash, GLM-5.3 and GLM-5.2 across providers", + "roleplay:intelligence": "fixed order: GLM-5.3, then GLM-5.3-Flash and GLM-5.2 across providers, then MiMo-V2.6-Pro (NanoGPT, ClinePass)", }); function normalizedPreference(value) { diff --git a/wrangler.jsonc b/wrangler.jsonc index 2748bc1c..d0c3ffa0 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -110,7 +110,7 @@ "ROLEPLAY_PROVIDER_FAMILIES": "{\"nanogpt\":[\"glm\"],\"linkapi\":[\"kimi\"],\"navyai\":[\"glm\"]}", "ROLEPLAY_PROVIDER_LIMITS": "{}", "ROLEPLAY_AUTO_ROUTE": "intelligence", - "ROLEPLAY_INTELLIGENCE_MODELS": "opencode:deepseek-v4.1-flash,opencode:glm-5.3,opencode:mimo-v2.6-pro,cline-pass:cline-pass/glm-5.3,nanogpt:xiaomi/mimo-v2.6-pro,nanogpt:z-ai/glm-5.3,nanogpt:z-ai/glm-5.3-flash,nanogpt:z-ai/glm-5.2,cline-pass:cline-pass/glm-5.3-flash,cline-pass:cline-pass/mimo-v2.6-pro", + "ROLEPLAY_INTELLIGENCE_MODELS": "opencode:glm-5.3,cline-pass:cline-pass/glm-5.3,nanogpt:z-ai/glm-5.3,opencode:deepseek-v4.1-flash,nanogpt:z-ai/glm-5.3-flash,nanogpt:z-ai/glm-5.2,cline-pass:cline-pass/glm-5.3-flash,opencode:mimo-v2.6-pro,nanogpt:xiaomi/mimo-v2.6-pro,cline-pass:cline-pass/mimo-v2.6-pro", "GLM_AUTO_OPTIMIZE": "true", "GLM_AUTO_OPTIMIZE_TRIGGER_TOKENS": "8000", "GLM_AUTO_OPTIMIZE_KEEP_RECENT_TURNS": "8", @@ -164,8 +164,6 @@ "PROMPT_CACHE_AFFINITY_ENABLED": "true", "PROMPT_CACHE_USAGE_BUCKETS_ENABLED": "true", "ROLEPLAY_CANDIDATE_CONTEXT_REFIT": "window", - "ROLEPLAY_HANDOFF_FROM": "opencode:deepseek-v4.1-flash", - "ROLEPLAY_HANDOFF_TO": "opencode:glm-5.3,cline-pass:cline-pass/glm-5.3", "UPSTREAM_RETRY_AFTER_ADVICE_ENABLED": "true", "MULTILLM_STREAM_PREFLIGHT": "strict" }