Files
OmniRoute/src/app/api/settings/combo-defaults/route.ts
Randi 5b2c2d6be4 fix(combo): gate reasoning token buffer (#3700)
Integrated into release/v3.8.23. Makes the #3588 reasoning token buffer safe and configurable: only inflates max_tokens when the model has a known, non-default output cap and the buffered value fits inside it; otherwise preserves/clamps the client limit. Adds the reasoningTokenBufferEnabled kill switch (default ON). Validated: combo-routing-engine 81/81, combo-config 25/25, combo-quality-validator-reasoning 12/12, phase1f 10/10, typecheck:core clean.
2026-06-12 08:28:17 -03:00

118 lines
3.8 KiB
TypeScript

import { NextResponse } from "next/server";
import { getSettings, updateSettings } from "@/lib/localDb";
import { updateComboDefaultsSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
const LEGACY_COMBO_RESILIENCE_KEYS = new Set([
"timeoutMs",
"healthCheckEnabled",
"healthCheckTimeoutMs",
]);
function sanitizeComboRuntimeConfig(config?: Record<string, any> | null) {
if (!config || typeof config !== "object") return {};
return Object.fromEntries(
Object.entries(config).filter(
([key, value]) =>
value !== undefined && value !== null && !LEGACY_COMBO_RESILIENCE_KEYS.has(key)
)
);
}
function sanitizeProviderOverrides(overrides?: Record<string, any> | null) {
if (!overrides || typeof overrides !== "object") return {};
return Object.fromEntries(
Object.entries(overrides).map(([providerId, config]) => [
providerId,
sanitizeComboRuntimeConfig(config),
])
);
}
/**
* GET /api/settings/combo-defaults
* Returns the current combo global defaults and provider overrides
*/
export async function GET(request: Request) {
const authError = await requireManagementAuth(request);
if (authError) return authError;
try {
const settings: any = await getSettings();
const comboDefaults = sanitizeComboRuntimeConfig(settings.comboDefaults);
const providerOverrides = sanitizeProviderOverrides(settings.providerOverrides);
return NextResponse.json({
comboDefaults:
Object.keys(comboDefaults).length > 0
? comboDefaults
: {
strategy: "priority",
maxRetries: 1,
retryDelayMs: 2000,
fallbackDelayMs: 0,
handoffThreshold: 0.85,
handoffModel: "",
maxMessagesForSummary: 30,
maxComboDepth: 3,
trackMetrics: true,
reasoningTokenBufferEnabled: true,
zeroLatencyOptimizationsEnabled: false,
},
providerOverrides,
});
} catch (error) {
console.log("Error fetching combo defaults:", error);
return NextResponse.json({ error: "Failed to fetch combo defaults" }, { status: 500 });
}
}
/**
* PATCH /api/settings/combo-defaults
* Update combo global defaults and/or provider overrides
* Body: { comboDefaults?: {...}, providerOverrides?: {...} }
*/
export async function PATCH(request: Request) {
const authError = await requireManagementAuth(request);
if (authError) return authError;
let rawBody;
try {
rawBody = await request.json();
} catch {
return NextResponse.json(
{
error: {
message: "Invalid request",
details: [{ field: "body", message: "Invalid JSON body" }],
},
},
{ status: 400 }
);
}
try {
const validation = validateBody(updateComboDefaultsSchema, rawBody);
if (isValidationFailure(validation)) {
return NextResponse.json({ error: validation.error }, { status: 400 });
}
const body = validation.data;
const updates: Record<string, any> = {};
if (body.comboDefaults) {
updates.comboDefaults = sanitizeComboRuntimeConfig(body.comboDefaults);
}
if (body.providerOverrides) {
updates.providerOverrides = sanitizeProviderOverrides(body.providerOverrides);
}
const settings: any = await updateSettings(updates);
return NextResponse.json({
comboDefaults: sanitizeComboRuntimeConfig(settings.comboDefaults),
providerOverrides: sanitizeProviderOverrides(settings.providerOverrides),
});
} catch (error) {
console.log("Error updating combo defaults:", error);
return NextResponse.json({ error: "Failed to update combo defaults" }, { status: 500 });
}
}