feat(memory): surface active embedder, expand docs

Add a read-only Embedding row to the /memory Settings tab showing the resolved model and source, or offline (hashbag-v2) on fallback.
Expand memory docs to cover API key requirement, supported models, auto-resolution, and how to verify the embedder is active (#115).

Co-Authored-By: SoulForge <[email protected]>
This commit is contained in:
PouiiroandSoulForge committed 2026-06-23 18:38:13 +02:00
1 parent 02e8f55b82
commit 3a67afc309
2 files changed
+38 -3

No files matched your search

+25 -1
View File
@@ -81,4 +81,28 @@ Memory works in any script — English, CJK, Arabic, Cyrillic, mixed-script iden
}
```
Optional. Sets a real embedding provider for semantic recall. Default is a built-in offline embedder that works without any API calls — good enough for word-overlap paraphrases.
Optional. Sets a real embedding provider for semantic recall. Default is a built-in offline embedder (hashbag-v2) that works without any API calls, good enough for word-overlap paraphrases.
### Do I need an API key?
Yes, if you set a provider model. The embedder runs through the AI SDK, so it needs that provider's key. For `openai/text-embedding-3-small` that is your OpenAI key. Without a valid key the embedder fails its startup probe and silently falls back to the offline embedder. Memory keeps working either way.
### Which models can I use?
Any AI SDK `provider/model` id. Verified routes:
| Provider | Model |
|---|---|
| OpenAI | `openai/text-embedding-3-small`, `openai/text-embedding-3-large` |
| Google | `google/text-embedding-004` |
| Vercel Gateway | `vercel_gateway/openai/text-embedding-3-small` |
| LLM Gateway | `llmgateway/openai/text-embedding-3-small` |
| OpenRouter | `openrouter/openai/text-embedding-3-small` |
Providers with no embedding API (Anthropic, xAI, Groq, DeepSeek, Mistral, Bedrock, proxy, codex, copilot) always fall back to the offline embedder. Local providers (Ollama, LM Studio) and custom OpenAI-compatible providers work only if you set `embeddingModel` explicitly.
You do not have to set this at all. When unset, it auto-resolves in order: `taskRouter.semantic`, a default for your active chat provider, then the offline embedder.
### How do I check it is working?
Open `/memory`, go to the **Settings** tab, and read the **Embedding** row. It shows the active model and where the choice came from, or `offline (hashbag-v2)` when the offline embedder is in use. If you set a provider model but the row still says offline, the key is missing or the model was rejected.
+13 -2
View File
@@ -43,7 +43,7 @@ interface SettingsRow {
meta?: string;
active?: boolean;
status?: "online" | "offline" | "warning" | "error" | "idle";
kind: "write" | "read" | "settings-storage";
kind: "write" | "read" | "settings-storage" | "embedding";
}
const SETTINGS_MODAL_TITLE: Record<SettingsModalKind, string> = {
@@ -318,6 +318,10 @@ export function MemoryBrowser({ visible, contextManager, cwd, onClose, onSystemM
// Settings groups: scope rules.
const settingsGroups = useMemo<GroupedListGroup<SettingsRow>[]>(() => {
const scopeCfg = memMgr.scopeConfig;
const resolution = contextManager.getEmbedderResolution();
const embedderMeta = resolution?.modelId
? `${resolution.modelId} (${resolution.source})`
: "offline (hashbag-v2)";
return [
{
id: "scopes",
@@ -342,10 +346,17 @@ export function MemoryBrowser({ visible, contextManager, cwd, onClose, onSystemM
meta: memMgr.settingsScope,
kind: "settings-storage" as const,
},
{
id: "embedding",
label: "Embedding",
meta: embedderMeta,
status: resolution?.modelId ? ("online" as const) : ("offline" as const),
kind: "embedding" as const,
},
],
},
];
}, [memMgr]);
}, [memMgr, contextManager]);
const settingsRows = useMemo(
() => buildGroupedRows(settingsGroups, new Set(["scopes"])),