From 37ac38f17f205bcd18b7e3395758db059cdc341a Mon Sep 17 00:00:00 2001 From: Xiangzhe Date: Tue, 7 Jul 2026 11:24:42 +0800 Subject: [PATCH] fix(combos): default reasoning token buffer off --- open-sse/services/combo.ts | 7 +++++-- open-sse/services/combo/comboSetup.ts | 6 ++---- open-sse/services/comboConfig.ts | 2 +- .../settings/components/ComboDefaultsTab.tsx | 9 ++++----- src/app/api/settings/combo-defaults/route.ts | 2 +- tests/unit/combo-config.test.ts | 2 +- tests/unit/combo-routing-engine.test.ts | 13 ++++++------- tests/unit/combo/combo-context.test.ts | 12 ++++++++++-- 8 files changed, 30 insertions(+), 23 deletions(-) diff --git a/open-sse/services/combo.ts b/open-sse/services/combo.ts index 94a090c87c..e0240adf81 100644 --- a/open-sse/services/combo.ts +++ b/open-sse/services/combo.ts @@ -2431,7 +2431,7 @@ async function handleRoundRobinCombo({ const maxRetries = config.maxRetries ?? 1; const retryDelayMs = resolveDelayMs(config.retryDelayMs, 2000); const fallbackDelayMs = resolveDelayMs(config.fallbackDelayMs, 0); - const reasoningTokenBufferEnabled = config.reasoningTokenBufferEnabled !== false; + const reasoningTokenBufferEnabled = config.reasoningTokenBufferEnabled === true; const resilienceSettings: ResilienceSettings = settings ? resolveResilienceSettings(settings) @@ -3032,7 +3032,10 @@ async function handleRoundRobinCombo({ resilienceSettings.providerCooldown.enabled && provider && provider !== "unknown" && - !(result.status === 500 && hasPerModelQuota(provider, parseModel(modelStr).model || modelStr)) + !( + result.status === 500 && + hasPerModelQuota(provider, parseModel(modelStr).model || modelStr) + ) ) { recordProviderCooldown( provider, diff --git a/open-sse/services/combo/comboSetup.ts b/open-sse/services/combo/comboSetup.ts index 4b7e8b56e9..c146e8c7b5 100644 --- a/open-sse/services/combo/comboSetup.ts +++ b/open-sse/services/combo/comboSetup.ts @@ -90,9 +90,7 @@ export function phaseComboSetup(ctx: ComboContext): ComboSetup { const universalHandoffConfig = resolveUniversalHandoffConfig( (combo.universal_handoff || combo.universalHandoff) as - | Record - | null - | undefined, + Record | null | undefined, relayOptions?.universalHandoffConfig as Record | null | undefined ); @@ -118,7 +116,7 @@ export function phaseComboSetup(ctx: ComboContext): ComboSetup { FETCH_TIMEOUT_MS, DEFAULT_COMBO_TARGET_TIMEOUT_MS ); - const reasoningTokenBufferEnabled = config.reasoningTokenBufferEnabled !== false; + const reasoningTokenBufferEnabled = config.reasoningTokenBufferEnabled === true; return { strategy, diff --git a/open-sse/services/comboConfig.ts b/open-sse/services/comboConfig.ts index aa26cd4703..9dcc585ec8 100644 --- a/open-sse/services/comboConfig.ts +++ b/open-sse/services/comboConfig.ts @@ -53,7 +53,7 @@ const DEFAULT_COMBO_CONFIG = { maxComboDepth: 3, nestedComboMode: "flatten", trackMetrics: true, - reasoningTokenBufferEnabled: true, + reasoningTokenBufferEnabled: false, manifestRouting: false, // Complexity-aware auto routing (2026): when on, the auto router scores // candidates by how well their tier matches the request's classified diff --git a/src/app/(dashboard)/dashboard/settings/components/ComboDefaultsTab.tsx b/src/app/(dashboard)/dashboard/settings/components/ComboDefaultsTab.tsx index 8544506287..e88f6f050f 100644 --- a/src/app/(dashboard)/dashboard/settings/components/ComboDefaultsTab.tsx +++ b/src/app/(dashboard)/dashboard/settings/components/ComboDefaultsTab.tsx @@ -93,7 +93,7 @@ export default function ComboDefaultsTab() { retryDelayMs: 2000, maxComboDepth: 3, trackMetrics: true, - reasoningTokenBufferEnabled: true, + reasoningTokenBufferEnabled: false, handoffThreshold: 0.85, handoffModel: "", maxMessagesForSummary: 30, @@ -292,8 +292,7 @@ export default function ComboDefaultsTab() { // Filtered provider list — excludes already-added ones, filtered by search query const filteredProviders = availableProviders.filter( - (p) => - !providerOverrides[p.provider] && matchesSearch(p.provider, searchQuery) + (p) => !providerOverrides[p.provider] && matchesSearch(p.provider, searchQuery) ); const handleDropdownKeyDown = (e: React.KeyboardEvent) => { @@ -690,11 +689,11 @@ export default function ComboDefaultsTab() {

setComboDefaults((prev) => ({ ...prev, - reasoningTokenBufferEnabled: prev.reasoningTokenBufferEnabled === false, + reasoningTokenBufferEnabled: prev.reasoningTokenBufferEnabled !== true, })) } /> diff --git a/src/app/api/settings/combo-defaults/route.ts b/src/app/api/settings/combo-defaults/route.ts index 9e6ca358e4..27d76073d7 100644 --- a/src/app/api/settings/combo-defaults/route.ts +++ b/src/app/api/settings/combo-defaults/route.ts @@ -55,7 +55,7 @@ export async function GET(request: Request) { maxMessagesForSummary: 30, maxComboDepth: 3, trackMetrics: true, - reasoningTokenBufferEnabled: true, + reasoningTokenBufferEnabled: false, zeroLatencyOptimizationsEnabled: false, }, providerOverrides, diff --git a/tests/unit/combo-config.test.ts b/tests/unit/combo-config.test.ts index e3b99e9733..2ece13c3df 100644 --- a/tests/unit/combo-config.test.ts +++ b/tests/unit/combo-config.test.ts @@ -30,7 +30,7 @@ test("getDefaultComboConfig returns a fresh copy of the defaults", () => { assert.equal(first.failoverBeforeRetry, true); assert.equal(first.maxSetRetries, 0); assert.equal(first.setRetryDelayMs, 2000); - assert.equal(first.reasoningTokenBufferEnabled, true); + assert.equal(first.reasoningTokenBufferEnabled, false); assert.equal(first.zeroLatencyOptimizationsEnabled, false); assert.equal(first.hedging, false); assert.equal(first.fallbackCompressionMode, "lite"); diff --git a/tests/unit/combo-routing-engine.test.ts b/tests/unit/combo-routing-engine.test.ts index 7ea5271345..14df6a198c 100644 --- a/tests/unit/combo-routing-engine.test.ts +++ b/tests/unit/combo-routing-engine.test.ts @@ -2869,7 +2869,7 @@ test("handleComboChat aborts combo when 503 response does NOT contain the unavai ); }); -test("#3587 reasoning model gets max_tokens buffer applied", async () => { +test("#3587 reasoning model gets max_tokens buffer applied when explicitly enabled", async () => { saveModelsDevCapabilities({ openai: { "gpt-4o-reasoning": capabilityEntry(12000, { reasoning: true, limit_output: 12000 }), @@ -2882,6 +2882,7 @@ test("#3587 reasoning model gets max_tokens buffer applied", async () => { combo: { name: "reasoning-buffer", models: ["openai/gpt-4o-reasoning"], + config: { reasoningTokenBufferEnabled: true }, }, handleSingleModel: async (body: Record) => { bodies.push(body); @@ -2934,6 +2935,7 @@ test("#3587 reasoning buffer preserves max_tokens when the full buffer exceeds m combo: { name: "reasoning-buffer-near-cap", models: ["openai/gemini-high-cap"], + config: { reasoningTokenBufferEnabled: true }, }, handleSingleModel: async (body: Record) => { bodies.push(body); @@ -2983,7 +2985,7 @@ test("#3587 reasoning buffer is disabled without explicit model capability data" ); }); -test("#3588 reasoning token buffer feature flag preserves client max_tokens", async () => { +test("#3588 reasoning token buffer is disabled by default and preserves client max_tokens", async () => { saveModelsDevCapabilities({ openai: { "flagged-reasoning": capabilityEntry(12000, { reasoning: true, limit_output: 12000 }), @@ -3009,11 +3011,7 @@ test("#3588 reasoning token buffer feature flag preserves client max_tokens", as }, isModelAvailable: async () => true, log: createLog(), - settings: { - comboDefaults: { - reasoningTokenBufferEnabled: false, - }, - }, + settings: null, relayOptions: null, allCombos: null, }); @@ -3078,6 +3076,7 @@ test("#3587 round-robin buffer does NOT compound across reasoning models", async name: "rr-reasoning-no-compound", strategy: "round-robin", models: ["openai/rr-reasoning-a", "openai/rr-reasoning-b"], + config: { reasoningTokenBufferEnabled: true }, }, handleSingleModel: async (body: Record, modelStr: string) => { seen.push({ model: modelStr, maxTokens: body.max_tokens }); diff --git a/tests/unit/combo/combo-context.test.ts b/tests/unit/combo/combo-context.test.ts index 1895e042aa..926a6b7d11 100644 --- a/tests/unit/combo/combo-context.test.ts +++ b/tests/unit/combo/combo-context.test.ts @@ -15,7 +15,11 @@ test("createComboContext carries inputs and the body BY REFERENCE", () => { const body = { model: "auto", messages: [], stream: true }; const combo = { name: "c1", models: ["a", "b"] }; const ctx = createComboContext({ body, combo, log }); - assert.equal(ctx.body, body, "body must be the same reference (not copied) for byte-identical pinning"); + assert.equal( + ctx.body, + body, + "body must be the same reference (not copied) for byte-identical pinning" + ); assert.equal(ctx.combo, combo); assert.equal(ctx.settings, null); assert.equal(ctx.relayOptions, null); @@ -34,7 +38,11 @@ test("phaseComboSetup resolves strategy/config/stream with pinning OFF (pure, no assert.equal(setup.effectiveSessionId, null); assert.equal(setup.clientRequestedStream, true, "body.stream === true"); assert.equal(typeof setup.comboTargetTimeoutMs, "number"); - assert.equal(typeof setup.reasoningTokenBufferEnabled, "boolean"); + assert.equal( + setup.reasoningTokenBufferEnabled, + false, + "reasoning token buffering is opt-in by default" + ); assert.ok(setup.config && typeof setup.config === "object", "config cascade resolved"); assert.ok( setup.resilienceSettings && typeof setup.resilienceSettings === "object",