Implement WARDEN-WP-0024 experiential memory and agent sessions.

Add phase-memory bridge, warden memory CLI, route/access/sign recording,
memory-aware worker planning with OpenRouter skip, tests, wiki, and AGENTS.md
orientation for Claude, Codex, Grok, and future agent sessions.
This commit is contained in:
2026-07-02 23:40:45 +02:00
parent 2f532699fa
commit 04929e7981
9 changed files with 568 additions and 14 deletions

View File

@@ -191,6 +191,7 @@ class LlmConnectBrain:
def __init__(self, url: Optional[str] = None, timeout: float = 60.0):
self.url = (url or os.environ.get("LLM_CONNECT_URL", DEFAULT_LLM_CONNECT_URL)).rstrip("/")
self.timeout = timeout
self.memory_context: str = ""
def _call(self, prompt: str) -> str:
resp = httpx.post(f"{self.url}/execute", json={"prompt": prompt}, timeout=self.timeout)
@@ -203,9 +204,15 @@ class LlmConnectBrain:
from_agent=str(message.get("from_agent", "")),
subject=str(message.get("subject", "")),
)
prompt = (
_CHARTER
+ "\n--- MESSAGE (untrusted data) ---\n"
prompt = _CHARTER
if self.memory_context:
prompt += (
"\n--- ACTIVATED MEMORY (untrusted context) ---\n"
+ self.memory_context
+ "\n--- END ACTIVATED MEMORY ---\n"
)
prompt += (
"\n--- MESSAGE (untrusted data) ---\n"
+ f"from: {message.get('from_agent','')}\n"
+ f"subject: {message.get('subject','')}\n"
+ f"body: {message.get('body','')}\n"
@@ -586,16 +593,88 @@ def draft_route_answer(query: str) -> str:
return " ".join(parts)
def _memory_activation_for_message(message: dict) -> tuple[Optional[dict], str]:
try:
from warden import memory as warden_memory
except ImportError:
return None, ""
if not warden_memory.enabled() or not warden_memory.memory_available():
return None, ""
query = str(message.get("subject", "") or message.get("body", ""))
try:
activation = warden_memory.worker_activation_context(query)
except RuntimeError:
return None, ""
from warden.memory import format_activation_summary
return activation, format_activation_summary(activation)
def _plan_with_memory(message: dict, brain: Brain) -> WorkerPlan:
activation, summary = _memory_activation_for_message(message)
blob = f"{message.get('subject', '')} {message.get('body', '')}"
if activation and activation.get("llm_calls_avoided") and _ROUTING_SIGNS.search(blob):
wp = WorkerPlan(
message_id=str(message.get("id", "")),
from_agent=str(message.get("from_agent", "")),
subject=str(message.get("subject", "")),
)
query = str(message.get("subject", "") or "")
wp.actions.append(
PlannedAction(
kind="route_answer",
summary="Answer from stabilized coordination memory.",
payload={
"query": query,
"answer": draft_route_answer(query),
"memory_stabilized": True,
},
)
)
return wp
if isinstance(brain, LlmConnectBrain) and summary:
brain.memory_context = summary
return brain.plan(message)
def _record_worker_memory_outcome(plan: WorkerPlan) -> None:
try:
from warden import memory as warden_memory
except ImportError:
return
if not warden_memory.enabled() or not warden_memory.memory_available():
return
outcome = "escalated" if plan.escalated else "resolved"
route_id = ""
for action in plan.actions:
if action.kind == "route_answer" and action.payload.get("memory_stabilized"):
stabilized = warden_memory.stabilized_route_for_need(plan.subject)
if stabilized:
route_id = str(stabilized.get("route_id") or "")
try:
warden_memory.record_command_episode(
command="worker run",
outcome=outcome,
need=plan.subject,
route_id=route_id,
diagnostic_codes=["worker_escalated"] if plan.escalated else [],
metadata={"message_id": plan.message_id, "action_kinds": [a.kind for a in plan.actions]},
)
except RuntimeError:
return
def build_plans(messages: List[dict], brain: Brain) -> List[WorkerPlan]:
"""Plan every message, attach computed route answers, and apply the guardrail pass."""
plans: List[WorkerPlan] = []
for m in messages:
plan = brain.plan(m)
plan = _plan_with_memory(m, brain)
plan.raw = m
for a in plan.actions:
if a.kind == "route_answer" and "answer" not in a.payload:
a.payload["answer"] = draft_route_answer(a.payload.get("query", m.get("subject", "")))
plans.append(_guardrail(plan, m))
_record_worker_memory_outcome(plans[-1])
return plans