codebase-nav-env / server /memory.py
Chirag0123's picture
v2.0 — agent reliability & evaluation layer
a5c1fa0
# server/memory.py
"""
Context and memory optimization tracker.
Records what the agent has seen, how much context it consumed,
and detects wasteful patterns (re-reading, reading irrelevant content).
This answers: "How efficiently does the agent use its context window?"
"""
from typing import Dict, List, Optional
from dataclasses import dataclass, field
@dataclass
class FileReadRecord:
"""Record of a single file read."""
path: str
size_bytes: int
read_count: int
was_relevant: bool
first_read_step: int
@dataclass
class MemoryStats:
"""Comprehensive context usage statistics."""
total_bytes_read: int = 0
unique_bytes_read: int = 0
redundant_bytes_read: int = 0
total_files_read: int = 0
unique_files_read: int = 0
redundant_reads: int = 0
relevant_files_read: int = 0
irrelevant_files_read: int = 0
context_efficiency: float = 0.0 # unique_useful / total
search_queries: int = 0
total_content_written: int = 0 # bytes written by agent
def to_dict(self) -> dict:
return {
"total_bytes_read": self.total_bytes_read,
"unique_bytes_read": self.unique_bytes_read,
"redundant_bytes_read": self.redundant_bytes_read,
"total_files_read": self.total_files_read,
"unique_files_read": self.unique_files_read,
"redundant_reads": self.redundant_reads,
"relevant_files_read": self.relevant_files_read,
"irrelevant_files_read": self.irrelevant_files_read,
"context_efficiency": round(self.context_efficiency, 3),
"search_queries": self.search_queries,
"total_content_written": self.total_content_written,
}
class MemoryTracker:
"""
Tracks agent's context consumption and memory patterns.
Usage:
tracker = MemoryTracker()
tracker.start_episode(relevant_files=["src/auth.py", "tests/test_auth.py"])
tracker.record_read("src/auth.py", 500, step=1)
tracker.record_read("src/auth.py", 500, step=3) # redundant!
stats = tracker.get_stats()
"""
def __init__(self):
self._reads: Dict[str, FileReadRecord] = {}
self._relevant_files: set = set()
self._search_count: int = 0
self._bytes_written: int = 0
def start_episode(self, relevant_files: List[str] = None):
"""Reset tracker for new episode."""
self._reads.clear()
self._relevant_files = set(relevant_files or [])
self._search_count = 0
self._bytes_written = 0
def record_read(self, path: str, size_bytes: int, step: int):
"""Record a file read action."""
if path in self._reads:
self._reads[path].read_count += 1
else:
self._reads[path] = FileReadRecord(
path=path,
size_bytes=size_bytes,
read_count=1,
was_relevant=path in self._relevant_files,
first_read_step=step,
)
def record_search(self):
"""Record a search query."""
self._search_count += 1
def record_write(self, content_bytes: int):
"""Record bytes written by agent."""
self._bytes_written += content_bytes
def get_stats(self) -> MemoryStats:
"""Compute comprehensive memory statistics."""
total_bytes = 0
unique_bytes = 0
redundant_bytes = 0
redundant_reads = 0
relevant_count = 0
irrelevant_count = 0
for record in self._reads.values():
first_read_bytes = record.size_bytes
unique_bytes += first_read_bytes
total_bytes += first_read_bytes * record.read_count
if record.read_count > 1:
redundant_reads += record.read_count - 1
redundant_bytes += first_read_bytes * (record.read_count - 1)
if record.was_relevant:
relevant_count += 1
else:
irrelevant_count += 1
# Context efficiency: what fraction of bytes read was useful (relevant + unique)?
relevant_bytes = sum(
r.size_bytes for r in self._reads.values() if r.was_relevant
)
efficiency = relevant_bytes / max(1, total_bytes)
return MemoryStats(
total_bytes_read=total_bytes,
unique_bytes_read=unique_bytes,
redundant_bytes_read=redundant_bytes,
total_files_read=sum(r.read_count for r in self._reads.values()),
unique_files_read=len(self._reads),
redundant_reads=redundant_reads,
relevant_files_read=relevant_count,
irrelevant_files_read=irrelevant_count,
context_efficiency=efficiency,
search_queries=self._search_count,
total_content_written=self._bytes_written,
)
def get_wasteful_patterns(self) -> List[str]:
"""Identify specific wasteful patterns for debugging."""
patterns = []
# Files read multiple times
for record in self._reads.values():
if record.read_count > 1:
patterns.append(
f"REDUNDANT_READ: '{record.path}' read {record.read_count} times "
f"({record.size_bytes * record.read_count} bytes wasted)"
)
# Irrelevant files read
for record in self._reads.values():
if not record.was_relevant and record.read_count > 0:
patterns.append(
f"IRRELEVANT_READ: '{record.path}' not in relevant files "
f"({record.size_bytes} bytes wasted)"
)
return patterns