mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-14 10:52:17 +03:00
feat(routing): add relayMode for schema-locked context handoffs (#11839)
Boarded with #12003/#11841/#11840 in one combined worktree: typecheck:core, check:file-size, check:changelog-integrity, check:complexity, check:cognitive-complexity, check:cycles all green; 24/24 focused tests pass. relayMode is opt-in and defaults to standard, so this is backward-compatible as claimed — verified the plumbing through resolveUniversalHandoffConfig/resolveContextRelayConfig/selectMessagesForSummary. Thanks for the clean, well-tested addition.
This commit is contained in:
@@ -1640,7 +1640,8 @@ async function handleComboChatInner({
|
||||
lastModel,
|
||||
modelStr,
|
||||
`Model routing: ${lastModel} → ${modelStr}`,
|
||||
existingHandoff
|
||||
existingHandoff,
|
||||
universalHandoffConfig.relayMode
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ export interface ContextRelayConfig {
|
||||
handoffThreshold?: number;
|
||||
handoffProviders?: string[];
|
||||
maxMessagesForSummary?: number;
|
||||
relayMode?: "schema-locked" | "standard";
|
||||
}
|
||||
|
||||
export interface UniversalHandoffConfig {
|
||||
@@ -65,6 +66,7 @@ export interface UniversalHandoffConfig {
|
||||
ttlMinutes: number;
|
||||
/** Preserve existing system prompt when injecting handoff */
|
||||
preserveSystemPrompt: boolean;
|
||||
relayMode?: "schema-locked" | "standard";
|
||||
}
|
||||
|
||||
export const DEFAULT_UNIVERSAL_HANDOFF_CONFIG: UniversalHandoffConfig = {
|
||||
@@ -155,6 +157,8 @@ export function resolveUniversalHandoffConfig(
|
||||
"preserveSystemPrompt",
|
||||
DEFAULT_UNIVERSAL_HANDOFF_CONFIG.preserveSystemPrompt
|
||||
),
|
||||
relayMode:
|
||||
getString("relayMode", "standard") === "schema-locked" ? "schema-locked" : "standard",
|
||||
};
|
||||
}
|
||||
export interface ParsedHandoffContent {
|
||||
@@ -192,6 +196,7 @@ export function resolveContextRelayConfig(
|
||||
Number.isFinite(rawMaxMessages) && rawMaxMessages >= 5 && rawMaxMessages <= 100
|
||||
? Math.round(rawMaxMessages)
|
||||
: DEFAULT_MAX_MESSAGES_FOR_SUMMARY,
|
||||
relayMode: config?.relayMode === "schema-locked" ? "schema-locked" : "standard",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -232,7 +237,8 @@ function formatMessagesForPrompt(messages: MessageLike[]): string {
|
||||
|
||||
export function selectMessagesForSummary(
|
||||
messages: MessageLike[],
|
||||
maxMessages: number
|
||||
maxMessages: number,
|
||||
relayMode?: "schema-locked" | "standard"
|
||||
): MessageLike[] {
|
||||
const validMessages = messages.filter((m) => m && typeof m === "object");
|
||||
const system = validMessages.filter(
|
||||
@@ -242,15 +248,23 @@ export function selectMessagesForSummary(
|
||||
(m) => typeof m.role !== "string" || (m.role !== "system" && m.role !== "developer")
|
||||
);
|
||||
|
||||
const recentMessages = [...system, ...nonSystem.slice(-maxMessages)];
|
||||
const recentMessages =
|
||||
relayMode === "schema-locked"
|
||||
? [...nonSystem.slice(-maxMessages)]
|
||||
: [...system, ...nonSystem.slice(-maxMessages)];
|
||||
let working = [...recentMessages];
|
||||
|
||||
while (working.length > system.length + 1) {
|
||||
const minWorkingLength = relayMode === "schema-locked" ? 1 : system.length + 1;
|
||||
|
||||
while (working.length > minWorkingLength) {
|
||||
const history = formatMessagesForPrompt(working);
|
||||
if (estimateTokens(history) <= MAX_HISTORY_TOKENS_FOR_SUMMARY) {
|
||||
return working;
|
||||
}
|
||||
working = [...system, ...working.slice(system.length + 1)];
|
||||
working =
|
||||
relayMode === "schema-locked"
|
||||
? working.slice(1)
|
||||
: [...system, ...working.slice(system.length + 1)];
|
||||
}
|
||||
|
||||
const fallbackHistory = formatMessagesForPrompt(working);
|
||||
@@ -258,7 +272,7 @@ export function selectMessagesForSummary(
|
||||
// If there are system messages, return them so the caller can still produce context.
|
||||
// If there are no system messages (system=[]), fall back to the single most-recent
|
||||
// non-system message rather than returning [] which would silently drop the handoff.
|
||||
if (system.length > 0) {
|
||||
if (relayMode !== "schema-locked" && system.length > 0) {
|
||||
return system;
|
||||
}
|
||||
const lastNonSystem = nonSystem[nonSystem.length - 1];
|
||||
@@ -386,7 +400,8 @@ async function generateHandoffAsync(options: {
|
||||
const summaryModel = relayConfig.handoffModel || options.model;
|
||||
const selectedMessages = selectMessagesForSummary(
|
||||
Array.isArray(options.messages) ? options.messages : [],
|
||||
relayConfig.maxMessagesForSummary
|
||||
relayConfig.maxMessagesForSummary,
|
||||
relayConfig.relayMode
|
||||
);
|
||||
const historyText = formatMessagesForPrompt(selectedMessages);
|
||||
if (!historyText) return;
|
||||
@@ -499,7 +514,8 @@ The context above contains a concise summary of the prior work. Continue seamles
|
||||
|
||||
export function injectHandoffIntoBody(
|
||||
body: Record<string, unknown>,
|
||||
payload: HandoffPayload
|
||||
payload: HandoffPayload,
|
||||
_relayMode?: "schema-locked" | "standard"
|
||||
): Record<string, unknown> {
|
||||
const handoffContent = buildHandoffSystemMessage(payload);
|
||||
const isResponsesRequest =
|
||||
@@ -680,12 +696,14 @@ async function generateUniversalHandoffAsync(options: {
|
||||
handoffModel: string;
|
||||
ttlMs: number;
|
||||
maxMessages: number;
|
||||
relayMode?: "schema-locked" | "standard";
|
||||
providerAllowlist: string[];
|
||||
handleSingleModel: (body: Record<string, unknown>, modelStr: string) => Promise<Response>;
|
||||
}): Promise<UniversalHandoffOutcome> {
|
||||
const selectedMessages = selectMessagesForSummary(
|
||||
Array.isArray(options.messages) ? options.messages : [],
|
||||
options.maxMessages
|
||||
options.maxMessages,
|
||||
options.relayMode
|
||||
);
|
||||
const historyText = formatMessagesForPrompt(selectedMessages);
|
||||
if (!historyText) return "unavailable";
|
||||
@@ -789,6 +807,7 @@ export function maybeGenerateUniversalHandoff(options: {
|
||||
handoffModel: options.universalConfig.handoffModel || options.currModel,
|
||||
ttlMs,
|
||||
maxMessages: options.universalConfig.maxMessagesForSummary,
|
||||
relayMode: options.universalConfig.relayMode,
|
||||
providerAllowlist: options.universalConfig.providerAllowlist,
|
||||
handleSingleModel: options.handleSingleModel,
|
||||
})
|
||||
@@ -812,7 +831,8 @@ export function injectUniversalHandoffBody(
|
||||
prevModel: string,
|
||||
currModel: string,
|
||||
reason: string,
|
||||
existingPayload?: HandoffPayload | null
|
||||
existingPayload?: HandoffPayload | null,
|
||||
_relayMode?: "schema-locked" | "standard"
|
||||
): Record<string, unknown> {
|
||||
const handoffContent = buildUniversalHandoffSystemMessage(
|
||||
prevModel,
|
||||
|
||||
@@ -200,6 +200,7 @@ export const comboRuntimeConfigSchema = z
|
||||
fallbackCompressionMode: compressionModeSchema.optional(),
|
||||
fallbackCompressionThreshold: z.coerce.number().int().min(0).max(2_000_000).optional(),
|
||||
predictiveTtftMs: z.coerce.number().int().min(0).max(300000).optional(),
|
||||
relayMode: z.enum(["schema-locked", "standard"]).optional(),
|
||||
// Auto-Combo / LKGP Extensions
|
||||
candidatePool: z.array(z.string().min(1)).optional(),
|
||||
weights: scoringWeightsSchema.optional(),
|
||||
|
||||
@@ -307,6 +307,63 @@ test("maybeGenerateHandoff allows a new attempt after a failed in-flight generat
|
||||
assert.equal(calls, 2);
|
||||
});
|
||||
|
||||
test("selectMessagesForSummary handles schema-locked vs standard relayMode", () => {
|
||||
const messages = [
|
||||
{ role: "system", content: "System instruction" },
|
||||
{ role: "user", content: "Msg 1" },
|
||||
{ role: "assistant", content: "Msg 2" },
|
||||
{ role: "user", content: "Msg 3" },
|
||||
];
|
||||
|
||||
// Standard mode includes system message
|
||||
const standard = contextHandoff.selectMessagesForSummary(messages, 2, "standard");
|
||||
assert.equal(standard[0].role, "system");
|
||||
assert.equal(standard.length, 3); // system + last 2
|
||||
|
||||
// Schema-locked mode excludes system message
|
||||
const locked = contextHandoff.selectMessagesForSummary(messages, 2, "schema-locked");
|
||||
assert.equal(locked[0].role, "assistant");
|
||||
assert.equal(locked[0].content, "Msg 2");
|
||||
assert.equal(locked.length, 2); // only non-system slice
|
||||
});
|
||||
|
||||
test("selectMessagesForSummary trims non-system messages and excludes system in schema-locked token overflow", () => {
|
||||
// Input with system messages and huge non-system messages exceeding token limit
|
||||
const hugeText = "x".repeat(35000);
|
||||
const messages = [
|
||||
{ role: "system", content: "System prompt" },
|
||||
{ role: "developer", content: "Developer prompt" },
|
||||
{ role: "user", content: `User msg 1: ${hugeText}` },
|
||||
{ role: "assistant", content: `Assistant msg 2: ${hugeText}` },
|
||||
{ role: "user", content: "User msg 3 short" },
|
||||
];
|
||||
|
||||
const trimmedLocked = contextHandoff.selectMessagesForSummary(messages, 10, "schema-locked");
|
||||
// Should exclude system and developer messages
|
||||
assert.ok(trimmedLocked.every((m) => m.role !== "system" && m.role !== "developer"));
|
||||
// Should have trimmed down to non-overflowing messages (or last non-system)
|
||||
assert.ok(trimmedLocked.length < 3);
|
||||
assert.equal(trimmedLocked[trimmedLocked.length - 1].content, "User msg 3 short");
|
||||
});
|
||||
|
||||
test("resolveUniversalHandoffConfig correctly parses relayMode", async () => {
|
||||
const comboSchema = await import("../../src/shared/validation/schemas/combo.ts");
|
||||
const parsedLocked = comboSchema.comboRuntimeConfigSchema.parse({
|
||||
relayMode: "schema-locked",
|
||||
});
|
||||
assert.equal(parsedLocked.relayMode, "schema-locked");
|
||||
|
||||
const parsedStandard = comboSchema.comboRuntimeConfigSchema.parse({
|
||||
relayMode: "standard",
|
||||
});
|
||||
assert.equal(parsedStandard.relayMode, "standard");
|
||||
|
||||
const resolvedConfig = contextHandoff.resolveUniversalHandoffConfig({
|
||||
relayMode: "schema-locked",
|
||||
});
|
||||
assert.equal(resolvedConfig.relayMode, "schema-locked");
|
||||
});
|
||||
|
||||
test("maybeGenerateHandoff respects explicit empty handoffProviders and skips generation", async () => {
|
||||
let called = false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user