diff --git a/context.lua b/context.lua index 00222a1..01ea1ee 100644 --- a/context.lua +++ b/context.lua @@ -136,6 +136,22 @@ end -- model (user → assistant → user → assistant), no strict-template breakage. -- -- The system prompt is NOT stored in self.turns per §6. +-- Phase 4: [background] block composer. Memory items from memory.jsonl +-- are stored on self.memory_items (loaded by repl.lua at startup) and +-- rendered as a dim-styled suffix on the system prompt. Suppressed when +-- norris_active to avoid stacking large background contexts in +-- per-iteration broker calls (R-C1 review fold-in). Cap honored via +-- inject_max_chars argument from the caller (already truncated by repl). +local function compose_background(items) + if not items or #items == 0 then return "" end + local lines = { "", "", "[background] (memory.jsonl; manage via :memory)" } + for _, it in ipairs(items) do + lines[#lines + 1] = + ("- (%s) %s"):format(it.kind or "?", (it.content or ""):gsub("\n", " ")) + end + return table.concat(lines, "\n") +end + -- Phase 3: NORRIS MODE suffix appended to the system prompt when -- self.norris_active. Carries self.norris_goal so eviction of the -- user's "[norris] goal: ..." turn doesn't lose the anchor. @@ -165,6 +181,12 @@ message if they declined.]] function Context:to_messages() local sys_content = self.system_prompt + -- Phase 4 [background] memory block. Suppressed during Norris (R-C1 + -- — avoid ~16K of redundant tokens per planning iteration). + if not self.norris_active then + sys_content = sys_content .. compose_background(self.memory_items) + end + -- Phase 3 NORRIS MODE suffix. Last block so its instructions dominate. if self.norris_active and self.norris_goal then sys_content = sys_content .. string.format(NORRIS_SUFFIX_TEMPLATE, self.norris_goal)