"""Tests for the evolution layer (5 cognitive upgrades).""" import pytest import numpy as np from palimseste.lm import PalimpsesteForCausalLM, PalimpsesteConfig from palimseste.chat import Conversation from palimseste.evolution import ( ResponseSynthesizer, EntityTracker, QueryRouter, CodePatternBank, ConfidenceCalibrator, SynthesisResult, Entity, QueryIntent, CodePattern, CalibrationResult, ) def _build_model(D=5000, ctx=128, radius=200): cfg = PalimpsesteConfig(D=D, context_window=ctx, kernel_radius=radius, temperature=0.0) lm = PalimpsesteForCausalLM(config=cfg) pairs = [ ("hello", "hi i am palimpseste"), ("who are you", "i am palimpseste a hypervectorial cortex"), ("what is python", "python is a programming language"), ("what is java", "java is a programming language"), ("what is recursion", "recursion is when a function calls itself"), ("what is the capital of france", "the capital of france is paris"), ("what is the capital of japan", "the capital of japan is tokyo"), ] lm.build_tokenizer("".join(q + a for q, a in pairs)) lm.train_on_qa_pairs(pairs) conv = Conversation(model=lm, fuzzy_threshold=0.75) conv.register_questions(pairs) return lm, conv # ================================================================ SYNTHESIZER class TestResponseSynthesizer: def test_single_fact(self): _, conv = _build_model() synth = ResponseSynthesizer(conv=conv) result = synth.synthesize("what is python") assert isinstance(result, SynthesisResult) assert result.synthesis_type == 'single' def test_no_match(self): _, conv = _build_model() synth = ResponseSynthesizer(conv=conv) result = synth.synthesize("xyz123unknown") assert result.n_facts_used == 0 or result.confidence <= 0.5 def test_extract_topics(self): _, conv = _build_model() synth = ResponseSynthesizer(conv=conv) topics = synth._extract_topics("compare python and java") assert len(topics) >= 2 assert "python" in topics[0] or "python" in topics # ================================================================ ENTITY TRACKER class TestEntityTracker: def test_track_entity(self): tracker = EntityTracker() tracker.update("what is python") assert tracker.get_entity("python") is not None assert tracker.n_entities >= 1 def test_pronoun_resolution(self): tracker = EntityTracker() tracker.update("what is python") resolved = tracker.update("what about its speed") assert "python" in resolved.lower() def test_no_pronoun(self): tracker = EntityTracker() tracker.update("what is python") resolved = tracker.update("what is java") assert "python" not in resolved.lower() def test_reset(self): tracker = EntityTracker() tracker.update("what is python") assert tracker.n_entities > 0 tracker.reset() assert tracker.n_entities == 0 def test_all_entities(self): tracker = EntityTracker() tracker.update("what is python and java") entities = tracker.all_entities() assert len(entities) >= 2 def test_multiple_mentions(self): tracker = EntityTracker() tracker.update("what is python") tracker.update("tell me about python") ent = tracker.get_entity("python") assert ent is not None assert ent.mentions >= 2 # ================================================================ QUERY ROUTER class TestQueryRouter: def test_greeting(self): router = QueryRouter() intent = router.classify("hello there") assert intent.intent == 'greeting' assert intent.strategy == 'direct' def test_comparison(self): router = QueryRouter() intent = router.classify("compare python and java") assert intent.intent == 'comparison' assert intent.strategy == 'synthesize' def test_howto(self): router = QueryRouter() intent = router.classify("how do i write a loop") assert intent.intent == 'howto' def test_code(self): router = QueryRouter() intent = router.classify("write code for fibonacci") assert intent.intent == 'code' def test_definition(self): router = QueryRouter() intent = router.classify("what is gravity") assert intent.intent == 'definition' def test_factual(self): router = QueryRouter() intent = router.classify("who won the world cup") assert intent.intent == 'factual' def test_topics_extracted(self): router = QueryRouter() intent = router.classify("what is python programming") assert len(intent.topics) > 0 # ================================================================ CODE BANK class TestCodePatternBank: def test_store(self): bank = CodePatternBank() p = bank.store("python", "read file", "open('f')", "read", ["open"]) assert p.id == 0 assert bank.n_patterns == 1 def test_retrieve(self): bank = CodePatternBank() bank.load_defaults() results = bank.retrieve("how to read a file", language="python") assert len(results) > 0 assert results[0][0].task == 'read file' def test_retrieve_by_language(self): bank = CodePatternBank() bank.load_defaults() results = bank.retrieve("function", language="javascript") assert len(results) == 0 # no JS patterns loaded def test_load_defaults(self): bank = CodePatternBank() bank.load_defaults() assert bank.n_patterns >= 10 def test_no_match(self): bank = CodePatternBank() bank.load_defaults() results = bank.retrieve("xyz123 nonexistent") # Might get 0 results or very low scores assert all(s < 0.2 for _, s in results) or len(results) == 0 # ================================================================ CALIBRATOR class TestConfidenceCalibrator: def test_high_confidence(self): cal = ConfidenceCalibrator() result = cal.calibrate("paris", 1.0, "capital of france", "paris") assert result.calibrated_confidence > 0.5 assert not result.hedged def test_low_confidence(self): cal = ConfidenceCalibrator() result = cal.calibrate("xyz", 0.1, "meaning of life", "xyz") assert result.hedged assert result.hedge_phrase is not None def test_no_double_hedge(self): cal = ConfidenceCalibrator() result = cal.calibrate("i'm not sure about this", 0.1, "q", "a") assert not result.hedged # already starts with hedge def test_medium_confidence(self): cal = ConfidenceCalibrator() result = cal.calibrate("maybe paris", 0.5, "capital", "paris") assert isinstance(result, CalibrationResult) def test_calibrated_less_than_raw(self): cal = ConfidenceCalibrator() result = cal.calibrate("short", 1.0, "what is quantum mechanics", "short") # Very short answer to an unrelated question should be calibrated down assert result.calibrated_confidence < result.raw_confidence