generated from coulomb/repo-seed
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:
122
src/warden/memory.py
Normal file
122
src/warden/memory.py
Normal file
@@ -0,0 +1,122 @@
|
||||
"""phase-memory bridge for ops-warden cross-runtime experiential memory."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from typing import Any, Mapping, Optional
|
||||
|
||||
_PHASE_MEMORY_ERROR = (
|
||||
"phase-memory is required for warden memory commands. "
|
||||
"Install with: pip install phase-memory (or set PYTHONPATH to phase-memory/src)."
|
||||
)
|
||||
|
||||
|
||||
def _phase_memory():
|
||||
try:
|
||||
import phase_memory.ops_warden as pm
|
||||
|
||||
return pm
|
||||
except ImportError as exc: # pragma: no cover - exercised via tests with PYTHONPATH
|
||||
raise RuntimeError(_PHASE_MEMORY_ERROR) from exc
|
||||
|
||||
|
||||
def memory_available() -> bool:
|
||||
try:
|
||||
_phase_memory()
|
||||
return True
|
||||
except RuntimeError:
|
||||
return False
|
||||
|
||||
|
||||
def enabled(environ: Mapping[str, str] | None = None) -> bool:
|
||||
environ = environ or os.environ
|
||||
return str(environ.get("WARDEN_MEMORY", "1")).strip().lower() not in {"0", "false", "no", "off"}
|
||||
|
||||
|
||||
def store_path(environ: Mapping[str, str] | None = None):
|
||||
return _phase_memory().default_memory_store_path(environ)
|
||||
|
||||
|
||||
def session_kind(environ: Mapping[str, str] | None = None) -> str:
|
||||
return _phase_memory().resolve_session_kind(environ)
|
||||
|
||||
|
||||
def status(environ: Mapping[str, str] | None = None) -> dict[str, Any]:
|
||||
pm = _phase_memory()
|
||||
return pm.OpsWardenMemoryStore.open(environ=environ).status()
|
||||
|
||||
|
||||
def activate(
|
||||
*,
|
||||
need: str = "",
|
||||
agent: Optional[str] = None,
|
||||
session_id: str = "",
|
||||
environ: Mapping[str, str] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
pm = _phase_memory()
|
||||
env = dict(environ or os.environ)
|
||||
if agent:
|
||||
env["WARDEN_AGENT_ID"] = agent
|
||||
kind = pm.resolve_session_kind(env)
|
||||
return pm.activate_ops_warden_memory(
|
||||
pm.OpsWardenMemoryStore.open(environ=env),
|
||||
session_kind=kind,
|
||||
need=need,
|
||||
session_id=session_id,
|
||||
)
|
||||
|
||||
|
||||
def record_command_episode(
|
||||
*,
|
||||
command: str,
|
||||
outcome: str,
|
||||
need: str = "",
|
||||
route_id: str = "",
|
||||
diagnostic_codes: Optional[list[str]] = None,
|
||||
metadata: Optional[dict[str, Any]] = None,
|
||||
environ: Mapping[str, str] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
if not enabled(environ):
|
||||
return {"valid": True, "skipped": True, "reason": "WARDEN_MEMORY=0"}
|
||||
pm = _phase_memory()
|
||||
env = dict(environ or os.environ)
|
||||
event = pm.build_session_event(
|
||||
command=command,
|
||||
session_kind=pm.resolve_session_kind(env),
|
||||
outcome=outcome,
|
||||
need=need,
|
||||
route_id=route_id,
|
||||
agent_id=str(env.get("WARDEN_AGENT_ID") or ""),
|
||||
session_id=str(env.get("WARDEN_SESSION_ID") or ""),
|
||||
diagnostic_codes=diagnostic_codes,
|
||||
metadata=metadata,
|
||||
)
|
||||
return pm.record_session_event(pm.OpsWardenMemoryStore.open(environ=env), event)
|
||||
|
||||
|
||||
def worker_activation_context(need: str = "", environ: Mapping[str, str] | None = None) -> dict[str, Any]:
|
||||
env = dict(environ or os.environ)
|
||||
env["WARDEN_SESSION_KIND"] = "warden.worker"
|
||||
return activate(need=need, environ=env)
|
||||
|
||||
|
||||
def stabilized_route_for_need(need: str, environ: Mapping[str, str] | None = None) -> Optional[dict[str, Any]]:
|
||||
pm = _phase_memory()
|
||||
store = pm.OpsWardenMemoryStore.open(environ=environ)
|
||||
return pm.stabilized_route_match(store.list_events(), need=need)
|
||||
|
||||
|
||||
def format_activation_summary(activation: dict[str, Any]) -> str:
|
||||
lines = [
|
||||
f"store: {activation.get('episode_count', 0)} episodes",
|
||||
f"session_kind: {activation.get('session_kind', '')}",
|
||||
f"selected: {len(activation.get('selected_episodes', ()) )}",
|
||||
]
|
||||
stabilized = activation.get("stabilized_route")
|
||||
if stabilized:
|
||||
lines.append(
|
||||
f"stabilized: {stabilized.get('route_id')} ({stabilized.get('confirmations')} confirmations)"
|
||||
)
|
||||
if activation.get("llm_calls_avoided"):
|
||||
lines.append("llm_calls_avoided: true")
|
||||
return "\n".join(lines)
|
||||
Reference in New Issue
Block a user