context: [project] block plumbing (Phase 6 commit #1)
Foundation for Phase 6 — adds the field + composer + composition order with no callers yet. Nothing sets ctx.project; the meta hookup and startup auto-inject land in commit #2. Changes: - Context.new gains `project` (string, nil) and `_project_opts` (cached scan opts for `:tree refresh`; R7). - compose_project(text) helper mirrors compose_background / compose_summary. Returns "" for nil/empty; otherwise emits "\n\n[project]\n" + text. - to_messages inserts compose_project BETWEEN compose_background and compose_summary so the model reads memory facts -> project tree -> earlier conversation -> NORRIS suffix. - Same Norris-suppression guard as the other two dynamic blocks (R-C1 / R-C4 parity; planner stays on goal anchor). - Context:reset preserves ctx.project (R8 — matches the Phase 4 memory_items rule; startup-injected facts survive a user-driven context reset). Smoke verified (14/14 inline cases): - project nil -> no [project] block in sys_content - project set -> block present with contents - ordering: [background] < [project] < [earlier conversation summary] - norris_active suppresses all three; NORRIS suffix still appears - :reset clears turns/pending_exec_output/summary; preserves memory_items AND project Regression: test_safety 87/87, test_router_model 31/31, repl loads. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+20
-4
@@ -56,6 +56,12 @@ function M.new(opts)
|
||||
summarize_fn = opts.summarize_fn,
|
||||
summary = nil, -- rolling summary string
|
||||
max_summary_chars = opts.max_summary_chars or 2000,
|
||||
-- Phase 6 (#issue Phase 6 §6): project file-tree block, set by
|
||||
-- repl.lua via :tree meta or the cfg.project.auto_tree startup
|
||||
-- hook. nil = no block injected. Cached scan opts (depth /
|
||||
-- max_chars overrides) live on _project_opts for :tree refresh.
|
||||
project = nil,
|
||||
_project_opts = nil,
|
||||
}, Context)
|
||||
end
|
||||
|
||||
@@ -171,6 +177,15 @@ local function compose_summary(summary_text)
|
||||
return "\n\n[earlier conversation summary]\n" .. summary_text
|
||||
end
|
||||
|
||||
-- Phase 6: project file-tree composer. Inserted between [background]
|
||||
-- and [earlier summary] so the reading order is memory facts →
|
||||
-- project tree → earlier conversation → NORRIS suffix. Same Norris-
|
||||
-- suppression rule (callers gate via self.norris_active).
|
||||
local function compose_project(project_text)
|
||||
if not project_text or project_text == "" then return "" end
|
||||
return "\n\n[project]\n" .. project_text
|
||||
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.
|
||||
@@ -200,12 +215,13 @@ message if they declined.]]
|
||||
|
||||
function Context:to_messages()
|
||||
local sys_content = self.system_prompt
|
||||
-- Phase 4 [background] memory block + Phase 5 [earlier summary]
|
||||
-- block. Both suppressed during Norris (R-C1 / R-C4 — avoid
|
||||
-- redundant tokens per planning iteration; planner stays focused
|
||||
-- on its goal anchor).
|
||||
-- Phase 4 [background] memory block + Phase 6 [project] file-tree
|
||||
-- block + Phase 5 [earlier summary] block. All suppressed during
|
||||
-- Norris (R-C1 / R-C4 — avoid redundant tokens per planning
|
||||
-- iteration; planner stays focused on its goal anchor).
|
||||
if not self.norris_active then
|
||||
sys_content = sys_content .. compose_background(self.memory_items)
|
||||
sys_content = sys_content .. compose_project(self.project)
|
||||
sys_content = sys_content .. compose_summary(self.summary)
|
||||
end
|
||||
-- Phase 3 NORRIS MODE suffix. Last block so its instructions dominate.
|
||||
|
||||
Reference in New Issue
Block a user