feat(FN-925): add memoryEnabled setting with UI toggle and engine integration

- Add memoryEnabled boolean setting to core types and default settings
- Add Memory section toggle to SettingsModal dashboard UI
- Integrate memoryEnabled check in executor and triage engine prompts
- Add tests for settings UI, executor prompt behavior, and triage prompt behavior
- Update SettingsModal section count test for the new Memory section
This commit is contained in:
gsxdsm
2026-04-04 15:06:57 -07:00
parent 3d1cfda517
commit ea4fe6fe0f
8 changed files with 198 additions and 4 deletions

View File

@@ -2125,6 +2125,31 @@ describe("buildExecutionPrompt", () => {
expect(agentPrompt).toContain("- **Test:** `npm test`");
expect(agentPrompt).toContain("- **Build:** `npm run build`");
});
describe("memoryEnabled setting", () => {
it("accepts memoryEnabled: true without error", () => {
const task = createMockTaskDetail();
const result = buildExecutionPrompt(task, "/project", {
memoryEnabled: true,
} as any);
// Memory instructions are a placeholder until FN-810; just verify no crash
expect(result).toContain("Execute this task.");
});
it("accepts memoryEnabled: false without error", () => {
const task = createMockTaskDetail();
const result = buildExecutionPrompt(task, "/project", {
memoryEnabled: false,
} as any);
expect(result).toContain("Execute this task.");
});
it("accepts undefined memoryEnabled (default enabled) without error", () => {
const task = createMockTaskDetail();
const result = buildExecutionPrompt(task, "/project", {} as any);
expect(result).toContain("Execute this task.");
});
});
});
// Import the summarizeToolArgs helper directly (not affected by mocks above)

View File

@@ -2224,6 +2224,17 @@ git log --oneline
commandsSection = "\n" + lines.join("\n") + "\n";
}
// Build project memory section from settings
// When enabled, agents consult and update .fusion/memory.md for durable project learnings.
// Actual memory instructions will be injected by FN-810; this placeholder establishes
// the conditional integration point.
const memoryEnabled = settings?.memoryEnabled !== false;
let memorySection = "";
if (memoryEnabled && rootDir) {
// TODO(FN-810): Call buildMemoryInstructions(rootDir) to populate memory context
memorySection = "";
}
// Build steering comments section (last 10 comments only to avoid context bloat)
let steeringSection = "";
if (task.steeringComments && task.steeringComments.length > 0) {
@@ -2253,7 +2264,7 @@ ${task.dependencies.length > 0 ? `Dependencies: ${task.dependencies.join(", ")}`
## PROMPT.md
${task.prompt}
${attachmentsSection}${commandsSection}${progressSection}${steeringSection}
${attachmentsSection}${commandsSection}${memorySection}${progressSection}${steeringSection}
## Review level: ${reviewLevel}
${reviewLevel === 0 ? "No reviews required. Implement directly." : ""}

View File

@@ -214,6 +214,52 @@ describe("buildSpecificationPrompt", () => {
expect(prompt).toContain("If splitting: use the \\\`task_create\\\` tool");
expect(prompt).not.toContain("## Subtask Consideration");
});
describe("memoryEnabled setting", () => {
it("accepts memoryEnabled: true without error", () => {
const settings: Settings = {
maxConcurrent: 2,
maxWorktrees: 4,
pollIntervalMs: 10000,
groupOverlappingFiles: false,
autoMerge: true,
memoryEnabled: true,
};
const prompt = buildSpecificationPrompt(
baseTask,
".fusion/tasks/KB-001/PROMPT.md",
settings,
);
// Memory instructions are a placeholder until FN-810; just verify no crash
expect(prompt).toContain("Specify this task");
});
it("accepts memoryEnabled: false without error", () => {
const settings: Settings = {
maxConcurrent: 2,
maxWorktrees: 4,
pollIntervalMs: 10000,
groupOverlappingFiles: false,
autoMerge: true,
memoryEnabled: false,
};
const prompt = buildSpecificationPrompt(
baseTask,
".fusion/tasks/KB-001/PROMPT.md",
settings,
);
expect(prompt).toContain("Specify this task");
});
it("accepts undefined memoryEnabled (default enabled) without error", () => {
const prompt = buildSpecificationPrompt(
baseTask,
".fusion/tasks/KB-001/PROMPT.md",
undefined,
);
expect(prompt).toContain("Specify this task");
});
});
});
describe("TRIAGE_SYSTEM_PROMPT", () => {

View File

@@ -1193,6 +1193,17 @@ export function buildSpecificationPrompt(
commandsSection = "\n\n" + lines.join("\n");
}
// Build project memory section from settings.
// When enabled, agents consult .fusion/memory.md for durable project learnings.
// Actual memory instructions will be injected by FN-810; this placeholder
// establishes the conditional integration point.
const memoryEnabled = settings?.memoryEnabled !== false;
let memorySection = "";
if (memoryEnabled) {
// TODO(FN-810): Call buildMemoryInstructions(rootDir) to populate memory context
memorySection = "";
}
let attachmentsSection = "";
if (attachmentContents && attachmentContents.length > 0) {
const parts = ["## Attachments", ""];
@@ -1276,5 +1287,5 @@ ${task.dependencies.length > 0 ? `- **Dependencies:** ${task.dependencies.join("
## Instructions
${isRevision ? "1. Review the existing specification and user feedback carefully\n2. Revise the PROMPT.md to address the feedback while maintaining the structure\n3. Ensure the specification is detailed enough for an AI agent to execute" : "1. Read the project structure to understand context (package.json, source files, etc.)\n2. Write a complete PROMPT.md specification to the given path following the format in your system prompt\n3. The specification must be detailed enough for an autonomous AI agent to implement without asking questions\n4. Name actual files, functions, and patterns from the codebase — be specific"}
Use the write tool to write the specification file.${commandsSection}${attachmentsSection}`;
Use the write tool to write the specification file.${commandsSection}${memorySection}${attachmentsSection}`;
}