45 lines
1.7 KiB
TypeScript
45 lines
1.7 KiB
TypeScript
/**
|
|||
|
|
* What is new or changed in agent memory since the user last looked.
|
||
|
|
*
|
||
|
|
* Derived from the entry's own timestamps against a per-scope "last viewed"
|
||
|
|
* mark, so the store carries no review state and the user is never asked to
|
||
|
|
* confirm anything. Looking at the tab is the acknowledgement.
|
||
|
|
*
|
||
|
|
* The two badges are worth separating: a memory the agent has just invented
|
||
|
|
* and one it has quietly rewritten need different attention, and lumping them
|
||
|
|
* together as "new" would hide every correction.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import type { AgentMemoryEntry, AgentMemoryScope } from './agentMemoryApi';
|
||
|
|
|
||
|
|
export type MemoryBadge = 'new' | 'changed' | null;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The key a scope's mark is stored under. Project marks are keyed by path
|
||
|
|
* because each project has its own store — one shared mark would let opening
|
||
|
|
* one project silently clear another's badges.
|
||
|
|
*/
|
||
|
|
export const memoryViewKey = (scope: AgentMemoryScope, projectPath: string | null): string => (
|
||
|
|
scope === 'global' ? 'global' : `project:${projectPath ?? ''}`
|
||
|
|
);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* `viewedAt` of 0 means the user has never opened this scope. Everything stored
|
||
|
|
* is then genuinely new to them, which is what a first look should show.
|
||
|
|
*/
|
||
|
|
export const classifyMemory = (entry: AgentMemoryEntry, viewedAt: number): MemoryBadge => {
|
||
|
|
if (entry.createdAt > viewedAt) {
|
||
|
|
return 'new';
|
||
|
|
}
|
||
|
|
// Only a change the user has not seen counts. An entry rewritten before their
|
||
|
|
// last look was already accounted for by that look.
|
||
|
|
if (entry.updatedAt > viewedAt) {
|
||
|
|
return 'changed';
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
};
|
||
|
|
|
||
|
|
export const countHighlightedMemories = (entries: AgentMemoryEntry[], viewedAt: number): number => (
|
||
|
|
entries.reduce((total, entry) => (classifyMemory(entry, viewedAt) ? total + 1 : total), 0)
|
||
|
|
);
|