Claude
Initial Codette cognitive architecture demo Space
7c3f0ce
"""
Base class for all reasoning agents in the forge.
Each agent must implement analyze() and get_analysis_templates().
The base class provides keyword matching and template selection utilities.
"""
from abc import ABC, abstractmethod
import random
import re
class ReasoningAgent(ABC):
"""Abstract base class for all reasoning agents."""
name: str = "BaseAgent"
perspective: str = "general"
def __init__(self):
self._templates = self.get_analysis_templates()
self._keyword_map = self.get_keyword_map()
@abstractmethod
def analyze(self, concept: str) -> str:
"""Analyze a concept from this agent's perspective.
Args:
concept: The concept text to analyze.
Returns:
A substantive analysis string from this agent's perspective.
"""
raise NotImplementedError
@abstractmethod
def get_analysis_templates(self) -> list[str]:
"""Return diverse analysis templates.
Each template should contain {concept} placeholder and produce
genuine expert-level reasoning, not placeholder text.
Returns:
List of template strings.
"""
raise NotImplementedError
def get_keyword_map(self) -> dict[str, list[int]]:
"""Return a mapping of keywords to preferred template indices.
Override in subclasses to steer template selection based on
concept content. Keys are lowercase keywords/phrases, values
are lists of template indices that work well for that keyword.
Returns:
Dictionary mapping keywords to template index lists.
"""
return {}
def select_template(self, concept: str) -> str:
"""Select the best template for the given concept.
Uses keyword matching to find relevant templates. Falls back
to random selection if no keywords match.
Args:
concept: The concept text.
Returns:
A single template string.
"""
concept_lower = concept.lower()
scored_indices: dict[int, int] = {}
for keyword, indices in self._keyword_map.items():
if keyword in concept_lower:
for idx in indices:
if 0 <= idx < len(self._templates):
scored_indices[idx] = scored_indices.get(idx, 0) + 1
if scored_indices:
max_score = max(scored_indices.values())
best = [i for i, s in scored_indices.items() if s == max_score]
chosen = random.choice(best)
return self._templates[chosen]
return random.choice(self._templates)
def extract_key_terms(self, concept: str) -> list[str]:
"""Extract significant terms from the concept for template filling.
Args:
concept: The concept text.
Returns:
List of key terms found in the concept.
"""
stop_words = {
"the", "a", "an", "is", "are", "was", "were", "be", "been",
"being", "have", "has", "had", "do", "does", "did", "will",
"would", "could", "should", "may", "might", "can", "shall",
"of", "in", "to", "for", "with", "on", "at", "from", "by",
"about", "as", "into", "through", "during", "before", "after",
"above", "below", "between", "and", "but", "or", "nor", "not",
"so", "yet", "both", "either", "neither", "each", "every",
"this", "that", "these", "those", "it", "its", "they", "them",
"their", "we", "our", "you", "your", "he", "she", "his", "her",
"how", "what", "when", "where", "which", "who", "why",
}
words = re.findall(r'\b[a-zA-Z]{3,}\b', concept.lower())
return [w for w in words if w not in stop_words]
def __repr__(self) -> str:
return f"{self.__class__.__name__}(name={self.name!r}, perspective={self.perspective!r})"