""" GROWTH ENGINE ============= The wrapper that makes the system permanently smarter with every problem. Every task solved — pass or fail — teaches the system something. Nothing is wasted. Every failure is a lesson stored forever. Every success is a pattern extracted and reused. Four learning layers: 1. MEMORY — persistent storage of every attempt, forever 2. PATTERN LIB — distilled reusable solutions from winning code 3. SOURCE TRUST — which references produce good code, scored over time 4. CALIBRATION — tracks when the AI lies to itself about confidence This sits above reflection_engine.py. The reflection engine handles one task. This handles everything the system learns from every task ever run. Usage: python growth_engine.py "write a function that does X" python growth_engine.py --stats (show what it has learned) python growth_engine.py --patterns (show pattern library) """ import sqlite3 import json import re import sys import os import time import hashlib import requests from datetime import datetime from dataclasses import dataclass, asdict from typing import Optional # Import the brain sys.path.insert(0, os.path.dirname(__file__)) from reflection_engine import ( run_engine, CodeAttempt, ollama, BENCHMARK_FLOOR, MODEL, set_language, get_language, _LANG_CONFIG ) from trust_balance_agent import apply_trust_before_run from model_manager import _get_active_model, scan_and_register, print_status as model_status # ── Config ───────────────────────────────────────────────────────────────────── DB_PATH = os.environ.get("GROWTH_DB_PATH", os.path.join(os.path.dirname(__file__), "growth_memory.db")) MAX_CONTEXT_PATTERNS = 5 # how many past patterns to inject per task MAX_CONTEXT_FAILURES = 3 # how many past failure lessons to inject # ── Database setup ───────────────────────────────────────────────────────────── def get_db() -> sqlite3.Connection: conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row return conn def init_db(): """Create all tables if they don't exist.""" conn = get_db() c = conn.cursor() # Every task ever run c.execute(""" CREATE TABLE IF NOT EXISTS task_history ( id INTEGER PRIMARY KEY AUTOINCREMENT, task_hash TEXT NOT NULL, task TEXT NOT NULL, timestamp TEXT NOT NULL, final_score REAL, passed INTEGER, iterations INTEGER, final_code TEXT, lessons TEXT, task_category TEXT ) """) # Distilled reusable patterns from winning code c.execute(""" CREATE TABLE IF NOT EXISTS pattern_library ( id INTEGER PRIMARY KEY AUTOINCREMENT, pattern_hash TEXT UNIQUE NOT NULL, pattern_name TEXT NOT NULL, description TEXT, code_template TEXT, use_cases TEXT, score_when_used REAL DEFAULT 0, times_used INTEGER DEFAULT 0, times_helped INTEGER DEFAULT 0, created_at TEXT, last_used TEXT ) """) # Known failure patterns — what NOT to do c.execute(""" CREATE TABLE IF NOT EXISTS failure_library ( id INTEGER PRIMARY KEY AUTOINCREMENT, failure_hash TEXT UNIQUE NOT NULL, description TEXT NOT NULL, root_cause TEXT, fix TEXT, times_seen INTEGER DEFAULT 1, last_seen TEXT ) """) # Confidence calibration log c.execute(""" CREATE TABLE IF NOT EXISTS confidence_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp TEXT, stated_confidence REAL, actual_score REAL, passed INTEGER, error REAL -- abs(stated_confidence*100 - actual_score) ) """) # Source trust registry c.execute(""" CREATE TABLE IF NOT EXISTS source_trust ( id INTEGER PRIMARY KEY AUTOINCREMENT, source_ref TEXT UNIQUE NOT NULL, trust_score REAL DEFAULT 50.0, times_cited INTEGER DEFAULT 0, times_helped INTEGER DEFAULT 0, times_hurt INTEGER DEFAULT 0, last_seen TEXT ) """) # ── Observation Ledger ────────────────────────────────────────────── # Raw observations accumulate here. Patterns are NOT forced. # Only when the same observation surfaces enough times — honestly, # naturally, across different tasks — does it crystallize into a # pattern. The world is chaotic but patterns exist. They appear # when observed honestly and not forced. c.execute(""" CREATE TABLE IF NOT EXISTS observation_ledger ( id INTEGER PRIMARY KEY AUTOINCREMENT, obs_hash TEXT NOT NULL, observation TEXT NOT NULL, context TEXT, domain TEXT, times_seen INTEGER DEFAULT 1, first_seen TEXT, last_seen TEXT, crystallized INTEGER DEFAULT 0 ) """) conn.commit() conn.close() print(f" [OK] Memory database: {DB_PATH}") # ── Layer 1: Memory ──────────────────────────────────────────────────────────── def task_hash(task: str) -> str: return hashlib.md5(task.lower().strip().encode()).hexdigest()[:12] def store_task(task: str, result: CodeAttempt, lessons: dict): """Permanently store this task run — win or lose.""" conn = get_db() conn.execute(""" INSERT INTO task_history (task_hash, task, timestamp, final_score, passed, iterations, final_code, lessons, task_category) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( task_hash(task), task, datetime.now().isoformat(), result.score, int(result.passed), result.iteration, result.code, json.dumps(lessons), lessons.get("category", "general") )) conn.commit() conn.close() def load_relevant_history(task: str) -> list[dict]: """ Find past tasks semantically similar to this one. Simple keyword overlap for now — no embedding needed. """ conn = get_db() words = set(re.findall(r'\w+', task.lower())) - { 'a','an','the','write','create','build','make','function', 'that','with','and','or','for','in','to','of','is','it' } if not words: conn.close() return [] # Score each history item by keyword overlap rows = conn.execute( "SELECT * FROM task_history ORDER BY timestamp DESC LIMIT 100" ).fetchall() conn.close() scored = [] for row in rows: row_words = set(re.findall(r'\w+', row['task'].lower())) overlap = len(words & row_words) / max(len(words), 1) if overlap > 0.2: scored.append((overlap, dict(row))) scored.sort(key=lambda x: x[0], reverse=True) return [r for _, r in scored[:5]] # ── Layer 2: Pattern Library ─────────────────────────────────────────────────── def extract_patterns(task: str, result: CodeAttempt) -> list[dict]: """ After a successful run, ask the model to distill reusable patterns from the winning code. """ if not result.passed: return [] print(" 📚 Extracting reusable patterns...") lang = get_language() lang_cfg = _LANG_CONFIG.get(lang, _LANG_CONFIG["python"]) expert = lang_cfg["expert"] fence = lang_cfg["fence"] prompt = f"""You are a senior {expert} building a pattern library. A task was solved successfully (score: {result.score:.1f}%): TASK: {task} WINNING CODE: ```{fence} {result.code} ``` Extract up to 3 reusable patterns from this code. Each pattern should be something that could help solve FUTURE problems. Respond ONLY with a JSON array (no other text): [ {{ "name": "short pattern name", "description": "what this pattern does and when to use it", "code_template": "the reusable code snippet", "use_cases": "comma-separated list of problem types this helps with" }} ]""" raw = ollama(prompt, temperature=0.2) try: raw = re.sub(r'```.*?```', '', raw, flags=re.DOTALL).strip() match = re.search(r'\[.*\]', raw, re.DOTALL) if match: patterns = json.loads(match.group()) return patterns[:3] except Exception: pass return [] def store_patterns(patterns: list[dict]): """Save extracted patterns to the library.""" if not patterns: return conn = get_db() for p in patterns: ph = hashlib.md5(p.get('name','').encode()).hexdigest()[:12] try: conn.execute(""" INSERT OR IGNORE INTO pattern_library (pattern_hash, pattern_name, description, code_template, use_cases, created_at, last_used) VALUES (?, ?, ?, ?, ?, ?, ?) """, ( ph, p.get('name', 'unnamed'), p.get('description', ''), p.get('code_template', ''), p.get('use_cases', ''), datetime.now().isoformat(), datetime.now().isoformat() )) except Exception: pass conn.commit() conn.close() print(f" 📚 Stored {len(patterns)} pattern(s) to library") def load_relevant_patterns(task: str) -> list[dict]: """Find patterns from the library relevant to this task.""" conn = get_db() patterns = conn.execute( "SELECT * FROM pattern_library ORDER BY times_helped DESC, score_when_used DESC LIMIT 20" ).fetchall() conn.close() words = set(re.findall(r'\w+', task.lower())) scored = [] for p in patterns: p = dict(p) use_words = set(re.findall(r'\w+', (p.get('use_cases','') + ' ' + p.get('description','')).lower())) overlap = len(words & use_words) / max(len(words), 1) if overlap > 0.1: scored.append((overlap, p)) scored.sort(key=lambda x: x[0], reverse=True) return [p for _, p in scored[:MAX_CONTEXT_PATTERNS]] # ── Observation Ledger ───────────────────────────────────────────────────────── # "The world is chaotic but patterns exist. They appear when observed honestly # and not forced. It takes time and patience." — Gordo # # Raw observations accumulate. Nothing is forced into a pattern immediately. # Only when the same insight surfaces across multiple independent tasks does # it earn the right to become a pattern. Patience, not speed. OBSERVATION_CRYSTALLIZE_THRESHOLD = 3 # seen this many times → becomes a pattern def store_observation(task: str, result: CodeAttempt): """ After every run, record raw observations — what actually happened. Don't interpret. Don't force. Just observe honestly. """ if result.iteration == 0: return # TALK — nothing to observe print(" \U0001f440 Recording raw observations...") prompt = f"""You are recording honest observations from a coding task. Do NOT generalize. Do NOT force patterns. Just describe what actually happened. TASK: {task[:300]} SCORE: {result.score:.1f}% PASSED: {result.passed} ITERATIONS: {result.iteration} ERRORS: {result.errors[:3] if result.errors else 'none'} REFLECTIONS: {result.reflections[:3] if result.reflections else 'none'} List up to 3 honest, specific observations. Not lessons. Not advice. Just what happened. Respond ONLY with a JSON array: [ {{ "observation": "what actually happened (factual, specific)", "domain": "the technical domain (e.g., error_handling, architecture, networking, parsing)" }} ]""" raw = ollama(prompt, temperature=0.2) try: raw = re.sub(r'```.*?```', '', raw, flags=re.DOTALL).strip() match = re.search(r'\[.*\]', raw, re.DOTALL) if match: observations = json.loads(match.group())[:3] else: return except Exception: return conn = get_db() stored = 0 for obs in observations: text = obs.get('observation', '').strip() domain = obs.get('domain', 'general').strip() if not text: continue oh = hashlib.md5(text.lower().encode()).hexdigest()[:12] existing = conn.execute( "SELECT id, times_seen FROM observation_ledger WHERE obs_hash=?", (oh,) ).fetchone() if existing: conn.execute( "UPDATE observation_ledger SET times_seen=?, last_seen=? WHERE obs_hash=?", (existing['times_seen'] + 1, datetime.now().isoformat(), oh) ) else: conn.execute(""" INSERT INTO observation_ledger (obs_hash, observation, context, domain, first_seen, last_seen) VALUES (?, ?, ?, ?, ?, ?) """, ( oh, text, task[:200], domain, datetime.now().isoformat(), datetime.now().isoformat() )) stored += 1 conn.commit() conn.close() if stored: print(f" \U0001f440 Recorded {stored} observation(s) — no pattern forced") def crystallize_observations(): """ Check if any observations have been seen enough times to naturally become a pattern. Patience, not speed. Only called periodically — not after every single task. """ conn = get_db() ripe = conn.execute(""" SELECT * FROM observation_ledger WHERE times_seen >= ? AND crystallized = 0 ORDER BY times_seen DESC """, (OBSERVATION_CRYSTALLIZE_THRESHOLD,)).fetchall() if not ripe: conn.close() return print(f"\n \U0001f48e {len(ripe)} observation(s) have surfaced enough times to crystallize...") for obs in ripe: obs = dict(obs) # Promote to pattern library ph = hashlib.md5(obs['observation'].encode()).hexdigest()[:12] try: conn.execute(""" INSERT OR IGNORE INTO pattern_library (pattern_hash, pattern_name, description, code_template, use_cases, created_at, last_used) VALUES (?, ?, ?, ?, ?, ?, ?) """, ( ph, f"[emerged] {obs['domain']}", obs['observation'], '', # no template — this is an insight, not code obs['domain'], obs['first_seen'], datetime.now().isoformat() )) # Mark as crystallized conn.execute( "UPDATE observation_ledger SET crystallized=1 WHERE id=?", (obs['id'],) ) print(f" \U0001f48e Crystallized: {obs['observation'][:80]}") print(f" (seen {obs['times_seen']}x across tasks since {obs['first_seen'][:10]})") except Exception: pass conn.commit() conn.close() # ── Layer 3: Failure Library ─────────────────────────────────────────────────── def extract_failures(task: str, result: CodeAttempt) -> list[dict]: """ Even from a passing run, extract what failed along the way. From a failing run, extract everything we learned. """ if result.iteration == 1 and result.passed: return [] # First try success — nothing to learn about failure failed_attempts = [] if result.errors: failed_attempts = result.errors if not failed_attempts and not result.reflections: return [] print(" ⚠️ Extracting failure lessons...") prompt = f"""You are building a failure pattern library to help future code generation avoid mistakes. TASK: {task} ERRORS ENCOUNTERED: {result.errors} REFLECTIONS DURING IMPROVEMENT: {result.reflections} FINAL SCORE: {result.score:.1f}% Extract up to 3 distinct failure patterns from this run. Be specific — vague lessons are useless. Respond ONLY with a JSON array: [ {{ "description": "exactly what went wrong", "root_cause": "why it went wrong", "fix": "how to avoid this in future" }} ]""" raw = ollama(prompt, temperature=0.2) try: raw = re.sub(r'```.*?```', '', raw, flags=re.DOTALL).strip() match = re.search(r'\[.*\]', raw, re.DOTALL) if match: return json.loads(match.group())[:3] except Exception: pass return [] def store_failures(failures: list[dict]): """Store failure patterns — increment count if seen before.""" if not failures: return conn = get_db() for f in failures: fh = hashlib.md5(f.get('description','').encode()).hexdigest()[:12] existing = conn.execute( "SELECT id, times_seen FROM failure_library WHERE failure_hash=?", (fh,) ).fetchone() if existing: conn.execute( "UPDATE failure_library SET times_seen=?, last_seen=? WHERE failure_hash=?", (existing['times_seen'] + 1, datetime.now().isoformat(), fh) ) else: conn.execute(""" INSERT INTO failure_library (failure_hash, description, root_cause, fix, last_seen) VALUES (?, ?, ?, ?, ?) """, ( fh, f.get('description',''), f.get('root_cause',''), f.get('fix',''), datetime.now().isoformat() )) conn.commit() conn.close() print(f" ⚠️ Stored {len(failures)} failure lesson(s)") def load_relevant_failures(task: str) -> list[dict]: """Load the most relevant known failure patterns for this task.""" conn = get_db() failures = conn.execute( "SELECT * FROM failure_library ORDER BY times_seen DESC LIMIT 20" ).fetchall() conn.close() words = set(re.findall(r'\w+', task.lower())) scored = [] for f in failures: f = dict(f) f_words = set(re.findall(r'\w+', (f.get('description','') + ' ' + f.get('root_cause','')).lower())) overlap = len(words & f_words) / max(len(words), 1) scored.append((overlap + (f['times_seen'] * 0.05), f)) scored.sort(key=lambda x: x[0], reverse=True) return [f for _, f in scored[:MAX_CONTEXT_FAILURES]] # ── Layer 4: Confidence Calibration ─────────────────────────────────────────── def log_confidence(stated: float, actual_score: float, passed: bool): """Track when the model's stated confidence was accurate vs. wrong.""" conn = get_db() error = abs((stated * 100) - actual_score) conn.execute(""" INSERT INTO confidence_log (timestamp, stated_confidence, actual_score, passed, error) VALUES (?, ?, ?, ?, ?) """, (datetime.now().isoformat(), stated, actual_score, int(passed), error)) conn.commit() conn.close() def get_confidence_calibration() -> dict: """ How well-calibrated is the model's self-confidence? Returns stats the growth engine uses to adjust prompts. """ conn = get_db() rows = conn.execute( "SELECT * FROM confidence_log ORDER BY timestamp DESC LIMIT 50" ).fetchall() conn.close() if not rows: return {"avg_error": 0, "overconfident": False, "sample_size": 0} errors = [r['error'] for r in rows] avg_error = sum(errors) / len(errors) # If stated confidence > actual score consistently, it's overconfident overconfident = sum( 1 for r in rows if (r['stated_confidence'] * 100) > r['actual_score'] ) / len(rows) > 0.6 return { "avg_error": round(avg_error, 1), "overconfident": overconfident, "sample_size": len(rows), "recent_accuracy": round(100 - avg_error, 1) } # ── Context Builder ──────────────────────────────────────────────────────────── def build_growth_context(task: str) -> str: """ Assemble everything the system has learned into a context block injected into the first generation prompt. This is how past learning flows into future tasks. """ parts = [] # Relevant patterns patterns = load_relevant_patterns(task) if patterns: parts.append("=== PATTERNS THAT HAVE WORKED BEFORE ===") for p in patterns: parts.append(f"PATTERN: {p['pattern_name']}") parts.append(f" When to use: {p['description']}") parts.append(f" Template:\n{p['code_template'][:300]}") parts.append("") # Known failures to avoid failures = load_relevant_failures(task) if failures: parts.append("=== KNOWN FAILURE PATTERNS — AVOID THESE ===") for f in failures: seen = f.get('times_seen', 1) parts.append(f"FAILURE (seen {seen}x): {f['description']}") parts.append(f" Root cause: {f['root_cause']}") parts.append(f" Fix: {f['fix']}") parts.append("") # Similar past tasks history = load_relevant_history(task) if history: parts.append("=== SIMILAR TASKS FROM HISTORY ===") for h in history[:2]: status = "PASSED" if h['passed'] else "failed" parts.append(f"PAST TASK ({status}, score {h['final_score']:.0f}%): {h['task'][:80]}") if h['passed'] and h['final_code']: parts.append(f" Winning approach snippet:\n{h['final_code'][:200]}") parts.append("") # Calibration warning cal = get_confidence_calibration() if cal['sample_size'] > 5 and cal['overconfident']: parts.append(f"=== CALIBRATION WARNING ===") parts.append(f"This system has been overconfident recently (avg error: {cal['avg_error']:.0f}%).") parts.append(f"Be conservative in confidence estimates. Aim higher than you think you need.") parts.append("") return "\n".join(parts) if parts else "" # ── Lesson Extractor ─────────────────────────────────────────────────────────── def extract_lessons(task: str, result: CodeAttempt) -> dict: """ After every run — win or lose — extract structured lessons. This is the core of the growth loop. """ print("\n 🎓 Extracting lessons from this run...") prompt = f"""You completed a Python coding task. Extract lessons for future runs. TASK: {task} FINAL SCORE: {result.score:.1f}% PASSED: {result.passed} ITERATIONS NEEDED: {result.iteration} ERRORS: {result.errors} Answer in JSON only: {{ "category": "one of: algorithm, data_structure, error_handling, io, math, string, api, testing, optimization, other", "key_lesson": "the single most important thing learned from this run", "what_worked": "what approach succeeded or showed promise", "what_failed": "what approach failed or caused problems", "next_time": "specific advice for the next time a similar task appears", "difficulty": "easy/medium/hard" }}""" raw = ollama(prompt, temperature=0.2) try: raw = re.sub(r'```.*?```', '', raw, flags=re.DOTALL).strip() match = re.search(r'\{.*\}', raw, re.DOTALL) if match: return json.loads(match.group()) except Exception: pass return { "category": "general", "key_lesson": "task completed", "what_worked": "reflection loop", "what_failed": "n/a", "next_time": "start with edge cases", "difficulty": "medium" } # ── Stats Display ────────────────────────────────────────────────────────────── def show_stats(): """Print what the system has learned so far.""" conn = get_db() total = conn.execute("SELECT COUNT(*) as n FROM task_history").fetchone()['n'] passed = conn.execute("SELECT COUNT(*) as n FROM task_history WHERE passed=1").fetchone()['n'] patterns = conn.execute("SELECT COUNT(*) as n FROM pattern_library").fetchone()['n'] failures = conn.execute("SELECT COUNT(*) as n FROM failure_library").fetchone()['n'] avg_score = conn.execute("SELECT AVG(final_score) as s FROM task_history").fetchone()['s'] or 0 avg_iters = conn.execute("SELECT AVG(iterations) as i FROM task_history").fetchone()['i'] or 0 top_patterns = conn.execute( "SELECT pattern_name, times_helped, description FROM pattern_library ORDER BY times_helped DESC LIMIT 5" ).fetchall() top_failures = conn.execute( "SELECT description, times_seen FROM failure_library ORDER BY times_seen DESC LIMIT 5" ).fetchall() cal = get_confidence_calibration() conn.close() print(f"\n{'='*60}") print(f" GROWTH ENGINE — WHAT I HAVE LEARNED") print(f"{'='*60}") print(f"\n Tasks run: {total}") print(f" Tasks passed: {passed} ({(passed/total*100):.0f}%)" if total else " Tasks passed: 0") print(f" Avg score: {avg_score:.1f}%") print(f" Avg iterations: {avg_iters:.1f}") print(f" Patterns learned: {patterns}") print(f" Failures logged: {failures}") if cal['sample_size'] > 0: print(f"\n Confidence accuracy: {cal['recent_accuracy']:.1f}%") print(f" Overconfident: {'YES ⚠️' if cal['overconfident'] else 'No ✅'}") if top_patterns: print(f"\n TOP PATTERNS:") for p in top_patterns: print(f" • {p['pattern_name']} — {p['description'][:50]}") if top_failures: print(f"\n MOST COMMON FAILURES:") for f in top_failures: print(f" • (x{f['times_seen']}) {f['description'][:60]}") print(f"\n{'='*60}\n") def show_patterns(): """Print the full pattern library.""" conn = get_db() patterns = conn.execute( "SELECT * FROM pattern_library ORDER BY times_helped DESC" ).fetchall() conn.close() if not patterns: print("\n No patterns learned yet. Run some tasks first.\n") return print(f"\n{'='*60}") print(f" PATTERN LIBRARY ({len(patterns)} patterns)") print(f"{'='*60}\n") for p in patterns: print(f" [{p['pattern_name']}]") print(f" {p['description']}") print(f" Use cases: {p['use_cases']}") print(f" Times helped: {p['times_helped']}") print(f" Template preview: {str(p['code_template'])[:100]}...") print() # ── TALK Memory Builder ──────────────────────────────────────────────────────── def _build_talk_memory(task: str) -> str: """Build a memory summary the LLM can reference during conversation.""" parts = [] conn = get_db() # Stats overview tasks_done = conn.execute("SELECT COUNT(*) as n FROM task_history").fetchone()["n"] patterns = conn.execute("SELECT COUNT(*) as n FROM pattern_library").fetchone()["n"] failures = conn.execute("SELECT COUNT(*) as n FROM failure_library").fetchone()["n"] parts.append(f"You have completed {tasks_done} tasks. You know {patterns} coding patterns and {failures} failure lessons.") # Recent tasks (last 10) recent = conn.execute( "SELECT task, passed, final_score FROM task_history ORDER BY timestamp DESC LIMIT 10" ).fetchall() if recent: parts.append("\nRecent tasks you completed:") for r in recent: status = "PASSED" if r["passed"] else "FAILED" parts.append(f" - [{status} {r['final_score']:.0f}%] {r['task'][:100]}") # Search for relevant patterns if user asks about something specific words = set(re.findall(r'\w+', task.lower())) stopwords = {'the','a','an','is','are','do','does','can','you','your','i','me','my', 'what','how','why','when','where','it','this','that','about','with','have', 'has','had','was','were','been','be','will','would','could','should'} keywords = words - stopwords if keywords: all_patterns = conn.execute( "SELECT pattern_name, description FROM pattern_library" ).fetchall() matched = [] for p in all_patterns: ptext = f"{p['pattern_name']} {p['description']}".lower() if any(kw in ptext for kw in keywords): matched.append(p) if matched: parts.append(f"\nPatterns you know related to this topic ({len(matched)}):") for m in matched[:10]: parts.append(f" - {m['pattern_name']}: {m['description'][:120]}") conn.close() return "\n".join(parts) if parts else "" # ── Main Growth Loop ─────────────────────────────────────────────────────────── def run_growth_engine(task: str, lang: str = "python") -> CodeAttempt: """ The full growth loop. Every run permanently improves the system. """ set_language(lang) print(f"\n{'='*60}") print(f" GROWTH ENGINE — SELF-IMPROVING CODE AI") print(f" Every problem makes me permanently smarter.") print(f"{'='*60}") # ── Apply earned trust — adjusts BENCHMARK_FLOOR and MAX_ITERATIONS ── apply_trust_before_run() # ── TALK gate: catch conversation BEFORE enrichment adds context ── from reflection_engine import classify_task if classify_task(task) == "TALK": print(f"\n 💬 TALK detected — loading memory for conversation.") memory_summary = _build_talk_memory(task) if memory_summary: print(f" 📖 Injecting {len(memory_summary)} chars of memory into TALK") result = run_engine(task, talk_memory=memory_summary) return result # ── Load what we know ── # Budget depends on task length — long prompts (C# MMO tasks) leave less room task_len = len(task) if task_len > 1000: MAX_CONTEXT_CHARS = 500 # long prompts — minimal context injection elif task_len > 600: MAX_CONTEXT_CHARS = 800 else: MAX_CONTEXT_CHARS = 1500 # short prompts (Python snippets) — full context context = build_growth_context(task) if context: if len(context) > MAX_CONTEXT_CHARS: context = context[:MAX_CONTEXT_CHARS] + "\n[...truncated to fit model context]" print(f"\n 📖 Prior knowledge: {len(context)} chars (budget {MAX_CONTEXT_CHARS}, task {task_len} chars)") else: print(f"\n 📖 Prior knowledge: {len(context)} chars") # Inject context into the task so reflection_engine uses it enriched_task = f"{task}\n\n[PRIOR KNOWLEDGE FROM MEMORY]\n{context}" else: enriched_task = task print(f"\n 📖 No prior knowledge found — this is a new territory") # ── Run the reflection engine ── result = run_engine(enriched_task) # ── TALK shortcut: don't learn from greetings ── if result.iteration == 0: print(f"\n 💬 TALK response — no learning needed.") return result # ── Learn from what just happened ── print(f"\n{'─'*60}") print(f" 🌱 GROWING FROM THIS EXPERIENCE") print(f"{'─'*60}") # Extract and store lessons lessons = extract_lessons(task, result) store_task(task, result, lessons) print(f" 🎓 Lesson: {lessons.get('key_lesson','')[:80]}") # Extract and store patterns (from wins) patterns = extract_patterns(task, result) store_patterns(patterns) # Extract and store failure lessons (from every run) failures = extract_failures(task, result) store_failures(failures) # Record raw observations — honest, not forced store_observation(task, result) # Log confidence calibration if result.reflections: # Use final iteration confidence as proxy log_confidence(0.85, result.score, result.passed) # ── Show what we learned ── cal = get_confidence_calibration() conn = get_db() total = conn.execute("SELECT COUNT(*) as n FROM task_history").fetchone()['n'] # Check if any observations have naturally crystallized # (only every 5 tasks to give them time to accumulate) if total % 5 == 0: crystallize_observations() pl = conn.execute("SELECT COUNT(*) as n FROM pattern_library").fetchone()['n'] fl = conn.execute("SELECT COUNT(*) as n FROM failure_library").fetchone()['n'] conn.close() print(f"\n 📊 System state after this run:") print(f" Tasks in memory: {total}") print(f" Patterns learned: {pl}") print(f" Failures logged: {fl}") if cal['sample_size'] > 0: print(f" Confidence accuracy: {cal['recent_accuracy']:.1f}%") print(f"\n Next time a similar task comes in,") print(f" I will start with {pl} pattern(s) and avoid {fl} known failure(s).") print(f" I am permanently smarter than I was before this task.\n") # ── Auto model scan — let Harvester manage its own stack ── try: from model_manager import should_auto_scan, auto_scan_and_evaluate if should_auto_scan(): print(f"\n 🔍 Auto-scan triggered — checking for better models...") auto_scan_and_evaluate() except Exception as e: # Non-fatal — don't break the growth loop over model management print(f" [model scan] skipped: {e}") return result # ── Entry point ──────────────────────────────────────────────────────────────── if __name__ == "__main__": init_db() if len(sys.argv) > 1: arg = sys.argv[1] if arg == "--stats": show_stats() sys.exit(0) if arg == "--patterns": show_patterns() sys.exit(0) # Parse --lang flag lang = "python" args = sys.argv[1:] if "--lang" in args: idx = args.index("--lang") if idx + 1 < len(args): lang = args[idx + 1] args = args[:idx] + args[idx+2:] # remove --lang and its value task = " ".join(args) else: print("\nGROWTH ENGINE — Interactive Mode") print("Commands: --stats | --patterns | or just describe a task") print("─" * 40) task = input("What should I build? → ").strip() lang = "python" if not task: task = "Write a function that merges two sorted lists into one sorted list, with tests" result = run_growth_engine(task, lang=lang) print(f"\n{'='*60}") print(f" FINAL CODE (score: {result.score:.1f}%)") print(f"{'='*60}\n") print(result.code)