File size: 5,909 Bytes
12ab90a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
123
124
125
126
127
128
129
# -*- coding: utf-8 -*-
"""
context_engine.py β€” Agentic Context Engine (ACE) & Auto-Compactor
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Implements the 3-agent self-improvement loop:
  1. Generator:  Space 3 (Forge) executes code based on prompt.
  2. Reflector:  Analyzes the test log and verdict from Space 6 (Sandbox).
                 Determines what succeeded, what failed, and why.
  3. Curator:    Updates the persistent "playbook" in the Second Brain
                 with actionable instructions to avoid repeating mistakes.

Also implements the Auto-Compactor:
  - Scans playbooks and logs.
  - Summarises and merges duplicate rules to keep context within
    the Bell Curve apex (preventing context poisoning).
"""

import json
import logging
import time
from second_brain import SecondBrainWrapper
from swarm_llm import swarm

logger = logging.getLogger("context_engine")

class ContextEngine:
    def __init__(self, brain: SecondBrainWrapper):
        self.brain = brain

    # ── ACE Reflect & Curate ──────────────────────────────────────────────────

    async def reflect_and_curate(
        self,
        project_name: str,
        task_prompt: str,
        result_summary: str,
        verdict: str,
        reason: str
    ) -> str:
        """
        Runs after an execution cycle.
        If failed, reflects on why and updates the project playbook.
        If succeeded, records the success pattern.
        """
        playbook_path = f"space3-forge/debugging/{project_name}_playbook.md"
        current_playbook = self.brain.read(playbook_path, "brain")

        if verdict == "FAIL":
            logger.info(f"[ACE] Project '{project_name}' failed verification. Reflecting…")
            reflection_prompt = f"""Task attempted:
"{task_prompt}"

Execution summary:
"{result_summary}"

Test Failure Reason:
"{reason}"

Current Playbook rules:
{current_playbook if current_playbook else "_No rules yet._"}

---
What went wrong? Write exactly 1 or 2 new concrete guidelines for the coder agent to prevent this specific failure in the future.
Keep guidelines extremely brief, specific, and actionable. Do NOT repeat existing rules.
"""
            # Use local SwarmLLM to reflect (saving NIM quota)
            new_rules = await swarm.infer(reflection_prompt, system="You are a senior code architect reflecting on test failures.")
            
            # Curate: Append new rules to playbook
            updated_playbook = current_playbook + f"\n\n### Failure Correction ({time.strftime('%Y-%m-%d')})\n{new_rules.strip()}"
            self.brain.write(playbook_path, updated_playbook, f"[ACE] Add failure corrections for {project_name}")
            logger.info(f"[ACE] Curated playbook for '{project_name}' updated on GitHub.")
            return new_rules
            
        elif verdict == "PASS" and not current_playbook:
            # Seed the playbook with success patterns
            logger.info(f"[ACE] Project '{project_name}' passed. Seeding playbook.")
            seed_content = f"""# Playbook: {project_name}
_Self-improving ruleset curated by ACE (Agentic Context Engine)_

## Success Rules
- Initial implementation passed test suite successfully. Keep code simple and modular.
"""
            self.brain.write(playbook_path, seed_content, f"[ACE] Seed playbook for {project_name}")
            return "Seed rules created"
            
        return "No curation required"

    # ── Auto-Compactor ────────────────────────────────────────────────────────

    async def compact_wiki(self):
        """
        Auto-Compaction Protocol.
        Scans all files in the Second Brain.
        If a playbook or log exceeds its slot budget, consolidates and merges
        duplicate rules to prevent context poisoning.
        """
        logger.info("[Compactor] Running wiki compaction sweep…")
        
        # 1. Compact playbooks in space3-forge/debugging/
        playbooks = self.brain.list_files("space3-forge/debugging")
        for p in playbooks:
            content = self.brain.read(p, "brain")
            if len(content) > 3000:
                logger.info(f"[Compactor] Playbook '{p}' is large ({len(content)} chars). Compacting…")
                compaction_prompt = f"""The following is a coding playbook with rules collected over multiple cycles:
{content}

---
Consolidate the rules above. Remove duplicates, merge similar guidelines, and output a clean, highly condensed list of rules.
Maintain the markdown header structure. Do NOT lose important technical details.
"""
                compacted = await swarm.infer(compaction_prompt, system="You are an expert compiler that deduplicates and condenses playbooks.")
                self.brain.write(p, compacted, f"[Compactor] Compacted playbook {p}")
                logger.info(f"[Compactor] Compacted '{p}' down to {len(compacted)} chars.")

        # 2. Compact loop logs in space2-cerebrum/loop_log.md
        log_path = "space2-cerebrum/loop_log.md"
        log_content = self.brain.read(log_path, "brain")
        if len(log_content) > 4000:
            logger.info(f"[Compactor] Log '{log_path}' exceeds limit. Archiving old entries…")
            lines = log_content.splitlines()
            # Keep only the last 30 lines, archive the rest
            recent = "\n".join(lines[-30:])
            self.brain.write(log_path, recent, "[Compactor] Trim and archive old loop logs")
            logger.info(f"[Compactor] Loop log trimmed.")
            
        logger.info("[Compactor] Compaction sweep complete.")