mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
Rebuilt onto release/v3.8.33 (base was the now-merged #4511 branch). Integrated into release/v3.8.33.
This commit is contained in:
committed by
GitHub
parent
b28f6e9346
commit
2601a557b8
@@ -249,11 +249,7 @@ import {
|
||||
getTokenLimit,
|
||||
resolveComboContextLimit,
|
||||
} from "../services/contextManager.ts";
|
||||
import {
|
||||
getBackgroundTaskReason,
|
||||
getDegradedModel,
|
||||
getBackgroundDegradationConfig,
|
||||
} from "../services/backgroundTaskDetector.ts";
|
||||
import { resolveBackgroundTaskRedirect } from "./chatCore/backgroundRedirect.ts";
|
||||
import type { CompressionConfig, CompressionPipelineStep } from "../services/compression/types.ts";
|
||||
import { prepareWebSearchFallbackBody } from "../services/webSearchFallback.ts";
|
||||
import {
|
||||
@@ -904,35 +900,35 @@ export async function handleChatCore({
|
||||
// Detect source format and get target format
|
||||
// Model-specific targetFormat takes priority over provider default
|
||||
|
||||
// ── Background Task Redirection (T41) ──
|
||||
const bgConfig = getBackgroundDegradationConfig();
|
||||
const backgroundReason = bgConfig.enabled
|
||||
? getBackgroundTaskReason(body, clientRawRequest?.headers)
|
||||
: null;
|
||||
if (backgroundReason) {
|
||||
const degradedModel = getDegradedModel(model);
|
||||
if (degradedModel !== model) {
|
||||
const originalModel = model;
|
||||
log?.info?.(
|
||||
"BACKGROUND",
|
||||
`Background task redirect (${backgroundReason}): ${originalModel} → ${degradedModel}`
|
||||
);
|
||||
model = degradedModel;
|
||||
if (body && typeof body === "object") {
|
||||
body.model = model;
|
||||
}
|
||||
|
||||
logAuditEvent({
|
||||
action: "routing.background_task_redirect",
|
||||
actor: apiKeyInfo?.name || "system",
|
||||
target: connectionId || provider || "chat",
|
||||
details: {
|
||||
original_model: originalModel,
|
||||
redirected_to: degradedModel,
|
||||
reason: backgroundReason,
|
||||
},
|
||||
});
|
||||
// ── Background Task Redirection (T41) — decision extracted to chatCore/backgroundRedirect.ts (#3501)
|
||||
// backgroundReason is the detection signal (threaded into memory/skills injection below); redirect
|
||||
// is the actual model downgrade to apply, if any.
|
||||
const { backgroundReason, redirect: bgRedirect } = resolveBackgroundTaskRedirect({
|
||||
body,
|
||||
headers: clientRawRequest?.headers,
|
||||
model,
|
||||
});
|
||||
if (bgRedirect) {
|
||||
const originalModel = model;
|
||||
log?.info?.(
|
||||
"BACKGROUND",
|
||||
`Background task redirect (${bgRedirect.reason}): ${originalModel} → ${bgRedirect.degradedModel}`
|
||||
);
|
||||
model = bgRedirect.degradedModel;
|
||||
if (body && typeof body === "object") {
|
||||
body.model = model;
|
||||
}
|
||||
|
||||
logAuditEvent({
|
||||
action: "routing.background_task_redirect",
|
||||
actor: apiKeyInfo?.name || "system",
|
||||
target: connectionId || provider || "chat",
|
||||
details: {
|
||||
original_model: originalModel,
|
||||
redirected_to: bgRedirect.degradedModel,
|
||||
reason: bgRedirect.reason,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Apply custom model aliases (Settings → Model Aliases → Pattern→Target) before routing (#315, #472)
|
||||
|
||||
41
open-sse/handlers/chatCore/backgroundRedirect.ts
Normal file
41
open-sse/handlers/chatCore/backgroundRedirect.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* chatCore Background Task Redirection decision (T41) (Quality Gate v2 / Fase 9 — chatCore god-file
|
||||
* decomposition, #3501).
|
||||
*
|
||||
* Decides whether a request should be downgraded to a cheaper "degraded" model: only when the
|
||||
* feature is enabled, the request looks like a background/utility task, AND the model has a
|
||||
* degradation mapping. Returns the target model + the detection reason, or null for no redirect.
|
||||
* The handler keeps the side effects byte-identically (the BACKGROUND log, the model + body.model
|
||||
* mutation, and the audit event). Reads the live backgroundTaskDetector config, mirroring the
|
||||
* previous inline block.
|
||||
*/
|
||||
|
||||
import {
|
||||
getBackgroundDegradationConfig,
|
||||
getBackgroundTaskReason,
|
||||
getDegradedModel,
|
||||
} from "../../services/backgroundTaskDetector.ts";
|
||||
|
||||
export function resolveBackgroundTaskRedirect(opts: {
|
||||
body: unknown;
|
||||
headers: Record<string, string> | null | undefined;
|
||||
model: string;
|
||||
}): {
|
||||
/** The background-task detection reason (truthy iff the request looks like a background task),
|
||||
* threaded downstream into memory/skills injection — independent of whether a redirect happens. */
|
||||
backgroundReason: string | null;
|
||||
/** The actual model redirect to apply, or null when there is none (disabled, not a background
|
||||
* task, or the model has no — or a self — degradation mapping). */
|
||||
redirect: { degradedModel: string; reason: string } | null;
|
||||
} {
|
||||
const bgConfig = getBackgroundDegradationConfig();
|
||||
const backgroundReason = bgConfig.enabled
|
||||
? getBackgroundTaskReason(opts.body, opts.headers ?? null)
|
||||
: null;
|
||||
if (!backgroundReason) return { backgroundReason: null, redirect: null };
|
||||
|
||||
const degradedModel = getDegradedModel(opts.model);
|
||||
if (degradedModel === opts.model) return { backgroundReason, redirect: null };
|
||||
|
||||
return { backgroundReason, redirect: { degradedModel, reason: backgroundReason } };
|
||||
}
|
||||
69
tests/unit/chatcore-background-redirect.test.ts
Normal file
69
tests/unit/chatcore-background-redirect.test.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
// tests/unit/chatcore-background-redirect.test.ts
|
||||
// Characterization of resolveBackgroundTaskRedirect — the Background Task Redirection (T41)
|
||||
// decision extracted from handleChatCore (chatCore god-file decomposition, #3501). Decides whether
|
||||
// a request should be downgraded to a cheaper model: only when the feature is enabled, the request
|
||||
// looks like a background task, AND the model has a degradation mapping. The handler keeps the
|
||||
// effects (log, model/body mutation, audit). Uses the real backgroundTaskDetector config via its
|
||||
// setter so the decision is exercised end-to-end.
|
||||
import { test, afterEach } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { resolveBackgroundTaskRedirect } from "../../open-sse/handlers/chatCore/backgroundRedirect.ts";
|
||||
import { setBackgroundDegradationConfig } from "../../open-sse/services/backgroundTaskDetector.ts";
|
||||
|
||||
afterEach(() => {
|
||||
setBackgroundDegradationConfig({ enabled: false, degradationMap: {} });
|
||||
});
|
||||
|
||||
test("disabled config → no detection, no redirect (even for a clear background task)", () => {
|
||||
setBackgroundDegradationConfig({ enabled: false, degradationMap: { "gpt-5": "gpt-5-mini" } });
|
||||
assert.deepEqual(
|
||||
resolveBackgroundTaskRedirect({ body: { max_tokens: 10 }, headers: null, model: "gpt-5" }),
|
||||
{ backgroundReason: null, redirect: null }
|
||||
);
|
||||
});
|
||||
|
||||
test("enabled + low-max-tokens background + mapped model → detection + redirect", () => {
|
||||
setBackgroundDegradationConfig({ enabled: true, degradationMap: { "gpt-5": "gpt-5-mini" } });
|
||||
const r = resolveBackgroundTaskRedirect({
|
||||
body: { max_tokens: 10 },
|
||||
headers: null,
|
||||
model: "gpt-5",
|
||||
});
|
||||
assert.deepEqual(r, {
|
||||
backgroundReason: "low_max_tokens",
|
||||
redirect: { degradedModel: "gpt-5-mini", reason: "low_max_tokens" },
|
||||
});
|
||||
});
|
||||
|
||||
test("enabled + x-task-type:background header → reason header_background", () => {
|
||||
setBackgroundDegradationConfig({ enabled: true, degradationMap: { "gpt-5": "gpt-5-mini" } });
|
||||
const r = resolveBackgroundTaskRedirect({
|
||||
body: { messages: [{ role: "user", content: "hi" }] },
|
||||
headers: { "x-task-type": "background" },
|
||||
model: "gpt-5",
|
||||
});
|
||||
assert.deepEqual(r, {
|
||||
backgroundReason: "header_background",
|
||||
redirect: { degradedModel: "gpt-5-mini", reason: "header_background" },
|
||||
});
|
||||
});
|
||||
|
||||
test("enabled but the request is not a background task → no detection, no redirect", () => {
|
||||
setBackgroundDegradationConfig({ enabled: true, degradationMap: { "gpt-5": "gpt-5-mini" } });
|
||||
assert.deepEqual(
|
||||
resolveBackgroundTaskRedirect({
|
||||
body: { max_tokens: 4096, messages: [{ role: "user", content: "write an essay" }] },
|
||||
headers: null,
|
||||
model: "gpt-5",
|
||||
}),
|
||||
{ backgroundReason: null, redirect: null }
|
||||
);
|
||||
});
|
||||
|
||||
test("enabled + background but the model has no degradation mapping → detection but no redirect", () => {
|
||||
setBackgroundDegradationConfig({ enabled: true, degradationMap: { "gpt-5": "gpt-5-mini" } });
|
||||
assert.deepEqual(
|
||||
resolveBackgroundTaskRedirect({ body: { max_tokens: 10 }, headers: null, model: "claude-opus-4" }),
|
||||
{ backgroundReason: "low_max_tokens", redirect: null }
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user