Ayush
Update
4156f51
Raw
History Blame Contribute Delete
1.97 kB
"""
environments/trace_env/agents/memory.py
MemoryAgent — episodic + semantic memory store for the Trace agent.
Stores findings across steps without centralizing raw data.
Provides a compressed summary for the observation prompt.
"""
from __future__ import annotations
from typing import Any
from collections import deque
class MemoryAgent:
MAX_ENTRIES = 20 # hard cap to prevent memory stuffing
def __init__(self, config: dict):
self.config = config
self._episodic: deque = deque(maxlen=self.MAX_ENTRIES)
self._semantic: dict[str, Any] = {}
def reset(self):
self._episodic.clear()
self._semantic.clear()
def store(self, content: str, metadata: dict = None):
"""Store a finding into episodic memory."""
entry = {"content": content, "metadata": metadata or {}}
self._episodic.append(entry)
# Build semantic index (simple keyword extraction)
for word in content.lower().split():
if len(word) > 4:
self._semantic.setdefault(word, []).append(len(self._episodic) - 1)
def recall(self, query: str, top_k: int = 3) -> list[str]:
"""Retrieve relevant memories by keyword match."""
scores = {}
for word in query.lower().split():
if word in self._semantic:
for idx in self._semantic[word]:
scores[idx] = scores.get(idx, 0) + 1
top = sorted(scores, key=scores.get, reverse=True)[:top_k]
return [self._episodic[i]["content"] for i in top if i < len(self._episodic)]
def summarize(self) -> str:
"""Return a compressed summary for the observation prompt."""
if not self._episodic:
return "(empty memory)"
entries = list(self._episodic)[-5:] # last 5 entries
lines = [f"- {e['content'][:80]}" for e in entries]
return "\n".join(lines)
def size(self) -> int:
return len(self._episodic)