File size: 6,289 Bytes
4d2ab8d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
"""Controlled evolution pipeline over compact structured experiences."""
from datetime import datetime, timezone
import json
import sqlite3

from ..config import settings
from ..memory.store import Store
from ..skills.registry import Skill, SkillRegistry
from .evaluator import evaluate_outcome
from .pattern_extractor import extract_pattern


class EvolutionEngine:
    def __init__(self, store: Store, skills: SkillRegistry):
        self.store = store
        self.skills = skills
        with self.store.connection() as conn:
            conn.execute('''CREATE TABLE IF NOT EXISTS evolution_patterns(

                content_hash TEXT PRIMARY KEY, pattern_json TEXT NOT NULL,

                observations INTEGER NOT NULL DEFAULT 1, successes INTEGER NOT NULL DEFAULT 0,

                failures INTEGER NOT NULL DEFAULT 0, confidence REAL NOT NULL DEFAULT .5,

                status TEXT NOT NULL DEFAULT 'candidate', created_at TEXT NOT NULL,

                updated_at TEXT NOT NULL)''')

    def observe(self, experience: dict, quality_score: float) -> dict:
        """Record a compact pattern and evaluate it; raw task content is never accepted."""
        pattern = extract_pattern(experience)
        now = datetime.now(timezone.utc).isoformat()
        success = pattern['result'] == 'success'
        with self.store.connection() as conn:
            row = conn.execute(
                'SELECT observations,successes,failures FROM evolution_patterns WHERE content_hash=?',
                (pattern['content_hash'],),
            ).fetchone()
            observations = int(row['observations']) + 1 if row else 1
            successes = int(row['successes']) + int(success) if row else int(success)
            failures = int(row['failures']) + int(not success) if row else int(not success)
            evaluation = evaluate_outcome(
                success=success,
                verified=pattern['verified'],
                quality_score=float(quality_score),
                observations=observations,
                min_quality=settings.evolution_min_confidence,
            )
            status = 'validated' if evaluation.accepted else 'candidate'
            conn.execute('''INSERT OR REPLACE INTO evolution_patterns(

                content_hash,pattern_json,observations,successes,failures,confidence,status,created_at,updated_at)

                VALUES(?,?,?,?,?,?,?,?,?)''', (
                pattern['content_hash'], json.dumps(pattern, sort_keys=True), observations,
                successes, failures, evaluation.confidence, status,
                row['created_at'] if row and 'created_at' in row.keys() else now, now,
            ))
        return {
            'pattern_hash': pattern['content_hash'], 'observations': observations,
            'status': status, 'confidence': evaluation.confidence,
            'reasons': list(evaluation.reasons),
        }

    def build_skill_candidate(self, pattern_hash: str) -> Skill:
        with self.store.connection() as conn:
            row = conn.execute(
                'SELECT * FROM evolution_patterns WHERE content_hash=?', (pattern_hash,)
            ).fetchone()
        if not row or row['status'] != 'validated':
            raise ValueError('only validated patterns can become skill candidates')
        pattern = json.loads(row['pattern_json'])
        skill_id = f"evolved-{pattern['task_class']}-{pattern_hash[:10]}"
        return Skill(
            skill_id=skill_id,
            name=f"Validated {pattern['task_class']} pattern",
            version='0.1.0',
            description='Candidate derived from repeated verified outcomes.',
            capabilities=(pattern['task_class'],),
            instructions=(
                f"Use the verified {pattern['task_class']} route pattern. "
                "All tool calls remain subject to MCP permission and approval policy."
            ),
            tool_requirements=(),
            confidence=float(row['confidence']),
            source='evolution',
            trust_state='untrusted',
        ).normalized()

    def register_validated_skill(self, candidate: Skill, *, approved: bool = False) -> Skill:
        if not approved or candidate.source != 'evolution':
            raise PermissionError('evolved skills require explicit validation approval')
        verified = Skill(**{**candidate.to_dict(), 'trust_state': 'verified'}).normalized()
        return self.skills.register(verified, replace=True)

    def create_training_candidate(self, pattern_hash: str) -> str:
        """Create a future dataset candidate; this never mutates model weights."""
        with self.store.connection() as conn:
            row = conn.execute(
                'SELECT pattern_json,status FROM evolution_patterns WHERE content_hash=?',
                (pattern_hash,),
            ).fetchone()
            if not row or row['status'] != 'validated':
                raise ValueError('training candidates require a validated pattern')
            now = datetime.now(timezone.utc).isoformat()
            conn.execute('''INSERT OR IGNORE INTO training_candidates(

                candidate_type,payload_json,content_hash,privacy_status,evaluation_status,created_at,updated_at)

                VALUES('validated_pattern',?,?, 'pending','validated',?,?)''',
                (row['pattern_json'], pattern_hash, now, now),
            )
        return pattern_hash

    def status(self) -> dict:
        with self.store.connection() as conn:
            counts = {}
            for table in ('structured_experiences', 'evolution_patterns', 'training_candidates'):
                counts[table] = conn.execute(f'SELECT COUNT(*) FROM {table}').fetchone()[0]
            counts['validated_patterns'] = conn.execute(
                "SELECT COUNT(*) FROM evolution_patterns WHERE status='validated'"
            ).fetchone()[0]
        return {
            'enabled': settings.evolution_enabled,
            'knowledge_evolution': 'enabled' if settings.evolution_enabled else 'disabled',
            'skill_evolution': 'validation_required',
            'model_evolution': 'dataset_candidates_only',
            **counts,
        }