feat: Add memory reminders to improve memory use (#366)

This commit is contained in:
Devansh Jain
2025-12-23 12:00:34 -08:00
committed by GitHub
parent ef09af92f2
commit 54f0f233b3
6 changed files with 133 additions and 3 deletions

View File

@@ -89,6 +89,10 @@ import {
} from "./helpers/accumulator";
import { backfillBuffers } from "./helpers/backfill";
import { formatErrorDetails } from "./helpers/errorFormatter";
import {
buildMemoryReminder,
parseMemoryPreference,
} from "./helpers/memoryReminder";
import {
buildMessageContentFromDisplay,
clearPlaceholdersInText,
@@ -505,6 +509,9 @@ export default function App({
// Track if we've sent the session context for this CLI session
const hasSentSessionContextRef = useRef(false);
// Track conversation turn count for periodic memory reminders
const turnCountRef = useRef(0);
// Static items (things that are done rendering and can be frozen)
const [staticItems, setStaticItems] = useState<StaticItem[]>([]);
@@ -1674,6 +1681,9 @@ export default function App({
setStaticItems([]);
setStaticRenderEpoch((e) => e + 1);
// Reset turn counter for memory reminders when switching agents
turnCountRef.current = 0;
// Update agent state - also update ref immediately for any code that runs before re-render
agentIdRef.current = targetAgentId;
setAgentId(targetAgentId);
@@ -2287,6 +2297,9 @@ export default function App({
// emittedIdsRef.current.clear();
// setStaticItems([]);
// Reset turn counter for memory reminders
turnCountRef.current = 0;
// Update command with success
buffersRef.current.byId.set(cmdId, {
kind: "command",
@@ -3246,12 +3259,21 @@ DO NOT respond to these messages or otherwise consider them in your response unl
bashCommandCacheRef.current = [];
}
// Combine reminders with content (session context first, then plan mode, then skill unload, then bash commands)
// Build memory reminder if interval is set and we've reached the Nth turn
const memoryReminderContent = await buildMemoryReminder(
turnCountRef.current,
);
// Increment turn count for next iteration
turnCountRef.current += 1;
// Combine reminders with content (session context first, then plan mode, then skill unload, then bash commands, then memory reminder)
const allReminders =
sessionContextReminder +
planModeReminder +
skillUnloadReminder +
bashCommandPrefix;
bashCommandPrefix +
memoryReminderContent;
const messageContent =
allReminders && typeof contentParts === "string"
? allReminders + contentParts
@@ -4476,6 +4498,9 @@ DO NOT respond to these messages or otherwise consider them in your response unl
// Get questions from approval args
const questions = getQuestionsFromApproval(approval);
// Check for memory preference question and update setting
parseMemoryPreference(questions, answers);
// Format the answer string like Claude Code does
const answerParts = questions.map((q) => {
const answer = answers[q.question] || "";

View File

@@ -0,0 +1,90 @@
// src/cli/helpers/memoryReminder.ts
// Handles periodic memory reminder logic and preference parsing
import { settingsManager } from "../../settings-manager";
// Memory reminder interval presets
const MEMORY_INTERVAL_FREQUENT = 3;
const MEMORY_INTERVAL_OCCASIONAL = 8;
/**
* Get the effective memory reminder interval (local setting takes precedence over global)
* @returns The memory interval setting, or null if disabled
*/
function getMemoryInterval(): number | null {
// Check local settings first (may not be loaded, so catch errors)
try {
const localSettings = settingsManager.getLocalProjectSettings();
if (localSettings.memoryReminderInterval !== undefined) {
return localSettings.memoryReminderInterval;
}
} catch {
// Local settings not loaded, fall through to global
}
// Fall back to global setting
return settingsManager.getSetting("memoryReminderInterval");
}
/**
* Build a memory check reminder if the turn count matches the interval
* @param turnCount - Current conversation turn count
* @returns Promise resolving to the reminder string (empty if not applicable)
*/
export async function buildMemoryReminder(turnCount: number): Promise<string> {
const memoryInterval = getMemoryInterval();
if (memoryInterval && turnCount > 0 && turnCount % memoryInterval === 0) {
const { MEMORY_CHECK_REMINDER } = await import(
"../../agent/promptAssets.js"
);
return MEMORY_CHECK_REMINDER;
}
return "";
}
interface Question {
question: string;
header?: string;
}
/**
* Parse user's answer to a memory preference question and update settings
* @param questions - Array of questions that were asked
* @param answers - Record of question -> answer
* @returns true if a memory preference was detected and setting was updated
*/
export function parseMemoryPreference(
questions: Question[],
answers: Record<string, string>,
): boolean {
for (const q of questions) {
const questionLower = q.question.toLowerCase();
const headerLower = q.header?.toLowerCase() || "";
// Match memory-related questions
if (
questionLower.includes("memory") ||
questionLower.includes("remember") ||
headerLower.includes("memory")
) {
const answer = answers[q.question]?.toLowerCase() || "";
// Parse answer: "frequent" → MEMORY_INTERVAL_FREQUENT, "occasional" → MEMORY_INTERVAL_OCCASIONAL
if (answer.includes("frequent")) {
settingsManager.updateLocalProjectSettings({
memoryReminderInterval: MEMORY_INTERVAL_FREQUENT,
});
return true;
} else if (answer.includes("occasional")) {
settingsManager.updateLocalProjectSettings({
memoryReminderInterval: MEMORY_INTERVAL_OCCASIONAL,
});
return true;
}
break; // Only process first matching question
}
}
return false;
}