@vellumai/assistant 0.10.5-dev.202607061137.28aab2f → 0.10.5-dev.202607061324.2dbc3d4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/__tests__/lexical-index-dual-write.test.ts +0 -7
- package/src/__tests__/plugin-disabled-state.test.ts +0 -107
- package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -1
- package/src/plugins/defaults/memory/__tests__/jobs-worker-pkb-schedule.test.ts +0 -9
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +0 -10
- package/src/plugins/defaults/memory/__tests__/persistence-lifecycle-seam.test.ts +0 -19
- package/src/plugins/defaults/memory/jobs-worker.ts +15 -8
- package/src/plugins/defaults/memory/persistence-hooks-registration.ts +5 -77
- package/src/plugins/defaults/memory/persistence-hooks.ts +0 -18
- package/src/plugins/defaults/memory/persistence-lifecycle-seam.ts +0 -32
package/package.json
CHANGED
|
@@ -356,13 +356,6 @@ describe("delete paths route through the persistence-hook seam", () => {
|
|
|
356
356
|
deletedBatches.push(ids);
|
|
357
357
|
},
|
|
358
358
|
async onAllConversationsCleared() {},
|
|
359
|
-
onWorkerStartup() {},
|
|
360
|
-
countMemoryBufferLines() {
|
|
361
|
-
return 0;
|
|
362
|
-
},
|
|
363
|
-
hasPkbBufferContent() {
|
|
364
|
-
return false;
|
|
365
|
-
},
|
|
366
359
|
};
|
|
367
360
|
|
|
368
361
|
beforeEach(() => {
|
|
@@ -17,8 +17,6 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
|
17
17
|
|
|
18
18
|
import { getHooksFor } from "../hooks/registry.js";
|
|
19
19
|
import { RiskLevel } from "../permissions/types.js";
|
|
20
|
-
import { guardPersistenceHooksByDisabledState } from "../plugins/defaults/memory/persistence-hooks-registration.js";
|
|
21
|
-
import type { MessagePersistedEvent } from "../plugins/defaults/memory/persistence-lifecycle-seam.js";
|
|
22
20
|
import {
|
|
23
21
|
clearInjectorRegistry,
|
|
24
22
|
getRegisteredInjectors,
|
|
@@ -258,109 +256,4 @@ describe("per-surface disabled-state filtering", () => {
|
|
|
258
256
|
hooks = await getHooksFor("user-prompt-submit");
|
|
259
257
|
expect(hooks).toHaveLength(0);
|
|
260
258
|
});
|
|
261
|
-
|
|
262
|
-
test("persistence hooks no-op while the memory plugin is disabled", async () => {
|
|
263
|
-
let calls = 0;
|
|
264
|
-
const bufferLines = 25;
|
|
265
|
-
const guarded = guardPersistenceHooksByDisabledState("default-memory", {
|
|
266
|
-
onMessagePersisted() {
|
|
267
|
-
calls++;
|
|
268
|
-
},
|
|
269
|
-
onConversationForked() {},
|
|
270
|
-
onConversationWiped() {
|
|
271
|
-
return 0;
|
|
272
|
-
},
|
|
273
|
-
onConversationDeleted() {},
|
|
274
|
-
onMessagesDeleted() {},
|
|
275
|
-
async onAllConversationsCleared() {},
|
|
276
|
-
onWorkerStartup() {},
|
|
277
|
-
countMemoryBufferLines() {
|
|
278
|
-
return bufferLines;
|
|
279
|
-
},
|
|
280
|
-
hasPkbBufferContent() {
|
|
281
|
-
return true;
|
|
282
|
-
},
|
|
283
|
-
});
|
|
284
|
-
const event: MessagePersistedEvent = {
|
|
285
|
-
messageId: "msg-1",
|
|
286
|
-
conversationId: "conv-1",
|
|
287
|
-
role: "user",
|
|
288
|
-
content: "[]",
|
|
289
|
-
createdAt: 0,
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
// Enabled: the wrapped handler runs.
|
|
293
|
-
await guarded.onMessagePersisted(event);
|
|
294
|
-
expect(calls).toBe(1);
|
|
295
|
-
// The gated queries return the real buffer state while enabled.
|
|
296
|
-
expect(guarded.countMemoryBufferLines()).toBe(25);
|
|
297
|
-
expect(guarded.hasPkbBufferContent()).toBe(true);
|
|
298
|
-
|
|
299
|
-
// Disable via sentinel — checked at call time, no restart needed.
|
|
300
|
-
await createSentinel("default-memory");
|
|
301
|
-
await guarded.onMessagePersisted(event);
|
|
302
|
-
expect(calls).toBe(1);
|
|
303
|
-
// Gated: reports empty buffers while disabled, so scheduled consolidation
|
|
304
|
-
// and filing stay inert.
|
|
305
|
-
expect(guarded.countMemoryBufferLines()).toBe(0);
|
|
306
|
-
expect(guarded.hasPkbBufferContent()).toBe(false);
|
|
307
|
-
|
|
308
|
-
// Re-enable.
|
|
309
|
-
await removeSentinel("default-memory");
|
|
310
|
-
await guarded.onMessagePersisted(event);
|
|
311
|
-
expect(calls).toBe(2);
|
|
312
|
-
expect(guarded.countMemoryBufferLines()).toBe(25);
|
|
313
|
-
expect(guarded.hasPkbBufferContent()).toBe(true);
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
test("cleanup persistence hooks run even while the memory plugin is disabled", async () => {
|
|
317
|
-
let wiped = 0;
|
|
318
|
-
let swept = 0;
|
|
319
|
-
const deleted: string[][] = [];
|
|
320
|
-
const convDeleted: string[] = [];
|
|
321
|
-
let cleared = 0;
|
|
322
|
-
const guarded = guardPersistenceHooksByDisabledState("default-memory", {
|
|
323
|
-
onMessagePersisted() {},
|
|
324
|
-
onConversationForked() {},
|
|
325
|
-
onConversationWiped() {
|
|
326
|
-
wiped++;
|
|
327
|
-
return 7;
|
|
328
|
-
},
|
|
329
|
-
onConversationDeleted(id) {
|
|
330
|
-
convDeleted.push(id);
|
|
331
|
-
},
|
|
332
|
-
onMessagesDeleted(ids) {
|
|
333
|
-
deleted.push(ids);
|
|
334
|
-
},
|
|
335
|
-
async onAllConversationsCleared() {
|
|
336
|
-
cleared++;
|
|
337
|
-
},
|
|
338
|
-
onWorkerStartup() {
|
|
339
|
-
swept++;
|
|
340
|
-
},
|
|
341
|
-
countMemoryBufferLines() {
|
|
342
|
-
return 0;
|
|
343
|
-
},
|
|
344
|
-
hasPkbBufferContent() {
|
|
345
|
-
return false;
|
|
346
|
-
},
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
await createSentinel("default-memory");
|
|
350
|
-
|
|
351
|
-
// Cleanup hooks are NOT gated: they must still run (and return real values)
|
|
352
|
-
// while disabled, or state created while enabled would be orphaned.
|
|
353
|
-
expect(guarded.onConversationWiped("conv-1")).toBe(7);
|
|
354
|
-
guarded.onConversationDeleted("conv-9");
|
|
355
|
-
guarded.onMessagesDeleted(["msg-1", "msg-2"]);
|
|
356
|
-
await guarded.onAllConversationsCleared();
|
|
357
|
-
guarded.onWorkerStartup();
|
|
358
|
-
expect(wiped).toBe(1);
|
|
359
|
-
expect(convDeleted).toEqual(["conv-9"]);
|
|
360
|
-
expect(deleted).toEqual([["msg-1", "msg-2"]]);
|
|
361
|
-
expect(cleared).toBe(1);
|
|
362
|
-
expect(swept).toBe(1);
|
|
363
|
-
|
|
364
|
-
await removeSentinel("default-memory");
|
|
365
|
-
});
|
|
366
259
|
});
|
|
@@ -218,7 +218,6 @@ const BASELINE: Record<string, readonly string[]> = {
|
|
|
218
218
|
"../../../util/sqlite-retry.js",
|
|
219
219
|
"../../../util/strip-comment-lines.js",
|
|
220
220
|
"../../../util/worker-memory.js",
|
|
221
|
-
"../../disabled-state.js",
|
|
222
221
|
"../../types.js",
|
|
223
222
|
"../injection-presence.js",
|
|
224
223
|
"../injector-order.js",
|
|
@@ -71,15 +71,6 @@ const { enqueueMemoryJob } =
|
|
|
71
71
|
await import("../../../../persistence/jobs-store.js");
|
|
72
72
|
const { GRAPH_MAINTENANCE_CHECKPOINTS, maybeEnqueueGraphMaintenanceJobs } =
|
|
73
73
|
await import("../jobs-worker.js");
|
|
74
|
-
const { registerMemoryPersistenceHooks } =
|
|
75
|
-
await import("../persistence-lifecycle-seam.js");
|
|
76
|
-
const { memoryPersistenceHooks } = await import("../persistence-hooks.js");
|
|
77
|
-
|
|
78
|
-
// The scheduler reads the PKB buffer state through the persistence seam;
|
|
79
|
-
// register the real memory implementation so `hasPkbBufferContent` reflects
|
|
80
|
-
// the buffer files these tests write.
|
|
81
|
-
registerMemoryPersistenceHooks(memoryPersistenceHooks);
|
|
82
|
-
|
|
83
74
|
const FILING_KEY = GRAPH_MAINTENANCE_CHECKPOINTS.pkbFiling;
|
|
84
75
|
const COMPACTION_KEY = GRAPH_MAINTENANCE_CHECKPOINTS.pkbCompaction;
|
|
85
76
|
|
|
@@ -57,7 +57,6 @@ afterAll(() => {
|
|
|
57
57
|
process.env.VELLUM_WORKSPACE_DIR = previousWorkspaceEnv;
|
|
58
58
|
}
|
|
59
59
|
rmSync(tmpWorkspace, { recursive: true, force: true });
|
|
60
|
-
resetMemoryPersistenceHooksForTests();
|
|
61
60
|
});
|
|
62
61
|
|
|
63
62
|
const { getMemoryDb } =
|
|
@@ -70,15 +69,6 @@ const { applyNestedDefaults } = await import("../../../../config/loader.js");
|
|
|
70
69
|
const { getMemoryCheckpoint, setMemoryCheckpoint, deleteMemoryCheckpoint } =
|
|
71
70
|
await import("../../../../persistence/checkpoints.js");
|
|
72
71
|
const { maybeEnqueueGraphMaintenanceJobs } = await import("../jobs-worker.js");
|
|
73
|
-
const { registerMemoryPersistenceHooks, resetMemoryPersistenceHooksForTests } =
|
|
74
|
-
await import("../persistence-lifecycle-seam.js");
|
|
75
|
-
const { memoryPersistenceHooks } = await import("../persistence-hooks.js");
|
|
76
|
-
|
|
77
|
-
// The scheduler reads the memory buffer's line count through the persistence
|
|
78
|
-
// seam; register the real memory implementation so `countMemoryBufferLines`
|
|
79
|
-
// reflects the buffer files these tests write.
|
|
80
|
-
registerMemoryPersistenceHooks(memoryPersistenceHooks);
|
|
81
|
-
|
|
82
72
|
const CONSOLIDATE_CHECKPOINT_KEY = "memory_v2_consolidate_last_run";
|
|
83
73
|
|
|
84
74
|
function buildConfig(overrides: {
|
|
@@ -26,13 +26,6 @@ const baseHooks: MemoryPersistenceHooks = {
|
|
|
26
26
|
onConversationDeleted() {},
|
|
27
27
|
onMessagesDeleted() {},
|
|
28
28
|
async onAllConversationsCleared() {},
|
|
29
|
-
onWorkerStartup() {},
|
|
30
|
-
countMemoryBufferLines() {
|
|
31
|
-
return 0;
|
|
32
|
-
},
|
|
33
|
-
hasPkbBufferContent() {
|
|
34
|
-
return false;
|
|
35
|
-
},
|
|
36
29
|
};
|
|
37
30
|
|
|
38
31
|
describe("memory persistence-lifecycle seam", () => {
|
|
@@ -43,18 +36,6 @@ describe("memory persistence-lifecycle seam", () => {
|
|
|
43
36
|
await getMemoryPersistenceHooks().onMessagePersisted(event);
|
|
44
37
|
});
|
|
45
38
|
|
|
46
|
-
test("countMemoryBufferLines defaults to 0 when memory is not present", () => {
|
|
47
|
-
expect(getMemoryPersistenceHooks().countMemoryBufferLines()).toBe(0);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
test("countMemoryBufferLines returns the registered implementation's count", () => {
|
|
51
|
-
registerMemoryPersistenceHooks({
|
|
52
|
-
...baseHooks,
|
|
53
|
-
countMemoryBufferLines: () => 42,
|
|
54
|
-
});
|
|
55
|
-
expect(getMemoryPersistenceHooks().countMemoryBufferLines()).toBe(42);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
39
|
test("getMemoryPersistenceHooks returns the registered implementation", async () => {
|
|
59
40
|
const seen: MessagePersistedEvent[] = [];
|
|
60
41
|
registerMemoryPersistenceHooks({
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
|
|
1
3
|
import { getConfig } from "../../../config/loader.js";
|
|
2
4
|
import { isMemoryV3Live } from "../../../config/memory-v3-gate.js";
|
|
3
5
|
import type { AssistantConfig } from "../../../config/types.js";
|
|
@@ -49,7 +51,10 @@ import {
|
|
|
49
51
|
} from "../../../persistence/jobs-store.js";
|
|
50
52
|
import { spawnMemoryWorkerProcess } from "../../../persistence/worker-control.js";
|
|
51
53
|
import { getLogger } from "../../../util/logger.js";
|
|
52
|
-
import {
|
|
54
|
+
import { getWorkspaceDir } from "../../../util/platform.js";
|
|
55
|
+
import { sweepOrphanMemoryRetrospectiveConversations } from "./memory-retrospective-startup-cleanup.js";
|
|
56
|
+
import { hasPkbBufferContent } from "./pkb-schedule.js";
|
|
57
|
+
import { countBufferLines } from "./v2/consolidation-job.js";
|
|
53
58
|
|
|
54
59
|
const log = getLogger("memory-jobs-worker");
|
|
55
60
|
|
|
@@ -240,7 +245,7 @@ export function startInProcessMemoryJobsWorker(
|
|
|
240
245
|
// left behind by daemon crashes mid-job. Best-effort — never block worker
|
|
241
246
|
// startup on cleanup failures.
|
|
242
247
|
try {
|
|
243
|
-
|
|
248
|
+
sweepOrphanMemoryRetrospectiveConversations();
|
|
244
249
|
} catch (err) {
|
|
245
250
|
log.warn(
|
|
246
251
|
{ err },
|
|
@@ -773,6 +778,11 @@ function isWithinPkbActiveHours(
|
|
|
773
778
|
return hour >= start || hour < end;
|
|
774
779
|
}
|
|
775
780
|
|
|
781
|
+
/** Line count of the memory buffer, the scheduler's consolidation gate. */
|
|
782
|
+
function memoryBufferLineCount(): number {
|
|
783
|
+
return countBufferLines(join(getWorkspaceDir(), "memory", "buffer.md"));
|
|
784
|
+
}
|
|
785
|
+
|
|
776
786
|
export function maybeEnqueueGraphMaintenanceJobs(
|
|
777
787
|
config: AssistantConfig,
|
|
778
788
|
nowMs = Date.now(),
|
|
@@ -846,10 +856,7 @@ export function maybeEnqueueGraphMaintenanceJobs(
|
|
|
846
856
|
// The checkpoint advances so the next check fires after the regular
|
|
847
857
|
// interval. Manual "Run now" is unaffected (routes layer, not schedule).
|
|
848
858
|
if (jobType === consolidateEntry.jobType) {
|
|
849
|
-
if (
|
|
850
|
-
getMemoryPersistenceHooks().countMemoryBufferLines() <
|
|
851
|
-
MIN_BUFFER_LINES_FOR_CONSOLIDATION
|
|
852
|
-
) {
|
|
859
|
+
if (memoryBufferLineCount() < MIN_BUFFER_LINES_FOR_CONSOLIDATION) {
|
|
853
860
|
log.debug(
|
|
854
861
|
"Scheduled consolidation skipped: buffer under minimum line threshold",
|
|
855
862
|
);
|
|
@@ -884,7 +891,7 @@ export function maybeEnqueueGraphMaintenanceJobs(
|
|
|
884
891
|
maxLines !== null &&
|
|
885
892
|
!hasActiveJobOfType(consolidateEntry.jobType)
|
|
886
893
|
) {
|
|
887
|
-
if (
|
|
894
|
+
if (memoryBufferLineCount() >= maxLines) {
|
|
888
895
|
enqueueMemoryJob(
|
|
889
896
|
consolidateEntry.jobType,
|
|
890
897
|
AUTOMATIC_CONSOLIDATION_JOB_PAYLOAD,
|
|
@@ -926,7 +933,7 @@ export function maybeEnqueueGraphMaintenanceJobs(
|
|
|
926
933
|
intervalMs: filingConfig.intervalMs,
|
|
927
934
|
jobType: "pkb_filing",
|
|
928
935
|
enabled: filingConfig.enabled,
|
|
929
|
-
hasWork: () =>
|
|
936
|
+
hasWork: () => hasPkbBufferContent(),
|
|
930
937
|
},
|
|
931
938
|
{
|
|
932
939
|
key: GRAPH_MAINTENANCE_CHECKPOINTS.pkbCompaction,
|
|
@@ -1,95 +1,23 @@
|
|
|
1
|
-
import { isPluginDisabled } from "../../disabled-state.js";
|
|
2
|
-
import memoryPkg from "./package.json" with { type: "json" };
|
|
3
1
|
import { memoryPersistenceHooks } from "./persistence-hooks.js";
|
|
4
|
-
import {
|
|
5
|
-
type MemoryPersistenceHooks,
|
|
6
|
-
registerMemoryPersistenceHooks,
|
|
7
|
-
} from "./persistence-lifecycle-seam.js";
|
|
2
|
+
import { registerMemoryPersistenceHooks } from "./persistence-lifecycle-seam.js";
|
|
8
3
|
|
|
9
4
|
/**
|
|
10
5
|
* Registration entry point for the memory plugin's persistence-lifecycle seam
|
|
11
6
|
* (`persistence-lifecycle-seam.ts`): wires the plugin's handler implementation
|
|
12
|
-
* (`persistence-hooks.ts`) into the seam's slot
|
|
13
|
-
* guard.
|
|
7
|
+
* (`persistence-hooks.ts`) into the seam's slot.
|
|
14
8
|
*
|
|
15
9
|
* Kept separate from the seam module on purpose: this module transitively
|
|
16
10
|
* imports persistence (through the handler implementation) while persistence
|
|
17
11
|
* imports the seam, so folding the two together would close an import cycle.
|
|
18
12
|
*/
|
|
19
13
|
|
|
20
|
-
/**
|
|
21
|
-
* Wrap the plugin's persistence hooks so its ACTIVE side-effect hooks no-op while
|
|
22
|
-
* the plugin is disabled (`assistant plugins disable <name>`), mirroring the
|
|
23
|
-
* read-time disabled-state filtering the injector/hook/job-handler/tool surfaces
|
|
24
|
-
* apply. The sentinel is checked per call, so enable/disable takes effect on the
|
|
25
|
-
* next write without a daemon restart. CLEANUP hooks (`onConversationWiped`,
|
|
26
|
-
* `onConversationDeleted`, `onMessagesDeleted`, `onAllConversationsCleared`,
|
|
27
|
-
* `onWorkerStartup`) are intentionally NOT gated — they must run even when the
|
|
28
|
-
* plugin is disabled so state created while it was enabled is not orphaned.
|
|
29
|
-
*/
|
|
30
|
-
export function guardPersistenceHooksByDisabledState(
|
|
31
|
-
pluginName: string,
|
|
32
|
-
hooks: MemoryPersistenceHooks,
|
|
33
|
-
): MemoryPersistenceHooks {
|
|
34
|
-
return {
|
|
35
|
-
onMessagePersisted(event) {
|
|
36
|
-
if (isPluginDisabled(pluginName)) return;
|
|
37
|
-
return hooks.onMessagePersisted(event);
|
|
38
|
-
},
|
|
39
|
-
onConversationForked(event) {
|
|
40
|
-
if (isPluginDisabled(pluginName)) return;
|
|
41
|
-
return hooks.onConversationForked(event);
|
|
42
|
-
},
|
|
43
|
-
// Gated like the active side effects above: a disabled plugin reports an
|
|
44
|
-
// empty buffer, so the maintenance scheduler treats it as "no buffered
|
|
45
|
-
// work" and skips consolidation — matching how disabled injectors/hooks go
|
|
46
|
-
// inert.
|
|
47
|
-
countMemoryBufferLines() {
|
|
48
|
-
if (isPluginDisabled(pluginName)) return 0;
|
|
49
|
-
return hooks.countMemoryBufferLines();
|
|
50
|
-
},
|
|
51
|
-
// Gated the same way: a disabled plugin reports an empty PKB buffer, so
|
|
52
|
-
// the maintenance scheduler skips scheduled filing.
|
|
53
|
-
hasPkbBufferContent() {
|
|
54
|
-
if (isPluginDisabled(pluginName)) return false;
|
|
55
|
-
return hooks.hasPkbBufferContent();
|
|
56
|
-
},
|
|
57
|
-
// Cleanup hooks are NOT gated on disabled-state: they must run even while
|
|
58
|
-
// the plugin is disabled, or jobs/conversations created while it was
|
|
59
|
-
// enabled would be orphaned.
|
|
60
|
-
onConversationWiped(conversationId) {
|
|
61
|
-
return hooks.onConversationWiped(conversationId);
|
|
62
|
-
},
|
|
63
|
-
onConversationDeleted(conversationId) {
|
|
64
|
-
return hooks.onConversationDeleted(conversationId);
|
|
65
|
-
},
|
|
66
|
-
onMessagesDeleted(messageIds) {
|
|
67
|
-
return hooks.onMessagesDeleted(messageIds);
|
|
68
|
-
},
|
|
69
|
-
onAllConversationsCleared() {
|
|
70
|
-
return hooks.onAllConversationsCleared();
|
|
71
|
-
},
|
|
72
|
-
onWorkerStartup() {
|
|
73
|
-
return hooks.onWorkerStartup();
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
14
|
/**
|
|
79
15
|
* Install the memory feature's persistence-lifecycle handlers into the seam.
|
|
80
16
|
* `bootstrapPlugins` calls this before the per-plugin init loop so the seam is
|
|
81
17
|
* wired up front (the standalone memory jobs worker, which has no plugin
|
|
82
|
-
* bootstrap, calls it directly)
|
|
83
|
-
*
|
|
84
|
-
* drives no persistence side effects and re-enabling it takes effect on the
|
|
85
|
-
* next write. The seam holds a single handler set, so this replaces any prior
|
|
86
|
-
* registration.
|
|
18
|
+
* bootstrap, calls it directly). The seam holds a single handler set, so this
|
|
19
|
+
* replaces any prior registration.
|
|
87
20
|
*/
|
|
88
21
|
export function registerDefaultPluginPersistenceHooks(): void {
|
|
89
|
-
registerMemoryPersistenceHooks(
|
|
90
|
-
guardPersistenceHooksByDisabledState(
|
|
91
|
-
memoryPkg.name,
|
|
92
|
-
memoryPersistenceHooks,
|
|
93
|
-
),
|
|
94
|
-
);
|
|
22
|
+
registerMemoryPersistenceHooks(memoryPersistenceHooks);
|
|
95
23
|
}
|
|
@@ -1,29 +1,23 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
|
-
|
|
3
1
|
import { getConfig } from "../../../config/loader.js";
|
|
4
2
|
import {
|
|
5
3
|
clearMessagesLexicalIndex,
|
|
6
4
|
enqueueDeleteMessageLexical,
|
|
7
5
|
enqueuePurgeConversationLexical,
|
|
8
6
|
} from "../../../persistence/job-handlers/message-lexical.js";
|
|
9
|
-
import { getWorkspaceDir } from "../../../util/platform.js";
|
|
10
7
|
import { getMemoryConfig } from "./config.js";
|
|
11
8
|
import { forkGraphMemoryState } from "./graph/graph-memory-state-store.js";
|
|
12
9
|
import { indexMessageNow } from "./indexer.js";
|
|
13
|
-
import { sweepOrphanMemoryRetrospectiveConversations } from "./memory-retrospective-startup-cleanup.js";
|
|
14
10
|
import { forkRetrospectiveState } from "./memory-retrospective-state.js";
|
|
15
11
|
import type {
|
|
16
12
|
ConversationForkedEvent,
|
|
17
13
|
MemoryPersistenceHooks,
|
|
18
14
|
MessagePersistedEvent,
|
|
19
15
|
} from "./persistence-lifecycle-seam.js";
|
|
20
|
-
import { hasPkbBufferContent as pkbBufferHasContent } from "./pkb-schedule.js";
|
|
21
16
|
import { cancelPendingJobsForConversation } from "./task-memory-cleanup.js";
|
|
22
17
|
import {
|
|
23
18
|
forkActivationState,
|
|
24
19
|
seedForkActivationState,
|
|
25
20
|
} from "./v2/activation-store.js";
|
|
26
|
-
import { countBufferLines } from "./v2/consolidation-job.js";
|
|
27
21
|
import {
|
|
28
22
|
extractInjectedConceptSlugs,
|
|
29
23
|
readInjectedBlock,
|
|
@@ -154,16 +148,4 @@ export const memoryPersistenceHooks: MemoryPersistenceHooks = {
|
|
|
154
148
|
// be erased when the drop lands.
|
|
155
149
|
await clearMessagesLexicalIndex(getConfig());
|
|
156
150
|
},
|
|
157
|
-
|
|
158
|
-
onWorkerStartup(): void {
|
|
159
|
-
sweepOrphanMemoryRetrospectiveConversations();
|
|
160
|
-
},
|
|
161
|
-
|
|
162
|
-
countMemoryBufferLines(): number {
|
|
163
|
-
return countBufferLines(join(getWorkspaceDir(), "memory", "buffer.md"));
|
|
164
|
-
},
|
|
165
|
-
|
|
166
|
-
hasPkbBufferContent(): boolean {
|
|
167
|
-
return pkbBufferHasContent();
|
|
168
|
-
},
|
|
169
151
|
};
|
|
@@ -134,31 +134,6 @@ export interface MemoryPersistenceHooks {
|
|
|
134
134
|
* collection that is about to be dropped).
|
|
135
135
|
*/
|
|
136
136
|
onAllConversationsCleared(): Promise<void>;
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* The background-job worker is starting. The memory feature sweeps orphan
|
|
140
|
-
* retrospective conversations left by a crash mid-job. Best-effort; the caller
|
|
141
|
-
* wraps it in try/catch. Cleanup — runs even while the plugin is disabled.
|
|
142
|
-
*/
|
|
143
|
-
onWorkerStartup(): void;
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Current line count of the memory buffer (`memory/buffer.md`). The
|
|
147
|
-
* maintenance scheduler reads it to gate scheduled consolidation — skip a
|
|
148
|
-
* scheduled run below a floor, force one above a ceiling. Returns 0 when
|
|
149
|
-
* memory is not present, which the scheduler reads as "no buffered work" and
|
|
150
|
-
* therefore no consolidation.
|
|
151
|
-
*/
|
|
152
|
-
countMemoryBufferLines(): number;
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Whether the PKB buffer (`pkb/buffer.md`) has any filable content. The
|
|
156
|
-
* maintenance scheduler reads it to gate the scheduled `pkb_filing` job —
|
|
157
|
-
* an empty buffer means no work, so no LLM run. Returns false when memory
|
|
158
|
-
* is not present, which the scheduler reads as "no buffered work" and
|
|
159
|
-
* therefore no filing.
|
|
160
|
-
*/
|
|
161
|
-
hasPkbBufferContent(): boolean;
|
|
162
137
|
}
|
|
163
138
|
|
|
164
139
|
const NOOP: MemoryPersistenceHooks = {
|
|
@@ -170,13 +145,6 @@ const NOOP: MemoryPersistenceHooks = {
|
|
|
170
145
|
onConversationDeleted() {},
|
|
171
146
|
onMessagesDeleted() {},
|
|
172
147
|
async onAllConversationsCleared() {},
|
|
173
|
-
onWorkerStartup() {},
|
|
174
|
-
countMemoryBufferLines() {
|
|
175
|
-
return 0;
|
|
176
|
-
},
|
|
177
|
-
hasPkbBufferContent() {
|
|
178
|
-
return false;
|
|
179
|
-
},
|
|
180
148
|
};
|
|
181
149
|
|
|
182
150
|
let current: MemoryPersistenceHooks = NOOP;
|