fix(cli): align OpenCode config preview and add multi-model selection (#1602)

Integrated into release/v3.7.0
This commit is contained in:
Jason Landbridge
2026-04-25 20:55:41 +02:00
committed by GitHub
parent 1beb372057
commit 604d55ed42
41 changed files with 662 additions and 150 deletions

View File

@@ -45,7 +45,6 @@ const nextApp = next({
hostname,
port: dashboardPort,
turbopack: useTurbopack,
webpack: dev && !useTurbopack,
});
async function start() {

View File

@@ -5,6 +5,7 @@ import { Card, Button, ModelSelectModal } from "@/shared/components";
import Image from "next/image";
import { useTranslations } from "next-intl";
import { copyToClipboard } from "@/shared/utils/clipboard";
import { buildOpenCodeConfigDocument } from "@/shared/services/opencodeConfig";
export default function DefaultToolCard({
toolId,
@@ -31,6 +32,7 @@ export default function DefaultToolCard({
const [copiedField, setCopiedField] = useState(null);
const [showModelModal, setShowModelModal] = useState(false);
const [modelValue, setModelValue] = useState("");
const [modelValues, setModelValues] = useState<string[]>([]);
const [runtimeStatus, setRuntimeStatus] = useState(null);
const [message, setMessage] = useState(null);
const [saving, setSaving] = useState(false);
@@ -40,11 +42,32 @@ export default function DefaultToolCard({
const [selectedApiKeyId, setSelectedApiKeyId] = useState(() =>
apiKeys?.length > 0 ? apiKeys[0].id : ""
);
const isMultiModelTool = tool.modelSelectionMode === "multiple";
const usesOpenCodePreview = tool.previewConfigMode === "opencode";
// Persist and restore model selection per tool via localStorage
useEffect(() => {
const savedModel = localStorage.getItem(`omniroute-cli-model-${toolId}`);
if (savedModel) setModelValue(savedModel);
if (savedModel) {
if (isMultiModelTool) {
try {
const parsed = JSON.parse(savedModel);
if (Array.isArray(parsed)) {
const normalized = parsed.map((value) => String(value || "").trim()).filter(Boolean);
setModelValues(normalized);
setModelValue(normalized[0] || "");
} else {
setModelValue(savedModel);
setModelValues([savedModel]);
}
} catch {
setModelValue(savedModel);
setModelValues([savedModel]);
}
} else {
setModelValue(savedModel);
}
}
const savedKey = localStorage.getItem(`omniroute-cli-key-${toolId}`);
// (#523) localStorage may contain a masked key string from before the fix —
// match by prefix/suffix against known keys to find the id.
@@ -56,7 +79,7 @@ export default function DefaultToolCard({
);
if (matchedKey) setSelectedApiKeyId(matchedKey.id);
}
}, [toolId, apiKeys]);
}, [toolId, apiKeys, isMultiModelTool]);
const handleModelChange = useCallback(
(value) => {
@@ -70,6 +93,24 @@ export default function DefaultToolCard({
[toolId]
);
const handleModelValuesChange = useCallback(
(values) => {
const normalized = Array.isArray(values)
? [...new Set(values.map((value) => String(value || "").trim()).filter(Boolean))]
: [];
setModelValues(normalized);
setModelValue(normalized[0] || "");
if (normalized.length > 0) {
localStorage.setItem(`omniroute-cli-model-${toolId}`, JSON.stringify(normalized));
} else {
localStorage.removeItem(`omniroute-cli-model-${toolId}`);
}
},
[toolId]
);
const handleApiKeyChange = useCallback(
(value) => {
setSelectedApiKeyId(value);
@@ -89,24 +130,28 @@ export default function DefaultToolCard({
.then((res) => res.json())
.then((data) => setRuntimeStatus(data))
.catch((error) => setRuntimeStatus({ error: error?.message || t("runtimeCheckFailed") }));
}, [isExpanded, runtimeStatus, toolId]);
}, [isExpanded, runtimeStatus, t, toolId]);
const replaceVars = (text) => {
// (#523) Look up the key object by id to get the masked display value.
const selectedKeyObj = apiKeys?.find((k) => k.id === selectedApiKeyId);
const keyToUse =
selectedKeyObj?.key || (!cloudEnabled ? "sk_omniroute" : t("yourApiKeyPlaceholder"));
const replaceVars = useCallback(
(text) => {
// (#523) Look up the key object by id to get the masked display value.
const selectedKeyObj = apiKeys?.find((k) => k.id === selectedApiKeyId);
let keyToUse =
selectedKeyObj?.key || (!cloudEnabled ? "sk_omniroute" : t("yourApiKeyPlaceholder"));
if (keyToUse.includes("***")) keyToUse = "<YOUR_API_KEY>";
const normalizedBaseUrl = baseUrl || "http://localhost:20128";
const baseUrlWithV1 = normalizedBaseUrl.endsWith("/v1")
? normalizedBaseUrl
: `${normalizedBaseUrl}/v1`;
const normalizedBaseUrl = baseUrl || "http://localhost:20128";
const baseUrlWithV1 = normalizedBaseUrl.endsWith("/v1")
? normalizedBaseUrl
: `${normalizedBaseUrl}/v1`;
return text
.replace(/\{\{baseUrl\}\}/g, baseUrlWithV1)
.replace(/\{\{apiKey\}\}/g, keyToUse)
.replace(/\{\{model\}\}/g, modelValue || t("modelPlaceholder"));
};
return text
.replace(/\{\{baseUrl\}\}/g, baseUrlWithV1)
.replace(/\{\{apiKey\}\}/g, keyToUse)
.replace(/\{\{model\}\}/g, modelValue || t("modelPlaceholder"));
},
[apiKeys, baseUrl, cloudEnabled, modelValue, selectedApiKeyId, t]
);
const handleCopy = async (text, field) => {
await copyToClipboard(replaceVars(text));
@@ -114,8 +159,63 @@ export default function DefaultToolCard({
setTimeout(() => setCopiedField(null), 2000);
};
const getSelectedModels = useCallback(() => {
if (!isMultiModelTool) return modelValue ? [modelValue] : [];
return modelValues.length > 0 ? modelValues : modelValue ? [modelValue] : [];
}, [isMultiModelTool, modelValue, modelValues]);
const getRenderedCodeBlock = useCallback(() => {
if (!tool.codeBlock?.code) return "";
if (!usesOpenCodePreview) return replaceVars(tool.codeBlock.code);
const selectedKeyObj = apiKeys?.find((k) => k.id === selectedApiKeyId);
let keyToUse =
selectedKeyObj?.key || (!cloudEnabled ? "sk_omniroute" : t("yourApiKeyPlaceholder"));
if (keyToUse.includes("***")) keyToUse = "<YOUR_API_KEY>";
const normalizedBaseUrl = baseUrl || "http://localhost:20128";
const baseUrlWithV1 = normalizedBaseUrl.endsWith("/v1")
? normalizedBaseUrl
: `${normalizedBaseUrl}/v1`;
return JSON.stringify(
buildOpenCodeConfigDocument({
baseUrl: baseUrlWithV1,
apiKey: keyToUse,
models: getSelectedModels(),
model: getSelectedModels()[0],
}),
null,
2
);
}, [
apiKeys,
baseUrl,
cloudEnabled,
getSelectedModels,
replaceVars,
selectedApiKeyId,
t,
tool.codeBlock?.code,
usesOpenCodePreview,
]);
const handleSelectModel = (model) => {
handleModelChange(model.value);
if (!isMultiModelTool) {
handleModelChange(model.value);
return;
}
if (!model) {
handleModelValuesChange([]);
return;
}
if (modelValues.includes(model.value)) {
handleModelValuesChange(modelValues.filter((value) => value !== model.value));
return;
}
handleModelValuesChange([...modelValues, model.value]);
};
const hasActiveProviders = activeProviders.length > 0;
@@ -142,6 +242,7 @@ export default function DefaultToolCard({
apiKey: !cloudEnabled ? "sk_omniroute" : null,
keyId: selectedKeyId,
model: modelValue,
models: isMultiModelTool ? getSelectedModels() : undefined,
}),
});
const data = await res.json();
@@ -199,12 +300,23 @@ export default function DefaultToolCard({
};
const renderModelSelector = () => {
const displayValue = isMultiModelTool ? getSelectedModels().join(", ") : modelValue;
return (
<div className="mt-2 flex items-center gap-2">
<input
type="text"
value={modelValue}
onChange={(e) => handleModelChange(e.target.value)}
value={displayValue}
onChange={(e) =>
isMultiModelTool
? handleModelValuesChange(
e.target.value
.split(",")
.map((value) => value.trim())
.filter(Boolean)
)
: handleModelChange(e.target.value)
}
placeholder={t("modelPlaceholder")}
className="flex-1 px-3 py-2 bg-bg-secondary rounded-lg text-sm border border-border focus:outline-none focus:ring-1 focus:ring-primary/50"
/>
@@ -219,10 +331,10 @@ export default function DefaultToolCard({
>
{t("selectModel")}
</button>
{modelValue && (
{displayValue && (
<>
<button
onClick={() => handleCopy(modelValue, "model")}
onClick={() => handleCopy(displayValue, "model")}
className="shrink-0 px-3 py-2 bg-bg-secondary hover:bg-bg-tertiary rounded-lg border border-border transition-colors"
>
<span className="material-symbols-outlined text-lg">
@@ -230,7 +342,9 @@ export default function DefaultToolCard({
</span>
</button>
<button
onClick={() => handleModelChange("")}
onClick={() =>
isMultiModelTool ? handleModelValuesChange([]) : handleModelChange("")
}
className="p-2 text-text-muted hover:text-red-500 rounded transition-colors"
title={t("clear")}
>
@@ -398,7 +512,7 @@ export default function DefaultToolCard({
{tool.codeBlock.language}
</span>
<button
onClick={() => handleCopy(tool.codeBlock.code, "codeblock")}
onClick={() => handleCopy(getRenderedCodeBlock(), "codeblock")}
className="flex items-center gap-1 px-2 py-1 text-xs bg-bg-secondary hover:bg-bg-tertiary rounded border border-border transition-colors"
>
<span className="material-symbols-outlined text-sm">
@@ -408,9 +522,7 @@ export default function DefaultToolCard({
</button>
</div>
<pre className="p-4 bg-bg-secondary rounded-lg border border-border overflow-x-auto">
<code className="text-sm font-mono whitespace-pre">
{replaceVars(tool.codeBlock.code)}
</code>
<code className="text-sm font-mono whitespace-pre">{getRenderedCodeBlock()}</code>
</pre>
</div>
)}
@@ -434,7 +546,7 @@ export default function DefaultToolCard({
variant="primary"
size="sm"
onClick={handleSaveConfig}
disabled={!modelValue}
disabled={isMultiModelTool ? getSelectedModels().length === 0 : !modelValue}
loading={saving}
>
<span className="material-symbols-outlined text-[14px] mr-1">save</span>
@@ -445,7 +557,7 @@ export default function DefaultToolCard({
<Button
variant={supportsDirectSave ? "outline" : "primary"}
size="sm"
onClick={() => handleCopy(tool.codeBlock.code, "codeblock")}
onClick={() => handleCopy(getRenderedCodeBlock(), "codeblock")}
>
<span className="material-symbols-outlined text-[14px] mr-1">
{copiedField === "codeblock" ? "check" : "content_copy"}
@@ -453,7 +565,7 @@ export default function DefaultToolCard({
{copiedField === "codeblock" ? t("copied") : t("copyConfig")}
</Button>
)}
{modelValue && (
{(isMultiModelTool ? getSelectedModels().length > 0 : !!modelValue) && (
<span className="text-xs text-text-muted flex items-center gap-1">
<span className="material-symbols-outlined text-[14px] text-green-500">
check_circle
@@ -578,8 +690,11 @@ export default function DefaultToolCard({
onClose={() => setShowModelModal(false)}
onSelect={handleSelectModel}
selectedModel={modelValue}
selectedModels={isMultiModelTool ? getSelectedModels() : []}
activeProviders={activeProviders}
title={t("selectModel")}
multiSelect={isMultiModelTool}
showCombos={!tool.hideComboModels}
/>
</Card>
);

View File

@@ -40,7 +40,7 @@ export async function POST(request, { params }) {
if (isValidationFailure(validation)) {
return NextResponse.json({ error: validation.error }, { status: 400 });
}
const { baseUrl, model } = validation.data;
const { baseUrl, model, models } = validation.data;
// (#523) Extract keyId BEFORE validation — Zod strips unknown fields!
const apiKeyId = typeof rawBody?.keyId === "string" ? rawBody.keyId.trim() : null;
const apiKey = await resolveApiKey(apiKeyId, validation.data.apiKey);
@@ -51,8 +51,8 @@ export async function POST(request, { params }) {
return await saveContinueConfig({ baseUrl, apiKey, model });
case "opencode":
// (#524) OpenCode config was never saved because only 'continue' was handled here.
// opencode reads ~/.config/opencode/config.toml — write the OmniRoute settings there.
return await saveOpenCodeConfig({ baseUrl, apiKey, model });
// OpenCode reads ~/.config/opencode/opencode.json — write the OmniRoute settings there.
return await saveOpenCodeConfig({ baseUrl, apiKey, model, models });
case "qwen":
return await saveQwenConfig({ baseUrl, apiKey, model });
default:
@@ -149,7 +149,7 @@ async function saveContinueConfig({ baseUrl, apiKey, model }) {
*
* (#524) OpenCode was silently failing because this handler was missing.
*/
async function saveOpenCodeConfig({ baseUrl, apiKey, model }) {
async function saveOpenCodeConfig({ baseUrl, apiKey, model, models }) {
const configPath = getOpenCodeConfigPath();
const configDir = path.dirname(configPath);
@@ -173,6 +173,7 @@ async function saveOpenCodeConfig({ baseUrl, apiKey, model }) {
baseUrl: normalizedBaseUrl,
apiKey,
model,
models,
});
await fs.writeFile(configPath, JSON.stringify(nextConfig, null, 2), "utf-8");

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"checkSystemStatus": "Check System Status",
"goToDashboard": "Go to Dashboard",
"nothingHere": "Nothing here yet"
"nothingHere": "Nothing here yet",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "الصفحة الرئيسية",
@@ -644,7 +649,9 @@
"kiro": "يُستخدم عند دمج Kiro والتحكم في توجيه النموذج مركزيًا من OmniRoute.",
"antigravity": "يُستخدم عندما يجب اعتراض حركة مرور Antigravity/Kiro عبر MITM وتوجيهها إلى OmniRoute.",
"copilot": "استخدمه عندما تريد UX بأسلوب دردشة Copilot أثناء فرض مفاتيح OmniRoute وقواعد التوجيه.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "جوجل مكافحة الجاذبية IDE مع MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"checkSystemStatus": "Check System Status",
"goToDashboard": "Go to Dashboard",
"nothingHere": "Nothing here yet"
"nothingHere": "Nothing here yet",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Начало",
@@ -644,7 +649,9 @@
"kiro": "Използвайте, когато интегрирате Kiro и контролирате маршрутизирането на модела централно от OmniRoute.",
"antigravity": "Използвайте, когато трафикът на Antigravity/Kiro трябва да бъде прихванат чрез MITM и насочен към OmniRoute.",
"copilot": "Използвайте, когато искате UX в стил на чат Copilot, като същевременно налагате OmniRoute ключове и правила за маршрутизиране.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE с MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"goToDashboard": "Go to Dashboard",
"nothingHere": "Nothing here yet",
"checkSystemStatus": "Check System Status"
"checkSystemStatus": "Check System Status",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Domov",
@@ -644,7 +649,9 @@
"kiro": "Použijte při integraci Kiro a centrálním řízení směrování modelů z OmniRoute.",
"antigravity": "Použijte, pokud musí být provoz Antigravity/Kiro zachycen prostřednictvím MITM a směrován do OmniRoute.",
"copilot": "Použijte, pokud chcete uživatelské rozhraní ve stylu Copilot chat a zároveň vynutit klíče a pravidla směrování OmniRoute.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE s MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro AI poháněné IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"goToDashboard": "Go to Dashboard",
"checkSystemStatus": "Check System Status",
"nothingHere": "Nothing here yet"
"nothingHere": "Nothing here yet",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Hjem",
@@ -644,7 +649,9 @@
"kiro": "Bruges ved integration af Kiro og styring af modelrouting centralt fra OmniRoute.",
"antigravity": "Bruges, når Antigravity/Kiro-trafik skal opsnappes gennem MITM og dirigeres til OmniRoute.",
"copilot": "Brug, når du ønsker Copilot-chatstil UX, mens du håndhæver OmniRoute-nøgler og routingregler.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE med MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"nothingHere": "Nothing here yet",
"checkSystemStatus": "Check System Status",
"goToDashboard": "Go to Dashboard"
"goToDashboard": "Go to Dashboard",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Zuhause",
@@ -644,7 +649,9 @@
"kiro": "Zur Verwendung bei der Integration von Kiro und der zentralen Steuerung des Modellroutings über OmniRoute.",
"antigravity": "Wird verwendet, wenn Antigravity/Kiro-Verkehr über MITM abgefangen und an OmniRoute weitergeleitet werden muss.",
"copilot": "Verwenden Sie diese Option, wenn Sie eine UX im Copilot-Chat-Stil wünschen und gleichzeitig OmniRoute-Schlüssel und Routing-Regeln durchsetzen möchten.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE mit MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"apikey": "API Key",
"http": "HTTP",
"goToDashboard": "Go to Dashboard",
"checkSystemStatus": "Check System Status"
"checkSystemStatus": "Check System Status",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Home",
@@ -649,8 +654,8 @@
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"antigravity": "Use when Antigravity/Kiro traffic must be intercepted through MITM and routed to OmniRoute.",
"copilot": "Use when you want Copilot chat style UX while enforcing OmniRoute keys and routing rules.",
"qwen": "Use when you need Alibaba Qwen Code CLI for coding tasks.",
"amp": "Use when you want Amp shorthand workflows but still need OmniRoute alias and routing rules enforcement.",
"qwen": "Use when you need Alibaba Qwen Code CLI for coding tasks.",
"hermes": "Use when you need a lightweight terminal-native AI assistant for quick tasks.",
"custom": "Use for custom tool implementations or generic OpenAI-compatible configurations."
},

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"checkSystemStatus": "Check System Status",
"nothingHere": "Nothing here yet",
"goToDashboard": "Go to Dashboard"
"goToDashboard": "Go to Dashboard",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Inicio",
@@ -644,7 +649,9 @@
"kiro": "Utilícelo al integrar Kiro y controlar el enrutamiento de modelos de forma centralizada desde OmniRoute.",
"antigravity": "Úselo cuando el tráfico de Antigravity/Kiro debe interceptarse a través de MITM y enrutarse a OmniRoute.",
"copilot": "Úselo cuando desee una experiencia de usuario estilo chat Copilot mientras aplica las claves de OmniRoute y las reglas de enrutamiento.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "IDE antigravedad de Google con MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"checkSystemStatus": "Check System Status",
"nothingHere": "Nothing here yet",
"goToDashboard": "Go to Dashboard"
"goToDashboard": "Go to Dashboard",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Kotiin",
@@ -644,7 +649,9 @@
"kiro": "Käytä integroitaessa Kiroa ja ohjattaessa mallin reititystä keskitetysti OmniRoutesta.",
"antigravity": "Käytä, kun Antigravity/Kiro-liikenne on siepattava MITM:n kautta ja ohjattava OmniRouteen.",
"copilot": "Käytä, kun haluat Copilot-chat-tyylisen UX:n ja pakota OmniRoute-avaimia ja reitityssääntöjä.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE ja MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"nothingHere": "Nothing here yet",
"goToDashboard": "Go to Dashboard",
"checkSystemStatus": "Check System Status"
"checkSystemStatus": "Check System Status",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Accueil",
@@ -644,7 +649,9 @@
"kiro": "À utiliser lors de l'intégration de Kiro et du contrôle centralisé du routage de modèles à partir d'OmniRoute.",
"antigravity": "À utiliser lorsque le trafic Antigravity/Kiro doit être intercepté via MITM et acheminé vers OmniRoute.",
"copilot": "À utiliser lorsque vous souhaitez une UX de style chat Copilot tout en appliquant les clés OmniRoute et les règles de routage.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "IDE Google Antigravity avec MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"checkSystemStatus": "Check System Status",
"goToDashboard": "Go to Dashboard",
"nothingHere": "Nothing here yet"
"nothingHere": "Nothing here yet",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "בית",
@@ -644,7 +649,9 @@
"kiro": "השתמש בעת שילוב Kiro ושליטה בניתוב מודלים באופן מרכזי מ- OmniRoute.",
"antigravity": "השתמש כאשר יש ליירט תעבורת Antigravity/Kiro דרך MITM ולנתב אל OmniRoute.",
"copilot": "השתמש כאשר אתה רוצה UX בסגנון צ'אט Copilot תוך אכיפת מפתחות וכללי ניתוב OmniRoute.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE עם MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"nothingHere": "Nothing here yet",
"checkSystemStatus": "Check System Status",
"goToDashboard": "Go to Dashboard"
"goToDashboard": "Go to Dashboard",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "घर",
@@ -644,7 +649,9 @@
"kiro": "किरो को एकीकृत करते समय और ओमनीरूट से केंद्रीय रूप से मॉडल रूटिंग को नियंत्रित करते समय उपयोग करें।",
"antigravity": "इसका उपयोग तब करें जब एंटीग्रेविटी/किरो ट्रैफिक को एमआईटीएम के माध्यम से रोका जाना चाहिए और ओमनीरूट पर भेजा जाना चाहिए।",
"copilot": "जब आप ओम्निरूट कुंजी और रूटिंग नियमों को लागू करते समय कोपायलट चैट शैली यूएक्स चाहते हैं तो इसका उपयोग करें।",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "एमआईटीएम के साथ गूगल एंटीग्रेविटी आईडीई",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"nothingHere": "Nothing here yet",
"goToDashboard": "Go to Dashboard",
"checkSystemStatus": "Check System Status"
"checkSystemStatus": "Check System Status",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Otthon",
@@ -644,7 +649,9 @@
"kiro": "Használja a Kiro integrálásához és a modell-útválasztás központi vezérléséhez az OmniRoute-ból.",
"antigravity": "Akkor használja, ha az Antigravity/Kiro forgalmat MITM-en keresztül kell elfogni, és az OmniRoute-hoz kell irányítani.",
"copilot": "Használja, ha másodpilóta csevegési stílusú UX-et szeretne, miközben betartja az OmniRoute kulcsokat és útválasztási szabályokat.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE MITM-mel",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"nothingHere": "Nothing here yet",
"goToDashboard": "Go to Dashboard",
"checkSystemStatus": "Check System Status"
"checkSystemStatus": "Check System Status",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Rumah",
@@ -644,7 +649,9 @@
"kiro": "Gunakan saat mengintegrasikan Kiro dan mengontrol perutean model secara terpusat dari OmniRoute.",
"antigravity": "Gunakan ketika lalu lintas Antigravitasi/Kiro harus dicegat melalui MITM dan dialihkan ke OmniRoute.",
"copilot": "Gunakan saat Anda menginginkan UX gaya obrolan kopilot sambil menerapkan kunci OmniRoute dan aturan perutean.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "IDE Antigravitasi Google dengan MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"checkSystemStatus": "Check System Status",
"goToDashboard": "Go to Dashboard",
"nothingHere": "Nothing here yet"
"nothingHere": "Nothing here yet",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Casa",
@@ -644,7 +649,9 @@
"kiro": "Da utilizzare quando si integra Kiro e si controlla l'instradamento del modello centralmente da OmniRoute.",
"antigravity": "Da utilizzare quando il traffico Antigravity/Kiro deve essere intercettato tramite MITM e instradato a OmniRoute.",
"copilot": "Utilizzalo quando desideri un'esperienza utente in stile chat Copilot applicando al tempo stesso le chiavi OmniRoute e le regole di routing.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "IDE Antigravità di Google con MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"checkSystemStatus": "Check System Status",
"nothingHere": "Nothing here yet",
"goToDashboard": "Go to Dashboard"
"goToDashboard": "Go to Dashboard",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "ホーム",
@@ -644,7 +649,9 @@
"kiro": "Kiro を統合し、OmniRoute からモデルのルーティングを一元的に制御する場合に使用します。",
"antigravity": "Antigravity/Kiro トラフィックを MITM 経由でインターセプトし、OmniRoute にルーティングする必要がある場合に使用します。",
"copilot": "OmniRoute キーとルーティング ルールを適用しながら、Copilot チャット スタイルの UX が必要な場合に使用します。",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "MITM を備えた Google Antigravity IDE",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"goToDashboard": "Go to Dashboard",
"nothingHere": "Nothing here yet",
"checkSystemStatus": "Check System Status"
"checkSystemStatus": "Check System Status",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "홈",
@@ -644,7 +649,9 @@
"kiro": "Kiro를 통합하고 OmniRoute에서 중앙에서 모델 라우팅을 제어할 때 사용합니다.",
"antigravity": "Antigravity/Kiro 트래픽이 MITM을 통해 가로채어 OmniRoute로 라우팅되어야 하는 경우에 사용합니다.",
"copilot": "OmniRoute 키와 라우팅 규칙을 적용하면서 Copilot 채팅 스타일 UX를 원할 때 사용하세요.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "MITM이 포함된 Google 반중력 IDE",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"checkSystemStatus": "Check System Status",
"nothingHere": "Nothing here yet",
"goToDashboard": "Go to Dashboard"
"goToDashboard": "Go to Dashboard",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Rumah",
@@ -644,7 +649,9 @@
"kiro": "Gunakan apabila menyepadukan Kiro dan mengawal penghalaan model secara berpusat daripada OmniRoute.",
"antigravity": "Gunakan apabila trafik Antigraviti/Kiro mesti dipintas melalui MITM dan dihalakan ke OmniRoute.",
"copilot": "Gunakan apabila anda mahu Copilot gaya sembang UX sambil menguatkuasakan kekunci OmniRoute dan peraturan penghalaan.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "IDE Antigraviti Google dengan MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"goToDashboard": "Go to Dashboard",
"checkSystemStatus": "Check System Status",
"nothingHere": "Nothing here yet"
"nothingHere": "Nothing here yet",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Thuis",
@@ -644,7 +649,9 @@
"kiro": "Te gebruiken bij het integreren van Kiro en het centraal beheren van modelrouting vanuit OmniRoute.",
"antigravity": "Gebruik wanneer Antigravity/Kiro-verkeer moet worden onderschept via MITM en naar OmniRoute moet worden gerouteerd.",
"copilot": "Gebruik wanneer u UX in Copilot-chatstijl wilt terwijl u OmniRoute-sleutels en routeringsregels afdwingt.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE met MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"goToDashboard": "Go to Dashboard",
"checkSystemStatus": "Check System Status",
"nothingHere": "Nothing here yet"
"nothingHere": "Nothing here yet",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Hjem",
@@ -644,7 +649,9 @@
"kiro": "Brukes når du integrerer Kiro og kontrollerer modellruting sentralt fra OmniRoute.",
"antigravity": "Brukes når Antigravity/Kiro-trafikk må avskjæres gjennom MITM og rutes til OmniRoute.",
"copilot": "Bruk når du vil ha Copilot chat-stil UX mens du håndhever OmniRoute-nøkler og rutingsregler.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE med MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"checkSystemStatus": "Check System Status",
"nothingHere": "Nothing here yet",
"goToDashboard": "Go to Dashboard"
"goToDashboard": "Go to Dashboard",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Bahay",
@@ -644,7 +649,9 @@
"kiro": "Gamitin kapag isinasama ang Kiro at kinokontrol ang pagruruta ng modelo sa gitna mula sa OmniRoute.",
"antigravity": "Gamitin kapag ang trapiko ng Antigravity/Kiro ay dapat ma-intercept sa MITM at iruta sa OmniRoute.",
"copilot": "Gamitin kapag gusto mong Copilot chat style UX habang ipinapatupad ang mga OmniRoute key at mga panuntunan sa pagruruta.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE na may MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"goToDashboard": "Go to Dashboard",
"nothingHere": "Nothing here yet",
"checkSystemStatus": "Check System Status"
"checkSystemStatus": "Check System Status",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Dom",
@@ -644,7 +649,9 @@
"kiro": "Użyj podczas integracji Kiro i centralnego sterowania routingiem modeli z OmniRoute.",
"antigravity": "Użyj, gdy ruch antygrawitacyjny/Kiro musi zostać przechwycony przez MITM i skierowany do OmniRoute.",
"copilot": "Użyj, jeśli chcesz mieć UX w stylu czatu Copilot, jednocześnie wymuszając klucze OmniRoute i reguły routingu.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE z MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"nothingHere": "Nothing here yet",
"checkSystemStatus": "Check System Status",
"goToDashboard": "Go to Dashboard"
"goToDashboard": "Go to Dashboard",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Início",
@@ -672,6 +677,7 @@
"antigravity": "Use quando o tráfego Antigravity/Kiro deve ser interceptado através do MITM e roteado para OmniRoute.",
"copilot": "Use quando desejar UX no estilo de bate-papo do Copilot enquanto impõe chaves OmniRoute e regras de roteamento.",
"windsurf": "Use quando quiser uma IDE AI-first com modelos Codeium/Windsurf roteados pelo OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use quando precisar do Alibaba Qwen Code CLI para tarefas de programação.",
"custom": "Use quando seu CLI ou SDK não estiver hardcoded no OmniRoute, mas ainda aceitar base URL, chave de API e model string compatíveis com OpenAI."
},
@@ -691,6 +697,7 @@
"windsurf": "Windsurf — Editor de Código com IA",
"copilot": "GitHub Copilot — Assistente de IA",
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI",
"custom": "Gerador genérico de configuração para CLI ou SDK OpenAI-compatible"
},
"guides": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"checkSystemStatus": "Check System Status",
"goToDashboard": "Go to Dashboard",
"nothingHere": "Nothing here yet"
"nothingHere": "Nothing here yet",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Página inicial",
@@ -644,7 +649,9 @@
"kiro": "Use ao integrar o Kiro e controlar o roteamento do modelo centralmente no OmniRoute.",
"antigravity": "Use quando o tráfego Antigravity/Kiro deve ser interceptado através do MITM e roteado para OmniRoute.",
"copilot": "Use quando desejar UX no estilo de bate-papo do Copilot enquanto impõe chaves OmniRoute e regras de roteamento.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "IDE antigravidade do Google com MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"checkSystemStatus": "Check System Status",
"goToDashboard": "Go to Dashboard",
"nothingHere": "Nothing here yet"
"nothingHere": "Nothing here yet",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Acasă",
@@ -644,7 +649,9 @@
"kiro": "Utilizați atunci când integrați Kiro și controlați rutarea modelului central din OmniRoute.",
"antigravity": "Utilizați atunci când traficul Antigravity/Kiro trebuie interceptat prin MITM și direcționat către OmniRoute.",
"copilot": "Utilizați atunci când doriți UX în stilul de chat Copilot, în timp ce aplicați cheile și regulile de rutare OmniRoute.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE cu MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"checkSystemStatus": "Check System Status",
"goToDashboard": "Go to Dashboard",
"nothingHere": "Nothing here yet"
"nothingHere": "Nothing here yet",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Главная",
@@ -644,7 +649,9 @@
"kiro": "Используйте при интеграции Kiro и централизованном управлении маршрутизацией модели из OmniRoute.",
"antigravity": "Используйте, когда трафик Антигравитации/Киро необходимо перехватить через MITM и направить в OmniRoute.",
"copilot": "Используйте его, если вам нужен пользовательский интерфейс в стиле чата Copilot, одновременно обеспечивая соблюдение ключей OmniRoute и правил маршрутизации.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE с MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro - IDE с ИИ",
"windsurf": "Редактор кода Windsurf с ИИ",
"copilot": "Ассистент GitHub Copilot с ИИ",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"nothingHere": "Nothing here yet",
"checkSystemStatus": "Check System Status",
"goToDashboard": "Go to Dashboard"
"goToDashboard": "Go to Dashboard",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Domov",
@@ -644,7 +649,9 @@
"kiro": "Použite pri integrácii Kiro a centrálnom riadení smerovania modelu z OmniRoute.",
"antigravity": "Použite, keď musí byť premávka Antigravity/Kiro zachytená cez MITM a nasmerovaná na OmniRoute.",
"copilot": "Použite, keď chcete UX v štýle chatu Copilot pri presadzovaní kľúčov OmniRoute a pravidiel smerovania.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE s MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"goToDashboard": "Go to Dashboard",
"nothingHere": "Nothing here yet",
"checkSystemStatus": "Check System Status"
"checkSystemStatus": "Check System Status",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Hem",
@@ -644,7 +649,9 @@
"kiro": "Använd när du integrerar Kiro och styr modelldirigering centralt från OmniRoute.",
"antigravity": "Använd när Antigravity/Kiro-trafik måste avlyssnas genom MITM och dirigeras till OmniRoute.",
"copilot": "Använd när du vill ha Copilot chattstil UX samtidigt som du upprätthåller OmniRoute-nycklar och routingregler.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE med MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"goToDashboard": "Go to Dashboard",
"nothingHere": "Nothing here yet",
"checkSystemStatus": "Check System Status"
"checkSystemStatus": "Check System Status",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "บ้าน",
@@ -644,7 +649,9 @@
"kiro": "ใช้เมื่อรวม Kiro และควบคุมการกำหนดเส้นทางโมเดลจากส่วนกลางจาก OmniRoute",
"antigravity": "ใช้เมื่อต้องสกัดกั้นการรับส่งข้อมูล Antigravity/Kiro ผ่าน MITM และกำหนดเส้นทางไปยัง OmniRoute",
"copilot": "ใช้เมื่อคุณต้องการ UX รูปแบบการแชทของ Copilot ในขณะที่บังคับใช้คีย์ OmniRoute และกฎการกำหนดเส้นทาง",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google ต้านแรงโน้มถ่วง IDE พร้อม MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"nothingHere": "Nothing here yet",
"goToDashboard": "Go to Dashboard",
"checkSystemStatus": "Check System Status"
"checkSystemStatus": "Check System Status",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Ana Sayfa",
@@ -644,7 +649,9 @@
"kiro": "Kiro'yu entegre ederken model yönlendirmesini OmniRoute üzerinden merkezi olarak yönetmek istediğinizde kullanın.",
"antigravity": "Antigravity/Kiro trafiğinin MITM üzerinden yakalanıp OmniRoute'a yönlendirilmesi gerektiğinde kullanın.",
"copilot": "OmniRoute anahtarları ve yönlendirme kuralları uygulanırken Copilot sohbet tarzı bir UX istediğinizde kullanın.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "MITM ile Google Antigravity IDE",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro - AI destekli IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"nothingHere": "Nothing here yet",
"checkSystemStatus": "Check System Status",
"goToDashboard": "Go to Dashboard"
"goToDashboard": "Go to Dashboard",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "додому",
@@ -644,7 +649,9 @@
"kiro": "Використовуйте під час інтеграції Kiro та централізованого керування маршрутизацією моделі з OmniRoute.",
"antigravity": "Використовуйте, коли трафік Antigravity/Kiro потрібно перехопити через MITM і направити на OmniRoute.",
"copilot": "Використовуйте, коли вам потрібен UX у стилі чату Copilot із застосуванням ключів OmniRoute і правил маршрутизації.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "Google Antigravity IDE з MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"http": "HTTP",
"nothingHere": "Nothing here yet",
"checkSystemStatus": "Check System Status",
"goToDashboard": "Go to Dashboard"
"goToDashboard": "Go to Dashboard",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "Trang chủ",
@@ -644,7 +649,9 @@
"kiro": "Sử dụng khi tích hợp Kiro và điều khiển định tuyến mô hình tập trung từ OmniRoute.",
"antigravity": "Sử dụng khi lưu lượng truy cập AntiGravity/Kiro phải bị chặn thông qua MITM và được định tuyến đến OmniRoute.",
"copilot": "Sử dụng khi bạn muốn UX kiểu trò chuyện Copilot trong khi thực thi các khóa OmniRoute và quy tắc định tuyến.",
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute."
"windsurf": "Use when you want an AI-first IDE with Codeium/Windsurf models routed through OmniRoute.",
"amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.",
"qwen": "Use when you want Qwen Code CLI with OmniRoute-managed provider settings and multi-provider model access."
},
"toolDescriptions": {
"antigravity": "IDE chống trọng lực của Google với MITM",
@@ -660,7 +667,8 @@
"kiro": "Amazon Kiro — AI-powered IDE",
"windsurf": "Windsurf AI Code Editor",
"copilot": "GitHub Copilot AI Assistant",
"qwen": "Alibaba Qwen Code CLI"
"qwen": "Alibaba Qwen Code CLI",
"amp": "Sourcegraph Amp coding assistant CLI"
},
"guides": {
"cursor": {

View File

@@ -139,7 +139,12 @@
"apikey": "API 密钥",
"http": "HTTP",
"goToDashboard": "前往仪表板",
"checkSystemStatus": "查看系统状态"
"checkSystemStatus": "查看系统状态",
"selectModel": "Select Model",
"combos": "Combos",
"noModelsFound": "No models found",
"clear": "Clear",
"done": "Done"
},
"sidebar": {
"home": "首页",
@@ -649,8 +654,8 @@
"windsurf": "当您需要 Windsurf AI IDE 并通过 OmniRoute 路由模型时使用。",
"antigravity": "当必须通过 MITM 拦截 Antigravity/Kiro 流量并将其路由到 OmniRoute 时使用。",
"copilot": "当您想要 Copilot 聊天风格的 UX 同时强制执行 OmniRoute 键和路由规则时使用。",
"qwen": "当您需要使用阿里云 Qwen Code CLI 进行编码任务时使用。",
"amp": "当您想要 Amp 简写工作流,但仍需要 OmniRoute 别名和路由规则支持时使用。",
"qwen": "当您需要使用阿里云 Qwen Code CLI 进行编码任务时使用。",
"hermes": "当您需要轻量级终端原生 AI 助手来处理快速任务时使用。",
"custom": "用于自定义工具实现或通用 OpenAI 兼容配置。"
},

View File

@@ -30,10 +30,13 @@ export default function ModelSelectModal({
onClose,
onSelect,
selectedModel,
selectedModels = [],
activeProviders = [],
title,
modelAliases = {},
addedModelValues = [],
multiSelect = false,
showCombos = true,
}) {
const t = useTranslations("common");
const resolvedTitle = title ?? t("selectModel");
@@ -283,10 +286,20 @@ export default function ModelSelectModal({
return filtered;
}, [groupedModels, searchQuery]);
const resolvedSelectedModels = multiSelect
? selectedModels
: selectedModel
? [selectedModel]
: [];
const isValueSelected = (value: string) => resolvedSelectedModels.includes(value);
const handleSelect = (model: any) => {
onSelect(model);
onClose();
setSearchQuery("");
if (!multiSelect) {
onClose();
setSearchQuery("");
}
};
return (
@@ -319,7 +332,7 @@ export default function ModelSelectModal({
{/* Models grouped by provider - compact */}
<div className="max-h-[300px] overflow-y-auto space-y-3">
{/* Combos section - always first */}
{filteredCombos.length > 0 && (
{showCombos && filteredCombos.length > 0 && (
<div>
<div className="flex items-center gap-1.5 mb-1.5 sticky top-0 bg-surface py-0.5">
<span className="material-symbols-outlined text-primary text-[14px]">layers</span>
@@ -328,7 +341,7 @@ export default function ModelSelectModal({
</div>
<div className="flex flex-wrap gap-1.5">
{filteredCombos.map((combo) => {
const isSelected = selectedModel === combo.name;
const isSelected = isValueSelected(combo.name);
return (
<button
key={combo.id}
@@ -364,7 +377,7 @@ export default function ModelSelectModal({
<div className="flex flex-wrap gap-1.5">
{group.models.map((model) => {
const isSelected = selectedModel === model.value;
const isSelected = isValueSelected(model.value);
const isAdded = addedModelValues.includes(model.value);
return (
<button
@@ -402,6 +415,30 @@ export default function ModelSelectModal({
</div>
)}
</div>
{multiSelect && (
<div className="mt-4 flex items-center justify-between gap-2 border-t border-border pt-3">
<span className="text-xs text-text-muted">{resolvedSelectedModels.length} selected</span>
<div className="flex items-center gap-2">
<button
type="button"
onClick={() => onSelect(null)}
className="px-2 py-1 text-xs rounded border border-border bg-surface hover:bg-primary/5"
>
{t("clear")}
</button>
<button
type="button"
onClick={() => {
onClose();
setSearchQuery("");
}}
className="px-2 py-1 text-xs rounded border border-border bg-surface hover:bg-primary/5"
>
{t("done")}
</button>
</div>
</div>
)}
</Modal>
);
}
@@ -411,6 +448,7 @@ ModelSelectModal.propTypes = {
onClose: PropTypes.func.isRequired,
onSelect: PropTypes.func.isRequired,
selectedModel: PropTypes.string,
selectedModels: PropTypes.arrayOf(PropTypes.string),
activeProviders: PropTypes.arrayOf(
PropTypes.shape({
provider: PropTypes.string.isRequired,
@@ -419,4 +457,6 @@ ModelSelectModal.propTypes = {
title: PropTypes.string,
modelAliases: PropTypes.object,
addedModelValues: PropTypes.arrayOf(PropTypes.string),
multiSelect: PropTypes.bool,
showCombos: PropTypes.bool,
};

View File

@@ -242,13 +242,16 @@ export const CLI_TOOLS = {
opencode: {
id: "opencode",
name: "OpenCode",
image: "/providers/opencode.png",
image: "/providers/opencode.svg",
icon: "terminal",
color: "#FF6B35",
description: "OpenCode AI coding agent (Terminal)",
docsUrl: "/docs?section=cli-tools&tool=opencode",
configType: "guide",
defaultCommand: "opencode",
modelSelectionMode: "multiple",
hideComboModels: true,
previewConfigMode: "opencode",
notes: [
{
type: "warning",
@@ -273,18 +276,21 @@ export const CLI_TOOLS = {
codeBlock: {
language: "json",
code: `{
"providers": {
"$schema": "https://opencode.ai/config.json",
"provider": {
"omniroute": {
"npm": "@ai-sdk/openai-compatible",
"name": "OmniRoute",
"api": "openai",
"baseURL": "{{baseUrl}}",
"apiKey": "{{apiKey}}",
"models": [
"{{model}}",
"claude-sonnet-4-5-thinking",
"gemini-3.1-pro-high",
"gemini-3-flash"
]
"options": {
"baseURL": "{{baseUrl}}",
"apiKey": "{{apiKey}}"
},
"models": {
"{{model}}": { "name": "{{model}}" },
"claude-sonnet-4-5-thinking": { "name": "claude-sonnet-4-5-thinking" },
"gemini-3.1-pro-high": { "name": "gemini-3.1-pro-high" },
"gemini-3-flash": { "name": "gemini-3-flash" }
}
}
}
}`,

View File

@@ -2,6 +2,7 @@ type OpenCodeConfigInput = {
baseUrl?: string;
apiKey?: string;
model?: string;
models?: string[];
};
const OPENCODE_DEFAULT_MODELS = [
@@ -16,17 +17,27 @@ const normalizeValue = (value: unknown) =>
.trim()
.replace(/^\/+/, "");
const normalizeModels = (models: unknown): string[] => {
if (!Array.isArray(models)) return [];
return [...new Set(models.map((model) => normalizeValue(model)).filter(Boolean))];
};
export const buildOpenCodeProviderConfig = ({
baseUrl,
apiKey,
model,
models,
}: OpenCodeConfigInput): Record<string, any> => {
const normalizedBaseUrl = String(baseUrl || "")
.trim()
.replace(/\/+$/, "");
const normalizedModel = normalizeValue(model);
const normalizedModels = normalizeModels(models);
const uniqueModels = [...new Set([normalizedModel, ...OPENCODE_DEFAULT_MODELS].filter(Boolean))];
const uniqueModels =
normalizedModels.length > 0
? normalizedModels
: [...new Set([normalizedModel, ...OPENCODE_DEFAULT_MODELS].filter(Boolean))];
const modelsRecord: Record<string, { name: string }> = {};
for (const m of uniqueModels) {
@@ -46,6 +57,13 @@ export const buildOpenCodeProviderConfig = ({
};
};
export const buildOpenCodeConfigDocument = (input: OpenCodeConfigInput) => ({
$schema: "https://opencode.ai/config.json",
provider: {
omniroute: buildOpenCodeProviderConfig(input),
},
});
export const mergeOpenCodeConfig = (
existingConfig: Record<string, any> | null | undefined,
input: OpenCodeConfigInput
@@ -57,6 +75,7 @@ export const mergeOpenCodeConfig = (
return {
...safeConfig,
$schema: safeConfig.$schema || "https://opencode.ai/config.json",
provider: {
...((safeConfig as any).provider || {}),
omniroute: buildOpenCodeProviderConfig(input),

View File

@@ -1723,11 +1723,17 @@ export const codexProfileIdSchema = z.object({
profileId: z.string().trim().min(1, "profileId is required"),
});
export const guideSettingsSaveSchema = z.object({
baseUrl: z.string().trim().min(1).optional(),
apiKey: z.string().optional(),
model: z.string().trim().min(1, "Model is required"),
});
export const guideSettingsSaveSchema = z
.object({
baseUrl: z.string().trim().min(1).optional(),
apiKey: z.string().optional(),
model: z.string().trim().min(1, "Model is required").optional(),
models: z.array(z.string().trim().min(1, "Models must be non-empty")).min(1).optional(),
})
.refine((data) => !!data.model || !!data.models?.length, {
message: "Model is required",
path: ["model"],
});
// ── Search Schemas ─────────────────────────────────────────────────────
// Unified search request/response schemas. Final contract — all fields optional

View File

@@ -9,6 +9,7 @@ const guideSettingsRoute =
const DUMMY_HOME = path.join(os.tmpdir(), "omniroute-qwen-test-" + Date.now());
const QWEN_CONFIG_PATH = path.join(DUMMY_HOME, ".qwen", "settings.json");
const QWEN_ENV_PATH = path.join(DUMMY_HOME, ".qwen", ".env");
const OPENCODE_CONFIG_PATH = path.join(DUMMY_HOME, ".config", "opencode", "opencode.json");
type QwenProviderEntry = {
id?: string;
@@ -101,3 +102,46 @@ test("guide-settings POST merges into existing qwen settings.json", async () =>
assert.match(envContent, /^ANTHROPIC_API_KEY=sk-123$/m);
assert.match(envContent, /^GEMINI_API_KEY=sk-123$/m);
});
test("guide-settings POST writes OpenCode config with current schema and multi-model selection", async () => {
await fs.mkdir(path.dirname(OPENCODE_CONFIG_PATH), { recursive: true });
await fs.writeFile(
OPENCODE_CONFIG_PATH,
JSON.stringify({
$schema: "https://opencode.ai/config.json",
provider: {
custom: {
name: "Custom Provider",
},
},
}),
"utf-8"
);
const req = new Request("http://localhost/api/cli-tools/guide-settings/opencode", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
baseUrl: "http://my-omni/v1",
apiKey: "sk-123",
models: ["cc/claude-sonnet-4-20250514", "gg/gemini-2.5-pro"],
}),
});
const response = (await guideSettingsRoute.POST(req, {
params: { toolId: "opencode" },
})) as Response;
assert.equal(response.status, 200);
const content = JSON.parse(await fs.readFile(OPENCODE_CONFIG_PATH, "utf-8"));
assert.equal(content.$schema, "https://opencode.ai/config.json");
assert.ok(content.provider.custom);
assert.equal(content.provider.omniroute.npm, "@ai-sdk/openai-compatible");
assert.equal(content.provider.omniroute.options.baseURL, "http://my-omni/v1");
assert.equal(content.provider.omniroute.options.apiKey, "sk-123");
assert.deepEqual(Object.keys(content.provider.omniroute.models), [
"cc/claude-sonnet-4-20250514",
"gg/gemini-2.5-pro",
]);
assert.equal(content.providers, undefined);
});

View File

@@ -4,12 +4,15 @@ import path from "node:path";
const { CLI_TOOLS } = await import("../../src/shared/constants/cliTools.ts");
const { resolveOpencodeConfigPath } = await import("../../src/shared/services/cliRuntime.ts");
const { buildOpenCodeProviderConfig, mergeOpenCodeConfig } =
const { buildOpenCodeProviderConfig, buildOpenCodeConfigDocument, mergeOpenCodeConfig } =
await import("../../src/shared/services/opencodeConfig.ts");
test("T40: OpenCode card documents config paths and --variant usage", () => {
const opencode = CLI_TOOLS.opencode;
assert.ok(opencode, "OpenCode tool card must exist");
assert.equal(opencode.modelSelectionMode, "multiple");
assert.equal(opencode.hideComboModels, true);
assert.equal(opencode.previewConfigMode, "opencode");
const notesText = (opencode.notes || [])
.map((note) => note?.text || "")
@@ -66,6 +69,36 @@ test("T40: OpenCode config generator includes endpoint and selected API key", ()
assert.equal(mergedConfig.provider.omniroute.options.apiKey, "sk_test_opencode");
});
test("T40: OpenCode config document uses current provider schema", () => {
const configDocument = buildOpenCodeConfigDocument({
baseUrl: "http://localhost:20128/v1/",
apiKey: "sk_test_opencode",
models: ["cc/claude-sonnet-4-20250514", "gg/gemini-2.5-pro"],
});
assert.equal(configDocument.$schema, "https://opencode.ai/config.json");
assert.ok(configDocument.provider.omniroute);
assert.equal(configDocument.provider.omniroute.npm, "@ai-sdk/openai-compatible");
assert.equal(configDocument.provider.omniroute.options.baseURL, "http://localhost:20128/v1");
assert.equal(configDocument.provider.omniroute.options.apiKey, "sk_test_opencode");
assert.deepEqual(Object.keys(configDocument.provider.omniroute.models), [
"cc/claude-sonnet-4-20250514",
"gg/gemini-2.5-pro",
]);
assert.equal(configDocument.providers, undefined);
});
test("T40: OpenCode explicit multi-model selection overrides fallback defaults", () => {
const providerConfig = buildOpenCodeProviderConfig({
baseUrl: "http://localhost:20128/v1/",
apiKey: "sk_test_opencode",
models: ["custom/provider-a", "custom/provider-b"],
});
assert.deepEqual(Object.keys(providerConfig.models), ["custom/provider-a", "custom/provider-b"]);
assert.equal(providerConfig.models["claude-sonnet-4-5-thinking"], undefined);
});
test("T40: Windsurf card documents current official limitations honestly", () => {
const windsurf = CLI_TOOLS.windsurf;
assert.ok(windsurf, "Windsurf tool card must exist");