mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-11 01:32:22 +03:00
Bypass proxy compaction for native Codex context
This commit is contained in:
@@ -1102,10 +1102,9 @@ export async function handleChatCore({
|
||||
const compressionSettings: CompressionConfig | null = compressionSettingsResult.settings;
|
||||
// #8034 — operator-named model/endpoint exclusions bypass the whole pipeline, exactly
|
||||
// like compression being globally disabled, so the body is provably byte-identical.
|
||||
const compressionExcluded = isCompressionExcluded(
|
||||
{ provider, model: effectiveModel },
|
||||
compressionSettings?.exclusions
|
||||
);
|
||||
const compressionExcluded =
|
||||
nativeCodexPassthrough ||
|
||||
isCompressionExcluded({ provider, model: effectiveModel }, compressionSettings?.exclusions);
|
||||
let promptCompressionEnabled = compressionSettingsResult.enabled && !compressionExcluded;
|
||||
contextEditingEnabled = compressionSettingsResult.contextEditingEnabled;
|
||||
if (compressionExcluded) {
|
||||
@@ -1756,7 +1755,7 @@ export async function handleChatCore({
|
||||
// engines (Caveman/RTK). Codex Desktop / Responses clients need this path even
|
||||
// when those engines are off, otherwise multi-turn image sessions hard-reject
|
||||
// at the budget check below (#8560).
|
||||
if (estimatedTokens > threshold) {
|
||||
if (!nativeCodexPassthrough && estimatedTokens > threshold) {
|
||||
log?.info?.(
|
||||
"CONTEXT",
|
||||
`Proactive compression triggered: ${estimatedTokens} tokens > ${threshold} threshold (${contextLimit} limit)`
|
||||
@@ -1847,7 +1846,7 @@ export async function handleChatCore({
|
||||
|
||||
// Last-resort compaction against the concrete input budget (not the 70% threshold).
|
||||
// Covers cases where the proactive pass was skipped or still left the request oversized (#8560).
|
||||
if (finalEstimatedInputTokens >= finalContextLimit && body) {
|
||||
if (!nativeCodexPassthrough && finalEstimatedInputTokens >= finalContextLimit && body) {
|
||||
const lastResortTarget = Math.max(1, finalContextLimit - toolsReserve - 1);
|
||||
const lastResortAdapter = adaptBodyForCompression(body as Record<string, unknown>);
|
||||
const lastResortResult = compressContext(lastResortAdapter.body, {
|
||||
|
||||
@@ -569,6 +569,7 @@ export async function handleComboChat({
|
||||
signal,
|
||||
apiKeyAllowedConnections = null,
|
||||
nesting = null,
|
||||
clientManagedResponsesContext = false,
|
||||
}: HandleComboChatOptions): Promise<Response> {
|
||||
const comboCtx = createComboContext({ body, combo, settings, relayOptions, log });
|
||||
const {
|
||||
@@ -683,6 +684,7 @@ export async function handleComboChat({
|
||||
settings,
|
||||
allCombos,
|
||||
signal,
|
||||
clientManagedResponsesContext,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -707,6 +709,7 @@ export async function handleComboChat({
|
||||
isModelAvailable,
|
||||
handleSingleModelWithTimeout,
|
||||
buildAutoCandidates,
|
||||
clientManagedResponsesContext,
|
||||
});
|
||||
if ("earlyResponse" in targetResolution) return targetResolution.earlyResponse;
|
||||
const { stickyWeightedLimit, getWeightedStepKeyForTarget, preScreenMap } = targetResolution;
|
||||
@@ -2177,6 +2180,7 @@ async function handleRoundRobinCombo({
|
||||
settings,
|
||||
allCombos,
|
||||
signal,
|
||||
clientManagedResponsesContext,
|
||||
}: HandleRoundRobinOptions): Promise<Response> {
|
||||
const config = settings
|
||||
? resolveComboConfig(combo, settings)
|
||||
@@ -2219,7 +2223,9 @@ async function handleRoundRobinCombo({
|
||||
);
|
||||
const tagFilteredTargets = await applyRequestTagRouting(orderedTargets, body, log);
|
||||
const evalRankedTargets = orderTargetsByEvalScores(tagFilteredTargets, config.evalRouting, log);
|
||||
const knownContextOverflow = getKnownContextOverflow(evalRankedTargets, body);
|
||||
const knownContextOverflow = getKnownContextOverflow(evalRankedTargets, body, {
|
||||
clientManagedResponsesContext,
|
||||
});
|
||||
if (knownContextOverflow) {
|
||||
return errorResponseWithComboDiagnostics(
|
||||
400,
|
||||
|
||||
@@ -68,6 +68,7 @@ type PreludeBaseOptionArgs = {
|
||||
relayOptions?: HandleComboChatOptions["relayOptions"];
|
||||
signal?: AbortSignal | null;
|
||||
apiKeyAllowedConnections?: string[] | null;
|
||||
clientManagedResponsesContext?: boolean;
|
||||
};
|
||||
|
||||
/** Rebuild handleComboChat's option bag verbatim for a recursive dispatch. */
|
||||
@@ -83,6 +84,7 @@ function buildBaseOptions(a: PreludeBaseOptionArgs): HandleComboChatOptions {
|
||||
relayOptions: a.relayOptions,
|
||||
signal: a.signal,
|
||||
apiKeyAllowedConnections: a.apiKeyAllowedConnections,
|
||||
clientManagedResponsesContext: a.clientManagedResponsesContext,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ export function getKnownContextLimit(
|
||||
return limits.length > 0 ? Math.min(...limits) : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a hard context-overflow decision only when every target has a known
|
||||
* context limit and every one of those limits is too small for the request.
|
||||
@@ -69,9 +68,20 @@ export function getKnownContextLimit(
|
||||
*/
|
||||
export function getKnownContextOverflow(
|
||||
targets: ResolvedComboTarget[],
|
||||
body: Record<string, unknown>
|
||||
body: Record<string, unknown>,
|
||||
options: { clientManagedResponsesContext?: boolean } = {}
|
||||
): KnownContextOverflow | null {
|
||||
if (targets.length === 0) return null;
|
||||
// Native Codex Responses clients compact their own item history. Let the concrete
|
||||
// Codex target enforce its effective context limit (including operator overrides)
|
||||
// instead of rejecting early against a smaller catalog hint. Keep this scoped to
|
||||
// all-Codex pools so other Responses clients/providers retain the hard preflight.
|
||||
if (
|
||||
options.clientManagedResponsesContext === true &&
|
||||
targets.every((target) => target.provider === "codex")
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
const requirements = deriveRequestCompatibilityRequirements(body);
|
||||
if (requirements.requiredContextTokens <= 0) return null;
|
||||
|
||||
|
||||
@@ -111,6 +111,7 @@ export interface ResolveComboTargetPipelineDeps {
|
||||
* this leaf), so importing it directly would create an import cycle.
|
||||
*/
|
||||
buildAutoCandidates: ResolveAutoStrategyDeps["buildAutoCandidates"];
|
||||
clientManagedResponsesContext?: boolean;
|
||||
}
|
||||
|
||||
export interface ResolvedComboTargetPipeline {
|
||||
@@ -692,7 +693,9 @@ export async function resolveComboTargetPipeline(
|
||||
|
||||
orderedTargets = await applyRequestTagRouting(orderedTargets, body, log);
|
||||
|
||||
const overflow = getKnownContextOverflow(orderedTargets, body);
|
||||
const overflow = getKnownContextOverflow(orderedTargets, body, {
|
||||
clientManagedResponsesContext: deps.clientManagedResponsesContext,
|
||||
});
|
||||
if (overflow) {
|
||||
return { earlyResponse: buildContextOverflowResponse(overflow, orderedTargets, log) };
|
||||
}
|
||||
|
||||
@@ -107,6 +107,8 @@ export type HandleComboChatOptions = {
|
||||
signal?: AbortSignal | null;
|
||||
apiKeyAllowedConnections?: string[] | null;
|
||||
nesting?: ComboNestingContext | null;
|
||||
/** Native Responses clients (for example Codex CLI/Desktop) manage compaction themselves. */
|
||||
clientManagedResponsesContext?: boolean;
|
||||
};
|
||||
|
||||
export type HandleRoundRobinOptions = Omit<
|
||||
|
||||
@@ -33,7 +33,11 @@ import {
|
||||
HTTP_STATUS,
|
||||
ANTIGRAVITY_PRE_RESPONSE_TIMEOUT_CODE,
|
||||
} from "@omniroute/open-sse/config/constants.ts";
|
||||
import { getTargetFormat, detectFormatFromUrl } from "@omniroute/open-sse/services/provider.ts";
|
||||
import {
|
||||
getTargetFormat,
|
||||
detectFormatFromEndpoint,
|
||||
detectFormatFromUrl,
|
||||
} from "@omniroute/open-sse/services/provider.ts";
|
||||
import {
|
||||
getModelsByProviderId,
|
||||
getModelTargetFormat,
|
||||
@@ -778,6 +782,9 @@ export async function handleChat(
|
||||
const response = await (handleComboChat as any)({
|
||||
body,
|
||||
combo,
|
||||
clientManagedResponsesContext:
|
||||
sourceFormat === "openai-responses" &&
|
||||
new URL(request.url).pathname.split("/").includes("responses"),
|
||||
handleSingleModel: (
|
||||
b: any,
|
||||
m: string,
|
||||
@@ -1045,6 +1052,11 @@ async function handleSingleModelChat(
|
||||
return handleComboChat({
|
||||
body,
|
||||
combo: redirectCombo,
|
||||
clientManagedResponsesContext:
|
||||
detectFormatFromEndpoint(body, clientRawRequest?.endpoint || "") === "openai-responses" &&
|
||||
String(clientRawRequest?.endpoint || "")
|
||||
.split("/")
|
||||
.includes("responses"),
|
||||
handleSingleModel: (
|
||||
b: any,
|
||||
m: string,
|
||||
|
||||
@@ -57,7 +57,11 @@ function capabilityEntry(limitContext: number | null) {
|
||||
};
|
||||
}
|
||||
|
||||
function capabilityEntryWithLimits(limitInput: number | null, limitContext: number | null, limitOutput = 4096) {
|
||||
function capabilityEntryWithLimits(
|
||||
limitInput: number | null,
|
||||
limitContext: number | null,
|
||||
limitOutput = 4096
|
||||
) {
|
||||
return {
|
||||
...capabilityEntry(limitContext),
|
||||
limit_input: limitInput,
|
||||
@@ -270,6 +274,59 @@ test("combo rejects a known oversized request before upstream dispatch", async (
|
||||
assert.equal(body.diagnostics.attempted, 0);
|
||||
});
|
||||
|
||||
test("native Responses context bypasses catalog overflow only for all-Codex pools (#8932)", () => {
|
||||
saveModelsDevCapabilities({
|
||||
codex: {
|
||||
large: capabilityEntry(272_000),
|
||||
},
|
||||
"unit-known-context": {
|
||||
large: capabilityEntry(272_000),
|
||||
},
|
||||
});
|
||||
const body = bigContextBody(275_000);
|
||||
|
||||
assert.equal(
|
||||
getKnownContextOverflow([target("codex/large")], body, {
|
||||
clientManagedResponsesContext: true,
|
||||
}),
|
||||
null
|
||||
);
|
||||
assert.ok(
|
||||
getKnownContextOverflow([target("unit-known-context/large")], body, {
|
||||
clientManagedResponsesContext: true,
|
||||
}),
|
||||
"non-Codex pools must retain the catalog overflow guard"
|
||||
);
|
||||
});
|
||||
|
||||
test("native Responses context reaches an all-Codex target beyond its catalog hint (#8932)", async () => {
|
||||
saveModelsDevCapabilities({
|
||||
codex: {
|
||||
large: capabilityEntry(272_000),
|
||||
},
|
||||
});
|
||||
let dispatches = 0;
|
||||
|
||||
const response = await handleComboChat({
|
||||
body: bigContextBody(275_000),
|
||||
combo: {
|
||||
name: "native-codex-overflow",
|
||||
strategy: "priority",
|
||||
models: ["codex/large"],
|
||||
},
|
||||
clientManagedResponsesContext: true,
|
||||
isModelAvailable: async () => true,
|
||||
handleSingleModel: async () => {
|
||||
dispatches += 1;
|
||||
return new Response("ok", { status: 200 });
|
||||
},
|
||||
log: noopLog,
|
||||
});
|
||||
|
||||
assert.notEqual(response.status, 400);
|
||||
assert.equal(dispatches, 1);
|
||||
});
|
||||
|
||||
test("input-only maxInputTokens is not double-counted against the output reserve (#7039)", () => {
|
||||
// Faithful reproduction of #7039 (Codex gpt-5.5-xhigh):
|
||||
// maxInputTokens = 272_000, contextWindow = 400_000, maxOutputTokens = 128_000
|
||||
@@ -387,10 +444,10 @@ test("model_context_override lets a small-catalog target survive a large-context
|
||||
largeContextBody(),
|
||||
noopLog
|
||||
);
|
||||
assert.deepEqual(
|
||||
out.map((entry) => entry.modelStr).sort(),
|
||||
["unit-override/big", "unit-override/capped"]
|
||||
);
|
||||
assert.deepEqual(out.map((entry) => entry.modelStr).sort(), [
|
||||
"unit-override/big",
|
||||
"unit-override/capped",
|
||||
]);
|
||||
} finally {
|
||||
removeModelContextOverride("unit-override", "capped");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user