Spaces:
Sleeping
Sleeping
| import tiktoken | |
| from abc import ABC, abstractmethod | |
| from typing import List, Dict | |
| import logging | |
| logger = logging.getLogger("FinancialAgent") | |
| class BaseMemory(ABC): | |
| """ | |
| Abstract Base Class for memory management. | |
| """ | |
| def add_message(self, role: str, content: str): | |
| pass | |
| def get_history(self) -> List[Dict[str, str]]: | |
| pass | |
| def clear(self): | |
| pass | |
| class TokenBufferMemory(BaseMemory): | |
| """ | |
| Memory that keeps conversation within a strict token limit. | |
| Uses a FIFO (First-In-First-Out) eviction strategy when full. | |
| """ | |
| def __init__(self, max_tokens: int = 4096, encoding_name: str = "cl100k_base"): | |
| self.max_tokens = max_tokens | |
| self.messages = [] | |
| # cl100k_base is the encoding for GPT-4 and acts as a good standard proxy | |
| self.tokenizer = tiktoken.get_encoding(encoding_name) | |
| def _count_tokens(self, text: str) -> int: | |
| """Helper to count tokens in a string.""" | |
| try: | |
| return len(self.tokenizer.encode(text)) | |
| except Exception: | |
| # Fallback for empty strings or weird encoding errors | |
| return 0 | |
| def _evict_if_needed(self): | |
| """ | |
| Removes oldest messages until we are under the token limit. | |
| Safety: Never deletes the most recent message (index -1), | |
| so we always have at least the latest context. | |
| """ | |
| while len(self.messages) > 1: | |
| current_buffer_tokens = sum(self._count_tokens(m["content"]) for m in self.messages) | |
| if current_buffer_tokens <= self.max_tokens: | |
| break | |
| # Remove the oldest message | |
| removed = self.messages.pop(0) | |
| logger.info(f"🧹 Memory Full. Evicted message: {removed['role']} ({len(removed['content'])} chars)") | |
| def add_message(self, role: str, content: str): | |
| """Adds a message and triggers eviction check.""" | |
| self.messages.append({"role": role, "content": content}) | |
| self._evict_if_needed() | |
| def get_history(self) -> List[Dict[str, str]]: | |
| return self.messages | |
| def clear(self): | |
| self.messages = [] |