feat: Add memory reminders to improve memory use (#366)
This commit is contained in:
@@ -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] || "";
|
||||
|
||||
90
src/cli/helpers/memoryReminder.ts
Normal file
90
src/cli/helpers/memoryReminder.ts
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user