fix(FN-000): simplify qmd memory settings

This commit is contained in:
gsxdsm
2026-04-17 08:16:36 -07:00
parent 8a8f6bf938
commit 39cbfaba02
20 changed files with 576 additions and 511 deletions

View File

@@ -12691,7 +12691,7 @@ describe("GET /api/memory/backend", () => {
});
});
it("defaults to file backend when no backend type is set", async () => {
it("defaults to qmd backend when no backend type is set", async () => {
(store.getSettings as ReturnType<typeof vi.fn>).mockResolvedValue({
memoryEnabled: true,
});
@@ -12699,11 +12699,11 @@ describe("GET /api/memory/backend", () => {
const res = await GET(buildApp(), "/api/memory/backend");
expect(res.status).toBe(200);
expect(res.body.currentBackend).toBe("file");
expect(res.body.currentBackend).toBe("qmd");
});
it("returns file backend for unknown custom backend type (fallback)", async () => {
// Unknown backend types are persisted but fallback to file at runtime
it("returns qmd backend for unknown custom backend type (fallback)", async () => {
// Unknown backend types are persisted but fallback to qmd at runtime
(store.getSettings as ReturnType<typeof vi.fn>).mockResolvedValue({
memoryBackendType: "unknown-custom-backend",
memoryEnabled: true,
@@ -12712,8 +12712,8 @@ describe("GET /api/memory/backend", () => {
const res = await GET(buildApp(), "/api/memory/backend");
expect(res.status).toBe(200);
// currentBackend reflects the effective backend (file fallback)
expect(res.body.currentBackend).toBe("file");
// currentBackend reflects the effective backend (qmd fallback)
expect(res.body.currentBackend).toBe("qmd");
// But availableBackends is still the list of registered backends
expect(res.body.availableBackends).toContain("file");
expect(res.body.availableBackends).toContain("readonly");

View File

@@ -18,7 +18,7 @@ import * as nodeFs from "node:fs";
import { promisify } from "node:util";
import type { TaskStore, Column, ScheduleType, ActivityEventType, ModelPreset, MessageType, ParticipantType, RoutineTriggerType, ProjectSettings } from "@fusion/core";
import { COLUMNS, VALID_TRANSITIONS, GLOBAL_SETTINGS_KEYS, type BatchStatusEntry, type BatchStatusResponse, type BatchStatusResult, type IssueInfo, type PrInfo, type Task, type PiExtensionEntry, type PiExtensionSettings, getCurrentRepo, isGhAuthenticated, AutomationStore, validateBackupSchedule, validateBackupRetention, validateBackupDir, syncBackupRoutine, exportSettings, importSettings, validateImportData, MessageStore, RoutineStore, isWebhookTrigger, resolveMemoryBackend, getMemoryBackendCapabilities, listMemoryBackendTypes, listProjectMemoryFiles, readProjectMemoryFile, writeProjectMemoryFile, readMemory, writeMemory, MemoryBackendError, discoverPiExtensions, updatePiExtensionDisabledIds, getFusionAgentDir, getLegacyPiAgentDir } from "@fusion/core";
import { COLUMNS, VALID_TRANSITIONS, GLOBAL_SETTINGS_KEYS, type BatchStatusEntry, type BatchStatusResponse, type BatchStatusResult, type IssueInfo, type PrInfo, type Task, type PiExtensionEntry, type PiExtensionSettings, getCurrentRepo, isGhAuthenticated, AutomationStore, validateBackupSchedule, validateBackupRetention, validateBackupDir, syncBackupRoutine, exportSettings, importSettings, validateImportData, MessageStore, RoutineStore, isWebhookTrigger, resolveMemoryBackend, getMemoryBackendCapabilities, listMemoryBackendTypes, listProjectMemoryFiles, readProjectMemoryFile, writeProjectMemoryFile, readMemory, writeMemory, searchProjectMemory, isQmdAvailable, QMD_INSTALL_COMMAND, MemoryBackendError, discoverPiExtensions, updatePiExtensionDisabledIds, getFusionAgentDir, getLegacyPiAgentDir } from "@fusion/core";
import type { ServerOptions } from "./server.js";
import { GitHubClient, parseBadgeUrl } from "./github.js";
import { githubRateLimiter } from "./github-poll.js";
@@ -2645,6 +2645,8 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
currentBackend: resolveMemoryBackend(settings).type,
capabilities,
availableBackends,
qmdAvailable: await isQmdAvailable(),
qmdInstallCommand: QMD_INSTALL_COMMAND,
});
} catch (err: unknown) {
if (err instanceof ApiError) {
@@ -2654,6 +2656,36 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
}
});
router.post("/memory/test", async (req, res) => {
try {
const { store: scopedStore } = await getProjectContext(req);
const settings = await scopedStore.getSettings();
const rootDir = scopedStore.getRootDir();
const query = typeof req.body?.query === "string" && req.body.query.trim()
? req.body.query.trim()
: "project memory";
const qmdAvailable = await isQmdAvailable();
const results = await searchProjectMemory(
rootDir,
{ query, limit: 5 },
{ ...settings, memoryBackendType: "qmd" },
);
res.json({
query,
qmdAvailable,
usedFallback: !qmdAvailable,
qmdInstallCommand: QMD_INSTALL_COMMAND,
results,
});
} catch (err: unknown) {
if (err instanceof ApiError) {
throw err;
}
rethrowAsApiError(err, "Failed to test memory retrieval");
}
});
/**
* POST /api/memory/compact
* AI-powered memory compaction using the memory compaction service.