From 7857e0ac6dab8e09d6a43ae52b18fbaf9febcb0d Mon Sep 17 00:00:00 2001 From: "Bob.Hou" Date: Fri, 7 Aug 2026 19:52:51 -0400 Subject: [PATCH] refactor(sse): move the thinking-budget helpers out of base.ts (#9381) Merge-train validated (tip 6ce4effef8). Vitest failures confirmed as base-red (#9679). --- open-sse/executors/base.ts | 70 +++---------------------------- open-sse/utils/thinkingBudget.ts | 72 ++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 65 deletions(-) create mode 100644 open-sse/utils/thinkingBudget.ts diff --git a/open-sse/executors/base.ts b/open-sse/executors/base.ts index b71f717b97..c3391278bf 100644 --- a/open-sse/executors/base.ts +++ b/open-sse/executors/base.ts @@ -234,71 +234,11 @@ export function mergeAbortSignals(primary: AbortSignal, secondary: AbortSignal): return controller.signal; } -function hasActiveClaudeThinking(body: Record): boolean { - const thinking = body.thinking as Record | undefined; - return thinking?.type === "enabled" || thinking?.type === "adaptive"; -} - -/** - * Collect every `thinkingConfig` object in a transformed request body that holds - * a thinking budget, wherever the provider's envelope nests it: - * - body.generationConfig.thinkingConfig (native Gemini / openai→gemini) - * - body.request.generationConfig.thinkingConfig (Antigravity Cloud Code envelope) - * Returns only objects that actually carry a `thinkingBudget`/`thinking_budget` - * field — a request without thinking config is never mutated. - */ -function collectThinkingConfigs(body: unknown): Array> { - if (!body || typeof body !== "object") return []; - const root = body as Record; - const configs: Array> = []; - const envelopes: unknown[] = [ - root.generationConfig, - (root.request as Record | undefined)?.generationConfig, - ]; - for (const env of envelopes) { - if (!env || typeof env !== "object") continue; - const tc = (env as Record).thinkingConfig; - if (tc && typeof tc === "object") { - const tcr = tc as Record; - if ("thinkingBudget" in tcr || "thinking_budget" in tcr) configs.push(tcr); - } - } - return configs; -} - -/** - * Read the first thinking budget found in the body (any supported nest / naming). - * Returns null when the body carries no readable numeric budget. - */ -function readNestedThinkingBudget(body: unknown): number | null { - for (const tc of collectThinkingConfigs(body)) { - const raw = tc.thinkingBudget ?? tc.thinking_budget; - const n = Number(raw); - if (Number.isFinite(n)) return n; - } - return null; -} - -/** - * Clamp every thinking budget in the body down to `max` (only lowers; never - * raises a budget already below max). Mutates in place. Returns true when at - * least one budget was actually lowered (i.e. a retry would send a different - * body) — false means the 400 was not caused by an over-max budget we hold, so - * retrying would resend an identical body and loop. - */ -function clampNestedThinkingBudget(body: unknown, max: number): boolean { - let changed = false; - for (const tc of collectThinkingConfigs(body)) { - for (const key of ["thinkingBudget", "thinking_budget"] as const) { - const n = Number(tc[key]); - if (Number.isFinite(n) && n > max) { - tc[key] = max; - changed = true; - } - } - } - return changed; -} +import { + hasActiveClaudeThinking, + readNestedThinkingBudget, + clampNestedThinkingBudget, +} from "../utils/thinkingBudget.ts"; /** * Strip the OmniRoute provider prefix from tool model fields (e.g. diff --git a/open-sse/utils/thinkingBudget.ts b/open-sse/utils/thinkingBudget.ts new file mode 100644 index 0000000000..b97078f782 --- /dev/null +++ b/open-sse/utils/thinkingBudget.ts @@ -0,0 +1,72 @@ +/** + * Thinking-budget helpers extracted from base.ts. + * + * Pure utilities for reading / clamping the thinking budget fields that + * different providers nest inside the request body. + */ + +export function hasActiveClaudeThinking(body: Record): boolean { + const thinking = body.thinking as Record | undefined; + return thinking?.type === "enabled" || thinking?.type === "adaptive"; +} + +/** + * Collect every `thinkingConfig` object in a transformed request body that holds + * a thinking budget, wherever the provider's envelope nests it: + * - body.generationConfig.thinkingConfig (native Gemini / openai→gemini) + * - body.request.generationConfig.thinkingConfig (Antigravity Cloud Code envelope) + * Returns only objects that actually carry a `thinkingBudget`/`thinking_budget` + * field — a request without thinking config is never mutated. + */ +export function collectThinkingConfigs(body: unknown): Array> { + if (!body || typeof body !== "object") return []; + const root = body as Record; + const configs: Array> = []; + const envelopes: unknown[] = [ + root.generationConfig, + (root.request as Record | undefined)?.generationConfig, + ]; + for (const env of envelopes) { + if (!env || typeof env !== "object") continue; + const tc = (env as Record).thinkingConfig; + if (tc && typeof tc === "object") { + const tcr = tc as Record; + if ("thinkingBudget" in tcr || "thinking_budget" in tcr) configs.push(tcr); + } + } + return configs; +} + +/** + * Read the first thinking budget found in the body (any supported nest / naming). + * Returns null when the body carries no readable numeric budget. + */ +export function readNestedThinkingBudget(body: unknown): number | null { + for (const tc of collectThinkingConfigs(body)) { + const raw = tc.thinkingBudget ?? tc.thinking_budget; + const n = Number(raw); + if (Number.isFinite(n)) return n; + } + return null; +} + +/** + * Clamp every thinking budget in the body down to `max` (only lowers; never + * raises a budget already below max). Mutates in place. Returns true when at + * least one budget was actually lowered (i.e. a retry would send a different + * body) — false means the 400 was not caused by an over-max budget we hold, so + * retrying would resend an identical body and loop. + */ +export function clampNestedThinkingBudget(body: unknown, max: number): boolean { + let changed = false; + for (const tc of collectThinkingConfigs(body)) { + for (const key of ["thinkingBudget", "thinking_budget"] as const) { + const n = Number(tc[key]); + if (Number.isFinite(n) && n > max) { + tc[key] = max; + changed = true; + } + } + } + return changed; +}