mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
fix(combo): opt proactive-fallback compression into TV1 bail-out (no silent target drop) (#4228)
Integrated into release/v3.8.29 (opt proactive-fallback compression into TV1 bail-out; baseline combo.ts 2597->2601).
This commit is contained in:
committed by
GitHub
parent
89824fb0d3
commit
48773face6
@@ -55,6 +55,7 @@
|
||||
"_rebaseline_2026_06_17_ctx_editing_relays": "Context Editing relay coverage + 400-fallback (F4.2/F4.3) own growth: base.ts 1244->1292 (+48 at the existing dispatch chokepoint: extend the injection gate to anthropic-compatible-cc-* relays with an expanded comment documenting the claude-web / generic-anthropic-compatible exclusions; the contextEditingDisabled loop flag; and the 400-fallback block that, when an upstream rejects context_management with a 400, strips the param, re-serializes + re-signs (CCH), and retries the same URL once). Both edits sit on the per-URL request-build/fetch path and cannot be extracted without splitting the executor's fetch loop. No new file warranted — the logic is a few lines tightly coupled to the in-loop transformedBody/bodyString/response locals.",
|
||||
"_rebaseline_2026_06_17_ctx_editing_telemetry": "Context Editing telemetry (F4.1) own growth: chatCore.ts 5875->5898 (+23 = a best-effort, Claude-only, non-streaming block at the existing non-streaming response handler that extracts the provider's server-side context-editing receipt from responseBody and records it under engine \"context-editing\"). The pure extractor (extractContextEditingTelemetry) lives in the existing small open-sse/config/contextEditing.ts and the DB writer (recordContextEditingTelemetry) in src/lib/db/compressionAnalytics.ts — both under cap. Cohesive at the response-handling chokepoint next to the existing attachCompressionUsageReceipt call; not extractable without hiding the receipt-recording boundary.",
|
||||
"_rebaseline_2026_06_17_duckduckgo_free": "Free web search (free-claude-code port, Fase 6) own growth: handlers/search.ts 1442->1546 (+104 = tryDuckDuckGoFreeProvider, a dedicated provider path mirroring the existing tryZaiMCPProvider special-case: the lite endpoint returns HTML, not the JSON the generic tryProvider()/normalizeResponse() flow expects, so it cannot reuse that path). The reusable parser + guarded fetch (parseDuckDuckGoLite, freeWebSearch) live in the new small open-sse/services/freeWebSearch.ts (well under cap). Cohesive at the per-provider dispatch chokepoint; not extractable without hiding the provider boundary.",
|
||||
"_rebaseline_2026_06_18_4228_combo_fallback_bailout": "PR #4228 own growth: combo.ts 2597->2601 (+4 at the existing proactive-fallback applyCompression call in handleComboChat = opt into the TV1 bail-out so a throwing fallback engine is SKIPPED instead of propagating out of executeTarget and being swallowed as a 'Speculative task error' that silently drops the combo target). minGainPercent:0 keeps the advance behavior identical to the default path — this only adds skip-on-throw. The bailout option is threaded through the (non-frozen) strategySelector.ts applyCompression signature down to applyStackedCompression. Cohesive guard at the existing fallback-compression chokepoint; not extractable without hiding the call site.",
|
||||
"_rebaseline_2026_06_17_stream_recovery": "Stream recovery wiring (free-claude-code port, Fase 4) own growth: chatCore.ts 5898->5980 (+82 at the existing streaming-return chokepoint: read the resolved streamRecovery.enabled setting once; when ON, a reopenStream() thunk re-executes the SAME upstream — it closes over the ~15 per-attempt executor locals (executor/provider/modelToCall/bodyToSend/upstreamStream/execCreds/extendedContext/headers builders/onCredentialsRefreshed/skipUpstreamRetry/contextEditingEnabled) — and the body is wrapped with createRecoverableStream for transparent early-retry; OFF keeps the byte-identical wrapReadableStreamWithFinalize path). All reusable logic (HoldbackBuffer, createRecoverableStream, isRetryableStreamError, hasTerminalMarker) lives in the new open-sse/services/streamRecovery.ts (well under cap). Not extractable without hiding the per-attempt executor-dispatch boundary; opt-in (default OFF). Structural shrink of chatCore.ts tracked in #3501.",
|
||||
"cap": 800,
|
||||
"frozen": {
|
||||
@@ -84,7 +85,7 @@
|
||||
"open-sse/services/batchProcessor.ts": 828,
|
||||
"open-sse/services/browserBackedChat.ts": 850,
|
||||
"open-sse/services/claudeCodeCompatible.ts": 1202,
|
||||
"open-sse/services/combo.ts": 2597,
|
||||
"open-sse/services/combo.ts": 2601,
|
||||
"open-sse/services/rateLimitManager.ts": 1035,
|
||||
"open-sse/services/tokenRefresh.ts": 1997,
|
||||
"open-sse/services/usage.ts": 3408,
|
||||
|
||||
@@ -1281,7 +1281,11 @@ export async function handleComboChat({
|
||||
const compressionResult = applyCompression(
|
||||
attemptBody,
|
||||
config.fallbackCompressionMode as CompressionMode,
|
||||
{ model: modelStr }
|
||||
// Opt into the TV1 bail-out so a throwing fallback engine is SKIPPED rather than
|
||||
// propagating out of executeTarget and being swallowed as a "Speculative task
|
||||
// error" (which silently drops this combo target). minGainPercent:0 keeps the
|
||||
// advance behavior identical to the default path — this only adds skip-on-throw.
|
||||
{ model: modelStr, bailout: { enabled: true, minGainPercent: 0 } }
|
||||
);
|
||||
if (compressionResult.compressed) {
|
||||
log.info(
|
||||
|
||||
@@ -97,6 +97,12 @@ export function applyCompression(
|
||||
supportsVision?: boolean | null;
|
||||
config?: CompressionConfig;
|
||||
principalId?: string;
|
||||
/**
|
||||
* Opt into the TV1 stacked bail-out (skip-on-throw + min-gain). Default off keeps the
|
||||
* legacy behavior. The combo proactive-fallback path enables it so a throwing engine is
|
||||
* skipped instead of silently dropping the target. Flows through to applyStackedCompression.
|
||||
*/
|
||||
bailout?: BailoutConfig;
|
||||
}
|
||||
): CompressionResult {
|
||||
if (mode === "off") {
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { applyCompression } from "../../../open-sse/services/compression/strategySelector.ts";
|
||||
import { registerCompressionEngine } from "../../../open-sse/services/compression/index.ts";
|
||||
import type { CompressionEngine } from "../../../open-sse/services/compression/engines/types.ts";
|
||||
import type { CompressionConfig } from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
// The combo proactive-fallback path calls applyCompression(stacked); a throwing engine there
|
||||
// propagates and is swallowed as a "Speculative task error", silently dropping the target. The
|
||||
// fix lets that caller opt into the TV1 bail-out (enabled, minGainPercent 0 = skip-on-throw
|
||||
// without changing the min-gain advance behavior). This documents the opt-in contract.
|
||||
const THROWING_ENGINE: CompressionEngine = {
|
||||
id: "applycompress-bailout-throw",
|
||||
name: "Throwing Test Engine",
|
||||
description: "test fixture",
|
||||
icon: "",
|
||||
targets: ["messages"],
|
||||
stackable: true,
|
||||
stackPriority: 999,
|
||||
metadata: {
|
||||
id: "applycompress-bailout-throw",
|
||||
name: "Throwing Test Engine",
|
||||
description: "test",
|
||||
inputScope: "messages",
|
||||
targetLatencyMs: 1,
|
||||
supportsPreview: false,
|
||||
stable: false,
|
||||
},
|
||||
apply() {
|
||||
throw new Error("boom from fallback engine");
|
||||
},
|
||||
compress() {
|
||||
throw new Error("boom from fallback engine");
|
||||
},
|
||||
getConfigSchema() {
|
||||
return [];
|
||||
},
|
||||
validateConfig() {
|
||||
return { valid: true, errors: [] };
|
||||
},
|
||||
};
|
||||
|
||||
function stackedConfig(): CompressionConfig {
|
||||
return {
|
||||
stackedPipeline: [{ engine: "applycompress-bailout-throw" }],
|
||||
} as unknown as CompressionConfig;
|
||||
}
|
||||
|
||||
describe("applyCompression — combo fallback bail-out opt-in", () => {
|
||||
it("opting into bail-out skips a throwing engine instead of propagating (no silent drop)", () => {
|
||||
registerCompressionEngine(THROWING_ENGINE);
|
||||
const body = { messages: [{ role: "user", content: "hello world" }] };
|
||||
|
||||
let result: ReturnType<typeof applyCompression> | undefined;
|
||||
assert.doesNotThrow(() => {
|
||||
result = applyCompression(body, "stacked", {
|
||||
config: stackedConfig(),
|
||||
bailout: { enabled: true, minGainPercent: 0 },
|
||||
});
|
||||
});
|
||||
assert.ok(result, "returns a result instead of throwing");
|
||||
assert.equal(result!.compressed, false, "a crashing engine compresses nothing");
|
||||
});
|
||||
|
||||
it("without bail-out, a throwing engine still propagates (TV1 default unchanged)", () => {
|
||||
registerCompressionEngine(THROWING_ENGINE);
|
||||
const body = { messages: [{ role: "user", content: "hello world" }] };
|
||||
|
||||
assert.throws(
|
||||
() => applyCompression(body, "stacked", { config: stackedConfig() }),
|
||||
/boom from fallback engine/,
|
||||
"the default (opt-out) path is unchanged — bail-out is strictly opt-in"
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user