feat(FN-1399): add background memory summarization after task completion
- Add MemoryInsights class in @fusion/core for AI-powered memory audit generation - Add post-run hook to CronRunner for triggering memory summarization after scheduled tasks - Wire memory background processing in both dashboard and serve commands - Add memoryAuditEnabled and memoryAuditSchedule settings for configurable automation - Fix startup ordering: sync automation before cronRunner.start() to prevent race conditions - Add comprehensive tests for memory-insights and dashboard/serve integration - Update contributing.md and settings-reference.md with documentation
This commit is contained in:
@@ -276,6 +276,120 @@ describe("CronRunner", () => {
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.output).toContain("err");
|
||||
});
|
||||
|
||||
it("calls recordRun before callback on success", async () => {
|
||||
const store = createMockStore();
|
||||
const schedule = createMockSchedule({ command: "echo success" });
|
||||
const automationStore = createMockAutomationStore([schedule]);
|
||||
|
||||
const callOrder: string[] = [];
|
||||
const onProcessed = vi.fn().mockImplementation(() => {
|
||||
callOrder.push("callback");
|
||||
});
|
||||
|
||||
runner = new CronRunner(store, automationStore, { onScheduleRunProcessed: onProcessed });
|
||||
await runner.executeSchedule(schedule);
|
||||
|
||||
expect(callOrder).toContain("callback");
|
||||
// recordRun should have been called first
|
||||
expect(automationStore.recordRun).toHaveBeenCalledBefore(onProcessed);
|
||||
});
|
||||
|
||||
it("invokes callback on successful execution", async () => {
|
||||
const store = createMockStore();
|
||||
const schedule = createMockSchedule({ command: "echo success" });
|
||||
const automationStore = createMockAutomationStore([schedule]);
|
||||
|
||||
const onProcessed = vi.fn();
|
||||
runner = new CronRunner(store, automationStore, { onScheduleRunProcessed: onProcessed });
|
||||
|
||||
await runner.executeSchedule(schedule);
|
||||
|
||||
expect(onProcessed).toHaveBeenCalledTimes(1);
|
||||
expect(onProcessed).toHaveBeenCalledWith(
|
||||
schedule,
|
||||
expect.objectContaining({ success: true }),
|
||||
);
|
||||
});
|
||||
|
||||
it("invokes callback on failed execution", async () => {
|
||||
const store = createMockStore();
|
||||
const schedule = createMockSchedule({ command: "exit 1" });
|
||||
const automationStore = createMockAutomationStore([schedule]);
|
||||
|
||||
const onProcessed = vi.fn();
|
||||
runner = new CronRunner(store, automationStore, { onScheduleRunProcessed: onProcessed });
|
||||
|
||||
await runner.executeSchedule(schedule);
|
||||
|
||||
expect(onProcessed).toHaveBeenCalledTimes(1);
|
||||
expect(onProcessed).toHaveBeenCalledWith(
|
||||
schedule,
|
||||
expect.objectContaining({ success: false }),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not invoke callback when not provided", async () => {
|
||||
const store = createMockStore();
|
||||
const schedule = createMockSchedule({ command: "echo test" });
|
||||
const automationStore = createMockAutomationStore([schedule]);
|
||||
runner = new CronRunner(store, automationStore);
|
||||
|
||||
// Should not throw
|
||||
await runner.executeSchedule(schedule);
|
||||
});
|
||||
|
||||
it("callback errors do not throw or alter returned result", async () => {
|
||||
const store = createMockStore();
|
||||
const schedule = createMockSchedule({ command: "echo success" });
|
||||
const automationStore = createMockAutomationStore([schedule]);
|
||||
|
||||
const onProcessed = vi.fn().mockRejectedValue(new Error("callback failed"));
|
||||
runner = new CronRunner(store, automationStore, { onScheduleRunProcessed: onProcessed });
|
||||
|
||||
// Should not throw
|
||||
const result = await runner.executeSchedule(schedule);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.output).toContain("success");
|
||||
});
|
||||
|
||||
it("callback errors do not prevent recordRun", async () => {
|
||||
const store = createMockStore();
|
||||
const schedule = createMockSchedule({ command: "echo test" });
|
||||
const automationStore = createMockAutomationStore([schedule]);
|
||||
|
||||
const onProcessed = vi.fn().mockRejectedValue(new Error("callback failed"));
|
||||
runner = new CronRunner(store, automationStore, { onScheduleRunProcessed: onProcessed });
|
||||
|
||||
await runner.executeSchedule(schedule);
|
||||
|
||||
expect(automationStore.recordRun).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("passes schedule and result to callback", async () => {
|
||||
const store = createMockStore();
|
||||
const schedule = createMockSchedule({
|
||||
id: "custom-id",
|
||||
name: "Custom Schedule",
|
||||
command: "echo custom",
|
||||
});
|
||||
const automationStore = createMockAutomationStore([schedule]);
|
||||
|
||||
let receivedSchedule: ScheduledTask | undefined;
|
||||
let receivedResult: AutomationRunResult | undefined;
|
||||
const onProcessed = vi.fn().mockImplementation((s: ScheduledTask, r: AutomationRunResult) => {
|
||||
receivedSchedule = s;
|
||||
receivedResult = r;
|
||||
});
|
||||
|
||||
runner = new CronRunner(store, automationStore, { onScheduleRunProcessed: onProcessed });
|
||||
await runner.executeSchedule(schedule);
|
||||
|
||||
expect(receivedSchedule).toEqual(schedule);
|
||||
expect(receivedResult).toBeDefined();
|
||||
expect(receivedResult!.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("concurrent schedule prevention in tick", () => {
|
||||
|
||||
Reference in New Issue
Block a user