mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
Feat/qdrant embedding model discovery (#2086)
Integrated into release/v3.8.0
This commit is contained in:
138
Tuto_Qdrant.MD
Normal file
138
Tuto_Qdrant.MD
Normal 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.
|
||||
@@ -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">
|
||||
|
||||
93
src/app/api/settings/qdrant/embedding-models/route.ts
Normal file
93
src/app/api/settings/qdrant/embedding-models/route.ts
Normal 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 });
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
160
src/lib/embeddings/service.ts
Normal file
160
src/lib/embeddings/service.ts
Normal 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
409
src/lib/memory/qdrant.ts
Normal 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),
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user