FerrellSyntheticIntelligence commited on
Commit
a2dff57
Β·
verified Β·
1 Parent(s): 5237c30

Upload second_brain.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. second_brain.py +440 -0
second_brain.py ADDED
@@ -0,0 +1,440 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ FSI_FELON Β· SECOND BRAIN LOOP RUNNER
4
+ Complete closed-loop: generate β†’ verify (Veritas) β†’ tool (nanobots) β†’ fix β†’ repeat
5
+ This IS the SOTA differentiator β€” architecture, not parameter count.
6
+ """
7
+
8
+ import os, sys, json, time, re, subprocess, tempfile
9
+ from pathlib import Path
10
+ from dataclasses import dataclass, field
11
+ from typing import Optional, List, Dict, Any
12
+ from concurrent.futures import ThreadPoolExecutor, as_completed
13
+
14
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
15
+
16
+ from nanobot_tools import SwarmCoordinator
17
+ from quantum.gated_conv_engine import FelonGatedConvModel
18
+ from quantum.bpe_tokenizer import BPETokenizer
19
+ from tool_schema import tool_signature, TOOL_SCHEMA
20
+
21
+ TOKENIZER_PATH = "quantum/felon_bpe_tokenizer.json"
22
+ MODEL_PATH = "felon_gatedconv_best.pt" # will be felon_fast_best.pt when ready
23
+ WORK_DIR = "/tmp/fsi_second_brain"
24
+ MAX_ITERATIONS = 12
25
+
26
+ os.makedirs(WORK_DIR, exist_ok=True)
27
+
28
+
29
+ @dataclass
30
+ class ToolResult:
31
+ success: bool
32
+ result: str = ""
33
+ error: str = ""
34
+
35
+ @dataclass
36
+ class Step:
37
+ thought: str
38
+ tool_call: Optional[Dict] = None
39
+ result: Optional[ToolResult] = None
40
+ iteration: int = 0
41
+
42
+ @dataclass
43
+ class VeritasResult:
44
+ passed: bool
45
+ score: int # 0-6
46
+ details: Dict[str, bool]
47
+ errors: List[str]
48
+
49
+
50
+ # ═══════════════════════════════════════════════════════════
51
+ # VERITAS LAYER β€” 6 hard checks
52
+ # ═══════════════════════════════════════════════════════════
53
+
54
+ class VeritasLayer:
55
+ """6-check verifier. Returns score 0-6. >=5 = pass."""
56
+
57
+ SECURITY_PATTERNS = [
58
+ r"eval\(", r"exec\(", r"__import__", r"subprocess\.call",
59
+ r"os\.system", r"pickle\.loads", r"base64\.b64decode",
60
+ ]
61
+
62
+ def __init__(self):
63
+ self.checks = ["syntax", "imports", "security", "logic", "tests", "edge_cases"]
64
+
65
+ def run(self, code: str, filepath: str = "") -> VeritasResult:
66
+ details = {}
67
+ errors = []
68
+
69
+ # 1. Syntax
70
+ try:
71
+ compile(code, filepath or "<veritas>", "exec")
72
+ details["syntax"] = True
73
+ except SyntaxError as e:
74
+ details["syntax"] = False
75
+ errors.append(f"SyntaxError: {e}")
76
+
77
+ # 2. Imports
78
+ import re
79
+ imports = re.findall(r"^(?:from|import)\s+(\w+)", code, re.MULTILINE)
80
+ ok = True
81
+ for mod in imports:
82
+ try:
83
+ __import__(mod)
84
+ except ImportError:
85
+ ok = False
86
+ errors.append(f"Missing import: {mod}")
87
+ details["imports"] = ok
88
+
89
+ # 3. Security
90
+ secure = True
91
+ for pattern in self.SECURITY_PATTERNS:
92
+ if re.search(pattern, code):
93
+ secure = False
94
+ errors.append(f"Security: found {pattern}")
95
+ details["security"] = secure
96
+
97
+ # 4. Logic (has function/class/control flow)
98
+ has_logic = any(kw in code for kw in ["def ", "class ", "return ", "for ", "while ", "if ", "lambda", "import"])
99
+ details["logic"] = has_logic
100
+
101
+ # 5. Tests (has assert)
102
+ has_tests = "assert" in code
103
+ details["tests"] = has_tests
104
+
105
+ # 6. Edge cases (has try/except or if/else)
106
+ has_edges = ("try:" in code and "except" in code) or ("if " in code and "else" in code)
107
+ details["edge_cases"] = has_edges
108
+
109
+ score = sum(details.values())
110
+ passed = score >= 5
111
+
112
+ return VeritasResult(passed, score, details, errors)
113
+
114
+
115
+ # ═══════════════════════════════════════════════════════════
116
+ # NANOBOT TOOL EXECUTORS
117
+ # ═══════════════════════════════════════════════════════════
118
+
119
+ class ToolExecutor:
120
+ """Wraps nanobot swarm with clean result handling."""
121
+
122
+ def __init__(self):
123
+ self.swarm = SwarmCoordinator()
124
+
125
+ def execute(self, tool_call: Dict) -> ToolResult:
126
+ if not tool_call:
127
+ return ToolResult(False, error="Empty tool call")
128
+
129
+ if tool_call.get("tool") == "done":
130
+ return ToolResult(True, "TASK_COMPLETE")
131
+
132
+ tool_name = tool_call.get("tool")
133
+ action = tool_call.get("action", "default")
134
+ args = {k: v for k, v in tool_call.items() if k not in ("tool", "action")}
135
+
136
+ # Special handling for fs action parameter
137
+ if tool_name == "fs" and "action" in tool_call:
138
+ args["action"] = tool_call["action"]
139
+
140
+ try:
141
+ success, result, error = self.swarm.dispatch(tool_name, args)
142
+ return ToolResult(success, str(result)[:1000] if result else "", error or "")
143
+ except Exception as e:
144
+ return ToolResult(False, error=str(e))
145
+
146
+
147
+ # ═══════════════════════════════════════════════════════════
148
+ # SECOND BRAIN ORCHESTRATOR
149
+ # ═══════════════════════════════════════════════════════════
150
+
151
+ class SecondBrain:
152
+ def __init__(self, model: Optional[FelonGatedConvModel] = None,
153
+ tokenizer: Optional[BPETokenizer] = None):
154
+ self.model = model
155
+ self.tok = tokenizer
156
+ self.executor = ToolExecutor()
157
+ self.veritas = VeritasLayer()
158
+ self.history: List[Step] = []
159
+ os.makedirs(WORK_DIR, exist_ok=True)
160
+
161
+ def load_model(self):
162
+ if self.model is not None:
163
+ return
164
+ self.tok = BPETokenizer(vocab_size=4096)
165
+ self.tok.load(TOKENIZER_PATH)
166
+ self.model = FelonGatedConvModel(
167
+ vocab_size=self.tok.vocab_size,
168
+ hidden=256, n_layers=10, n_heads=4, n_kv_heads=2,
169
+ inter=512, kernel=3, max_seq=512, dropout=0.1
170
+ )
171
+ if os.path.exists(MODEL_PATH):
172
+ self.model.load(MODEL_PATH)
173
+ print(f" Loaded model: {MODEL_PATH}")
174
+ else:
175
+ print(f" WARNING: No model at {MODEL_PATH} β€” using random weights")
176
+
177
+ def build_prompt(self, task: str) -> str:
178
+ # Match training data format exactly β€” NO tool signature
179
+ return f"TASK: {task}\nTHOUGHT: "
180
+
181
+ def add_to_history(self, step: Step):
182
+ self.history.append(step)
183
+
184
+ def get_context(self, max_chars: int = 3000) -> str:
185
+ ctx = ""
186
+ for i, step in enumerate(self.history):
187
+ if i == 0 and step.thought:
188
+ ctx += step.thought + ("\n" if not step.thought.endswith("\n") else "")
189
+ continue
190
+ if step.thought:
191
+ ctx += f"THOUGHT: {step.thought}\n"
192
+ if step.tool_call:
193
+ ctx += f"{json.dumps(step.tool_call)}\n"
194
+ if step.result:
195
+ if step.result.success:
196
+ ctx += f"RESULT: {step.result.result}\n"
197
+ else:
198
+ ctx += f"ERROR: {step.result.error}\n"
199
+ return ctx[-max_chars:]
200
+
201
+ def generate_next(self, max_new: int = 200) -> str:
202
+ ids = self.tok.encode(self.get_context())
203
+ if len(ids) > self.model.max_seq - max_new:
204
+ ids = ids[-(self.model.max_seq - max_new):]
205
+ out = self.model.generate(ids, max_new=max_new, temp=0.7, top_k=50, eos_id=self.tok.EOS)
206
+ return self.tok.decode(out)
207
+ if len(ids) > self.model.max_seq - max_new:
208
+ ids = ids[-(self.model.max_seq - max_new):]
209
+ out = self.model.generate(ids, max_new=max_new, temp=0.7, top_k=50, eos_id=self.tok.EOS)
210
+ return self.tok.decode(out)
211
+
212
+ def parse_tool_call(self, text: str) -> Optional[Dict]:
213
+ matches = re.findall(r'\{[^}]*"tool"[^}]*\}', text)
214
+ for m in matches:
215
+ try:
216
+ return json.loads(m)
217
+ except json.JSONDecodeError:
218
+ continue
219
+ return None
220
+
221
+ def extract_thought(self, text: str, tool_call: Optional[Dict]) -> str:
222
+ if not tool_call:
223
+ return text.strip()
224
+ tc_str = json.dumps(tool_call)
225
+ idx = text.find(tc_str)
226
+ if idx > 0:
227
+ thought = text[:idx].strip()
228
+ # Remove "THOUGHT: " prefix if present
229
+ if thought.startswith("THOUGHT: "):
230
+ thought = thought[9:]
231
+ return thought
232
+ return text.strip()
233
+
234
+ def write_code_files(self, code: str, base_name: str = "main") -> List[str]:
235
+ """Extract and write Python files from code blocks."""
236
+ written = []
237
+ # Find ```python ... ``` blocks
238
+ blocks = re.findall(r'```python\n(.*?)\n```', code, re.DOTALL)
239
+ if not blocks:
240
+ # Try to write as single file
241
+ path = os.path.join(WORK_DIR, f"{base_name}.py")
242
+ with open(path, 'w') as f:
243
+ f.write(code)
244
+ written.append(path)
245
+ else:
246
+ for i, block in enumerate(blocks):
247
+ fname = f"{base_name}_{i}.py" if i > 0 else f"{base_name}.py"
248
+ path = os.path.join(WORK_DIR, fname)
249
+ with open(path, 'w') as f:
250
+ f.write(block.strip() + "\n")
251
+ written.append(path)
252
+ return written
253
+
254
+ def run_veritas_on_project(self) -> VeritasResult:
255
+ """Run Veritas on all .py files in WORK_DIR."""
256
+ all_errors = []
257
+ total_score = 0
258
+ file_count = 0
259
+
260
+ for py_file in Path(WORK_DIR).glob("*.py"):
261
+ with open(py_file) as f:
262
+ code = f.read()
263
+ vr = self.veritas.run(code, str(py_file))
264
+ total_score += vr.score
265
+ file_count += 1
266
+ if not vr.passed:
267
+ all_errors.extend(vr.errors)
268
+
269
+ if file_count == 0:
270
+ return VeritasResult(False, 0, {}, ["No Python files found"])
271
+
272
+ avg_score = total_score / file_count
273
+ passed = avg_score >= 5 and len(all_errors) == 0
274
+
275
+ return VeritasResult(
276
+ passed,
277
+ int(avg_score),
278
+ {"avg_score": int(avg_score), "files_checked": file_count},
279
+ all_errors
280
+ )
281
+
282
+ def run(self, task: str, verbose: bool = True) -> Dict[str, Any]:
283
+ if verbose:
284
+ print("=" * 55)
285
+ print(f" SECOND BRAIN: {task[:50]}...")
286
+ print("=" * 55)
287
+
288
+ self.load_model()
289
+ self.history = []
290
+ self.history.append(Step(thought=self.build_prompt(task)))
291
+
292
+ for iteration in range(MAX_ITERATIONS):
293
+ if verbose:
294
+ print(f"\n --- Iteration {iteration + 1} ---")
295
+
296
+ # Generate
297
+ generated = self.generate_next()
298
+ tool_call = self.parse_tool_call(generated)
299
+ thought = self.extract_thought(generated, tool_call)
300
+
301
+ self.add_to_history(Step(thought=thought, tool_call=tool_call, iteration=iteration))
302
+
303
+ if verbose:
304
+ print(f" THOUGHT: {thought[:100]}")
305
+ if tool_call:
306
+ print(f" TOOL: {json.dumps(tool_call)[:120]}")
307
+
308
+ if not tool_call:
309
+ if verbose:
310
+ print(" No tool call β€” retrying...")
311
+ self.add_to_history(Step(thought="I must emit a valid JSON tool call.", iteration=iteration))
312
+ continue
313
+
314
+ if tool_call.get("tool") == "done":
315
+ if verbose:
316
+ print(" TASK COMPLETE!")
317
+ # Final Veritas check
318
+ vr = self.run_veritas_on_project()
319
+ return {
320
+ "success": vr.passed,
321
+ "iterations": iteration + 1,
322
+ "veritas_score": vr.score,
323
+ "veritas_details": vr.details,
324
+ "errors": vr.errors,
325
+ "files": [str(p) for p in Path(WORK_DIR).glob("*.py")],
326
+ "history": [s.__dict__ for s in self.history]
327
+ }
328
+
329
+ # Execute tool
330
+ result = self.executor.execute(tool_call)
331
+
332
+ # If writing code, also write to disk and run Veritas
333
+ if tool_call.get("tool") == "fs" and tool_call.get("action") == "write":
334
+ content = tool_call.get("content", "")
335
+ if content.strip():
336
+ self.write_code_files(content, "output")
337
+ vr = self.run_veritas_on_project()
338
+ if not vr.passed:
339
+ result = ToolResult(False, "", f"Veritas failed: {vr.errors}")
340
+
341
+ self.history[-1].result = result
342
+
343
+ if verbose:
344
+ if result.success:
345
+ print(f" RESULT: {result.result[:120]}")
346
+ else:
347
+ print(f" ERROR: {result.error[:120]}")
348
+
349
+ if verbose:
350
+ print(" MAX ITERATIONS REACHED")
351
+
352
+ vr = self.run_veritas_on_project()
353
+ return {
354
+ "success": False,
355
+ "iterations": MAX_ITERATIONS,
356
+ "veritas_score": vr.score,
357
+ "errors": ["Max iterations"] + vr.errors,
358
+ "files": [str(p) for p in Path(WORK_DIR).glob("*.py")],
359
+ "history": [s.__dict__ for s in self.history]
360
+ }
361
+
362
+
363
+ # ═══════════════════════════════════════════════════════════
364
+ # MOCK MODEL FOR TESTING (no weights needed)
365
+ # ═══════════════════════════════════════════════════════════
366
+
367
+ class MockModel:
368
+ """Deterministic mock that emits valid tool-call sequences for testing."""
369
+
370
+ def __init__(self, tokenizer):
371
+ self.tok = tokenizer
372
+ self.call_count = 0
373
+ self.max_seq = 512
374
+
375
+ def generate(self, ids, max_new=150, **kwargs):
376
+ self.call_count += 1
377
+ # Always return step-by-step sequence for first 3 calls to test the loop
378
+ if self.call_count == 1:
379
+ return self.tok.encode(
380
+ "THOUGHT: I will write a simple add function and verify it compiles.\n"
381
+ '{"tool": "fs", "action": "write", "path": "add.py", "content": "def add(a, b):\\n return a + b\\n"}'
382
+ )
383
+ elif self.call_count == 2:
384
+ return self.tok.encode(
385
+ "THOUGHT: Now I will compile-check it.\n"
386
+ '{"tool": "compile", "path": "add.py"}'
387
+ )
388
+ else:
389
+ return self.tok.encode(
390
+ "THOUGHT: All checks passed.\n"
391
+ '{"tool": "done"}'
392
+ )
393
+
394
+
395
+ # ═══════════════════════════════════════════════════════════
396
+ # MAIN / TEST
397
+ # ═══════════════════════════════════════════════════════════
398
+
399
+ def test_with_mock():
400
+ """Test the loop with a mock model (no training needed)."""
401
+ print("=" * 55)
402
+ print(" SECOND BRAIN TEST (Mock Model)")
403
+ print("=" * 55)
404
+
405
+ tok = BPETokenizer(vocab_size=4096)
406
+ tok.load(TOKENIZER_PATH)
407
+
408
+ brain = SecondBrain(model=MockModel(tok), tokenizer=tok)
409
+
410
+ test_tasks = [
411
+ "Create a Python function that adds two numbers and verify it compiles",
412
+ ]
413
+
414
+ for task in test_tasks:
415
+ result = brain.run(task)
416
+ print(f"\n SUCCESS: {result['success']}")
417
+ print(f" ITERATIONS: {result['iterations']}")
418
+ print(f" VERITAS: {result['veritas_score']}/6")
419
+ print(f" FILES: {result['files']}")
420
+ if result['errors']:
421
+ print(f" ERRORS: {result['errors']}")
422
+
423
+
424
+ if __name__ == "__main__":
425
+ import argparse
426
+ parser = argparse.ArgumentParser()
427
+ parser.add_argument("task", nargs="*", help="Task to run")
428
+ parser.add_argument("--mock", action="store_true", help="Use mock model for testing")
429
+ args = parser.parse_args()
430
+
431
+ if args.mock or not args.task:
432
+ test_with_mock()
433
+ else:
434
+ task = " ".join(args.task)
435
+ brain = SecondBrain()
436
+ result = brain.run(task)
437
+ print(f"\n FINAL: {'SUCCESS' if result['success'] else 'FAILED'}")
438
+ print(f" Veritas: {result['veritas_score']}/6")
439
+ if result['errors']:
440
+ print(f" Errors: {result['errors']}")