diff --git a/.vscode/settings.json b/.vscode/settings.json index 8e3d0f161b..fae48f28c7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -16,5 +16,6 @@ "javascript:S3776": { "level": "off" } - } + }, + "git.ignoreLimitWarning": true } diff --git a/next.config.mjs b/next.config.mjs index a8589b8cc7..18a2be156d 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -67,10 +67,10 @@ const nextConfig = { // // We use two strategies: // 1. Exact-name externals for all known server-side packages. - // 2. Hash-strip catch-all: any require('-<16hexchars>' strips the - // suffix and falls through to the real package name. + // 2. Hash-strip catch-all: any require('-<16hexchars>[/subpath]') + // strips the hash suffix and falls through to the real package name. // - const HASH_PATTERN = /^(.+)-[0-9a-f]{16}$/; + const HASH_PATTERN = /^(.+)-[0-9a-f]{16}(\/.*)?$/; const KNOWN_EXTERNALS = new Set([ "better-sqlite3", @@ -102,13 +102,15 @@ const nextConfig = { if (KNOWN_EXTERNALS.has(request)) { return callback(null, `commonjs ${request}`); } - // Case 2: Hash-suffixed name — strip hash, use base name + // Case 2: Hash-suffixed name — strip hash, preserve subpath // e.g. "better-sqlite3-90e2652d1716b047" → "better-sqlite3" // "zod-dcb22c6336e0bc69" → "zod" + // "zod-dcb22c6336e0bc69/v3" → "zod/v3" + // "zod-dcb22c6336e0bc69/v4-mini" → "zod/v4-mini" const hashMatch = request?.match?.(HASH_PATTERN); if (hashMatch) { - const baseName = hashMatch[1]; - return callback(null, `commonjs ${baseName}`); + const resolved = hashMatch[2] ? `${hashMatch[1]}${hashMatch[2]}` : hashMatch[1]; + return callback(null, `commonjs ${resolved}`); } callback(); }, diff --git a/open-sse/executors/base.ts b/open-sse/executors/base.ts index f57e4010e0..58301632d3 100644 --- a/open-sse/executors/base.ts +++ b/open-sse/executors/base.ts @@ -206,9 +206,7 @@ export class BaseExecutor { headers["Authorization"] = `Bearer ${effectiveKey}`; } - if (stream) { - headers["Accept"] = "text/event-stream"; - } + headers["Accept"] = stream ? "text/event-stream" : "application/json"; return headers; } diff --git a/open-sse/executors/default.ts b/open-sse/executors/default.ts index aa55d1ffaf..15e2c0ff64 100644 --- a/open-sse/executors/default.ts +++ b/open-sse/executors/default.ts @@ -179,7 +179,7 @@ export class DefaultExecutor extends BaseExecutor { } } - if (stream) headers["Accept"] = "text/event-stream"; + headers["Accept"] = stream ? "text/event-stream" : "application/json"; // Qwen header cleanup: Remove X-Dashscope-* headers if using an API key (DashScope compatible mode). // If using OAuth (Qwen Code), we MUST keep them for portal.qwen.ai to accept the request. diff --git a/open-sse/handlers/chatCore.ts b/open-sse/handlers/chatCore.ts index cd73d3a122..4dcb362d1c 100644 --- a/open-sse/handlers/chatCore.ts +++ b/open-sse/handlers/chatCore.ts @@ -957,7 +957,10 @@ export async function handleChatCore({ let translatedBody = body; const isClaudePassthrough = sourceFormat === FORMATS.CLAUDE && targetFormat === FORMATS.CLAUDE; const isClaudeCodeCompatible = isClaudeCodeCompatibleProvider(provider); - const upstreamStream = stream || isClaudeCodeCompatible; + // Respect the client's explicit non-streaming intent for CC-compatible providers. + // Most upstreams can answer JSON directly; the SSE->JSON fallback remains as a + // compatibility path when an upstream still responds with event-stream. + const upstreamStream = stream; let ccSessionId: string | null = null; // Determine if we should preserve client-side cache_control headers diff --git a/open-sse/services/combo.ts b/open-sse/services/combo.ts index 83a60f567b..ad23e8ca2c 100644 --- a/open-sse/services/combo.ts +++ b/open-sse/services/combo.ts @@ -1730,22 +1730,21 @@ async function handleRoundRobinCombo({ }); recordedAttempts++; if (provider) { - import("../../src/lib/localDb") - .then(({ setLKGP }) => - Promise.all([ - setLKGP(combo.name, target.executionKey, provider), - setLKGP(combo.name, combo.id || combo.name, provider), - ]) - ) - .catch((err) => - log.warn( - "COMBO-RR", - "Failed to record Last Known Good Provider. This is non-fatal.", - { - err, - } - ) + try { + const { setLKGP } = await import("../../src/lib/localDb"); + await Promise.all([ + setLKGP(combo.name, target.executionKey, provider), + setLKGP(combo.name, combo.id || combo.name, provider), + ]); + } catch (err) { + log.warn( + "COMBO-RR", + "Failed to record Last Known Good Provider. This is non-fatal.", + { + err, + } ); + } } return result; } diff --git a/src/app/(dashboard)/dashboard/combos/page.tsx b/src/app/(dashboard)/dashboard/combos/page.tsx index a988deaa6a..9e46f4d163 100644 --- a/src/app/(dashboard)/dashboard/combos/page.tsx +++ b/src/app/(dashboard)/dashboard/combos/page.tsx @@ -45,20 +45,6 @@ const ModelSelectModal = dynamic(() => import("@/shared/components/ModelSelectMo const ProxyConfigModal = dynamic(() => import("@/shared/components/ProxyConfigModal"), { ssr: false, }); -const ModelRoutingSection = dynamic(() => import("@/shared/components/ModelRoutingSection"), { - ssr: false, - loading: () => ( -
-
- route -
-
-
-
-
-
- ), -}); // Validate combo name: letters, numbers, -, _, /, . const VALID_NAME_REGEX = /^[a-zA-Z0-9_/.-]+$/; @@ -883,6 +869,7 @@ export default function CombosPage() { setShowUsageGuide(false)} onHideForever={handleHideUsageGuideForever} + onCreateCombo={() => setShowCreateModal(true)} /> )} @@ -930,10 +917,6 @@ export default function CombosPage() {
)} - - {/* Model Routing Rules (#563) */} - -
{[ { @@ -1116,9 +1099,35 @@ export default function CombosPage() { ); } -function ComboUsageGuide({ onHide, onHideForever }) { +const COMBO_WIZARD_STEPS = [ + { + step: 1, + icon: "badge", + titleKey: "wizardStep1Title", + descKey: "wizardStep1Desc", + }, + { + step: 2, + icon: "hub", + titleKey: "wizardStep2Title", + descKey: "wizardStep2Desc", + }, + { + step: 3, + icon: "route", + titleKey: "wizardStep3Title", + descKey: "wizardStep3Desc", + }, + { + step: 4, + icon: "check_circle", + titleKey: "wizardStep4Title", + descKey: "wizardStep4Desc", + }, +]; + +function ComboUsageGuide({ onHide, onHideForever, onCreateCombo }) { const t = useTranslations("combos"); - const guideStrategies = ["priority", "cost-optimized", "least-used"]; return ( @@ -1130,8 +1139,16 @@ function ComboUsageGuide({ onHide, onHideForever }) {
-

{t("routingStrategy")}

-

{t("description")}

+

+ {getI18nOrFallback(t, "wizardGuideTitle", "Getting Started with Combos")} +

+

+ {getI18nOrFallback( + t, + "wizardGuideDesc", + "Create model combos to route AI traffic intelligently" + )} +

@@ -1149,27 +1166,45 @@ function ComboUsageGuide({ onHide, onHideForever }) {
-
- {guideStrategies.map((strategyValue) => { - const strategyMeta = getStrategyMeta(strategyValue); +
+ {COMBO_WIZARD_STEPS.map((step, index) => { return (
-
+
+ + {step.step} + - {strategyMeta.icon} + {step.icon} - {getStrategyLabel(t, strategyValue)}
-

- {getStrategyDescription(t, strategyValue)} +

+ {getI18nOrFallback(t, step.titleKey, step.titleKey)}

+

+ {getI18nOrFallback(t, step.descKey, step.descKey)} +

+ {index < COMBO_WIZARD_STEPS.length - 1 && ( + + arrow_forward + + )}
); })}
+ +
+ + + {getI18nOrFallback(t, "wizardGuideHint", "or click + Create Combo above")} + +
); } diff --git a/src/app/(dashboard)/dashboard/settings/components/ComboDefaultsTab.tsx b/src/app/(dashboard)/dashboard/settings/components/ComboDefaultsTab.tsx index 222b6820f6..afb37e2986 100644 --- a/src/app/(dashboard)/dashboard/settings/components/ComboDefaultsTab.tsx +++ b/src/app/(dashboard)/dashboard/settings/components/ComboDefaultsTab.tsx @@ -31,10 +31,15 @@ export default function ComboDefaultsTab() { handoffThreshold: 0.85, handoffModel: "", maxMessagesForSummary: 30, + stickyRoundRobinLimit: 3, }); const [providerOverrides, setProviderOverrides] = useState({}); const [newOverrideProvider, setNewOverrideProvider] = useState(""); const [saving, setSaving] = useState(false); + const [status, setStatus] = useState<{ type: "success" | "error" | ""; message: string }>({ + type: "", + message: "", + }); const t = useTranslations("settings"); const tc = useTranslations("common"); const strategyOptions = ROUTING_STRATEGIES.map((strategy) => ({ @@ -54,27 +59,75 @@ export default function ComboDefaultsTab() { ]; useEffect(() => { - fetch("/api/settings/combo-defaults") - .then((res) => res.json()) - .then((data) => { - if (data.comboDefaults) { - setComboDefaults((prev) => ({ ...prev, ...data.comboDefaults })); - } - if (data.providerOverrides) setProviderOverrides(data.providerOverrides); + Promise.all([ + fetch("/api/settings/combo-defaults").then((res) => res.json()), + fetch("/api/settings").then((res) => res.json()), + ]) + .then(([comboData, settingsData]) => { + setComboDefaults((prev) => ({ + ...prev, + ...(comboData.comboDefaults || {}), + strategy: + settingsData.fallbackStrategy ?? comboData.comboDefaults?.strategy ?? prev.strategy, + stickyRoundRobinLimit: + settingsData.stickyRoundRobinLimit ?? + comboData.comboDefaults?.stickyRoundRobinLimit ?? + prev.stickyRoundRobinLimit, + })); + if (comboData.providerOverrides) setProviderOverrides(comboData.providerOverrides); }) .catch((err) => console.error("Failed to fetch combo defaults:", err)); }, []); + const showStatus = (type: "success" | "error", message: string) => { + setStatus({ type, message }); + setTimeout(() => setStatus({ type: "", message: "" }), 2500); + }; + + const syncGlobalRoutingSettings = async (patch: Record) => { + const keys = Object.keys(patch); + if (keys.length === 0) return true; + + const res = await fetch("/api/settings", { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(patch), + }); + + if (!res.ok) { + throw new Error("Failed to sync global routing settings"); + } + + return true; + }; + const saveComboDefaults = async () => { setSaving(true); try { - await fetch("/api/settings/combo-defaults", { + const { stickyRoundRobinLimit, ...comboDefaultsPayload } = comboDefaults; + const settingsPatch: Record = {}; + if (comboDefaults.strategy) { + settingsPatch.fallbackStrategy = comboDefaults.strategy; + } + if (comboDefaults.strategy === "round-robin" && stickyRoundRobinLimit !== undefined) { + settingsPatch.stickyRoundRobinLimit = stickyRoundRobinLimit; + } + + const comboDefaultsRes = await fetch("/api/settings/combo-defaults", { method: "PATCH", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ comboDefaults, providerOverrides }), + body: JSON.stringify({ comboDefaults: comboDefaultsPayload, providerOverrides }), }); + + if (!comboDefaultsRes.ok) { + throw new Error("Failed to save combo defaults"); + } + + await syncGlobalRoutingSettings(settingsPatch); + showStatus("success", t("savedSuccessfully")); } catch (err) { console.error("Failed to save combo defaults:", err); + showStatus("error", t("errorOccurred")); } finally { setSaving(false); } @@ -103,8 +156,38 @@ export default function ComboDefaultsTab() { tune
-

{t("comboDefaultsTitle")}

+

+ {translateOrFallback(t, "comboDefaultsTitle", "Default Routing & Combo Settings")} +

{t("globalComboConfig")} + {status.message && ( + + {status.message} + + )} +
+
+

+ {translateOrFallback(t, "routingAdvancedGuideTitle", "Advanced routing guidance")} +

+

+ {translateOrFallback( + t, + "routingAdvancedGuideHint1", + "Use Fill First for predictable priority, Round Robin for fairness, and P2C for latency resilience." + )} +

+

+ {translateOrFallback( + t, + "routingAdvancedGuideHint2", + "If providers vary in quality or cost, start with Cost Opt for background work and Least Used for balanced wear." + )} +

@@ -130,7 +213,15 @@ export default function ComboDefaultsTab() { key={s.value} role="tab" aria-selected={comboDefaults.strategy === s.value} - onClick={() => setComboDefaults((prev) => ({ ...prev, strategy: s.value }))} + onClick={async () => { + setComboDefaults((prev) => ({ ...prev, strategy: s.value })); + try { + await syncGlobalRoutingSettings({ fallbackStrategy: s.value }); + } catch (error) { + console.error("Failed to sync fallback strategy:", error); + showStatus("error", t("errorOccurred")); + } + }} className={cn( "px-2 py-1 rounded text-xs font-medium transition-all flex items-center justify-center gap-0.5", comboDefaults.strategy === s.value @@ -145,6 +236,35 @@ export default function ComboDefaultsTab() {

+ {comboDefaults.strategy === "round-robin" && ( +
+
+

{t("stickyLimit")}

+

{t("stickyLimitDesc")}

+
+ { + const nextLimit = parseInt(e.target.value) || 3; + setComboDefaults((prev) => ({ + ...prev, + stickyRoundRobinLimit: nextLimit, + })); + try { + await syncGlobalRoutingSettings({ stickyRoundRobinLimit: nextLimit }); + } catch (error) { + console.error("Failed to sync sticky round robin limit:", error); + showStatus("error", t("errorOccurred")); + } + }} + className="w-20 text-center" + /> +
+ )} + {/* Numeric settings */}
{numericSettings.map(({ key, label, min, max, step }) => ( diff --git a/src/app/(dashboard)/dashboard/settings/components/ModelAliasesUnified.tsx b/src/app/(dashboard)/dashboard/settings/components/ModelAliasesUnified.tsx new file mode 100644 index 0000000000..f7e7ae265c --- /dev/null +++ b/src/app/(dashboard)/dashboard/settings/components/ModelAliasesUnified.tsx @@ -0,0 +1,366 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { Button, Card, Input } from "@/shared/components"; +import { useTranslations } from "next-intl"; + +interface WildcardAlias { + pattern: string; + target: string; +} + +type AliasMode = "exact" | "wildcard"; + +function translateOrFallback( + t: ReturnType, + key: string, + fallback: string +): string { + return typeof t.has === "function" && t.has(key) ? t(key) : fallback; +} + +export default function ModelAliasesUnified() { + const [wildcardAliases, setWildcardAliases] = useState([]); + const [builtInAliases, setBuiltInAliases] = useState>({}); + const [customAliases, setCustomAliases] = useState>({}); + const [aliasMode, setAliasMode] = useState("exact"); + const [loading, setLoading] = useState(true); + const [saving, setSaving] = useState(false); + const [status, setStatus] = useState<{ type: "success" | "error" | ""; message: string }>({ + type: "", + message: "", + }); + const [fromValue, setFromValue] = useState(""); + const [toValue, setToValue] = useState(""); + const t = useTranslations("settings"); + const builtInEntries = Object.entries(builtInAliases); + const customEntries = Object.entries(customAliases); + + useEffect(() => { + const loadAliases = async () => { + try { + const [settingsRes, aliasesRes] = await Promise.all([ + fetch("/api/settings"), + fetch("/api/settings/model-aliases"), + ]); + const settingsData = settingsRes.ok ? await settingsRes.json() : {}; + const aliasesData = aliasesRes.ok ? await aliasesRes.json() : {}; + setWildcardAliases(settingsData.wildcardAliases || []); + setBuiltInAliases(aliasesData.builtIn || {}); + setCustomAliases(aliasesData.custom || {}); + } catch (error) { + console.error("Failed to load model aliases:", error); + } finally { + setLoading(false); + } + }; + + loadAliases(); + }, []); + + const showStatus = (type: "success" | "error", message: string) => { + setStatus({ type, message }); + setTimeout(() => setStatus({ type: "", message: "" }), 2500); + }; + + const addExactAlias = async () => { + if (!fromValue.trim() || !toValue.trim()) return; + setSaving(true); + try { + const res = await fetch("/api/settings/model-aliases", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ from: fromValue.trim(), to: toValue.trim() }), + }); + if (!res.ok) throw new Error("Failed to save exact alias"); + const data = await res.json(); + setCustomAliases(data.custom || {}); + setFromValue(""); + setToValue(""); + showStatus("success", translateOrFallback(t, "saved", "Saved")); + } catch (error) { + console.error("Failed to save exact alias:", error); + showStatus("error", translateOrFallback(t, "errorOccurred", "An error occurred")); + } finally { + setSaving(false); + } + }; + + const removeExactAlias = async (from: string) => { + setSaving(true); + try { + const res = await fetch("/api/settings/model-aliases", { + method: "DELETE", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ from }), + }); + if (!res.ok) throw new Error("Failed to remove exact alias"); + const data = await res.json(); + setCustomAliases(data.custom || {}); + showStatus("success", translateOrFallback(t, "saved", "Saved")); + } catch (error) { + console.error("Failed to remove exact alias:", error); + showStatus("error", translateOrFallback(t, "errorOccurred", "An error occurred")); + } finally { + setSaving(false); + } + }; + + const addWildcardAlias = async () => { + if (!fromValue.trim() || !toValue.trim()) return; + setSaving(true); + try { + const updated = [...wildcardAliases, { pattern: fromValue.trim(), target: toValue.trim() }]; + const res = await fetch("/api/settings", { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ wildcardAliases: updated }), + }); + if (!res.ok) throw new Error("Failed to save wildcard alias"); + setWildcardAliases(updated); + setFromValue(""); + setToValue(""); + showStatus("success", translateOrFallback(t, "saved", "Saved")); + } catch (error) { + console.error("Failed to save wildcard alias:", error); + showStatus("error", translateOrFallback(t, "errorOccurred", "An error occurred")); + } finally { + setSaving(false); + } + }; + + const removeWildcardAlias = async (index: number) => { + setSaving(true); + try { + const updated = wildcardAliases.filter((_, currentIndex) => currentIndex !== index); + const res = await fetch("/api/settings", { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ wildcardAliases: updated }), + }); + if (!res.ok) throw new Error("Failed to remove wildcard alias"); + setWildcardAliases(updated); + showStatus("success", translateOrFallback(t, "saved", "Saved")); + } catch (error) { + console.error("Failed to remove wildcard alias:", error); + showStatus("error", translateOrFallback(t, "errorOccurred", "An error occurred")); + } finally { + setSaving(false); + } + }; + + const handleAdd = async () => { + if (aliasMode === "wildcard") { + await addWildcardAlias(); + return; + } + await addExactAlias(); + }; + + return ( + +
+
+ +
+
+

+ {translateOrFallback(t, "modelAliasesTitle", "Model Aliases")} +

+

+ {translateOrFallback( + t, + "modelAliasesDesc", + "Remap model names using exact matches or wildcard patterns." + )} +

+
+ {status.message && ( + + + {status.message} + + )} +
+ +
+
+ {[ + { + value: "exact", + label: translateOrFallback(t, "exactMatchMode", "Exact Match"), + }, + { + value: "wildcard", + label: translateOrFallback(t, "wildcardPatternMode", "Wildcard Pattern"), + }, + ].map((mode) => ( + + ))} +
+ +

+ {aliasMode === "exact" + ? translateOrFallback( + t, + "exactMatchModeDesc", + "Use exact aliases for deprecated or renamed model IDs." + ) + : translateOrFallback( + t, + "wildcardPatternModeDesc", + "Use wildcard aliases with * and ? when a family of models should map to one target." + )} +

+ +
+ setFromValue(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && void handleAdd()} + disabled={loading || saving} + /> +
+ +
+ setToValue(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && void handleAdd()} + disabled={loading || saving} + /> + +
+
+ +
+

+ {translateOrFallback(t, "customAliases", "Custom Aliases")} +

+
+ {customEntries.length === 0 ? ( +
+ {translateOrFallback( + t, + "noExactAliasesConfigured", + "No exact-match aliases configured." + )} +
+ ) : ( + customEntries.map(([from, to]) => ( +
+ {from} + + arrow_forward + + {to} + +
+ )) + )} +
+
+ +
+

+ {translateOrFallback(t, "wildcardRulesTitle", "Wildcard Rules")} +

+
+ {wildcardAliases.length === 0 ? ( +
+ {translateOrFallback( + t, + "noWildcardAliasesConfigured", + "No wildcard aliases configured." + )} +
+ ) : ( + wildcardAliases.map((alias, index) => ( +
+ {alias.pattern} + + arrow_forward + + {alias.target} + +
+ )) + )} +
+
+ +
+ + + chevron_right + + {translateOrFallback(t, "builtInAliases", "Built-in Aliases")} ({builtInEntries.length}) + +
+ {builtInEntries.map(([from, to]) => ( +
+ {from} + + arrow_forward + + {to} + lock +
+ ))} +
+
+
+ ); +} diff --git a/src/app/(dashboard)/dashboard/settings/components/RoutingTab.tsx b/src/app/(dashboard)/dashboard/settings/components/RoutingTab.tsx index 8b5cadaf3b..869d54603f 100644 --- a/src/app/(dashboard)/dashboard/settings/components/RoutingTab.tsx +++ b/src/app/(dashboard)/dashboard/settings/components/RoutingTab.tsx @@ -1,46 +1,24 @@ "use client"; -import { useState, useEffect } from "react"; -import { Card, Input, Button } from "@/shared/components"; -import FallbackChainsEditor from "./FallbackChainsEditor"; -import { - ROUTING_STRATEGIES, - SETTINGS_FALLBACK_STRATEGY_VALUES, -} from "@/shared/constants/routingStrategies"; +import { useEffect, useState } from "react"; +import { Button, Card } from "@/shared/components"; import { useTranslations } from "next-intl"; - -const STRATEGIES = ROUTING_STRATEGIES.filter((strategy) => - SETTINGS_FALLBACK_STRATEGY_VALUES.includes(strategy.value) -).map((strategy) => ({ - value: strategy.value, - labelKey: strategy.labelKey, - descKey: strategy.settingsDescKey, - icon: strategy.icon, -})); +import FallbackChainsEditor from "./FallbackChainsEditor"; export default function RoutingTab() { const [settings, setSettings] = useState({ - fallbackStrategy: "fill-first", alwaysPreserveClientCache: "auto", }); const [loading, setLoading] = useState(true); - const [aliases, setAliases] = useState([]); const [lkgpCacheLoading, setLkgpCacheLoading] = useState(false); const [lkgpCacheStatus, setLkgpCacheStatus] = useState({ type: "", message: "" }); - const [newPattern, setNewPattern] = useState(""); - const [newTarget, setNewTarget] = useState(""); const t = useTranslations("settings"); - const strategyHintKeyByValue = STRATEGIES.reduce>((acc, strategy) => { - acc[strategy.value] = strategy.descKey; - return acc; - }, {}); useEffect(() => { fetch("/api/settings") .then((res) => res.json()) .then((data) => { setSettings(data); - setAliases(data.wildcardAliases || []); setLoading(false); }) .catch(() => setLoading(false)); @@ -61,100 +39,8 @@ export default function RoutingTab() { } }; - const addAlias = async () => { - if (!newPattern.trim() || !newTarget.trim()) return; - const updated = [...aliases, { pattern: newPattern.trim(), target: newTarget.trim() }]; - await updateSetting({ wildcardAliases: updated }); - setAliases(updated); - setNewPattern(""); - setNewTarget(""); - }; - - const removeAlias = async (idx) => { - const updated = aliases.filter((_, i) => i !== idx); - await updateSetting({ wildcardAliases: updated }); - setAliases(updated); - }; - return (
- {/* Strategy Selection */} - -
-
- -
-

{t("routingStrategy")}

-
- -
-

- {t("routingAdvancedGuideTitle")} -

-

{t("routingAdvancedGuideHint1")}

-

{t("routingAdvancedGuideHint2")}

-
- -
- {STRATEGIES.map((s) => ( - - ))} -
- - {settings.fallbackStrategy === "round-robin" && ( -
-
-

{t("stickyLimit")}

-

{t("stickyLimitDesc")}

-
- updateSetting({ stickyRoundRobinLimit: parseInt(e.target.value) })} - disabled={loading} - className="w-20 text-center" - /> -
- )} - -

- {t(strategyHintKeyByValue[settings.fallbackStrategy] || "fillFirstDesc")} -

-
- - {/* Adaptive Volume Routing */}
@@ -188,7 +74,6 @@ export default function RoutingTab() {
- {/* LKGP Toggle */}
@@ -268,77 +153,8 @@ export default function RoutingTab() {
- {/* Wildcard Aliases */} - -
-
- -
-
-

{t("modelAliases")}

-

{t("modelAliasesDesc")}

-
-
- - {aliases.length > 0 && ( -
- {aliases.map((a, i) => ( -
-
- {a.pattern} - - arrow_forward - - {a.target} -
- -
- ))} -
- )} - -
-
- setNewPattern(e.target.value)} - /> -
-
- setNewTarget(e.target.value)} - /> -
- -
-
- - {/* Fallback Chains */} - {/* Client Cache Control */}
diff --git a/src/app/(dashboard)/dashboard/settings/page.tsx b/src/app/(dashboard)/dashboard/settings/page.tsx index 286ff5d3b2..e7a11c27a6 100644 --- a/src/app/(dashboard)/dashboard/settings/page.tsx +++ b/src/app/(dashboard)/dashboard/settings/page.tsx @@ -14,13 +14,14 @@ import AppearanceTab from "./components/AppearanceTab"; import ThinkingBudgetTab from "./components/ThinkingBudgetTab"; import CodexServiceTierTab from "./components/CodexServiceTierTab"; import SystemPromptTab from "./components/SystemPromptTab"; -import ModelAliasesTab from "./components/ModelAliasesTab"; +import ModelAliasesUnified from "./components/ModelAliasesUnified"; import BackgroundDegradationTab from "./components/BackgroundDegradationTab"; import CacheSettingsTab from "./components/CacheSettingsTab"; import MemorySkillsTab from "./components/MemorySkillsTab"; import ModelsDevSyncTab from "./components/ModelsDevSyncTab"; import ResilienceTab from "./components/ResilienceTab"; import CliproxyapiSettingsTab from "./components/CliproxyapiSettingsTab"; +import ModelRoutingSection from "@/shared/components/ModelRoutingSection"; const tabs = [ { id: "general", labelKey: "general", icon: "settings" }, @@ -105,8 +106,9 @@ export default function SettingsPage() { {activeTab === "routing" && (
+ - +
)} diff --git a/src/app/api/combos/test/route.ts b/src/app/api/combos/test/route.ts index d13952fa7e..01a0962168 100644 --- a/src/app/api/combos/test/route.ts +++ b/src/app/api/combos/test/route.ts @@ -40,6 +40,7 @@ async function testComboTarget(target, internalUrl) { // Force a fresh execution path so combo tests cannot be satisfied by // OmniRoute's semantic cache or other request reuse layers. "X-OmniRoute-No-Cache": "true", + ...(target.connectionId ? { "X-OmniRoute-Connection": target.connectionId } : {}), "X-Request-Id": `combo-test-${randomUUID()}`, }, body: JSON.stringify(testBody), diff --git a/src/app/api/openapi/spec/route.ts b/src/app/api/openapi/spec/route.ts index d48f748ab6..ca51698fe6 100644 --- a/src/app/api/openapi/spec/route.ts +++ b/src/app/api/openapi/spec/route.ts @@ -6,15 +6,12 @@ import { NextResponse } from "next/server"; import fs from "fs"; import path from "path"; -import { fileURLToPath } from "url"; import yaml from "js-yaml"; let cachedSpec: { data: any; mtime: number } | null = null; -const ROUTE_DIR = path.dirname(fileURLToPath(import.meta.url)); -const PROJECT_ROOT = path.resolve(ROUTE_DIR, "../../../../../"); const OPENAPI_SPEC_CANDIDATES = [ - path.join(PROJECT_ROOT, "docs", "openapi.yaml"), - path.join(PROJECT_ROOT, "app", "docs", "openapi.yaml"), + path.join(process.cwd(), "docs", "openapi.yaml"), + path.join(process.cwd(), "app", "docs", "openapi.yaml"), ]; export async function GET() { diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index 3472f48804..4881aafc9c 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "التكاليف", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "المكالمات لكل حساب قبل التبديل", "modelAliases": "الأسماء المستعارة النموذجية", "modelAliasesTitle": "أسماء بديلة للنماذج", - "modelAliasesDesc": "أنماط أحرف البدل لإعادة تعيين أسماء النماذج • استخدم * و؟", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "إضافة اسم بديل مخصص", "deprecatedModelId": "معرف النموذج المهمل", "newModelId": "معرف النموذج الجديد", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "مترجم", diff --git a/src/i18n/messages/bg.json b/src/i18n/messages/bg.json index dd49e0b5d2..be554a6def 100644 --- a/src/i18n/messages/bg.json +++ b/src/i18n/messages/bg.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Разходи", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Обаждания на акаунт преди превключване", "modelAliases": "Псевдоними на модела", "modelAliasesTitle": "Псевдоними на модели", - "modelAliasesDesc": "Шаблони за заместващи символи за пренасочване на имена на модели • Използвайте * и ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Добави потребителски псевдоним", "deprecatedModelId": "Остарял ID на модел", "newModelId": "Нов ID на модел", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Преводач", diff --git a/src/i18n/messages/cs.json b/src/i18n/messages/cs.json index db9b005624..b134a12cb8 100644 --- a/src/i18n/messages/cs.json +++ b/src/i18n/messages/cs.json @@ -997,7 +997,19 @@ "auto": "Auto Kombo", "autoDesc": "Samoopravný inteligentní směrovací pool (Optimalizovaný výkon)", "lkgp": "Režim LKGP", - "lkgpDesc": "Poslední známý dobrý poskytovatel (Predikovatelná odolnost)" + "lkgpDesc": "Poslední známý dobrý poskytovatel (Predikovatelná odolnost)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Náklady", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Volání účtem před přepnutím", "modelAliases": "Aliasy modelů", "modelAliasesTitle": "Aliasy modelů", - "modelAliasesDesc": "Vzory zástupných znaků pro přemapování názvů modelů • Použijte * a ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Přidat vlastní alias", "deprecatedModelId": "ID zastupovaného modelu", "newModelId": "Nové ID modelu", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Poslední známý dobrý poskytovatel (Predikovatelná odolnost)", "maintenance": "Údržba", "purgeExpiredLogs": "Vymazat expirované protokoly", - "purgeLogsFailed": "Nepodařilo se vymazat protokoly" + "purgeLogsFailed": "Nepodařilo se vymazat protokoly", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Překladatel", diff --git a/src/i18n/messages/da.json b/src/i18n/messages/da.json index 74621601c1..c155d098f0 100644 --- a/src/i18n/messages/da.json +++ b/src/i18n/messages/da.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Omkostninger", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Opkald pr. konto før skift", "modelAliases": "Model aliaser", "modelAliasesTitle": "Model Aliaser", - "modelAliasesDesc": "Wildcard-mønstre til omlægning af modelnavne • Brug * og ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Tilføj Tilpasset Alias", "deprecatedModelId": "Forældet model-ID", "newModelId": "Nyt model-ID", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Oversætter", diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index 5a84fe4850..9b0cf2622e 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Kosten", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Anrufe pro Konto vor dem Wechsel", "modelAliases": "Modell-Aliase", "modelAliasesTitle": "Modell-Aliase", - "modelAliasesDesc": "Platzhaltermuster zum Neuzuordnen von Modellnamen • Verwenden Sie * und ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Benutzerdefinierten Alias hinzufügen", "deprecatedModelId": "Veraltete Modell-ID", "newModelId": "Neue Modell-ID", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Übersetzer", diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index fdca460b08..6dacc1d433 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -1050,7 +1050,19 @@ "auto": "Intelligent Auto", "autoDesc": "Self-healing smart routing pool with multi-factor scoring", "lkgp": "LKGP Mode", - "lkgpDesc": "Prioritizes the last provider that successfully completed a request" + "lkgpDesc": "Prioritizes the last provider that successfully completed a request", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Costs", @@ -2101,7 +2113,7 @@ "stickyLimitDesc": "Calls per account before switching", "modelAliases": "Model Aliases", "modelAliasesTitle": "Model Aliases", - "modelAliasesDesc": "Wildcard patterns to remap model names • Use * and ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Add Custom Alias", "deprecatedModelId": "Deprecated model ID", "newModelId": "New model ID", @@ -2354,7 +2366,28 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Translator", diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json index 279c2271bd..1398393d8c 100644 --- a/src/i18n/messages/es.json +++ b/src/i18n/messages/es.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Costos", @@ -1947,7 +1959,7 @@ "stickyLimitDesc": "Llamadas por cuenta antes de cambiar", "modelAliases": "Alias de modelo", "modelAliasesTitle": "Aliases de Modelo", - "modelAliasesDesc": "Patrones comodín para reasignar nombres de modelos • Utilice * y ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Agregar Alias Personalizado", "deprecatedModelId": "ID del modelo obsoleto", "newModelId": "Nuevo ID del modelo", @@ -2236,7 +2248,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Traductor", diff --git a/src/i18n/messages/fi.json b/src/i18n/messages/fi.json index fc0972a70f..313b81c00a 100644 --- a/src/i18n/messages/fi.json +++ b/src/i18n/messages/fi.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Kustannukset", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Puhelut tilikohtaisesti ennen vaihtamista", "modelAliases": "Mallin aliakset", "modelAliasesTitle": "Mallialias", - "modelAliasesDesc": "Jokerimerkkikuviot mallien nimien yhdistämiseen • Käytä * ja ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Lisää Mukautettu Alias", "deprecatedModelId": "Vanhentunut malli-ID", "newModelId": "Uusi malli-ID", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Kääntäjä", diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index f18ad6e00a..3072df5553 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Coûts", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Appels par compte avant de changer", "modelAliases": "Alias de modèle", "modelAliasesTitle": "Alias de Modèles", - "modelAliasesDesc": "Modèles génériques pour remapper les noms de modèles • Utilisez * et ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Ajouter un Alias Personnalisé", "deprecatedModelId": "ID du modèle obsolète", "newModelId": "Nouvel ID de modèle", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Traducteur", diff --git a/src/i18n/messages/he.json b/src/i18n/messages/he.json index e2b9af068f..515b907964 100644 --- a/src/i18n/messages/he.json +++ b/src/i18n/messages/he.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "עלויות", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "שיחות לכל חשבון לפני המעבר", "modelAliases": "כינויי דגם", "modelAliasesTitle": "כינויי מודלים", - "modelAliasesDesc": "תבניות תווים כלליים למיפוי מחדש של שמות מודלים • השתמש ב-* וב-?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "הוסף כינוי מותאם אישית", "deprecatedModelId": "מזהה מודל מיושן", "newModelId": "מזהה מודל חדש", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "מתרגם", diff --git a/src/i18n/messages/hi.json b/src/i18n/messages/hi.json index 23e1a71e02..efb23337e5 100644 --- a/src/i18n/messages/hi.json +++ b/src/i18n/messages/hi.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "लागत", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "स्विच करने से पहले प्रति खाता कॉल", "modelAliases": "मॉडल उपनाम", "modelAliasesTitle": "Model Alias", - "modelAliasesDesc": "मॉडल नामों को रीमैप करने के लिए वाइल्डकार्ड पैटर्न • * और ? का उपयोग करें", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Kustom Alias Tambahkan", "deprecatedModelId": "ID model yang tidak digunakan lagi", "newModelId": "ID model baru", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "अनुवादक", diff --git a/src/i18n/messages/hu.json b/src/i18n/messages/hu.json index 4495e05c18..38d83d27a5 100644 --- a/src/i18n/messages/hu.json +++ b/src/i18n/messages/hu.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Költségek", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Hívások fiókonként váltás előtt", "modelAliases": "Modell álnevek", "modelAliasesTitle": "Modell aliasok", - "modelAliasesDesc": "Helyettesítő karakter minták a modellnevek újratervezéséhez • Használja a * és a ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Egyéni Alias Hozzáadása", "deprecatedModelId": "Elavult modell ID", "newModelId": "Új modell ID", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Fordító", diff --git a/src/i18n/messages/id.json b/src/i18n/messages/id.json index 31ed9455a6..6f0175dfb2 100644 --- a/src/i18n/messages/id.json +++ b/src/i18n/messages/id.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Biaya", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Panggilan per akun sebelum beralih", "modelAliases": "Alias Model", "modelAliasesTitle": "Alias Model", - "modelAliasesDesc": "Pola karakter pengganti untuk memetakan ulang nama model • Gunakan * dan ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Tambah Alias Kustom", "deprecatedModelId": "ID model yang sudah usang", "newModelId": "ID model baru", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Penerjemah", diff --git a/src/i18n/messages/it.json b/src/i18n/messages/it.json index 51e9f04854..b648335ffb 100644 --- a/src/i18n/messages/it.json +++ b/src/i18n/messages/it.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Costi", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Chiamate per account prima del cambio", "modelAliases": "Alias ​​del modello", "modelAliasesTitle": "Alias dei Modelli", - "modelAliasesDesc": "Modelli di caratteri jolly per rimappare i nomi dei modelli • Utilizzare * e ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Aggiungi Alias Personalizzato", "deprecatedModelId": "ID modello deprecato", "newModelId": "Nuovo ID modello", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Traduttore", diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json index 3aeac027c7..95879f738e 100644 --- a/src/i18n/messages/ja.json +++ b/src/i18n/messages/ja.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "コスト", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "切り替える前のアカウントごとの通話数", "modelAliases": "モデルのエイリアス", "modelAliasesTitle": "モデルエイリアス", - "modelAliasesDesc": "モデル名を再マッピングするワイルドカード パターン • * と ? を使用します。", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "カスタムエイリアスを追加", "deprecatedModelId": "非推奨モデルID", "newModelId": "新しいモデルID", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "翻訳者", diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json index a6d52a34a8..7c38183270 100644 --- a/src/i18n/messages/ko.json +++ b/src/i18n/messages/ko.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "비용", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "전환 전 계정당 통화", "modelAliases": "모델 별칭", "modelAliasesTitle": "모델 별칭", - "modelAliasesDesc": "모델 이름을 다시 매핑하는 와일드카드 패턴 • * 및 ?를 사용합니다.", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "사용자 지정 별칭 추가", "deprecatedModelId": "사용 중단된 모델 ID", "newModelId": "새 모델 ID", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "번역기", diff --git a/src/i18n/messages/ms.json b/src/i18n/messages/ms.json index 06e64f696e..ad85d77910 100644 --- a/src/i18n/messages/ms.json +++ b/src/i18n/messages/ms.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Kos", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Panggilan setiap akaun sebelum bertukar", "modelAliases": "Alias Model", "modelAliasesTitle": "Alias Model", - "modelAliasesDesc": "Corak kad liar untuk memetakan semula nama model • Gunakan * dan ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Tambah Alias Tersuai", "deprecatedModelId": "ID model yang ditamatkan", "newModelId": "ID model baharu", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Penterjemah", diff --git a/src/i18n/messages/nl.json b/src/i18n/messages/nl.json index 48e8596b7b..d6283c8f04 100644 --- a/src/i18n/messages/nl.json +++ b/src/i18n/messages/nl.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Kosten", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Gesprekken per account voordat u overstapt", "modelAliases": "Modelaliassen", "modelAliasesTitle": "Model Aliases", - "modelAliasesDesc": "Jokertekenpatronen om modelnamen opnieuw toe te wijzen • Gebruik * en ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Aangepast Alias Toevoegen", "deprecatedModelId": "Verouderd model-ID", "newModelId": "Nieuw model-ID", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Vertaler", diff --git a/src/i18n/messages/no.json b/src/i18n/messages/no.json index c49ab844d0..c7d339ad33 100644 --- a/src/i18n/messages/no.json +++ b/src/i18n/messages/no.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Kostnader", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Anrop per konto før bytte", "modelAliases": "Modellaliaser", "modelAliasesTitle": "Modellaliaser", - "modelAliasesDesc": "Jokertegnmønstre for å tilordne modellnavn på nytt • Bruk * og ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Legg til Tilpasset Alias", "deprecatedModelId": "Utdatert modell-ID", "newModelId": "Ny modell-ID", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Oversetter", diff --git a/src/i18n/messages/phi.json b/src/i18n/messages/phi.json index 90fcf91ea4..838dd61629 100644 --- a/src/i18n/messages/phi.json +++ b/src/i18n/messages/phi.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Mga gastos", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Mga tawag sa bawat account bago lumipat", "modelAliases": "Mga Alyas ng Modelo", "modelAliasesTitle": "Mga Alias ng Model", - "modelAliasesDesc": "Mga pattern ng wildcard para i-remap ang mga pangalan ng modelo • Gamitin ang * at ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Magdagdag ng Custom na Alias", "deprecatedModelId": "Deprecated na Model ID", "newModelId": "Bagong Model ID", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Tagasalin", diff --git a/src/i18n/messages/pl.json b/src/i18n/messages/pl.json index 39d72ece2c..02e8c5c0a5 100644 --- a/src/i18n/messages/pl.json +++ b/src/i18n/messages/pl.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Koszty", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Połączenia na konto przed zmianą", "modelAliases": "Aliasy modeli", "modelAliasesTitle": "Aliasy modeli", - "modelAliasesDesc": "Wzorce wieloznaczne do zmiany nazw modeli • Użyj * i ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Dodaj niestandardowy alias", "deprecatedModelId": "Przestarzały ID modelu", "newModelId": "Nowy ID modelu", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Tłumacz", diff --git a/src/i18n/messages/pt-BR.json b/src/i18n/messages/pt-BR.json index de02bbf2a1..d64a16585b 100644 --- a/src/i18n/messages/pt-BR.json +++ b/src/i18n/messages/pt-BR.json @@ -1006,7 +1006,19 @@ "auto": "Auto Combo", "autoDesc": "Pool de roteamento inteligente (Otimizado)", "lkgp": "Modo LKGP", - "lkgpDesc": "Último Provedor Bom Conhecido (Resiliência previsível)" + "lkgpDesc": "Último Provedor Bom Conhecido (Resiliência previsível)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Custos", @@ -2006,7 +2018,7 @@ "stickyLimitDesc": "Chamadas por conta antes de trocar", "modelAliases": "Aliases de Modelo", "modelAliasesTitle": "Aliases de Modelo", - "modelAliasesDesc": "Padrões coringa para remapear nomes de modelos • Use * e ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Adicionar Alias Personalizado", "deprecatedModelId": "ID do modelo depreciado", "newModelId": "Novo ID do modelo", @@ -2301,7 +2313,28 @@ "clearLkgpCache": "Clear LKGP Cache", "lkgpCacheCleared": "LKGP cache cleared successfully", "lkgpCacheClearFailed": "Failed to clear LKGP cache", - "maintenance": "Maintenance" + "maintenance": "Maintenance", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Tradutor", diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index ba64dcbe49..237ae659be 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Pool de roteamento inteligente (Otimizado)", "lkgp": "Modo LKGP", - "lkgpDesc": "Último Provedor Bom Conhecido (Resiliência previsível)" + "lkgpDesc": "Último Provedor Bom Conhecido (Resiliência previsível)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Custos", @@ -1997,7 +2009,7 @@ "stickyLimitDesc": "Chamadas por conta antes de mudar", "modelAliases": "Aliases de modelo", "modelAliasesTitle": "Aliases de Modelo", - "modelAliasesDesc": "Padrões curinga para remapear nomes de modelos • Use * e ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Adicionar Alias Personalizado", "deprecatedModelId": "ID do modelo depreciado", "newModelId": "Novo ID do modelo", @@ -2286,7 +2298,30 @@ "clearLkgpCache": "Clear LKGP Cache", "lkgpCacheCleared": "LKGP cache cleared successfully", "lkgpCacheClearFailed": "Failed to clear LKGP cache", - "maintenance": "Maintenance" + "maintenance": "Maintenance", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Tradutor", diff --git a/src/i18n/messages/ro.json b/src/i18n/messages/ro.json index 92fc3ebad7..d5fca1461b 100644 --- a/src/i18n/messages/ro.json +++ b/src/i18n/messages/ro.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Costuri", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Apeluri pe cont înainte de a comuta", "modelAliases": "Aliasuri de model", "modelAliasesTitle": "Aliasuri de model", - "modelAliasesDesc": "Modele wildcard pentru a remapa numele modelelor • Utilizați * și ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Adaugă Alias Personalizat", "deprecatedModelId": "ID model depreciat", "newModelId": "ID model nou", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Traducător", diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json index e4eacef3d6..eb382eb6da 100644 --- a/src/i18n/messages/ru.json +++ b/src/i18n/messages/ru.json @@ -1021,7 +1021,19 @@ "auto": "Авто", "autoDesc": "Автоматическая стратегия - система сама выбирает подходящее поведение.", "lkgp": "LKGP", - "lkgpDesc": "Маршрутизация по последней известной хорошей политике" + "lkgpDesc": "Маршрутизация по последней известной хорошей политике", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Затраты", @@ -1985,7 +1997,7 @@ "stickyLimitDesc": "Звонки на аккаунт до переключения", "modelAliases": "Псевдонимы моделей", "modelAliasesTitle": "Псевдонимы моделей", - "modelAliasesDesc": "Шаблоны подстановочных знаков для переназначения названий моделей • Используйте * и ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Добавить пользовательский псевдоним", "deprecatedModelId": "Устаревший ID модели", "newModelId": "Новый ID модели", @@ -2260,7 +2272,30 @@ "skillsComingSoon": "Маркетплейс навыков скоро появится.", "memorySkillsTitle": "Память и навыки", "memorySkillsDesc": "Постоянный контекст и возможности", - "days": "Дни" + "days": "Дни", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Переводчик", diff --git a/src/i18n/messages/sk.json b/src/i18n/messages/sk.json index d764a2dcf9..554117f98e 100644 --- a/src/i18n/messages/sk.json +++ b/src/i18n/messages/sk.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "náklady", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Hovory na účet pred prepnutím", "modelAliases": "Aliasy modelov", "modelAliasesTitle": "Aliasy modelov", - "modelAliasesDesc": "Vzory zástupných znakov na premapovanie názvov modelov • Použite * a ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Pridať vlastný alias", "deprecatedModelId": "Zastaraný ID modelu", "newModelId": "Nový ID modelu", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Prekladateľ", diff --git a/src/i18n/messages/sv.json b/src/i18n/messages/sv.json index 68cfcd7381..11c95d46c3 100644 --- a/src/i18n/messages/sv.json +++ b/src/i18n/messages/sv.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Kostnader", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Samtal per konto innan byte", "modelAliases": "Modellalias", "modelAliasesTitle": "Modellalias", - "modelAliasesDesc": "Jokerteckenmönster för att mappa om modellnamn • Använd * och ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Lägg Till Anpassat Alias", "deprecatedModelId": "Föråldrat modell-ID", "newModelId": "Nytt modell-ID", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Översättare", diff --git a/src/i18n/messages/th.json b/src/i18n/messages/th.json index d2cefd55c1..4b1f35c9bd 100644 --- a/src/i18n/messages/th.json +++ b/src/i18n/messages/th.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "ค่าใช้จ่าย", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "โทรต่อบัญชีก่อนที่จะเปลี่ยน", "modelAliases": "นามแฝงของโมเดล", "modelAliasesTitle": "นามแฝงโมเดล", - "modelAliasesDesc": "รูปแบบไวด์การ์ดเพื่อทำการแมปชื่อโมเดลใหม่ • ใช้ * และ ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "เพิ่มนามแฝงที่กำหนดเอง", "deprecatedModelId": "ID โมเดลที่เลิกใช้", "newModelId": "ID โมเดลใหม่", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "นักแปล", diff --git a/src/i18n/messages/tr.json b/src/i18n/messages/tr.json index b5869178ee..c1c3fdacb5 100644 --- a/src/i18n/messages/tr.json +++ b/src/i18n/messages/tr.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Maliyetler", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Geçişten önce hesap başına çağrı sayısı", "modelAliases": "Model Takma Adları", "modelAliasesTitle": "Model Takma Adları", - "modelAliasesDesc": "Model adlarını yeniden eşlemek için joker karakter desenleri • * ve ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Özel Takma Ad Ekle", "deprecatedModelId": "Kullanımdan kaldırılan model kimliği", "newModelId": "Yeni model kimliği", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Çeviri", diff --git a/src/i18n/messages/uk-UA.json b/src/i18n/messages/uk-UA.json index 0e5a01ea65..f915ec7747 100644 --- a/src/i18n/messages/uk-UA.json +++ b/src/i18n/messages/uk-UA.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Витрати", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Дзвінки на обліковий запис перед переходом", "modelAliases": "Псевдоніми моделі", "modelAliasesTitle": "Псевдоніми моделей", - "modelAliasesDesc": "Шаблони шаблонів узагальнення для зміни назв моделей • Використовуйте * та ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Додати власний псевдонім", "deprecatedModelId": "Застарілий ID моделі", "newModelId": "Новий ID моделі", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Перекладач", diff --git a/src/i18n/messages/vi.json b/src/i18n/messages/vi.json index 5cadd9e835..1f8e77dc66 100644 --- a/src/i18n/messages/vi.json +++ b/src/i18n/messages/vi.json @@ -997,7 +997,19 @@ "auto": "Auto Combo", "autoDesc": "Self-healing smart routing pool (Performance optimized)", "lkgp": "LKGP Mode", - "lkgpDesc": "Last Known Good Provider (Predictable resilience)" + "lkgpDesc": "Last Known Good Provider (Predictable resilience)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "Chi phí", @@ -1942,7 +1954,7 @@ "stickyLimitDesc": "Cuộc gọi trên mỗi tài khoản trước khi chuyển đổi", "modelAliases": "Bí danh mẫu", "modelAliasesTitle": "Bí danh mô hình", - "modelAliasesDesc": "Các mẫu ký tự đại diện để ánh xạ lại tên mẫu máy • Sử dụng * và ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "Thêm Bí Danh Tùy Chỉnh", "deprecatedModelId": "ID mô hình ngừng sử dụng", "newModelId": "ID mô hình mới", @@ -2231,7 +2243,30 @@ "lkgpDesc": "Last Known Good Provider (Predictable resilience)", "maintenance": "Maintenance", "purgeExpiredLogs": "Purge Expired Logs", - "purgeLogsFailed": "Failed to purge logs" + "purgeLogsFailed": "Failed to purge logs", + "contextRelay": "Context Relay", + "contextRelayDesc": "Hands off context between providers with automatic summarization", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "Người phiên dịch", diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json index d679824d4d..92b43c8081 100644 --- a/src/i18n/messages/zh-CN.json +++ b/src/i18n/messages/zh-CN.json @@ -1006,7 +1006,19 @@ "auto": "自动组合", "autoDesc": "自愈型智能路由池(性能优化)", "lkgp": "LKGP 模式", - "lkgpDesc": "最后已知良好提供商(可预测的弹性)" + "lkgpDesc": "最后已知良好提供商(可预测的弹性)", + "wizardGuideTitle": "Getting Started with Combos", + "wizardGuideDesc": "Create model combos to route AI traffic intelligently", + "wizardGuideHint": "or click + Create Combo above", + "createFirstCombo": "Create Your First Combo", + "wizardStep1Title": "Name Your Combo", + "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", + "wizardStep2Title": "Add Models", + "wizardStep2Desc": "Select AI models and arrange their fallback priority order", + "wizardStep3Title": "Choose Strategy", + "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", + "wizardStep4Title": "Review & Save", + "wizardStep4Desc": "Review your configuration and activate the combo" }, "costs": { "title": "成本", @@ -2000,7 +2012,7 @@ "stickyLimitDesc": "切换前每个账户连续处理的请求次数", "modelAliases": "模型别名", "modelAliasesTitle": "模型别名", - "modelAliasesDesc": "重新映射模型名称的通配符模式 • 使用 * 和 ?", + "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", "addCustomAlias": "添加自定义别名", "deprecatedModelId": "已弃用的模型 ID", "newModelId": "新模型 ID", @@ -2253,7 +2265,28 @@ "lkgpDesc": "最后已知良好提供商(可预测的弹性)", "maintenance": "维护", "purgeExpiredLogs": "清理过期日志", - "purgeLogsFailed": "清理日志失败" + "purgeLogsFailed": "清理日志失败", + "contextOpt": "Context Optimized", + "contextOptDesc": "Routes based on context window requirements and conversation length", + "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", + "weightedDesc": "Distributes traffic by percentage weights across providers", + "modelRoutingTitle": "Model Routing Rules", + "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", + "addRule": "Add Rule", + "routeToCombo": "Route to Combo", + "selectCombo": "Select combo...", + "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", + "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", + "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", + "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", + "deleteRoutingRule": "Delete this model routing rule?", + "exactMatchMode": "Exact Match", + "wildcardPatternMode": "Wildcard Pattern", + "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", + "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", + "noExactAliasesConfigured": "No exact-match aliases configured.", + "wildcardRulesTitle": "Wildcard Rules", + "noWildcardAliasesConfigured": "No wildcard aliases configured." }, "translator": { "title": "翻译器", diff --git a/src/shared/components/ModelRoutingSection.tsx b/src/shared/components/ModelRoutingSection.tsx index 063f2435ac..20f763cc01 100644 --- a/src/shared/components/ModelRoutingSection.tsx +++ b/src/shared/components/ModelRoutingSection.tsx @@ -1,6 +1,7 @@ "use client"; import { useState, useEffect } from "react"; +import { useTranslations } from "next-intl"; export interface ModelMapping { id: string; @@ -17,11 +18,14 @@ interface Combo { name: string; } -export default function ModelRoutingSection({ combos = [] }: { combos?: Combo[] }) { +export default function ModelRoutingSection({ combos: externalCombos }: { combos?: Combo[] } = {}) { + const t = useTranslations("settings"); const [mappings, setMappings] = useState([]); + const [internalCombos, setInternalCombos] = useState([]); const [loading, setLoading] = useState(true); const [adding, setAdding] = useState(false); const [editingId, setEditingId] = useState(null); + const combos = externalCombos || internalCombos; // Form state const [pattern, setPattern] = useState(""); @@ -53,6 +57,22 @@ export default function ModelRoutingSection({ combos = [] }: { combos?: Combo[] }; }, []); + useEffect(() => { + if (externalCombos !== undefined) return; + let cancelled = false; + fetch("/api/combos") + .then((res) => (res.ok ? res.json() : { combos: [] })) + .then((data) => { + if (!cancelled) { + setInternalCombos(Array.isArray(data?.combos) ? data.combos : []); + } + }) + .catch(() => {}); + return () => { + cancelled = true; + }; + }, [externalCombos]); + const refetchMappings = async () => { const data = await loadMappings(); setMappings(data); @@ -100,7 +120,7 @@ export default function ModelRoutingSection({ combos = [] }: { combos?: Combo[] }; const handleDelete = async (id: string) => { - if (!confirm("Delete this model routing rule?")) return; + if (!confirm(t("deleteRoutingRule"))) return; try { await fetch(`/api/model-combo-mappings/${id}`, { method: "DELETE" }); setMappings((prev) => prev.filter((m) => m.id !== id)); @@ -126,10 +146,8 @@ export default function ModelRoutingSection({ combos = [] }: { combos?: Combo[]
route
-

Model Routing Rules

-

- Automatically route models to specific combos using glob patterns -

+

{t("modelRoutingTitle")}

+

{t("modelRoutingDesc")}

{!adding && ( @@ -139,7 +157,7 @@ export default function ModelRoutingSection({ combos = [] }: { combos?: Combo[] bg-primary/10 text-primary hover:bg-primary/20 transition-colors" > add - Add Rule + {t("addRule")} )}
@@ -150,7 +168,7 @@ export default function ModelRoutingSection({ combos = [] }: { combos?: Combo[]
-

- Use * for any chars, ? for single char. Case-insensitive. -

+

{t("patternHint")}

-

- Higher = checked first. Use 10+ for specific patterns. -

+

{t("priorityHint")}

- {editingId ? "Update" : "Save"} + {editingId ? t("update") : t("save")}
@@ -231,18 +245,11 @@ export default function ModelRoutingSection({ combos = [] }: { combos?: Combo[] {/* Mappings list */} {loading ? ( -
Loading...
+
{t("loading")}
) : mappings.length === 0 ? (
-

- No routing rules configured. Requests use the global combo by default. -

-

- Add a rule like{" "} - claude-opus* - {" → "} frontier-combo to automatically route - requests. -

+

{t("noRoutingRules")}

+

{t("routingRuleHint")}

) : (
@@ -277,7 +284,7 @@ export default function ModelRoutingSection({ combos = [] }: { combos?: Combo[]