From 3c7ee454a69cc7c4de9d426a74182835afed79aa Mon Sep 17 00:00:00 2001 From: Kan Ninomiya Date: Thu, 19 Mar 2026 11:22:08 +0900 Subject: [PATCH] feat: context re-injection with periodic and keyword triggers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, supermemory context was only injected on the first message of a session. This meant topic changes mid-session lost relevant memory context. Changes: - Add reinjectEveryN config (default 0 = first only) Set to e.g. 10 to re-inject context every 10 messages - Add recall keyword patterns (English + Japanese) 'recall', '思い出して', 'メモリ確認' etc. trigger immediate context re-injection on that message - Clean up session state on session.deleted - Track per-session message counts instead of boolean set Config example (supermemory.jsonc): { "reinjectEveryN": 10 } --- src/config.ts | 24 ++++++++++++++++++++++++ src/index.ts | 26 ++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/config.ts b/src/config.ts index d467991..0b044a4 100644 --- a/src/config.ts +++ b/src/config.ts @@ -23,6 +23,10 @@ interface SupermemoryConfig { filterPrompt?: string; keywordPatterns?: string[]; compactionThreshold?: number; + /** Re-inject context every N messages. 0 = first message only (default). */ + reinjectEveryN?: number; + /** Keywords that trigger immediate context re-injection. */ + recallKeywordPatterns?: string[]; } const DEFAULT_KEYWORD_PATTERNS = [ @@ -57,6 +61,19 @@ const DEFAULT_KEYWORD_PATTERNS = [ "ノートして", ]; +const DEFAULT_RECALL_KEYWORD_PATTERNS = [ + // English + "recall", + "what\\s+do\\s+you\\s+remember", + "check\\s+memory", + "search\\s+memory", + // Japanese + "思い出して", + "記憶を?検索", + "メモリ[ーを]?確認", + "何か覚えてる", +]; + const DEFAULTS: Required> = { similarityThreshold: 0.6, maxMemories: 5, @@ -67,6 +84,8 @@ const DEFAULTS: Required { const { directory } = ctx; const tags = getTags(directory); - const injectedSessions = new Set(); + const sessionMessageCount = new Map(); log("Plugin init", { directory, tags, configured: isConfigured() }); if (!isConfigured()) { @@ -171,10 +177,20 @@ export const SupermemoryPlugin: Plugin = async (ctx: PluginInput) => { output.parts.push(nudgePart); } - const isFirstMessage = !injectedSessions.has(input.sessionID); + // Determine whether to inject context + const count = (sessionMessageCount.get(input.sessionID) || 0) + 1; + sessionMessageCount.set(input.sessionID, count); + + const isFirstMessage = count === 1; + const recallTriggered = detectRecallKeyword(userMessage); + const periodicReinject = CONFIG.reinjectEveryN > 0 && count % CONFIG.reinjectEveryN === 0; + const shouldInjectContext = isFirstMessage || recallTriggered || periodicReinject; - if (isFirstMessage) { - injectedSessions.add(input.sessionID); + if (shouldInjectContext) { + log("chat.message: injecting context", { + reason: isFirstMessage ? "first-message" : recallTriggered ? "recall-keyword" : "periodic", + messageCount: count, + }); const [profileResult, userMemoriesResult, projectMemoriesListResult] = await Promise.all([ supermemoryClient.getProfile(tags.user, userMessage), @@ -220,6 +236,7 @@ export const SupermemoryPlugin: Plugin = async (ctx: PluginInput) => { log("chat.message: context injected", { duration, contextLength: memoryContext.length, + reason: isFirstMessage ? "first-message" : recallTriggered ? "recall-keyword" : "periodic", }); } } @@ -540,6 +557,7 @@ export const SupermemoryPlugin: Plugin = async (ctx: PluginInput) => { const sessionInfo = props?.info as { id?: string } | undefined; if (sessionInfo?.id) { await saveSessionSummary(sessionInfo.id); + sessionMessageCount.delete(sessionInfo.id); } }