/** * The shared `…` injection marker. * * Both the v2 graph-memory producers (`conversation-graph-memory.ts`) and the * v3 live renderer (`v3/render-injection.ts`) emit memory blocks with this * exact wrapper, and the strip/recognition machinery in * `conversation-graph-memory.ts` (`countMemoryPrefixBlocks`) matches the same * `"\n"` / `"\n"` delimiters. Keeping the producer wrapper in * one leaf module guarantees the byte-for-byte marker contract across v2 and * v3 — a change here updates every producer at once. * * This is a tiny dependency-free leaf so the pure v3 renderer can import it * without pulling in the heavyweight graph-memory module. */ export function wrapMemoryBlock(text: string): string { return `\n${text}\n`; } /** * Inverse of {@link wrapMemoryBlock}: recover the inner text from a wrapped * block. Only unwraps when the full `\n…\n` pair is present, * so payloads that merely start with the opening tag pass through unchanged — * the same defensive guard the metadata rehydration in * `daemon/conversation.ts` applies. */ export function unwrapMemoryBlock(block: string): string { return block.startsWith("\n") && block.endsWith("\n") ? block.slice("\n".length, -"\n".length) : block; } /** * The memory-v3 ephemeral spotlight wrapper. Unlike `` card blocks * (frozen into history), the spotlight block is re-rendered onto the current * user tail every turn: the per-turn scoped strip in * `context/strip-injections.ts` (`stripSpotlightInjections`) and the * compaction matcher in `RUNTIME_INJECTION_PREFIXES` both key off this exact * prefix/suffix pair, so the producer wrapper lives here beside the `` * marker it parallels. */ export const MEMORY_SPOTLIGHT_PREFIX = "\n"; export const MEMORY_SPOTLIGHT_SUFFIX = "\n"; export function wrapMemorySpotlightBlock(text: string): string { return `${MEMORY_SPOTLIGHT_PREFIX}${text}${MEMORY_SPOTLIGHT_SUFFIX}`; }