A file held in working memory with LRU and relevance metadata.
| 44 | |
| 45 | @dataclass |
| 46 | class WorkingMemoryItem: |
| 47 | """A file held in working memory with LRU and relevance metadata.""" |
| 48 | file_path: str |
| 49 | content: str |
| 50 | tokens: int |
| 51 | loaded_at: int # unix timestamp |
| 52 | last_used_at: int # unix timestamp (for wall-clock LRU) |
| 53 | last_used_turn: int = 0 # agent turn counter (for turn-based LRU eviction) |
| 54 | access_count: int = 1 |
| 55 | |
| 56 | @property |
| 57 | def name(self) -> str: |
| 58 | """Filename without directory — used by /context display.""" |
| 59 | return Path(self.file_path).name |
| 60 | |
| 61 | def relevance_score(self, message: str) -> float: |
| 62 | """Score 0-1 based on keyword overlap between message and file.""" |
| 63 | msg_words = set(re.findall(r'\w+', message.lower())) |
| 64 | file_words = set(re.findall(r'\w+', self.content.lower())) |
| 65 | name_words = set(re.findall(r'\w+', self.name.lower())) |
| 66 | name_overlap = len(msg_words & name_words) * 3 # filename hit = high signal |
| 67 | content_overlap = len(msg_words & file_words) |
| 68 | if not msg_words: |
| 69 | return 0.5 |
| 70 | return min(1.0, (name_overlap + content_overlap) / (len(msg_words) + 1)) |
| 71 | |
| 72 | |
| 73 | class WorkingMemory: |
no outgoing calls