Skip to content

Commit b932c27

Browse files
Merge branch 'alfonso/task/bg_90037e897a2033cc-cortexkit-alfonso-prompts-issue-599-identity-sch'
Co-authored-by: Alfonso <alfonso-magic-context@users.noreply.github.com>
2 parents 5587093 + 64fc04a commit b932c27

14 files changed

Lines changed: 904 additions & 15 deletions

File tree

‎packages/pi-plugin/src/dreamer/index.test.ts‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,27 @@ describe("Pi dreamer wiring", () => {
607607
expect(registration?.embeddingConfig?.provider).toBe("local");
608608
});
609609

610+
// Pi schedules through the plugin's dream timer, which stops scheduling and
611+
// deletes the schedule rows of a project whose `memory.enabled` is false. Pi
612+
// must pass that setting through, not leave it unset (which means enabled).
613+
test("threads a disabled project memory into scheduled maintenance", async () => {
614+
db = createDb();
615+
let registration: { memoryEnabled?: boolean } | undefined;
616+
__test.setStartDreamScheduleTimerFactory(async (captured) => {
617+
registration = captured;
618+
return mock(() => {});
619+
});
620+
const opts = dreamerOptions({
621+
database: db,
622+
projectIdentity: "git:pi-memory-disabled",
623+
});
624+
625+
registerPiDreamerProject({ ...opts, memoryEnabled: false });
626+
await flushMicrotasks();
627+
628+
expect(registration?.memoryEnabled).toBe(false);
629+
});
630+
610631
test("threads OMP identity into scheduled dreamer model resolution", async () => {
611632
db = createDb();
612633
let harness: string | undefined;
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { log } from "../../../shared/logger";
2+
import type { Database } from "../../../shared/sqlite";
3+
import { getDreamState, setDreamState } from "./storage-dream-state";
4+
import { deleteTaskScheduleRowsForProject } from "./storage-task-schedule";
5+
import { identityHasProjectInput } from "./task-gates";
6+
7+
/**
8+
* Pruning visits every identity that holds schedule rows, so it runs at most
9+
* once per day across all processes sharing the store, not on every tick.
10+
*/
11+
export const IDLE_SCHEDULE_PRUNE_INTERVAL_MS = 24 * 60 * 60 * 1000;
12+
13+
/** dream_state key holding the epoch-ms time of the last idle-identity prune. */
14+
export const IDLE_SCHEDULE_PRUNE_AT_KEY = "schedule_idle_prune_at";
15+
16+
/**
17+
* Delete every schedule row of identities that can do nothing now.
18+
*
19+
* Any directory that hosted a session used to keep a full set of schedule rows
20+
* forever, even when it never produced a memory (chat folders, downloads,
21+
* scratch directories). The timer only visits directories open in a running
22+
* process, so those rows were never even evaluated again; they just piled up
23+
* in the store and on the dashboard. An identity with active memories is never
24+
* pruned. A pruned identity gets rows back from the normal seeding path once it
25+
* has input again.
26+
*
27+
* Throttled through dream_state to once per IDLE_SCHEDULE_PRUNE_INTERVAL_MS.
28+
* Returns the identities whose rows were deleted (empty when throttled).
29+
*/
30+
export function pruneIdleScheduleIdentities(db: Database, now: number): string[] {
31+
const last = Number(getDreamState(db, IDLE_SCHEDULE_PRUNE_AT_KEY));
32+
if (Number.isFinite(last) && last > 0 && now - last < IDLE_SCHEDULE_PRUNE_INTERVAL_MS) {
33+
return [];
34+
}
35+
// Claim the slot before the scan: two processes racing here both prune, and
36+
// deleting the same rows twice is harmless.
37+
setDreamState(db, IDLE_SCHEDULE_PRUNE_AT_KEY, String(now));
38+
39+
const identities = db
40+
.prepare<[], { project_path: string }>(
41+
"SELECT DISTINCT project_path FROM task_schedule_state",
42+
)
43+
.all()
44+
.map((row) => row.project_path);
45+
const pruned: string[] = [];
46+
for (const identity of identities) {
47+
if (identityHasProjectInput(db, identity, now)) continue;
48+
const removed = deleteTaskScheduleRowsForProject(db, identity);
49+
if (removed > 0) pruned.push(identity);
50+
}
51+
if (pruned.length > 0) {
52+
log(
53+
`[dreamer] pruned schedule rows of ${pruned.length} idle identit${pruned.length === 1 ? "y" : "ies"} (no memories, no recent sessions, no task input)`,
54+
);
55+
}
56+
return pruned;
57+
}

0 commit comments

Comments
 (0)