From 2d1a281d12ba002a2e8469f950446bd7860ca566 Mon Sep 17 00:00:00 2001 From: Koosha Paridehpour <42529354+KooshaPari@users.noreply.github.com> Date: Mon, 14 Sep 2026 20:08:31 -0700 Subject: [PATCH] fix(providers): add alwaysReasons metadata for reka-flash-3 (#13531) `reka-flash-3` is marked `supportsReasoning` + `alwaysReasons` (with its 8192 output cap). `DefaultExecutor.ensureThinkingBudget` treats always-on reasoning as an implicit opt-in, so a small caller `max_tokens` gets the 4096 floor instead of being spent on reasoning and returning an empty answer (#13198). `alwaysReasons` is documented on `RegistryModel`. Maintainer addition: `tests/unit/reka-flash-3-always-reasons-13198.test.ts` asserts the floor for `reka-flash-3` without any reasoning settings (fails on the release tip) and that `reka-flash` keeps the caller value. The branch also carried the #13532 Compare-scroll commit, which landed first; its hunks are identical, so this squash only adds the reka change. Validated in one consolidated batch of this series (37 PRs boarded together on `release/v3.8.51`): `typecheck:core`, `check:open-sse-typecheck` and `check:dashboard-typecheck` clean; ESLint clean on every changed file; file-size, complexity, cognitive-complexity, changelog-integrity, docs-counts, docs-sync and migration-numbering gates green (only the pre-existing `open-sse/utils/stream.ts` file-size red remains, inherited from the base); 3,743 focused `node:test` cases plus 34 vitest cases green. Thanks @KooshaPari! --- .../config/providers/registry/reka/index.ts | 2 +- open-sse/config/providers/shared.ts | 7 ++++++ open-sse/executors/default.ts | 3 ++- .../reka-flash-3-always-reasons-13198.test.ts | 22 +++++++++++++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 tests/unit/reka-flash-3-always-reasons-13198.test.ts diff --git a/open-sse/config/providers/registry/reka/index.ts b/open-sse/config/providers/registry/reka/index.ts index b394800a09..c933eeb20d 100644 --- a/open-sse/config/providers/registry/reka/index.ts +++ b/open-sse/config/providers/registry/reka/index.ts @@ -11,7 +11,7 @@ export const rekaProvider: RegistryEntry = { models: [ // reka-flash-3 stays first so it remains the provider default (the free-tier // model in freeModelCatalog); reka-flash was added in #4621 as an extra option. - { id: "reka-flash-3", name: "Reka Flash 3" }, + { id: "reka-flash-3", name: "Reka Flash 3", supportsReasoning: true, alwaysReasons: true, maxOutputTokens: 8192 }, { id: "reka-flash", name: "Reka Flash" }, { id: "reka-edge-2603", name: "Reka Edge 2603" }, ], diff --git a/open-sse/config/providers/shared.ts b/open-sse/config/providers/shared.ts index 8b9b45bfec..250d631775 100644 --- a/open-sse/config/providers/shared.ts +++ b/open-sse/config/providers/shared.ts @@ -56,6 +56,13 @@ export interface RegistryModel { liveCatalogIds?: readonly string[]; toolCalling?: boolean; supportsReasoning?: boolean; + /** + * Model reasons unconditionally (always-on reasoning). When true, + * ensureThinkingBudget treats it as implicit reasoning opt-in so a tiny + * caller max_tokens gets the 4096 floor even without explicit thinking + * settings (#13198). + */ + alwaysReasons?: boolean; supportedThinkingEfforts?: readonly string[]; supportsVision?: boolean; supportsAudio?: boolean; diff --git a/open-sse/executors/default.ts b/open-sse/executors/default.ts index 4fb164a303..c267904d9f 100644 --- a/open-sse/executors/default.ts +++ b/open-sse/executors/default.ts @@ -1076,7 +1076,8 @@ export class DefaultExecutor extends BaseExecutor { const reasoningEnabled = thinking?.type === "enabled" || (typeof effort === "string" && effort !== "none" && effort !== "off") || - effort === true; + effort === true || + modelEntry.alwaysReasons === true; if (!reasoningEnabled) return body; const MIN_TOKENS = 4096; diff --git a/tests/unit/reka-flash-3-always-reasons-13198.test.ts b/tests/unit/reka-flash-3-always-reasons-13198.test.ts new file mode 100644 index 0000000000..c74bdf54a3 --- /dev/null +++ b/tests/unit/reka-flash-3-always-reasons-13198.test.ts @@ -0,0 +1,22 @@ +import test from "node:test"; +import assert from "node:assert/strict"; + +import { DefaultExecutor } from "../../open-sse/executors/default.ts"; + +// #13198: reka-flash-3 reasons on every request, so a tiny caller max_tokens is +// spent on reasoning and the answer comes back empty unless the 4096 floor applies +// even without an explicit reasoning_effort / thinking setting. + +test("#13198 reka-flash-3 gets the thinking-budget floor without explicit reasoning settings", () => { + const executor = new DefaultExecutor("reka"); + const body = { model: "reka-flash-3", max_tokens: 256 } as Record; + executor.ensureThinkingBudget(body, "reka-flash-3"); + assert.equal(body.max_tokens, 4096); +}); + +test("#13198 non-reasoning reka models keep the caller's max_tokens", () => { + const executor = new DefaultExecutor("reka"); + const body = { model: "reka-flash", max_tokens: 256 } as Record; + executor.ensureThinkingBudget(body, "reka-flash"); + assert.equal(body.max_tokens, 256); +});