diff --git a/src/resources/extensions/sf/commands-memory.ts b/src/resources/extensions/sf/commands-memory.ts index 4d9dbc7a0..a54528b36 100644 --- a/src/resources/extensions/sf/commands-memory.ts +++ b/src/resources/extensions/sf/commands-memory.ts @@ -26,6 +26,7 @@ import { enforceMemoryCap, getActiveMemories, getActiveMemoriesRanked, + getRelevantMemoriesRanked, supersedeMemory, } from "./memory-store.js"; import { _getAdapter, isDbAvailable } from "./sf-db.js"; @@ -117,6 +118,9 @@ export async function handleMemory( case "list": handleList(ctx); return; + case "search": + await handleSearch(ctx, parsed); + return; case "show": handleShow(ctx, parsed.positional[0]); return; @@ -160,6 +164,7 @@ function usage(): string { return [ "Usage: /sf memory ", " list list recent active memories", + ' search "" embedding-ranked search (gateway-aware; static fallback)', " show print one memory", " forget supersede a memory", " stats counts by category / sources / edges", @@ -199,6 +204,40 @@ function handleList(ctx: ExtensionCommandContext): void { ctx.ui.notify(lines.join("\n"), "info"); } +async function handleSearch( + ctx: ExtensionCommandContext, + parsed: MemoryCmdArgs, +): Promise { + if (!isDbAvailable()) { + ctx.ui.notify("No SF database available.", "warning"); + return; + } + const query = parsed.positional.join(" ").trim(); + if (!query) { + ctx.ui.notify( + 'Usage: /sf memory search "" (uses embeddings when SF_LLM_GATEWAY_KEY is set; static fallback otherwise)', + "warning", + ); + return; + } + const memories = await getRelevantMemoriesRanked(query, 10); + if (memories.length === 0) { + ctx.ui.notify("No matches.", "info"); + return; + } + const usingEmbeddings = !!process.env.SF_LLM_GATEWAY_KEY; + const header = usingEmbeddings + ? `Top ${memories.length} memories for "${truncate(query, 60)}" (embedding-ranked):` + : `Top ${memories.length} memories for "${truncate(query, 60)}" (static rank — set SF_LLM_GATEWAY_KEY for embeddings):`; + const lines = [header]; + for (const m of memories) { + lines.push( + ` [${m.id}] (${m.category}, conf ${m.confidence.toFixed(2)}) ${truncate(m.content, 100)}`, + ); + } + ctx.ui.notify(lines.join("\n"), "info"); +} + function handleShow(ctx: ExtensionCommandContext, id: string | undefined): void { if (!id) { ctx.ui.notify("Usage: /sf memory show ", "warning");