mirror of
https://github.com/sdwolf4103/opencode-working-memory.git
synced 2026-07-17 12:56:42 +02:00
fix: promotion accounting, sessionID extraction, and strengthened regression tests
Architecture review fixes: - Promotion accounting: only clear pending memories that survived workspace memory normalization/cap limits. Use retainedKeys from the returned normalized store instead of attemptedKeys. - Shared sessionID extraction: add sessionIDFromEventProperties() helper and use it in both session.compacted and session.deleted, fixing the previous gap where session.deleted only read info.id. - Strengthen compaction refresh test: seed workspace memory before first transform so firstSystem1 is non-empty, then assert refreshed system[1] preserves existing entries AND contains promoted memories.
This commit is contained in:
+14
-8
@@ -231,8 +231,7 @@ export const MemoryV2Plugin: Plugin = async (input) => {
|
||||
];
|
||||
if (pending.length === 0) return;
|
||||
|
||||
const promotedKeys = new Set<string>();
|
||||
await updateWorkspaceMemory(directory, workspaceMemory => {
|
||||
const updatedWorkspaceMemory = await updateWorkspaceMemory(directory, workspaceMemory => {
|
||||
const existingKeys = new Set(workspaceMemory.entries.map(memory => memoryKey(memory)));
|
||||
|
||||
for (const memory of pending) {
|
||||
@@ -241,21 +240,24 @@ export const MemoryV2Plugin: Plugin = async (input) => {
|
||||
workspaceMemory.entries.push(memory);
|
||||
existingKeys.add(key);
|
||||
}
|
||||
promotedKeys.add(key);
|
||||
}
|
||||
|
||||
return workspaceMemory;
|
||||
});
|
||||
|
||||
// Only clear pending memories that survived workspace normalization/limits.
|
||||
// updateWorkspaceMemory() may dedupe, supersede, redact, or cap entries.
|
||||
const retainedKeys = new Set(updatedWorkspaceMemory.entries.map(memory => memoryKey(memory)));
|
||||
|
||||
if (sessionID) {
|
||||
await updateSessionState(directory, sessionID, state => {
|
||||
state.pendingMemories = state.pendingMemories.filter(memory => !promotedKeys.has(memoryKey(memory)));
|
||||
state.pendingMemories = state.pendingMemories.filter(memory => !retainedKeys.has(memoryKey(memory)));
|
||||
return state;
|
||||
});
|
||||
clearFrozenWorkspaceMemoryCache(sessionID);
|
||||
}
|
||||
|
||||
await clearPendingMemories(directory, promotedKeys);
|
||||
await clearPendingMemories(directory, retainedKeys);
|
||||
}
|
||||
|
||||
function bashExitCode(hookOutput: unknown): number | undefined {
|
||||
@@ -314,6 +316,11 @@ export const MemoryV2Plugin: Plugin = async (input) => {
|
||||
frozenWorkspaceMemoryCache.delete(sessionID);
|
||||
}
|
||||
|
||||
function sessionIDFromEventProperties(properties: unknown): string | undefined {
|
||||
const props = properties as { sessionID?: string; info?: { id?: string } } | undefined;
|
||||
return props?.sessionID ?? props?.info?.id;
|
||||
}
|
||||
|
||||
return {
|
||||
// Inject workspace memory and hot session state into system prompt
|
||||
"experimental.chat.system.transform": async (hookInput, output) => {
|
||||
@@ -469,8 +476,7 @@ export const MemoryV2Plugin: Plugin = async (input) => {
|
||||
// Handle session events
|
||||
event: async ({ event }) => {
|
||||
if (event.type === "session.compacted") {
|
||||
const sessionID = (event.properties as { sessionID?: string; info?: { id?: string } })?.sessionID
|
||||
?? (event.properties as { info?: { id?: string } })?.info?.id;
|
||||
const sessionID = sessionIDFromEventProperties(event.properties);
|
||||
if (!sessionID) return;
|
||||
|
||||
// Sub-agents don't need post-compaction processing
|
||||
@@ -492,7 +498,7 @@ export const MemoryV2Plugin: Plugin = async (input) => {
|
||||
}
|
||||
|
||||
if (event.type === "session.deleted") {
|
||||
const sessionID = (event.properties as { info?: { id?: string } })?.info?.id;
|
||||
const sessionID = sessionIDFromEventProperties(event.properties);
|
||||
if (sessionID) {
|
||||
// Promote pending memories before deleting per-session state.
|
||||
// If promotion fails, leave session state and journal intact.
|
||||
|
||||
Reference in New Issue
Block a user