70 lines
2.6 KiB
TypeScript
70 lines
2.6 KiB
TypeScript
/**
|
|
* Compact, token-cheap rendering of Mem0 results for the model context.
|
|
*
|
|
* Mirrors the format used by the sibling Mem0 plugins
|
|
* (integrations/pi-agent-plugin/src/memory/formatting.ts) so a memory reads the
|
|
* same way across every harness: `[category] text (age) [mem0:id]`. Dumping the
|
|
* raw search envelope instead would spend most of the tokens on JSON scaffolding.
|
|
*/
|
|
|
|
export interface MemoryLike {
|
|
id: string;
|
|
memory?: string;
|
|
categories?: string[];
|
|
createdAt?: Date | string;
|
|
}
|
|
|
|
export function formatAge(date: Date | string): string {
|
|
const d = typeof date === "string" ? new Date(date) : date;
|
|
const ms = Date.now() - d.getTime();
|
|
const minutes = Math.floor(ms / 60_000);
|
|
if (minutes < 60) return `${minutes}m ago`;
|
|
const hours = Math.floor(minutes / 60);
|
|
if (hours < 24) return `${hours}h ago`;
|
|
const days = Math.floor(hours / 24);
|
|
return `${days}d ago`;
|
|
}
|
|
|
|
export function formatMemoryCompact(mem: MemoryLike): string {
|
|
const cat = mem.categories?.[0] ?? "uncategorized";
|
|
const age = mem.createdAt ? ` (${formatAge(mem.createdAt)})` : "";
|
|
return `[${cat}] ${mem.memory ?? "(empty)"}${age} [mem0:${mem.id}]`;
|
|
}
|
|
|
|
export function formatMemoryList(memories: MemoryLike[]): string {
|
|
if (memories.length === 0) return "No memories found.";
|
|
return memories
|
|
.map((m, i) => `${i + 1}. ${formatMemoryCompact(m)}`)
|
|
.join("\n");
|
|
}
|
|
|
|
/**
|
|
* One-line confirmation for a write.
|
|
*
|
|
* `client.add` hits the async `/v3/memories/add/` endpoint, which returns
|
|
* `{ event_id, status: "PENDING" }` — extraction runs server-side *after* the
|
|
* call returns, so the extracted memories are not in this response. Report the
|
|
* write as queued in that case; only render a list when the backend actually
|
|
* returns memories (older / OSS shapes).
|
|
*/
|
|
export function formatAddResult(result: unknown): string {
|
|
const items: MemoryLike[] = Array.isArray(result)
|
|
? (result as MemoryLike[])
|
|
: ((result as { results?: MemoryLike[] } | null)?.results ??
|
|
(result ? [result as MemoryLike] : []));
|
|
|
|
const pending = items.find(
|
|
(r) => (r as { status?: string }).status === "PENDING",
|
|
) as { eventId?: string; event_id?: string } | undefined;
|
|
if (pending) {
|
|
// The SDK camel-cases response keys (event_id -> eventId); accept either.
|
|
const id = pending.eventId ?? pending.event_id;
|
|
const evt = id ? ` (event ${id})` : "";
|
|
return `Memory queued for background extraction${evt}; it will be searchable shortly.`;
|
|
}
|
|
|
|
if (items.length === 0) return "Memory stored.";
|
|
const noun = items.length === 1 ? "memory" : "memories";
|
|
return `Stored ${items.length} ${noun}:\n${formatMemoryList(items)}`;
|
|
}
|