diff --git a/index.ts b/index.ts index 52f1962e..6913afb7 100644 --- a/index.ts +++ b/index.ts @@ -2052,94 +2052,6 @@ const memoryLanceDBProPlugin = { } ); - // ======================================================================== - // Memory Compaction (Progressive Summarization) - // ======================================================================== - - if (config.enableManagementTools) { - api.registerTool({ - name: "memory_compact", - description: - "Consolidate semantically similar old memories into refined single entries " + - "(progressive summarization). Reduces noise and improves retrieval quality over time. " + - "Use dry_run:true first to preview the compaction plan without making changes.", - inputSchema: { - type: "object" as const, - properties: { - dry_run: { - type: "boolean", - description: "Preview clusters without writing changes. Default: false.", - }, - min_age_days: { - type: "number", - description: "Only compact memories at least this many days old. Default: 7.", - }, - similarity_threshold: { - type: "number", - description: "Cosine similarity threshold for clustering [0-1]. Default: 0.88.", - }, - scopes: { - type: "array", - items: { type: "string" }, - description: "Scope filter. Omit to compact all scopes.", - }, - }, - required: [], - }, - execute: async (args: Record) => { - const compactionCfg: CompactionConfig = { - enabled: true, - minAgeDays: - typeof args.min_age_days === "number" - ? args.min_age_days - : (config.memoryCompaction?.minAgeDays ?? 7), - similarityThreshold: - typeof args.similarity_threshold === "number" - ? Math.max(0, Math.min(1, args.similarity_threshold)) - : (config.memoryCompaction?.similarityThreshold ?? 0.88), - minClusterSize: config.memoryCompaction?.minClusterSize ?? 2, - maxMemoriesToScan: config.memoryCompaction?.maxMemoriesToScan ?? 200, - dryRun: args.dry_run === true, - cooldownHours: config.memoryCompaction?.cooldownHours ?? 24, - }; - const scopes = - Array.isArray(args.scopes) && args.scopes.length > 0 - ? (args.scopes as string[]) - : undefined; - - const result = await runCompaction( - store, - embedder, - compactionCfg, - scopes, - api.logger, - ); - - return { - content: [ - { - type: "text", - text: JSON.stringify( - { - scanned: result.scanned, - clustersFound: result.clustersFound, - memoriesDeleted: result.memoriesDeleted, - memoriesCreated: result.memoriesCreated, - dryRun: result.dryRun, - summary: result.dryRun - ? `Dry run: found ${result.clustersFound} cluster(s) in ${result.scanned} memories — no changes made.` - : `Compacted ${result.memoriesDeleted} memories into ${result.memoriesCreated} consolidated entries.`, - }, - null, - 2, - ), - }, - ], - }; - }, - }); - } - // Auto-compaction at gateway_start (if enabled, respects cooldown) if (config.memoryCompaction?.enabled) { api.on("gateway_start", () => { diff --git a/test/plugin-manifest-regression.mjs b/test/plugin-manifest-regression.mjs index 65e9ec23..41f88e9c 100644 --- a/test/plugin-manifest-regression.mjs +++ b/test/plugin-manifest-regression.mjs @@ -152,7 +152,17 @@ try { plugin.register(api); assert.equal(services.length, 1, "plugin should register its background service"); assert.equal(typeof api.hooks.agent_end, "function", "autoCapture should remain enabled by default"); - assert.equal(api.hooks["command:new"], undefined, "sessionMemory should stay disabled by default"); + // selfImprovement defaults to enabled (#391), so command:new will have + // the appendSelfImprovementNote hook. Verify sessionMemory's /new hook + // is NOT registered by checking that the hook (if any) is the + // self-improvement one, not the sessionMemory one. + if (api.hooks["command:new"] !== undefined) { + assert.equal( + api.hooks["command:new"].name, + "appendSelfImprovementNote", + "command:new hook should only be the self-improvement note, not sessionMemory", + ); + } await assert.doesNotReject( services[0].stop(), "service stop should not throw when no access tracker is configured", @@ -172,11 +182,16 @@ try { }, }); plugin.register(sessionDefaultApi); - assert.equal( - sessionDefaultApi.hooks["command:new"], - undefined, - "sessionMemory:{} should not implicitly enable the /new hook", - ); + // selfImprovement defaults to enabled (#391), so command:new may carry the + // self-improvement hook. The key invariant is that sessionMemory:{} does NOT + // add its own /new hook. + if (sessionDefaultApi.hooks["command:new"] !== undefined) { + assert.equal( + sessionDefaultApi.hooks["command:new"].name, + "appendSelfImprovementNote", + "sessionMemory:{} should not implicitly enable its own /new hook", + ); + } const sessionEnabledApi = createMockApi({ dbPath: path.join(workDir, "db-session-enabled"), @@ -197,11 +212,14 @@ try { "function", "sessionMemory.enabled=true should register the async before_reset hook", ); - assert.equal( - sessionEnabledApi.hooks["command:new"], - undefined, - "sessionMemory.enabled=true should not register the blocking command:new hook", - ); + // Same as above: command:new may be the self-improvement hook, not sessionMemory's. + if (sessionEnabledApi.hooks["command:new"] !== undefined) { + assert.equal( + sessionEnabledApi.hooks["command:new"].name, + "appendSelfImprovementNote", + "sessionMemory.enabled=true should not register the blocking command:new hook", + ); + } const longText = `${"Long embedding payload. ".repeat(420)}tail`; const threshold = 6000; diff --git a/test/session-summary-before-reset.test.mjs b/test/session-summary-before-reset.test.mjs index d3c7a1a4..20cc92ba 100644 --- a/test/session-summary-before-reset.test.mjs +++ b/test/session-summary-before-reset.test.mjs @@ -104,7 +104,15 @@ describe("systemSessionMemory before_reset", () => { memoryLanceDBProPlugin.register(api); assert.equal(typeof api.hooks.before_reset, "function"); - assert.equal(api.hooks["command:new"], undefined); + // selfImprovement defaults to enabled (#391), so command:new may carry + // the self-improvement hook — verify sessionMemory didn't register its own. + if (api.hooks["command:new"] !== undefined) { + assert.equal( + api.hooks["command:new"].name, + "appendSelfImprovementNote", + "command:new hook should only be the self-improvement note, not sessionMemory", + ); + } await api.hooks.before_reset( {