Feat/qdrant embedding model discovery (#2086)

Integrated into release/v3.8.0
This commit is contained in:
Ramel Tecnologia
2026-05-10 00:54:04 -03:00
committed by GitHub
parent a8106bbadd
commit 7d6854e925
47 changed files with 2796 additions and 215 deletions

138
Tuto_Qdrant.MD Normal file
View File

@@ -0,0 +1,138 @@
# Tutorial Qdrant no OmniRoute (Guia para vídeo)
## 1) O que é o Qdrant no OmniRoute
O Qdrant é o banco vetorial usado para memória semântica.
No OmniRoute, ele ajuda a:
- Encontrar contexto por significado (não só palavra exata).
- Reaproveitar memórias antigas com mais precisão.
- Melhorar respostas com base em histórico relevante.
- Escalar melhor quando a base de memória cresce.
---
## 2) Quando o OmniRoute envia dados para o Qdrant
Com Qdrant habilitado e modelo de embedding configurado, o sistema envia vetores quando:
- Memórias são salvas (upsert de memória).
- Fluxos de chat recuperam contexto semântico/híbrido.
- Testes de busca no painel geram embedding e consultam a coleção.
Resumo prático:
- Sem Qdrant: busca mais limitada (texto/chave).
- Com Qdrant: busca por similaridade semântica (mais inteligente).
---
## 3) Pré-requisitos
Você precisa de:
- Instância Qdrant acessível (porta 6333).
- Coleção criada (ex.: `omniroute_memory`).
- Modelo de embedding válido (ex.: OpenRouter).
- Credencial do provider do embedding configurada no OmniRoute.
Exemplo de modelo OpenRouter:
- `openrouter/nvidia/llama-nemotron-embed-v1-1b-v2:free`
Importante:
- O texto do modelo deve estar em formato `provider/model`.
- Se usar modelo com dimensão diferente da coleção, a busca falha.
---
## 4) Como configurar no painel do OmniRoute
No menu:
- `Admin > Settings > Qdrant (Memória vetorial)`
Preencha:
- `Ativar Qdrant`: ligado.
- `Host`: IP ou URL do servidor Qdrant (sem porta no campo Host).
- `Porta`: `6333`.
- `Collection`: `omniroute_memory` (ou nome que você criou).
- `Modelo de embedding`: selecione da lista ou digite manualmente.
- `API Key`: opcional (preencha se seu Qdrant exigir).
Depois:
1. Clique em `Salvar`.
2. Clique em `Testar conexão`.
3. No `Teste de busca`, digite um texto e clique em `Buscar`.
---
## 5) Como criar a coleção no Dashboard do Qdrant (sem comando)
No Qdrant Dashboard:
1. Clique em `Create collection`.
2. Escolha `Global search`.
3. Em tipo de busca, use `Custom`.
4. Configure vetor:
- Vector name: `omniao` (padrão esperado pelo OmniRoute atualmente).
- Size: dimensão do seu modelo de embedding (ex.: 2048 em alguns modelos NVIDIA).
- Distance: `Cosine`.
5. Salve a coleção com nome `omniroute_memory`.
Se já tinha coleção com dimensão errada:
- Recrie a coleção com dimensão correta.
---
## 6) Como validar se está funcionando
Checklist rápido:
1. `Testar conexão` no OmniRoute retorna OK.
2. Busca no painel retorna resultados (não “Sem resultados”).
3. No Qdrant Dashboard, aparecem pontos na coleção (payload + vector).
4. Resultados de chat passam a recuperar contexto mais relevante.
Sinal clássico de problema:
- Dados entram no Qdrant, mas busca do painel não retorna nada.
Causas comuns:
- Dimensão do vetor incompatível.
- Nome do vetor diferente do esperado (`omniao`).
- Modelo inválido/incompleto no campo de embedding.
- Provider sem credencial ativa.
---
## 7) O que melhorou com esta atualização
Nesta melhoria do OmniRoute:
- Suporte a embeddings de qualquer provider compatível (não só OpenAI fixo).
- Endpoint para carregar modelos de embedding na tela de configurações.
- Campo manual para modelo custom quando não aparecer na lista.
- Ajuda visual (`?`) com passo rápido de configuração Qdrant + OpenRouter.
---
## 8) Roteiro curto para seu vídeo
Sugestão de demo (3-5 minutos):
1. Mostrar problema sem Qdrant (busca simples).
2. Abrir Settings e habilitar Qdrant.
3. Configurar host/porta/collection/modelo.
4. Salvar + testar conexão.
5. Fazer `Teste de busca` no painel.
6. Abrir Qdrant Dashboard e mostrar ponto salvo + vetor.
7. Rodar um chat e mostrar melhoria de recuperação semântica.
Mensagem final para a galera:
- "Qdrant no OmniRoute transforma memória de palavra-chave em memória por significado."
---
## 9) Referências de código (para equipe técnica)
- UI de configuração Qdrant:
- `src/app/(dashboard)/dashboard/settings/components/MemorySkillsTab.tsx`
- Endpoint de modelos de embedding para Qdrant:
- `src/app/api/settings/qdrant/embedding-models/route.ts`
- Integração backend com Qdrant (health, upsert, search, cleanup):
- `src/lib/memory/qdrant.ts`
- Recuperação de memórias no fluxo de chat:
- `src/lib/memory/retrieval.ts`
- `open-sse/handlers/chatCore.ts`
---
## 10) Observação importante de segurança
Nunca exponha em vídeo:
- API key completa do OpenRouter.
- Tokens reais de produção.
- Endpoints internos sem proteção.
Use chaves mascaradas e ambiente de demonstração.

View File

@@ -13,6 +13,21 @@ interface MemoryConfig {
skillsEnabled: boolean;
}
interface QdrantSettings {
enabled: boolean;
host: string;
port: number;
collection: string;
embeddingModel: string;
hasApiKey: boolean;
apiKeyMasked: string | null;
}
interface EmbeddingModelOption {
value: string;
label: string;
}
const STRATEGIES = [
{ value: "recent", labelKey: "recent", descKey: "recentDesc" },
{ value: "semantic", labelKey: "semantic", descKey: "semanticDesc" },
@@ -30,6 +45,35 @@ export default function MemorySkillsTab() {
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false);
const [status, setStatus] = useState("");
const [qdrant, setQdrant] = useState<QdrantSettings>({
enabled: false,
host: "",
port: 6333,
collection: "omniroute_memory",
embeddingModel: "openai/text-embedding-3-small",
hasApiKey: false,
apiKeyMasked: null,
});
const [qdrantApiKeyInput, setQdrantApiKeyInput] = useState("");
const [qdrantSaving, setQdrantSaving] = useState(false);
const [qdrantStatus, setQdrantStatus] = useState<"" | "saved" | "error">("");
const [qdrantHealth, setQdrantHealth] = useState<{
ok: boolean;
latencyMs: number;
error?: string;
} | null>(null);
const [qdrantChecking, setQdrantChecking] = useState(false);
const [qdrantQuery, setQdrantQuery] = useState("");
const [qdrantSearching, setQdrantSearching] = useState(false);
const [qdrantResults, setQdrantResults] = useState<
Array<{ id: string; score: number; payload?: Record<string, unknown> }>
>([]);
const [qdrantCleanupLoading, setQdrantCleanupLoading] = useState(false);
const [qdrantCleanupMsg, setQdrantCleanupMsg] = useState("");
const [embeddingOptions, setEmbeddingOptions] = useState<EmbeddingModelOption[]>([]);
const [qdrantHelpOpen, setQdrantHelpOpen] = useState(false);
const [skillsmpApiKey, setSkillsmpApiKey] = useState("");
const [skillsmpSaving, setSkillsmpSaving] = useState(false);
const [skillsmpStatus, setSkillsmpStatus] = useState("");
@@ -42,12 +86,21 @@ export default function MemorySkillsTab() {
Promise.all([
fetch("/api/settings/memory").then((res) => (res.ok ? res.json() : null)),
fetch("/api/settings").then((res) => (res.ok ? res.json() : null)),
fetch("/api/settings/qdrant").then((res) => (res.ok ? res.json() : null)),
fetch("/api/settings/qdrant/embedding-models").then((res) => (res.ok ? res.json() : null)),
])
.then(([memData, settingsData]) => {
.then(([memData, settingsData, qdrantData, embeddingData]) => {
if (memData) setConfig(memData);
if (settingsData?.skillsmpApiKey) {
setSkillsmpApiKey(settingsData.skillsmpApiKey);
}
if (qdrantData) {
setQdrant(qdrantData);
setQdrantApiKeyInput("");
}
if (embeddingData?.models && Array.isArray(embeddingData.models)) {
setEmbeddingOptions(embeddingData.models);
}
if (
settingsData?.skillsProvider === "skillsmp" ||
settingsData?.skillsProvider === "skillssh"
@@ -56,7 +109,111 @@ export default function MemorySkillsTab() {
}
})
.catch(() => {})
.finally(() => setLoading(false));
.finally(() => {
setLoading(false);
});
}, []);
const saveQdrant = useCallback(
async (updates: Partial<QdrantSettings> & { apiKey?: string }) => {
const previous = qdrant;
const next = { ...qdrant, ...updates };
setQdrant(next);
setQdrantSaving(true);
setQdrantStatus("");
try {
const res = await fetch("/api/settings/qdrant", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
enabled: next.enabled,
host: next.host,
port: next.port,
collection: next.collection,
embeddingModel: next.embeddingModel,
...(updates.apiKey !== undefined ? { apiKey: updates.apiKey } : {}),
}),
});
if (res.ok) {
const data = await res.json().catch(() => next);
setQdrant(data);
setQdrantApiKeyInput("");
setQdrantStatus("saved");
setTimeout(() => setQdrantStatus(""), 2000);
} else {
setQdrant(previous);
setQdrantStatus("error");
}
} catch {
setQdrant(previous);
setQdrantStatus("error");
} finally {
setQdrantSaving(false);
}
},
[qdrant]
);
const checkQdrant = useCallback(async () => {
setQdrantChecking(true);
try {
const res = await fetch("/api/settings/qdrant/health");
if (res.ok) setQdrantHealth(await res.json());
else setQdrantHealth({ ok: false, latencyMs: 0, error: "HTTP error" });
} catch (e) {
setQdrantHealth({
ok: false,
latencyMs: 0,
error: e instanceof Error ? e.message : String(e),
});
} finally {
setQdrantChecking(false);
}
}, []);
const testQdrantSearch = useCallback(async () => {
const q = qdrantQuery.trim();
if (!q) return;
setQdrantSearching(true);
setQdrantResults([]);
try {
const res = await fetch("/api/settings/qdrant/search", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query: q, topK: 5 }),
});
const data = await res.json().catch(() => null);
if (res.ok && data?.ok) {
setQdrantResults(Array.isArray(data.results) ? data.results : []);
} else {
setQdrantResults([]);
}
} catch {
setQdrantResults([]);
} finally {
setQdrantSearching(false);
}
}, [qdrantQuery]);
const runQdrantCleanup = useCallback(async () => {
setQdrantCleanupLoading(true);
setQdrantCleanupMsg("");
try {
const res = await fetch("/api/settings/qdrant/cleanup", { method: "POST" });
const data = await res.json().catch(() => null);
if (res.ok && data?.ok) {
setQdrantCleanupMsg(
`OK: removeu ${data.deletedCount ?? 0} ponto(s) (retencao: ${data.retentionDays} dias)`
);
} else {
const err = data?.error || "Falha na limpeza";
setQdrantCleanupMsg(`Erro: ${String(err)}`);
}
} catch (e) {
setQdrantCleanupMsg(`Erro: ${e instanceof Error ? e.message : String(e)}`);
} finally {
setQdrantCleanupLoading(false);
}
}, []);
const saveSkillsmpApiKey = useCallback(async () => {
@@ -280,6 +437,280 @@ export default function MemorySkillsTab() {
)}
</Card>
{/* Qdrant (optional semantic memory index) */}
<Card data-testid="qdrant-settings-card">
<div className="flex items-center gap-3 mb-5">
<div className="p-2 rounded-lg bg-emerald-500/10 text-emerald-500">
<span className="material-symbols-outlined text-[20px]" aria-hidden="true">
database
</span>
</div>
<div>
<h3 className="text-lg font-semibold">{t("qdrantTitle")}</h3>
<p className="text-sm text-text-muted">{t("qdrantDesc")}</p>
</div>
<span
className={`ml-auto inline-flex items-center gap-2 text-xs font-medium ${
qdrant.enabled
? qdrantHealth?.ok
? "text-emerald-500"
: "text-red-500"
: "text-text-muted"
}`}
>
<span
className={`inline-block w-2.5 h-2.5 rounded-full ${
qdrant.enabled ? (qdrantHealth?.ok ? "bg-emerald-500" : "bg-red-500") : "bg-border"
}`}
aria-hidden="true"
/>
{qdrant.enabled
? qdrantHealth?.ok
? t("qdrantStatusActive")
: t("qdrantStatusError")
: t("qdrantStatusDisabled")}
</span>
</div>
<div className="flex items-center justify-between p-4 rounded-lg bg-surface/30 border border-border/30 mb-4">
<div>
<p className="text-sm font-medium">{t("qdrantEnable")}</p>
<p className="text-xs text-text-muted mt-0.5">{t("qdrantEnableDesc")}</p>
</div>
<div className="flex items-center gap-2">
<button
onClick={checkQdrant}
disabled={qdrantChecking || qdrantSaving}
className="px-3 h-8 text-xs font-medium rounded-lg bg-white/5 border border-border/60 hover:bg-white/10 disabled:opacity-50 transition-colors"
>
{qdrantChecking ? t("qdrantTesting") : t("qdrantTestConnection")}
</button>
<button
data-testid="qdrant-enabled-switch"
onClick={() => saveQdrant({ enabled: !qdrant.enabled })}
disabled={qdrantSaving}
className={`relative w-11 h-6 rounded-full transition-colors ${
qdrant.enabled ? "bg-emerald-500" : "bg-border"
}`}
role="switch"
aria-checked={qdrant.enabled}
>
<span
className={`absolute top-1 left-1 w-4 h-4 bg-white rounded-full transition-transform ${
qdrant.enabled ? "translate-x-5" : "translate-x-0"
}`}
/>
</button>
</div>
</div>
{qdrantStatus === "saved" && (
<div className="mb-4 text-xs font-medium text-emerald-500 flex items-center gap-1">
<span className="material-symbols-outlined text-[14px]">check_circle</span>{" "}
{t("qdrantSaved")}
</div>
)}
{qdrantStatus === "error" && (
<div className="mb-4 text-xs font-medium text-red-500">{t("qdrantSaveError")}</div>
)}
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
<div className="p-4 rounded-lg bg-surface/30 border border-border/30">
<label className="text-sm font-medium block mb-2">Host</label>
<input
value={qdrant.host}
onChange={(e) => setQdrant((s) => ({ ...s, host: e.target.value }))}
placeholder="http://127.0.0.1"
className="w-full px-3 py-2 rounded-lg bg-background border border-border text-sm font-mono focus:outline-none focus:ring-1 focus:ring-emerald-500"
/>
<p className="text-xs text-text-muted mt-2">{t("qdrantHostHint")}</p>
</div>
<div className="p-4 rounded-lg bg-surface/30 border border-border/30">
<label className="text-sm font-medium block mb-2">{t("qdrantPort")}</label>
<input
value={qdrant.port}
onChange={(e) =>
setQdrant((s) => ({
...s,
port: Math.max(1, Math.min(65535, Number(e.target.value) || 0)),
}))
}
placeholder="6333"
className="w-full px-3 py-2 rounded-lg bg-background border border-border text-sm font-mono focus:outline-none focus:ring-1 focus:ring-emerald-500"
/>
<p className="text-xs text-text-muted mt-2">{t("qdrantPortHint")}</p>
</div>
<div className="p-4 rounded-lg bg-surface/30 border border-border/30">
<label className="text-sm font-medium block mb-2">Collection</label>
<input
value={qdrant.collection}
onChange={(e) => setQdrant((s) => ({ ...s, collection: e.target.value }))}
placeholder="omniroute_memory"
className="w-full px-3 py-2 rounded-lg bg-background border border-border text-sm font-mono focus:outline-none focus:ring-1 focus:ring-emerald-500"
/>
<p className="text-xs text-text-muted mt-2">{t("qdrantCollectionHint")}</p>
</div>
<div className="p-4 rounded-lg bg-surface/30 border border-border/30">
<div className="flex items-center gap-2 mb-2">
<label className="text-sm font-medium block">{t("qdrantEmbeddingModel")}</label>
<button
type="button"
onClick={() => setQdrantHelpOpen((v) => !v)}
className="inline-flex items-center justify-center w-5 h-5 rounded-full border border-border/70 text-xs text-text-muted hover:bg-white/10"
title={t("qdrantHelpTitle")}
aria-label={t("qdrantHelpTitle")}
>
?
</button>
</div>
{qdrantHelpOpen && (
<div className="mb-3 p-3 rounded-lg bg-background/60 border border-border/60 text-xs text-text-muted leading-relaxed">
<p className="font-medium text-white mb-1">{t("qdrantHelpQuickTitle")}</p>
<p>{t("qdrantHelpStep1")}</p>
<p>{t("qdrantHelpStep2")}</p>
<p>{t("qdrantHelpStep3")}</p>
<p>{t("qdrantHelpStep4")}</p>
</div>
)}
<select
value=""
onChange={(e) => {
const value = e.target.value;
if (value) setQdrant((s) => ({ ...s, embeddingModel: value }));
}}
className="w-full px-3 py-2 rounded-lg bg-background border border-border text-sm mb-2 focus:outline-none focus:ring-1 focus:ring-emerald-500"
>
<option value="">{t("qdrantEmbeddingQuickSelect")}</option>
{embeddingOptions.map((opt) => (
<option key={opt.value} value={opt.value}>
{opt.value}
</option>
))}
</select>
<input
value={qdrant.embeddingModel}
onChange={(e) => setQdrant((s) => ({ ...s, embeddingModel: e.target.value }))}
placeholder={t("qdrantEmbeddingInputPlaceholder")}
className="w-full px-3 py-2 rounded-lg bg-background border border-border text-sm font-mono focus:outline-none focus:ring-1 focus:ring-emerald-500"
/>
<p className="text-xs text-text-muted mt-2">{t("qdrantEmbeddingHint")}</p>
</div>
<div className="p-4 rounded-lg bg-surface/30 border border-border/30 md:col-span-2">
<label className="text-sm font-medium block mb-2">
API Key ({t("optional")}){" "}
{qdrant.hasApiKey && qdrant.apiKeyMasked ? (
<span className="text-xs text-text-muted font-mono">
{t("current")}: {qdrant.apiKeyMasked}
</span>
) : null}
</label>
<div className="flex gap-2">
<input
type="password"
value={qdrantApiKeyInput}
onChange={(e) => setQdrantApiKeyInput(e.target.value)}
placeholder={
qdrant.hasApiKey
? t("qdrantApiKeyPlaceholderKeep")
: t("qdrantApiKeyPlaceholderOptional")
}
className="flex-1 px-3 py-2 rounded-lg bg-background border border-border text-sm font-mono focus:outline-none focus:ring-1 focus:ring-emerald-500"
/>
{qdrant.hasApiKey && (
<button
onClick={() => saveQdrant({ apiKey: "" })}
disabled={qdrantSaving}
className="px-3 py-2 text-sm font-medium rounded-lg bg-white/5 border border-border/60 hover:bg-white/10 disabled:opacity-50 transition-colors"
>
{t("remove")}
</button>
)}
<button
onClick={() =>
saveQdrant(
qdrantApiKeyInput.trim().length > 0 ? { apiKey: qdrantApiKeyInput } : {}
)
}
disabled={qdrantSaving}
className="px-4 py-2 text-sm font-medium rounded-lg bg-emerald-500 text-white hover:bg-emerald-600 disabled:opacity-50 transition-colors"
>
{qdrantSaving ? t("saving") : t("save")}
</button>
</div>
<p className="text-xs text-text-muted mt-2">{t("qdrantSaveHint")}</p>
</div>
</div>
<div className="mt-4 p-4 rounded-lg bg-surface/30 border border-border/30">
<div className="flex items-center justify-between gap-2">
<div>
<p className="text-sm font-medium">{t("qdrantSearchTestTitle")}</p>
<p className="text-xs text-text-muted mt-0.5">{t("qdrantSearchTestDesc")}</p>
</div>
<button
onClick={testQdrantSearch}
disabled={qdrantSearching}
className="px-4 py-2 text-sm font-medium rounded-lg bg-white/5 border border-border/60 hover:bg-white/10 disabled:opacity-50 transition-colors"
>
{qdrantSearching ? t("searching") : t("search")}
</button>
</div>
<div className="mt-3 flex gap-2">
<input
value={qdrantQuery}
onChange={(e) => setQdrantQuery(e.target.value)}
placeholder={t("qdrantSearchPlaceholder")}
className="flex-1 px-3 py-2 rounded-lg bg-background border border-border text-sm focus:outline-none focus:ring-1 focus:ring-emerald-500"
/>
</div>
{qdrantResults.length > 0 && (
<div className="mt-3 space-y-2">
{qdrantResults.map((r) => (
<div key={r.id} className="p-3 rounded-lg bg-background/40 border border-border/40">
<div className="flex items-center justify-between">
<span className="text-xs font-mono text-text-muted">{r.id}</span>
<span className="text-xs font-mono text-emerald-400">
score {r.score.toFixed(4)}
</span>
</div>
<div className="mt-2 text-xs text-text-muted">
{(r.payload?.key as string) ? `key: ${String(r.payload?.key)}` : null}
</div>
</div>
))}
</div>
)}
{qdrantResults.length === 0 && qdrantQuery.trim().length > 0 && !qdrantSearching && (
<p className="mt-3 text-xs text-text-muted">{t("qdrantNoResults")}</p>
)}
</div>
<div className="mt-4 p-4 rounded-lg bg-surface/30 border border-border/30">
<div className="flex items-center justify-between gap-2">
<div>
<p className="text-sm font-medium">{t("qdrantCleanupTitle")}</p>
<p className="text-xs text-text-muted mt-0.5">
{t("qdrantCleanupDesc")} {t("retentionDays")} ({config.retentionDays} {t("days")}).
</p>
</div>
<button
onClick={runQdrantCleanup}
disabled={qdrantCleanupLoading}
className="px-4 py-2 text-sm font-medium rounded-lg bg-white/5 border border-border/60 hover:bg-white/10 disabled:opacity-50 transition-colors"
>
{qdrantCleanupLoading ? t("cleaning") : t("cleanNow")}
</button>
</div>
{qdrantCleanupMsg && <p className="mt-2 text-xs text-text-muted">{qdrantCleanupMsg}</p>}
</div>
</Card>
{/* Skills Settings (placeholder) */}
<Card data-testid="skills-settings-card">
<div className="flex items-center gap-3 mb-5">
<div className="p-2 rounded-lg bg-amber-500/10 text-amber-500">

View File

@@ -0,0 +1,93 @@
import { NextRequest, NextResponse } from "next/server";
import { isAuthenticated } from "@/shared/utils/apiAuth";
import { AI_MODELS } from "@/shared/constants/models";
import { getProviderConnections } from "@/lib/db/providers";
type EmbeddingModelOption = {
value: string;
label: string;
};
function isLikelyEmbeddingModel(provider: string, model: string, name: string): boolean {
const haystack = `${provider}/${model} ${name}`.toLowerCase();
if (haystack.includes("embedding")) return true;
if (haystack.includes("embed")) return true;
if (haystack.includes("text-embedding")) return true;
return false;
}
export async function GET(request: NextRequest) {
if (!(await isAuthenticated(request))) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
try {
const options: EmbeddingModelOption[] = AI_MODELS.filter((m: any) =>
isLikelyEmbeddingModel(String(m.provider || ""), String(m.model || ""), String(m.name || ""))
)
.map((m: any) => ({
value: `${m.provider}/${m.model}`,
label: `${m.provider}/${m.model} - ${m.name}`,
}))
.sort((a, b) => a.value.localeCompare(b.value));
// Add OpenRouter account models that explicitly support embeddings.
try {
const connections = (await getProviderConnections({
provider: "openrouter",
isActive: true,
})) as Array<Record<string, unknown>>;
const apiKey = connections.find(
(c) => typeof c.apiKey === "string" && (c.apiKey as string).trim().length > 0
)?.apiKey as string | undefined;
if (apiKey) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 7000);
let res: Response;
try {
res = await fetch("https://openrouter.ai/api/v1/models?output_modalities=embeddings", {
method: "GET",
headers: {
Authorization: `Bearer ${apiKey}`,
},
cache: "no-store",
signal: controller.signal,
});
} finally {
clearTimeout(timeout);
}
if (res.ok) {
const data = (await res.json().catch(() => null)) as any;
const rows = Array.isArray(data?.data) ? data.data : [];
for (const row of rows) {
const id = typeof row?.id === "string" ? row.id.trim() : "";
if (!id) continue;
const value = `openrouter/${id}`;
if (options.some((o) => o.value === value)) continue;
options.push({
value,
label: `${value} - ${String(row?.name || id)}`,
});
}
}
}
} catch {
// Best effort only: keep endpoint fast and resilient.
}
// Ensure the default always exists as a safe fallback.
if (!options.some((o) => o.value === "openai/text-embedding-3-small")) {
options.unshift({
value: "openai/text-embedding-3-small",
label: "openai/text-embedding-3-small - OpenAI Text Embedding 3 Small",
});
}
options.sort((a, b) => a.value.localeCompare(b.value));
return NextResponse.json({ models: options });
} catch (error) {
return NextResponse.json({ error: String(error), models: [] }, { status: 500 });
}
}

View File

@@ -1,35 +1,22 @@
import { handleEmbedding } from "@omniroute/open-sse/handlers/embeddings.ts";
import {
getProviderCredentials,
clearRecoveredProviderState,
extractApiKey,
isValidApiKey,
} from "@/sse/services/auth";
import {
parseEmbeddingModel,
getAllEmbeddingModels,
getEmbeddingProvider,
buildDynamicEmbeddingProvider,
type EmbeddingProviderNodeRow,
type EmbeddingProvider,
} from "@omniroute/open-sse/config/embeddingRegistry.ts";
import { errorResponse, unavailableResponse } from "@omniroute/open-sse/utils/error.ts";
import { errorResponse } from "@omniroute/open-sse/utils/error.ts";
import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
import * as log from "@/sse/utils/logger";
import { toJsonErrorPayload } from "@/shared/utils/upstreamError";
import { enforceApiKeyPolicy } from "@/shared/utils/apiKeyPolicy";
import { v1EmbeddingsSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { getAllCustomModels, getProviderNodes, getApiKeyMetadata } from "@/lib/localDb";
import { getAllCustomModels, getApiKeyMetadata } from "@/lib/localDb";
import { createEmbeddingResponse, type EmbeddingHandlerOptions } from "@/lib/embeddings/service";
import { extractApiKey, isValidApiKey } from "@/sse/services/auth";
function toProviderScopedModelId(providerId: string, modelId: string): string {
return modelId.startsWith(`${providerId}/`) ? modelId : `${providerId}/${modelId}`;
}
/**
* Handle CORS preflight
*/
export async function OPTIONS() {
return new Response(null, {
headers: {
@@ -39,9 +26,6 @@ export async function OPTIONS() {
});
}
/**
* GET /v1/embeddings — list available embedding models
*/
export async function GET() {
const builtInModels = getAllEmbeddingModels();
const timestamp = Math.floor(Date.now() / 1000);
@@ -55,7 +39,6 @@ export async function GET() {
dimensions: m.dimensions,
}));
// Include custom models tagged for embeddings
try {
const customModelsMap = (await getAllCustomModels()) as Record<string, any>;
for (const [providerId, models] of Object.entries(customModelsMap)) {
@@ -82,163 +65,13 @@ export async function GET() {
});
}
/**
* POST /v1/embeddings — create embeddings
*/
type ValidatedEmbeddingBody = Record<string, unknown> & { model: string };
interface EmbeddingHandlerOptions {
clientRawRequest?: {
endpoint: string;
body: Record<string, unknown>;
headers: Record<string, string>;
};
apiKeyId?: string | null;
apiKeyName?: string | null;
connectionId?: string | null;
}
export async function handleValidatedEmbeddingRequestBody(
body: ValidatedEmbeddingBody,
options: EmbeddingHandlerOptions = {}
) {
// Load local provider_nodes for embedding routing (only localhost — prevents auth bypass/SSRF)
let dynamicProviders: ReturnType<typeof buildDynamicEmbeddingProvider>[] = [];
try {
const nodes = (await getProviderNodes()) as unknown as EmbeddingProviderNodeRow[];
dynamicProviders = (Array.isArray(nodes) ? nodes : [])
.filter((n) => {
// provider_nodes apiType is "chat", "responses" or "embeddings" — local OpenAI-compatible
// backends expose /embeddings under the same base URL as chat, so we build the URL as baseUrl + /embeddings.
const validTypes = ["chat", "responses", "embeddings"];
if (!validTypes.includes(n.apiType || "")) return false;
try {
const hostname = new URL(n.baseUrl).hostname;
// Strictly matching 172.16.0.0/12 (Docker/local) and explicitly blocking ::1 per SSRF hardening
return (
hostname === "localhost" ||
hostname === "127.0.0.1" ||
/^172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}$/.test(hostname)
);
} catch {
return false;
}
})
.map((n) => {
try {
return buildDynamicEmbeddingProvider(n);
} catch (err) {
log.error("EMBED", `Skipping invalid provider_node ${n.prefix}: ${err}`);
return null;
}
})
.filter((p): p is NonNullable<typeof p> => p !== null);
} catch (err) {
log.error("EMBED", `Failed to load provider_nodes for embeddings: ${err}`);
}
// Parse model to get provider
const { provider, model: resolvedModel } = parseEmbeddingModel(body.model, dynamicProviders);
if (!provider) {
return errorResponse(
HTTP_STATUS.BAD_REQUEST,
`Invalid embedding model: ${body.model}. Use format: provider/model`
);
}
// Resolve provider config — dynamic first (local override), then hardcoded
let providerConfig: EmbeddingProvider | null =
dynamicProviders.find((dp) => dp.id === provider) || getEmbeddingProvider(provider) || null;
let credentialsProviderId = provider;
// #496: Fallback — resolve from ALL provider_nodes (not just localhost)
// This enables custom embedding models (e.g. google/gemini-embedding-001) whose
// providers have remote baseUrls. Safe because getProviderCredentials() authenticates.
if (!providerConfig) {
try {
const allNodes = (await getProviderNodes()) as unknown as EmbeddingProviderNodeRow[];
const matchingNode = (Array.isArray(allNodes) ? allNodes : []).find(
(n) =>
n.prefix === provider &&
(n.apiType === "chat" || n.apiType === "responses" || n.apiType === "embeddings") &&
n.baseUrl
);
if (matchingNode) {
const baseUrl = String(matchingNode.baseUrl).replace(/\/+$/, "");
providerConfig = {
id: matchingNode.prefix,
baseUrl: `${baseUrl}/embeddings`,
authType: "apikey",
authHeader: "bearer",
models: [],
};
credentialsProviderId = matchingNode.id || provider;
log.info(
"EMBED",
`Resolved custom embedding provider: ${provider}${providerConfig.baseUrl}`
);
}
} catch (err) {
log.error("EMBED", `Failed to resolve custom embedding provider ${provider}: ${err}`);
}
}
if (!providerConfig) {
return errorResponse(
HTTP_STATUS.BAD_REQUEST,
`Unknown embedding provider: ${provider}. No matching hardcoded or local provider found.`
);
}
// Get credentials — skip for local providers (authType: "none")
let credentials = null;
if (providerConfig && providerConfig.authType !== "none") {
credentials = await getProviderCredentials(credentialsProviderId);
if (!credentials) {
return errorResponse(
HTTP_STATUS.BAD_REQUEST,
`No credentials for embedding provider: ${provider}`
);
}
if (credentials.allRateLimited) {
return unavailableResponse(
HTTP_STATUS.RATE_LIMITED,
`[${provider}] All accounts rate limited`,
credentials.retryAfter,
credentials.retryAfterHuman
);
}
}
const result = await handleEmbedding({
body,
credentials,
log,
resolvedProvider: providerConfig,
resolvedModel,
clientRawRequest: options.clientRawRequest || null,
apiKeyId: options.apiKeyId || null,
apiKeyName: options.apiKeyName || null,
connectionId: options.connectionId || null,
});
const responseHeaders = new Headers(result.headers);
if (result.success) {
if (credentials) await clearRecoveredProviderState(credentials);
responseHeaders.set("Content-Type", "application/json");
return new Response(JSON.stringify(result.data), {
status: result.status,
headers: responseHeaders,
});
}
responseHeaders.set("Content-Type", "application/json");
const errorPayload = toJsonErrorPayload(result.error, "Embedding provider error");
return new Response(JSON.stringify(errorPayload), {
status: result.status,
headers: responseHeaders,
});
return createEmbeddingResponse(body, options);
}
export async function POST(request) {

View File

@@ -3315,7 +3315,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3472,7 +3472,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3331,7 +3331,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3758,7 +3758,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3472,7 +3472,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3472,7 +3472,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3319,7 +3319,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3472,7 +3472,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3317,7 +3317,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3472,7 +3472,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3432,7 +3432,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Memoria vetorial)",
"qdrantDesc": "Opcional. Indexa memorias semanticas em um banco vetorial externo para busca mais rapida.",
"qdrantStatusActive": "Ativo",
"qdrantStatusError": "Com erro",
"qdrantStatusDisabled": "Desativado",
"qdrantEnable": "Ativar Qdrant",
"qdrantEnableDesc": "Quando ativo, a estrategia semantic/hybrid pode usar Qdrant para recuperar memorias.",
"qdrantTesting": "Testando...",
"qdrantTestConnection": "Testar conexao",
"qdrantSaved": "Configuracao salva",
"qdrantSaveError": "Falha ao salvar configuracao",
"qdrantHostHint": "Sem a porta. Ex: 127.0.0.1 ou http://qdrant",
"qdrantPort": "Porta",
"qdrantPortHint": "Padrao do Qdrant: 6333",
"qdrantCollectionHint": "Onde os pontos de memoria serao gravados.",
"qdrantEmbeddingModel": "Modelo de embedding",
"qdrantHelpTitle": "Ajuda rapida de configuracao",
"qdrantHelpQuickTitle": "Configuracao rapida (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: IP/URL do Qdrant, Porta: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. Se usar nvidia/llama-nemotron-embed-vl-1b-v2:free, use dimensao 2048 na collection.",
"qdrantHelpStep3": "3. Modelo no campo: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Salvar, testar conexao e depois testar busca.",
"qdrantEmbeddingQuickSelect": "Selecao rapida de modelos descobertos...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Formato: provider/model. Precisa ter credencial desse provider configurada.",
"qdrantApiKeyPlaceholderKeep": "(deixe vazio para manter)",
"qdrantApiKeyPlaceholderOptional": "(deixe vazio se nao usar)",
"qdrantSaveHint": "Dica: edite host/porta/collection/modelo e clique em Salvar. A chave e opcional.",
"qdrantSearchTestTitle": "Teste de busca",
"qdrantSearchTestDesc": "Gera embedding e faz search no Qdrant.",
"qdrantSearchPlaceholder": "Ex: preferencias do usuario, historico, etc",
"qdrantNoResults": "Sem resultados (ou Qdrant desconfigurado).",
"qdrantCleanupTitle": "Retencao e limpeza",
"qdrantCleanupDesc": "Remove pontos expirados e antigos, baseado em",
"searching": "Buscando...",
"cleaning": "Limpando...",
"cleanNow": "Limpar agora"
},
"contextRtk": {
"title": "Motor RTK",

View File

@@ -3402,7 +3402,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Memoria vetorial)",
"qdrantDesc": "Opcional. Indexa memorias semanticas em um banco vetorial externo para busca mais rapida.",
"qdrantStatusActive": "Ativo",
"qdrantStatusError": "Com erro",
"qdrantStatusDisabled": "Desativado",
"qdrantEnable": "Ativar Qdrant",
"qdrantEnableDesc": "Quando ativo, a estrategia semantic/hybrid pode usar Qdrant para recuperar memorias.",
"qdrantTesting": "Testando...",
"qdrantTestConnection": "Testar conexao",
"qdrantSaved": "Configuracao salva",
"qdrantSaveError": "Falha ao salvar configuracao",
"qdrantHostHint": "Sem a porta. Ex: 127.0.0.1 ou http://qdrant",
"qdrantPort": "Porta",
"qdrantPortHint": "Padrao do Qdrant: 6333",
"qdrantCollectionHint": "Onde os pontos de memoria serao gravados.",
"qdrantEmbeddingModel": "Modelo de embedding",
"qdrantHelpTitle": "Ajuda rapida de configuracao",
"qdrantHelpQuickTitle": "Configuracao rapida (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: IP/URL do Qdrant, Porta: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. Se usar nvidia/llama-nemotron-embed-vl-1b-v2:free, use dimensao 2048 na collection.",
"qdrantHelpStep3": "3. Modelo no campo: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Salvar, testar conexao e depois testar busca.",
"qdrantEmbeddingQuickSelect": "Selecao rapida de modelos descobertos...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Formato: provider/model. Precisa ter credencial desse provider configurada.",
"qdrantApiKeyPlaceholderKeep": "(deixe vazio para manter)",
"qdrantApiKeyPlaceholderOptional": "(deixe vazio se nao usar)",
"qdrantSaveHint": "Dica: edite host/porta/collection/modelo e clique em Salvar. A chave e opcional.",
"qdrantSearchTestTitle": "Teste de busca",
"qdrantSearchTestDesc": "Gera embedding e faz search no Qdrant.",
"qdrantSearchPlaceholder": "Ex: preferencias do usuario, historico, etc",
"qdrantNoResults": "Sem resultados (ou Qdrant desconfigurado).",
"qdrantCleanupTitle": "Retencao e limpeza",
"qdrantCleanupDesc": "Remove pontos expirados e antigos, baseado em",
"searching": "Buscando...",
"cleaning": "Limpando...",
"cleanNow": "Limpar agora"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3339,7 +3339,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3472,7 +3472,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3472,7 +3472,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3472,7 +3472,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3472,7 +3472,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3315,7 +3315,44 @@
"requestBodyLimitSaveFailed": "Failed to save request body limit",
"requestBodyLimitSaving": "Saving...",
"requestBodyLimitSave": "Save",
"requestBodyLimitCurrent": "Current: {value}"
"requestBodyLimitCurrent": "Current: {value}",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -3424,7 +3424,44 @@
"compressionModeRtk": "RTK",
"compressionModeRtkDesc": "Command-aware tool output filtering",
"compressionModeStacked": "Stacked",
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression"
"compressionModeStackedDesc": "RTK tool-output filtering followed by Caveman message compression",
"qdrantTitle": "Qdrant (Vector memory)",
"qdrantDesc": "Optional. Indexes semantic memories in an external vector database for faster retrieval.",
"qdrantStatusActive": "Active",
"qdrantStatusError": "Error",
"qdrantStatusDisabled": "Disabled",
"qdrantEnable": "Enable Qdrant",
"qdrantEnableDesc": "When enabled, semantic/hybrid strategy can use Qdrant to retrieve memories.",
"qdrantTesting": "Testing...",
"qdrantTestConnection": "Test connection",
"qdrantSaved": "Configuration saved",
"qdrantSaveError": "Failed to save configuration",
"qdrantHostHint": "Without port. Example: 127.0.0.1 or http://qdrant",
"qdrantPort": "Port",
"qdrantPortHint": "Qdrant default: 6333",
"qdrantCollectionHint": "Where memory points will be stored.",
"qdrantEmbeddingModel": "Embedding model",
"qdrantHelpTitle": "Quick setup help",
"qdrantHelpQuickTitle": "Quick setup (Qdrant + OpenRouter)",
"qdrantHelpStep1": "1. Host: Qdrant IP/URL, Port: 6333, Collection: omniroute_memory.",
"qdrantHelpStep2": "2. If using nvidia/llama-nemotron-embed-vl-1b-v2:free, use collection dimension 2048.",
"qdrantHelpStep3": "3. Model field: openrouter/nvidia/llama-nemotron-embed-vl-1b-v2:free.",
"qdrantHelpStep4": "4. Save, test connection, then test search.",
"qdrantEmbeddingQuickSelect": "Quick select from discovered models...",
"qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small",
"qdrantEmbeddingHint": "Format: provider/model. The provider credential must be configured.",
"qdrantApiKeyPlaceholderKeep": "(leave empty to keep current key)",
"qdrantApiKeyPlaceholderOptional": "(leave empty if not used)",
"qdrantSaveHint": "Tip: edit host/port/collection/model and click Save. API key is optional.",
"qdrantSearchTestTitle": "Search test",
"qdrantSearchTestDesc": "Generates embedding and searches in Qdrant.",
"qdrantSearchPlaceholder": "Example: user preferences, history, etc",
"qdrantNoResults": "No results (or Qdrant is not configured).",
"qdrantCleanupTitle": "Retention and cleanup",
"qdrantCleanupDesc": "Removes expired and old points based on",
"searching": "Searching...",
"cleaning": "Cleaning...",
"cleanNow": "Clean now"
},
"contextRtk": {
"title": "RTK Engine",

View File

@@ -0,0 +1,160 @@
import { handleEmbedding } from "@omniroute/open-sse/handlers/embeddings.ts";
import {
parseEmbeddingModel,
getEmbeddingProvider,
buildDynamicEmbeddingProvider,
type EmbeddingProviderNodeRow,
type EmbeddingProvider,
} from "@omniroute/open-sse/config/embeddingRegistry.ts";
import { errorResponse, unavailableResponse } from "@omniroute/open-sse/utils/error.ts";
import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
import * as log from "@/sse/utils/logger";
import { toJsonErrorPayload } from "@/shared/utils/upstreamError";
import { getProviderCredentials, clearRecoveredProviderState } from "@/sse/services/auth";
import { getProviderNodes } from "@/lib/localDb";
type ValidatedEmbeddingBody = Record<string, unknown> & { model: string };
interface EmbeddingHandlerOptions {
clientRawRequest?: {
endpoint: string;
body: Record<string, unknown>;
headers: Record<string, string>;
};
apiKeyId?: string | null;
apiKeyName?: string | null;
connectionId?: string | null;
}
export async function createEmbeddingResponse(
body: ValidatedEmbeddingBody,
options: EmbeddingHandlerOptions = {}
): Promise<Response> {
let dynamicProviders: ReturnType<typeof buildDynamicEmbeddingProvider>[] = [];
try {
const nodes = (await getProviderNodes()) as unknown as EmbeddingProviderNodeRow[];
dynamicProviders = (Array.isArray(nodes) ? nodes : [])
.filter((n) => {
const validTypes = ["chat", "responses", "embeddings"];
if (!validTypes.includes(n.apiType || "")) return false;
try {
const hostname = new URL(n.baseUrl).hostname;
return (
hostname === "localhost" ||
hostname === "127.0.0.1" ||
/^172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}$/.test(hostname)
);
} catch {
return false;
}
})
.map((n) => {
try {
return buildDynamicEmbeddingProvider(n);
} catch (err) {
log.error("EMBED", `Skipping invalid provider_node ${n.prefix}: ${err}`);
return null;
}
})
.filter((p): p is NonNullable<typeof p> => p !== null);
} catch (err) {
log.error("EMBED", `Failed to load provider_nodes for embeddings: ${err}`);
}
const { provider, model: resolvedModel } = parseEmbeddingModel(body.model, dynamicProviders);
if (!provider) {
return errorResponse(
HTTP_STATUS.BAD_REQUEST,
`Invalid embedding model: ${body.model}. Use format: provider/model`
);
}
let providerConfig: EmbeddingProvider | null =
dynamicProviders.find((dp) => dp.id === provider) || getEmbeddingProvider(provider) || null;
let credentialsProviderId = provider;
if (!providerConfig) {
try {
const allNodes = (await getProviderNodes()) as unknown as EmbeddingProviderNodeRow[];
const matchingNode = (Array.isArray(allNodes) ? allNodes : []).find(
(n) =>
n.prefix === provider &&
(n.apiType === "chat" || n.apiType === "responses" || n.apiType === "embeddings") &&
n.baseUrl
);
if (matchingNode) {
const baseUrl = String(matchingNode.baseUrl).replace(/\/+$/, "");
providerConfig = {
id: matchingNode.prefix,
baseUrl: `${baseUrl}/embeddings`,
authType: "apikey",
authHeader: "bearer",
models: [],
};
credentialsProviderId = matchingNode.id || provider;
log.info(
"EMBED",
`Resolved custom embedding provider: ${provider} -> ${providerConfig.baseUrl}`
);
}
} catch (err) {
log.error("EMBED", `Failed to resolve custom embedding provider ${provider}: ${err}`);
}
}
if (!providerConfig) {
return errorResponse(
HTTP_STATUS.BAD_REQUEST,
`Unknown embedding provider: ${provider}. No matching hardcoded or local provider found.`
);
}
let credentials = null;
if (providerConfig.authType !== "none") {
credentials = await getProviderCredentials(credentialsProviderId);
if (!credentials) {
return errorResponse(
HTTP_STATUS.BAD_REQUEST,
`No credentials for embedding provider: ${provider}`
);
}
if (credentials.allRateLimited) {
return unavailableResponse(
HTTP_STATUS.RATE_LIMITED,
`[${provider}] All accounts rate limited`,
credentials.retryAfter,
credentials.retryAfterHuman
);
}
}
const result = await handleEmbedding({
body,
credentials,
log,
resolvedProvider: providerConfig,
resolvedModel,
clientRawRequest: options.clientRawRequest || null,
apiKeyId: options.apiKeyId || null,
apiKeyName: options.apiKeyName || null,
connectionId: options.connectionId || null,
});
const responseHeaders = new Headers(result.headers);
if (result.success) {
if (credentials) await clearRecoveredProviderState(credentials);
responseHeaders.set("Content-Type", "application/json");
return new Response(JSON.stringify(result.data), {
status: result.status,
headers: responseHeaders,
});
}
responseHeaders.set("Content-Type", "application/json");
const errorPayload = toJsonErrorPayload(result.error, "Embedding provider error");
return new Response(JSON.stringify(errorPayload), {
status: result.status,
headers: responseHeaders,
});
}

409
src/lib/memory/qdrant.ts Normal file
View File

@@ -0,0 +1,409 @@
import { getSettings } from "@/lib/db/settings";
import { createEmbeddingResponse } from "@/lib/embeddings/service";
type JsonRecord = Record<string, unknown>;
export type QdrantConfig = {
enabled: boolean;
host: string;
port: number;
apiKey: string | null;
collection: string;
embeddingModel: string;
};
export function normalizeQdrantConfig(settings: Record<string, unknown>): QdrantConfig {
const host = typeof settings.qdrantHost === "string" ? settings.qdrantHost.trim() : "";
const portRaw = settings.qdrantPort;
const port =
typeof portRaw === "number" && Number.isFinite(portRaw)
? Math.round(portRaw)
: typeof portRaw === "string"
? Math.round(Number(portRaw) || 6333)
: 6333;
const apiKey =
typeof settings.qdrantApiKey === "string" && settings.qdrantApiKey.trim().length > 0
? settings.qdrantApiKey.trim()
: null;
const collection =
typeof settings.qdrantCollection === "string" && settings.qdrantCollection.trim().length > 0
? settings.qdrantCollection.trim()
: "omniroute_memory";
const embeddingModel =
typeof settings.qdrantEmbeddingModel === "string" &&
settings.qdrantEmbeddingModel.trim().length > 0
? settings.qdrantEmbeddingModel.trim()
: "openai/text-embedding-3-small";
const enabled = settings.qdrantEnabled === true;
return { enabled, host, port, apiKey, collection, embeddingModel };
}
export async function getQdrantConfig(): Promise<QdrantConfig> {
const settings = (await getSettings()) as Record<string, unknown>;
return normalizeQdrantConfig(settings);
}
function baseUrl(cfg: QdrantConfig): string {
const host = cfg.host.replace(/\/+$/, "");
const withProto =
host.startsWith("http://") || host.startsWith("https://") ? host : `http://${host}`;
try {
const url = new URL(withProto);
if (!url.port) url.port = String(cfg.port);
return url.toString().replace(/\/+$/, "");
} catch {
return `${withProto}:${cfg.port}`;
}
}
async function qdrantFetch(cfg: QdrantConfig, path: string, init?: RequestInit): Promise<Response> {
const headers: Record<string, string> = {
"content-type": "application/json",
...(init?.headers as Record<string, string> | undefined),
};
if (cfg.apiKey) headers["api-key"] = cfg.apiKey;
return fetch(`${baseUrl(cfg)}${path}`, {
...init,
headers,
});
}
export async function checkQdrantHealth(): Promise<{
ok: boolean;
latencyMs: number;
error?: string;
}> {
const cfg = await getQdrantConfig();
const start = Date.now();
if (!cfg.enabled || !cfg.host) {
return { ok: false, latencyMs: 0, error: "not_configured" };
}
try {
const res = await qdrantFetch(cfg, "/readyz", { method: "GET" });
const latencyMs = Date.now() - start;
if (!res.ok) {
const text = await res.text().catch(() => "");
return { ok: false, latencyMs, error: text.slice(0, 200) || `HTTP ${res.status}` };
}
return { ok: true, latencyMs };
} catch (err) {
return {
ok: false,
latencyMs: Date.now() - start,
error: err instanceof Error ? err.message : String(err),
};
}
}
async function ensureCollection(cfg: QdrantConfig, vectorSize: number): Promise<void> {
const getRes = await qdrantFetch(cfg, `/collections/${encodeURIComponent(cfg.collection)}`, {
method: "GET",
});
if (getRes.ok) return;
const createRes = await qdrantFetch(cfg, `/collections/${encodeURIComponent(cfg.collection)}`, {
method: "PUT",
body: JSON.stringify({
vectors: { size: vectorSize, distance: "Cosine" },
}),
});
if (!createRes.ok) {
const text = await createRes.text().catch(() => "");
throw new Error(text.slice(0, 300) || `Failed to create collection (${createRes.status})`);
}
}
async function getCollectionVectorName(cfg: QdrantConfig): Promise<string | null> {
const res = await qdrantFetch(cfg, `/collections/${encodeURIComponent(cfg.collection)}`, {
method: "GET",
});
if (!res.ok) return null;
const data = (await res.json().catch(() => null)) as any;
const vectors = data?.result?.config?.params?.vectors;
if (!vectors || typeof vectors !== "object" || Array.isArray(vectors)) {
return null;
}
// Unnamed/single-vector config: { size, distance, ... } (not a named map)
if (
Object.prototype.hasOwnProperty.call(vectors, "size") &&
(typeof vectors.size === "number" || typeof vectors.size === "string")
) {
return null;
}
const names = Object.keys(vectors);
if (names.length === 0) return null;
return names[0] || null;
}
async function embedText(cfg: QdrantConfig, text: string): Promise<number[]> {
const modelStr = cfg.embeddingModel.trim();
if (!modelStr.includes("/")) {
throw new Error(`Invalid embedding model '${modelStr}'. Use provider/model format.`);
}
const res = await createEmbeddingResponse({
model: modelStr,
input: text,
});
if (!res.ok) {
const txt = await res.text().catch(() => "");
throw new Error(txt.slice(0, 300) || `Embeddings request failed (${res.status})`);
}
const data = (await res.json().catch(() => null)) as any;
const vec = data?.data?.[0]?.embedding;
if (!Array.isArray(vec) || vec.length === 0) {
throw new Error("Embedding response missing vector");
}
return vec as number[];
}
export async function upsertSemanticMemoryPoint(input: {
id: string;
apiKeyId: string;
sessionId: string;
key: string;
content: string;
metadata: JsonRecord;
createdAt: string;
expiresAt: string | null;
}): Promise<{ ok: boolean; latencyMs: number; error?: string }> {
const cfg = await getQdrantConfig();
if (!cfg.enabled || !cfg.host) return { ok: false, latencyMs: 0, error: "not_configured" };
const start = Date.now();
try {
const vector = await embedText(cfg, `${input.key}\n\n${input.content}`);
await ensureCollection(cfg, vector.length);
const vectorName = await getCollectionVectorName(cfg);
const createdAtUnix = Math.floor(new Date(input.createdAt).getTime() / 1000);
const expiresAtUnix = input.expiresAt
? Math.floor(new Date(input.expiresAt).getTime() / 1000)
: null;
const payload = {
kind: "omniroute_memory",
memoryId: input.id,
apiKeyId: input.apiKeyId || "",
sessionId: input.sessionId || "",
type: "semantic",
key: input.key || "",
content: input.content || "",
metadata: input.metadata || {},
createdAtUnix,
expiresAtUnix,
};
const res = await qdrantFetch(
cfg,
`/collections/${encodeURIComponent(cfg.collection)}/points?wait=true`,
{
method: "PUT",
body: JSON.stringify({
points: [
{
id: input.id,
vector: vectorName ? { [vectorName]: vector } : vector,
payload,
},
],
}),
}
);
const latencyMs = Date.now() - start;
if (!res.ok) {
const text = await res.text().catch(() => "");
return { ok: false, latencyMs, error: text.slice(0, 300) || `HTTP ${res.status}` };
}
return { ok: true, latencyMs };
} catch (err) {
return {
ok: false,
latencyMs: Date.now() - start,
error: err instanceof Error ? err.message : String(err),
};
}
}
export async function searchSemanticMemory(
query: string,
topK = 5,
scope?: { apiKeyId?: string; sessionId?: string | null }
): Promise<{
ok: boolean;
latencyMs: number;
results?: Array<{ id: string; score: number; payload?: JsonRecord }>;
error?: string;
}> {
const cfg = await getQdrantConfig();
if (!cfg.enabled || !cfg.host) return { ok: false, latencyMs: 0, error: "not_configured" };
const start = Date.now();
try {
const vector = await embedText(cfg, query);
await ensureCollection(cfg, vector.length);
const vectorName = await getCollectionVectorName(cfg);
const res = await qdrantFetch(
cfg,
`/collections/${encodeURIComponent(cfg.collection)}/points/search`,
{
method: "POST",
body: JSON.stringify({
vector: vectorName ? { name: vectorName, vector } : vector,
limit: Math.max(1, Math.min(20, topK)),
filter: {
must: [
{ key: "kind", match: { value: "omniroute_memory" } },
...(scope?.apiKeyId ? [{ key: "apiKeyId", match: { value: scope.apiKeyId } }] : []),
...(scope?.sessionId
? [{ key: "sessionId", match: { value: String(scope.sessionId) } }]
: []),
],
},
with_payload: true,
}),
}
);
const latencyMs = Date.now() - start;
if (!res.ok) {
const text = await res.text().catch(() => "");
return { ok: false, latencyMs, error: text.slice(0, 300) || `HTTP ${res.status}` };
}
const data = (await res.json().catch(() => null)) as any;
const result = Array.isArray(data?.result) ? data.result : [];
return {
ok: true,
latencyMs,
results: result.map((r: any) => ({
id: String(r.id),
score: typeof r.score === "number" ? r.score : 0,
payload: r.payload && typeof r.payload === "object" ? (r.payload as JsonRecord) : undefined,
})),
};
} catch (err) {
return {
ok: false,
latencyMs: Date.now() - start,
error: err instanceof Error ? err.message : String(err),
};
}
}
export async function deleteSemanticMemoryPoint(
id: string
): Promise<{ ok: boolean; latencyMs: number; error?: string }> {
const cfg = await getQdrantConfig();
if (!cfg.enabled || !cfg.host) return { ok: false, latencyMs: 0, error: "not_configured" };
const start = Date.now();
try {
const res = await qdrantFetch(
cfg,
`/collections/${encodeURIComponent(cfg.collection)}/points/delete?wait=true`,
{
method: "POST",
body: JSON.stringify({ points: [id] }),
}
);
const latencyMs = Date.now() - start;
if (!res.ok) {
const text = await res.text().catch(() => "");
return { ok: false, latencyMs, error: text.slice(0, 300) || `HTTP ${res.status}` };
}
return { ok: true, latencyMs };
} catch (err) {
return {
ok: false,
latencyMs: Date.now() - start,
error: err instanceof Error ? err.message : String(err),
};
}
}
export async function cleanupSemanticMemoryPoints(input: {
retentionDays: number;
}): Promise<{ ok: boolean; deletedCount: number; latencyMs: number; error?: string }> {
const cfg = await getQdrantConfig();
if (!cfg.enabled || !cfg.host)
return { ok: false, deletedCount: 0, latencyMs: 0, error: "not_configured" };
const retentionDays =
typeof input.retentionDays === "number" && Number.isFinite(input.retentionDays)
? Math.max(1, Math.min(3650, Math.round(input.retentionDays)))
: 30;
const start = Date.now();
try {
const nowUnix = Math.floor(Date.now() / 1000);
const cutoffUnix = nowUnix - retentionDays * 24 * 60 * 60;
const filter: Record<string, unknown> = {
must: [{ key: "kind", match: { value: "omniroute_memory" } }],
should: [
{ key: "expiresAtUnix", range: { lt: nowUnix } },
{ key: "createdAtUnix", range: { lt: cutoffUnix } },
],
};
// Count first (so we can show an actual number in the dashboard)
const countRes = await qdrantFetch(
cfg,
`/collections/${encodeURIComponent(cfg.collection)}/points/count`,
{
method: "POST",
body: JSON.stringify({ filter, exact: true }),
}
);
if (!countRes.ok) {
const text = await countRes.text().catch(() => "");
return {
ok: false,
deletedCount: 0,
latencyMs: Date.now() - start,
error: text.slice(0, 300) || `HTTP ${countRes.status}`,
};
}
const countData = (await countRes.json().catch(() => null)) as any;
const toDelete =
typeof countData?.result?.count === "number" && Number.isFinite(countData.result.count)
? Math.max(0, Math.round(countData.result.count))
: 0;
if (toDelete === 0) {
return { ok: true, deletedCount: 0, latencyMs: Date.now() - start };
}
const delRes = await qdrantFetch(
cfg,
`/collections/${encodeURIComponent(cfg.collection)}/points/delete?wait=true`,
{
method: "POST",
body: JSON.stringify({
filter,
}),
}
);
if (!delRes.ok) {
const text = await delRes.text().catch(() => "");
return {
ok: false,
deletedCount: 0,
latencyMs: Date.now() - start,
error: text.slice(0, 300) || `HTTP ${delRes.status}`,
};
}
return { ok: true, deletedCount: toDelete, latencyMs: Date.now() - start };
} catch (err) {
return {
ok: false,
deletedCount: 0,
latencyMs: Date.now() - start,
error: err instanceof Error ? err.message : String(err),
};
}
}