Yogesh
initial deploy
cd8bd0a
Raw
History Blame Contribute Delete
14.7 kB
import { z } from "zod";
import {
ACCOUNT_FALLBACK_STRATEGY_VALUES,
ROUTING_STRATEGY_VALUES,
} from "@/shared/constants/routingStrategies";
import { SUPPORTED_BATCH_ENDPOINTS } from "@/shared/constants/batchEndpoints";
import { MAX_REQUEST_BODY_LIMIT_MB, MIN_REQUEST_BODY_LIMIT_MB } from "@/shared/constants/bodySize";
import { COMBO_CONFIG_MODES } from "@/shared/constants/comboConfigMode";
import { providerAllowsOptionalApiKey } from "@/shared/constants/providers";
import { HIDEABLE_SIDEBAR_ITEM_IDS } from "@/shared/constants/sidebarVisibility";
import {
isForbiddenUpstreamHeaderName,
isForbiddenCustomHeaderName,
} from "@/shared/constants/upstreamHeaders";
import { MAX_TIMER_TIMEOUT_MS } from "@/shared/utils/runtimeTimeouts";
// ──── Combo Schemas ────
export const comboStepMetaSchema = {
id: z.string().trim().min(1).max(200).optional(),
weight: z.number().min(0).max(100).optional().default(0),
label: z.string().trim().min(1).max(200).optional(),
};
export const comboModelStepInputSchema = z.object({
kind: z.literal("model").optional(),
provider: z.string().trim().min(1).max(120).optional(),
providerId: z.string().trim().min(1).max(120).optional(),
model: z.string().trim().min(1).max(300),
connectionId: z.string().trim().min(1).max(200).nullable().optional(),
tags: z.array(z.string().trim().min(1).max(100)).max(20).optional(),
...comboStepMetaSchema,
});
export const comboRefStepInputSchema = z.object({
kind: z.literal("combo-ref"),
comboName: z.string().trim().min(1).max(100),
...comboStepMetaSchema,
});
// A combo entry can be a plain string (legacy), a legacy object, or a structured ComboStep.
export const comboModelEntry = z.union([
z.string().trim().min(1).max(300),
comboModelStepInputSchema,
comboRefStepInputSchema,
]);
export const shadowRoutingSchema = z
.object({
enabled: z.boolean().optional(),
targets: z.array(comboModelEntry).max(20).optional(),
sampleRate: z.coerce.number().min(0).max(1).optional(),
maxTargets: z.coerce.number().int().min(1).max(10).optional(),
timeoutMs: z.coerce.number().int().min(1000).max(120000).optional(),
})
.strict();
export const evalRoutingSchema = z
.object({
enabled: z.boolean().optional(),
suiteIds: z.array(z.string().trim().min(1).max(200)).max(50).optional(),
maxAgeHours: z.coerce.number().min(1).max(8760).optional(),
minCases: z.coerce.number().int().min(1).max(100000).optional(),
qualityWeight: z.coerce.number().min(0).max(1).optional(),
latencyWeight: z.coerce.number().min(0).max(1).optional(),
cacheTtlMs: z.coerce.number().int().min(1000).max(300000).optional(),
})
.strict();
export const comboStrategySchema = z.enum(ROUTING_STRATEGY_VALUES);
export const scoringWeightsSchema = z
.object({
quota: z.number().min(0).max(1),
health: z.number().min(0).max(1),
costInv: z.number().min(0).max(1),
latencyInv: z.number().min(0).max(1),
taskFit: z.number().min(0).max(1),
stability: z.number().min(0).max(1),
tierPriority: z.number().min(0).max(1).optional().default(0.05),
tierAffinity: z.number().min(0).max(1).optional().default(0.05),
specificityMatch: z.number().min(0).max(1).optional().default(0.05),
contextAffinity: z.number().min(0).max(1).optional().default(0.08),
resetWindowAffinity: z.number().min(0).max(1).optional().default(0),
})
.optional();
export const compositeTierEntrySchema = z
.object({
stepId: z.string().trim().min(1).max(200),
fallbackTier: z.string().trim().min(1).max(100).optional(),
label: z.string().trim().min(1).max(200).optional(),
description: z.string().trim().min(1).max(500).optional(),
})
.strict();
export const compositeTiersSchema = z
.object({
defaultTier: z.string().trim().min(1).max(100),
tiers: z.record(z.string().trim().min(1).max(100), compositeTierEntrySchema),
})
.strict();
export const compressionModeSchema = z.enum([
"off",
"lite",
"standard",
"aggressive",
"ultra",
"rtk",
"stacked",
]);
export const comboCompressionOverrideSchema = z.union([z.literal(""), compressionModeSchema]);
export const slaRoutingPolicySchema = z
.object({
targetP95Ms: z.coerce.number().int().positive().max(300000).optional(),
maxErrorRate: z.coerce.number().min(0).max(1).optional(),
maxCostPer1MTokens: z.coerce.number().positive().max(1000000).optional(),
hardConstraints: z.boolean().optional(),
})
.strict();
export const comboRuntimeConfigSchema = z
.object({
strategy: comboStrategySchema.optional(),
maxRetries: z.coerce.number().int().min(0).max(10).optional(),
retryDelayMs: z.coerce.number().int().min(0).max(60000).optional(),
fallbackDelayMs: z.coerce.number().int().min(0).max(60000).optional(),
timeoutMs: z.coerce.number().int().min(1000).optional(),
targetTimeoutMs: z.coerce.number().int().min(0).max(MAX_TIMER_TIMEOUT_MS).optional(),
concurrencyPerModel: z.coerce.number().int().min(1).max(20).optional(),
queueTimeoutMs: z.coerce.number().int().min(1000).max(120000).optional(),
// #3872: pre-cascade semaphore queue depth (round-robin). 0 = fail over immediately.
queueDepth: z.coerce.number().int().min(0).max(100).optional(),
// Per-combo sticky round-robin batch size. When unset, handleRoundRobinCombo
// falls back to the global `settings.stickyRoundRobinLimit` so the existing
// knob still controls the default. 0 clamps to 1 (no batching) upstream.
stickyRoundRobinLimit: z.coerce.number().int().min(0).max(1000).optional(),
stickyWeightedLimit: z.coerce.number().int().min(0).max(1000).optional(),
healthCheckEnabled: z.boolean().optional(),
healthCheckTimeoutMs: z.coerce.number().int().min(100).max(30000).optional(),
handoffThreshold: z.coerce.number().min(0.5).max(0.94).optional(),
handoffModel: z.string().trim().max(200).optional(),
handoffProviders: z.array(z.string().trim().min(1).max(100)).max(10).optional(),
maxMessagesForSummary: z.coerce.number().int().min(5).max(100).optional(),
maxComboDepth: z.coerce.number().int().min(1).max(10).optional(),
nestedComboMode: z.enum(["flatten", "execute"]).optional(),
trackMetrics: z.boolean().optional(),
reasoningTokenBufferEnabled: z.boolean().optional(),
compressionMode: compressionModeSchema.optional(),
failoverBeforeRetry: z.boolean().optional(),
maxSetRetries: z.coerce.number().int().min(0).max(10).optional(),
setRetryDelayMs: z.coerce.number().int().min(0).max(60000).optional(),
zeroLatencyOptimizationsEnabled: z.boolean().optional(),
hedging: z.boolean().optional(),
hedgeDelayMs: z.coerce.number().int().min(0).max(60000).optional(),
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(),
// Auto-Combo / LKGP Extensions
candidatePool: z.array(z.string().min(1)).optional(),
weights: scoringWeightsSchema.optional(),
modePack: z.string().max(100).optional(),
budgetCap: z.number().positive().optional(),
explorationRate: z.number().min(0).max(1).optional(),
routerStrategy: z.string().optional(),
slaTargetP95Ms: z.coerce.number().int().positive().max(300000).optional(),
slaMaxErrorRate: z.coerce.number().min(0).max(1).optional(),
slaMaxCostPer1MTokens: z.coerce.number().positive().max(1000000).optional(),
slaHardConstraints: z.boolean().optional(),
sla: slaRoutingPolicySchema.optional(),
compositeTiers: compositeTiersSchema.optional(),
resetAwareSessionWeight: z.coerce.number().min(0).max(100).optional(),
resetAwareWeeklyWeight: z.coerce.number().min(0).max(100).optional(),
resetAwareTieBandPercent: z.coerce.number().min(0).max(100).optional(),
resetAwareExhaustionGuardPercent: z.coerce.number().min(0).max(100).optional(),
resetAwareQuotaCacheTtlMs: z.coerce.number().int().min(0).max(300_000).optional(),
resetAwareQuotaCacheMaxStaleMs: z.coerce.number().int().min(0).max(3_600_000).optional(),
resetWindowWindows: z.array(z.enum(["weekly", "session", "monthly"])).optional(),
resetWindowIncludeSession: z.boolean().optional(),
resetWindowTieBandMs: z.coerce.number().int().min(0).max(86_400_000).optional(),
resetWindowQuotaCacheTtlMs: z.coerce.number().int().min(0).max(300_000).optional(),
resetWindowQuotaCacheMaxStaleMs: z.coerce.number().int().min(0).max(3_600_000).optional(),
shadowRouting: shadowRoutingSchema.optional(),
evalRouting: evalRoutingSchema.optional(),
// Fusion strategy (open-sse/services/fusion.ts): the panel is the combo's
// targets; `judgeModel` synthesizes the final answer (defaults to the first
// panel model when unset); `fusionTuning` controls quorum-grace collection.
judgeModel: z.string().trim().max(200).optional(),
fusionTuning: z
.object({
minPanel: z.coerce.number().int().min(1).max(50).optional(),
stragglerGraceMs: z.coerce.number().int().min(0).max(120_000).optional(),
panelHardTimeoutMs: z.coerce.number().int().min(1000).max(600_000).optional(),
})
.strict()
.optional(),
})
.passthrough()
.transform((config) => {
// Backward-compat shim: combos stored prior to v3.8.33 may carry zero-latency
// feature flags (fallbackCompressionMode !== "off", hedging === true, or
// predictiveTtftMs > 0) without the accompanying zeroLatencyOptimizationsEnabled
// gate that the new schema requires. Auto-promote the flag when any such feature
// is enabled but the gate is unset/false, so stored combos continue to round-trip
// through PUT /api/combos/{id} without returning 400. This replaces the prior
// superRefine that hard-rejected these payloads (see issue #4382).
if (config.zeroLatencyOptimizationsEnabled === true) return config;
const hasZeroLatencyFeature =
config.hedging === true ||
(typeof config.predictiveTtftMs === "number" && config.predictiveTtftMs > 0) ||
(!!config.fallbackCompressionMode && config.fallbackCompressionMode !== "off");
if (hasZeroLatencyFeature) {
return { ...config, zeroLatencyOptimizationsEnabled: true };
}
return config;
});
export const comboNameSchema = z
.string()
.trim()
.min(1, "Name is required")
.max(100)
.regex(
/^[a-zA-Z0-9_/.\-\[\] ]+$/,
"Name can only contain letters, numbers, spaces, -, _, /, ., [ and ]."
);
export const createComboSchema = z.object({
name: comboNameSchema,
description: z.string().max(2000).optional(),
models: z.array(comboModelEntry).optional().default([]),
strategy: comboStrategySchema.optional().default("priority"),
config: comboRuntimeConfigSchema.optional(),
allowedProviders: z.array(z.string().max(200)).optional(),
system_message: z.string().max(50000).optional(),
tool_filter_regex: z.string().max(1000).optional(),
context_cache_protection: z.boolean().optional(),
context_length: z.number().int().min(1000).max(2000000).optional(),
// Optional embedding dimensions override for embedding combos.
// When set, the value is injected into every upstream embedding request as
// the `dimensions` field (and translated to `outputDimensionality` for Gemini).
// Stored as a string to match the OpenAI API convention; coerced to number
// by the embedding handler. Leave unset to use each model's default.
dimensions: z.string().regex(/^\d+$/, "dimensions must be a positive integer string").optional().nullable(),
});
export const updateComboDefaultsSchema = z
.object({
comboDefaults: comboRuntimeConfigSchema.optional(),
providerOverrides: z.record(z.string().trim().min(1), comboRuntimeConfigSchema).optional(),
})
.superRefine((value, ctx) => {
if (!value.comboDefaults && !value.providerOverrides) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Nothing to update",
path: [],
});
}
if (value.comboDefaults?.compositeTiers) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "compositeTiers is only supported on concrete combos",
path: ["comboDefaults", "compositeTiers"],
});
}
for (const [providerId, config] of Object.entries(value.providerOverrides || {})) {
if (config?.compositeTiers) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "compositeTiers is only supported on concrete combos",
path: ["providerOverrides", providerId, "compositeTiers"],
});
}
}
});
export const updateComboSchema = z
.object({
name: comboNameSchema.optional(),
description: z.string().max(2000).optional().nullable(),
models: z.array(comboModelEntry).optional(),
strategy: comboStrategySchema.optional(),
config: comboRuntimeConfigSchema.optional(),
isActive: z.boolean().optional(),
allowedProviders: z.array(z.string().max(200)).optional(),
system_message: z.string().max(50000).optional(),
tool_filter_regex: z.string().max(1000).optional(),
context_cache_protection: z.boolean().optional(),
context_length: z.number().int().min(1000).max(2000000).optional().nullable(),
compressionOverride: comboCompressionOverrideSchema.optional(),
dimensions: z.string().regex(/^\d+$/, "dimensions must be a positive integer string").optional().nullable(),
})
.superRefine((value, ctx) => {
if (
value.name === undefined &&
value.description === undefined &&
value.models === undefined &&
value.strategy === undefined &&
value.config === undefined &&
value.isActive === undefined &&
value.allowedProviders === undefined &&
value.system_message === undefined &&
value.tool_filter_regex === undefined &&
value.context_cache_protection === undefined &&
value.context_length === undefined &&
value.compressionOverride === undefined &&
value.dimensions === undefined
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "No valid fields to update",
path: [],
});
}
});
export const reorderCombosSchema = z
.object({
comboIds: z.array(z.string().trim().min(1).max(200)).min(1).max(1000),
})
.superRefine((value, ctx) => {
if (new Set(value.comboIds).size !== value.comboIds.length) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "comboIds must be unique",
path: ["comboIds"],
});
}
});
export const testComboSchema = z.object({
comboName: z.string().trim().min(1, "comboName is required"),
});