M5.2: agent memory
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 1m48s
CI / e2e (pull_request) Successful in 4m33s

remember(name, description, fact) and forget(name, why): control tools for
the driver (before the go-ahead too) and conversations, writing only the
agent's own vault folder, one note per fact with its provenance. No one
agrees first; each change is a line in the thread. The harness keeps the
index and puts it into the transcript once per item, with a hash.

At an item's close, completed or abandoned, a bounded memory pass (the
driver's model, its own transcript and view) records what was decided and
learned; it never holds the close up (tuning.memory.max_turns).

With the operator: corrections may be paraphrased (L6 changed), the model
forgets on its own, and nothing limits what may prompt a note. The walk
remembers and forgets, and checks nothing lands outside the agent's folder.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
This commit is contained in:
dongarandClaude Opus 5.5 committed 2026-10-08 23:05:45 +00:00
1 parent 2a35475eec
commit 2b26f0cff5
16 files changed
+604 -16

No files matched your search

+39
View File
@@ -53,9 +53,11 @@ from nisse_dev.loop.items import (
WAITING,
loop_of,
)
from nisse_dev.memory import Memory
from nisse_dev.oplog import OpLog
from nisse_dev.tools import Workspace
from nisse_dev.transport import InboundMessage, InMemoryTransport
from nisse_dev.vault import Vault
from nisse_dev.worker import InlineWorker
# How many walks, and from which seed: all 48 by default; CI runs fewer on a
@@ -95,6 +97,20 @@ class PolicyModel:
"the design has merged" in t for t in facts
)
path = f"docs/d{self.n}.md" if design else f"f{self.n}.py"
if "memory_done" in offered:
# The memory pass at a close (M5.2): a note, a forgetting, done.
roll = self.rng.random()
if roll < 0.3:
return [
call("remember", name=f"n{self.n % 4}", description="d", fact="f")
]
if roll < 0.55:
return [call("forget", name=f"n{self.n % 4}", why="superseded")]
return [call("memory_done", summary="done")]
if "remember" in offered and self.rng.random() < 0.06:
if self.rng.random() < 0.4:
return [call("forget", name=f"n{self.n % 4}", why="superseded")]
return [call("remember", name=f"n{self.n % 4}", description="d", fact="f")]
if "toolchain_ready" in offered:
# A preflight (M4.1): usually reported, sometimes badly or not.
if self.rng.random() < 0.15:
@@ -326,6 +342,15 @@ class Walk:
self.drop_in = 0
self.while_down: list[str] = []
self.checking = False # the walk's own checks see the real VM
# M5.2: the agent's memory, in a vault that also holds the
# operator's notes; nothing may land outside its own folder.
vault_root = Path(self.world["repo"].root).parent / "vault"
(vault_root / "notes").mkdir(parents=True, exist_ok=True)
(vault_root / "notes" / "Ops.md").write_text("the operator's\n")
self.memory = Memory(
Vault(vault_root, {"memory/nisse-dev": "rw", "notes": "ro"}),
"memory/nisse-dev",
)
real = SSHHost.execute
walk = self
@@ -420,6 +445,9 @@ class Walk:
preflight=True,
preflight_turns=3,
markers=str(self.markers),
vault=self.memory._vault,
memory=self.memory,
memory_turns=3,
)
transport.on_message(agent.on_message)
return agent, transport
@@ -677,6 +705,17 @@ class Walk:
where = f"seed {self.seed}, steps {self.steps}"
# M4.1: the driver never works on a project whose VM has no marker.
assert not self.unready, f"ready_before_work: {self.unready}: {where}"
# M5.2: the agent writes only its own memory folder.
root = self.memory._vault.root
strays = [
str(p.relative_to(root))
for p in root.rglob("*")
if p.is_file()
and not p.is_relative_to(root / "memory" / "nisse-dev")
and p != root / "notes" / "Ops.md"
]
assert not strays, f"memory_stays_home: {strays}: {where}"
assert (root / "notes" / "Ops.md").read_text() == "the operator's\n", where
# #137: no model works on a project whose build VM is out of reach.
assert not self.while_down, f"no_model_on_a_lost_vm: {self.while_down}: {where}"
# M4.3: nothing runs for a project whose build VM is blocked.