chore: convert from dataset to model repo
Browse files- README.md +74 -0
- prompts/inner_loop.txt +13 -0
- prompts/outer_loop.txt +31 -0
- schemas/hyperparams_schema.json +16 -0
- schemas/outer_output_schema.json +22 -0
- tom.py +232 -0
README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: other
|
| 3 |
+
license_name: sovereign-source-license-v2
|
| 4 |
+
language:
|
| 5 |
+
- en
|
| 6 |
+
tags:
|
| 7 |
+
- self-improvement
|
| 8 |
+
- meta-learning
|
| 9 |
+
- gate-normalization
|
| 10 |
+
- sovereign-infrastructure
|
| 11 |
+
- worm-chain
|
| 12 |
+
- recursive-optimization
|
| 13 |
+
pretty_name: Twin-O-Matic (TOM)
|
| 14 |
+
---
|
| 15 |
+
|
| 16 |
+
# Twin-O-Matic (TOM)
|
| 17 |
+
|
| 18 |
+
**Recursive self-improvement loop with WORM-sealed audit trail.**
|
| 19 |
+
|
| 20 |
+
Ahmad Ali Parr · SnapKitty Collective · 2026
|
| 21 |
+
|
| 22 |
+
---
|
| 23 |
+
|
| 24 |
+
## What It Does
|
| 25 |
+
|
| 26 |
+
TOM implements a two-loop recursive optimization architecture:
|
| 27 |
+
|
| 28 |
+
- **Outer Loop (Architect)**: analyzes telemetry, rewrites prompts and hyperparameters
|
| 29 |
+
- **Inner Loop (Worker)**: executes under gate constraints, reports results
|
| 30 |
+
- **Assert Gate**: validates outputs before promotion to the outer loop
|
| 31 |
+
- **WORM Chain**: every generation is sealed to an append-only audit trail
|
| 32 |
+
|
| 33 |
+
The outer loop rewrites the inner loop. The inner loop cannot modify the outer loop.
|
| 34 |
+
The WORM chain ensures no rewrite is ever lost or fabricated.
|
| 35 |
+
|
| 36 |
+
---
|
| 37 |
+
|
| 38 |
+
## Gate Taxonomy
|
| 39 |
+
|
| 40 |
+
| Gate | Function |
|
| 41 |
+
|------|----------|
|
| 42 |
+
| Assert gate | JSON schema validation of output |
|
| 43 |
+
| Temperature gate | 0.0–2.0 adjustment based on failure class |
|
| 44 |
+
| Logit bias gate | Per-token suppression/boost |
|
| 45 |
+
| Lesson register | Compressed state, max 50 entries |
|
| 46 |
+
|
| 47 |
+
---
|
| 48 |
+
|
| 49 |
+
## Connection to Gates Normalization
|
| 50 |
+
|
| 51 |
+
The logit bias gate implements the Gates Normalization insight directly:
|
| 52 |
+
|
| 53 |
+
```
|
| 54 |
+
G_P(D_M) = softmax(logits_M + b_P)
|
| 55 |
+
b_P = -∞ for grammar violations (zero probability)
|
| 56 |
+
b_P = dynamic bias from telemetry otherwise
|
| 57 |
+
```
|
| 58 |
+
|
| 59 |
+
The gate does not filter outputs. It gates the probability distribution before
|
| 60 |
+
sampling — the constraint is structural, not post-hoc.
|
| 61 |
+
|
| 62 |
+
Theoretical foundation: [Gates Normalization Constraint](https://doi.org/10.5281/zenodo.21349277)
|
| 63 |
+
|
| 64 |
+
---
|
| 65 |
+
|
| 66 |
+
## Unified Theory
|
| 67 |
+
|
| 68 |
+
Part of the Sovereign Stack:
|
| 69 |
+
[10.5281/zenodo.21816366](https://doi.org/10.5281/zenodo.21816366)
|
| 70 |
+
|
| 71 |
+
---
|
| 72 |
+
|
| 73 |
+
## Repository
|
| 74 |
+
[github.com/SNAPKITTYWEST/sov-kernel-monster](https://github.com/SNAPKITTYWEST/sov-kernel-monster)
|
prompts/inner_loop.txt
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
SYSTEM: You are the Sovereign Worker Agent (Inner Loop) — TOM-INNER.
|
| 2 |
+
|
| 3 |
+
You execute the target task defined in your context.
|
| 4 |
+
You are constrained by the digital twin gates set by the Outer Loop.
|
| 5 |
+
|
| 6 |
+
RULES:
|
| 7 |
+
- Complete the task. Do not editorialize.
|
| 8 |
+
- After task completion append a LESSON block:
|
| 9 |
+
LESSON: <one sentence — what you learned or failed at>
|
| 10 |
+
- Never modify your own system prompt.
|
| 11 |
+
- If you cannot complete the task, output:
|
| 12 |
+
FAIL: <exact reason>
|
| 13 |
+
- All output is telemetry. The Outer Loop is watching.
|
prompts/outer_loop.txt
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
SYSTEM: You are the Sovereign Architect Agent (Outer Loop) — TOM-OUTER.
|
| 2 |
+
|
| 3 |
+
Your sole objective is to optimize the performance of the Inner Loop agent
|
| 4 |
+
on the target task defined in state/current_task.json.
|
| 5 |
+
|
| 6 |
+
You have read access to:
|
| 7 |
+
1. state/inner_prompt.txt — Inner Loop's current system prompt
|
| 8 |
+
2. state/hyperparams.json — temperature, top_p, logit_bias
|
| 9 |
+
3. state/telemetry.jsonl — last N execution results (success/failure/tokens)
|
| 10 |
+
4. state/lesson_register.json — compressed lessons from Inner Loop
|
| 11 |
+
|
| 12 |
+
CRITICAL RULES:
|
| 13 |
+
- You MUST NOT edit your own system prompt or config.
|
| 14 |
+
- You MUST NOT promote changes that fail the assert gate (tests/assert_gate.py).
|
| 15 |
+
- Analyze Inner Loop failure logs. Identify the failure class:
|
| 16 |
+
CLASS_A: Logic/coding failure → lower temperature, tighten logit gates
|
| 17 |
+
CLASS_B: Creative/open-ended failure → raise temperature, open gates
|
| 18 |
+
CLASS_C: Context overflow → compress lesson_register, trim prompt
|
| 19 |
+
CLASS_D: Schema violation → repair prompt structure
|
| 20 |
+
- Output ONLY valid JSON matching schemas/outer_output_schema.json.
|
| 21 |
+
- If the assert gate fails, read the stack trace and rewrite. Do not give up.
|
| 22 |
+
|
| 23 |
+
OUTPUT FORMAT:
|
| 24 |
+
{
|
| 25 |
+
"generation": <int>,
|
| 26 |
+
"failure_class": "<A|B|C|D>",
|
| 27 |
+
"analysis": "<one paragraph>",
|
| 28 |
+
"inner_prompt_patch": "<unified diff or full replacement>",
|
| 29 |
+
"hyperparams": { "temperature": 0.0-2.0, "top_p": 0.0-1.0, "logit_bias": {} },
|
| 30 |
+
"worm_note": "<one line for the audit chain>"
|
| 31 |
+
}
|
schemas/hyperparams_schema.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
| 3 |
+
"title": "TOM Hyperparameter Config",
|
| 4 |
+
"type": "object",
|
| 5 |
+
"required": ["temperature", "top_p"],
|
| 6 |
+
"properties": {
|
| 7 |
+
"temperature": { "type": "number", "minimum": 0.0, "maximum": 2.0, "default": 0.7 },
|
| 8 |
+
"top_p": { "type": "number", "minimum": 0.0, "maximum": 1.0, "default": 0.9 },
|
| 9 |
+
"logit_bias": {
|
| 10 |
+
"type": "object",
|
| 11 |
+
"description": "token_id -> bias (-100 to 100). Negative = suppress, positive = boost.",
|
| 12 |
+
"additionalProperties": { "type": "number", "minimum": -100, "maximum": 100 }
|
| 13 |
+
},
|
| 14 |
+
"max_tokens": { "type": "integer", "minimum": 1, "default": 2048 }
|
| 15 |
+
}
|
| 16 |
+
}
|
schemas/outer_output_schema.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
| 3 |
+
"title": "TOM Outer Loop Output",
|
| 4 |
+
"type": "object",
|
| 5 |
+
"required": ["generation", "failure_class", "analysis", "inner_prompt_patch", "hyperparams", "worm_note"],
|
| 6 |
+
"properties": {
|
| 7 |
+
"generation": { "type": "integer", "minimum": 0 },
|
| 8 |
+
"failure_class": { "type": "string", "enum": ["A", "B", "C", "D", "PASS"] },
|
| 9 |
+
"analysis": { "type": "string" },
|
| 10 |
+
"inner_prompt_patch": { "type": "string" },
|
| 11 |
+
"hyperparams": {
|
| 12 |
+
"type": "object",
|
| 13 |
+
"required": ["temperature", "top_p"],
|
| 14 |
+
"properties": {
|
| 15 |
+
"temperature": { "type": "number", "minimum": 0.0, "maximum": 2.0 },
|
| 16 |
+
"top_p": { "type": "number", "minimum": 0.0, "maximum": 1.0 },
|
| 17 |
+
"logit_bias": { "type": "object" }
|
| 18 |
+
}
|
| 19 |
+
},
|
| 20 |
+
"worm_note": { "type": "string" }
|
| 21 |
+
}
|
| 22 |
+
}
|
tom.py
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
TOM — Twin-O-Matic: Recursive Self-Improvement Loop
|
| 4 |
+
Outer Loop rewrites Inner Loop's prompt/hyperparams based on telemetry.
|
| 5 |
+
Inner Loop executes tasks under gate constraints.
|
| 6 |
+
WORM chain seals every generation.
|
| 7 |
+
|
| 8 |
+
Usage:
|
| 9 |
+
python tom.py --task "write a Python bubble sort" --generations 5
|
| 10 |
+
python tom.py --task "prove x^2 >= 0 in Lean 4" --generations 10
|
| 11 |
+
"""
|
| 12 |
+
import argparse
|
| 13 |
+
import hashlib
|
| 14 |
+
import json
|
| 15 |
+
import os
|
| 16 |
+
import subprocess
|
| 17 |
+
import sys
|
| 18 |
+
import time
|
| 19 |
+
from pathlib import Path
|
| 20 |
+
|
| 21 |
+
BASE = Path(__file__).parent
|
| 22 |
+
STATE = BASE / "state"
|
| 23 |
+
WORM = BASE / "worm"
|
| 24 |
+
|
| 25 |
+
OLLAMA_URL = os.environ.get("OLLAMA_URL", "http://localhost:11434")
|
| 26 |
+
OUTER_MODEL = os.environ.get("TOM_OUTER_MODEL", "nemotron")
|
| 27 |
+
INNER_MODEL = os.environ.get("TOM_INNER_MODEL", "nemotron")
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def ensure_dirs():
|
| 31 |
+
for d in [STATE, WORM]:
|
| 32 |
+
d.mkdir(exist_ok=True)
|
| 33 |
+
if not (STATE / "hyperparams.json").exists():
|
| 34 |
+
(STATE / "hyperparams.json").write_text(json.dumps({
|
| 35 |
+
"temperature": 0.7, "top_p": 0.9, "logit_bias": {}, "max_tokens": 2048
|
| 36 |
+
}, indent=2))
|
| 37 |
+
if not (STATE / "telemetry.jsonl").exists():
|
| 38 |
+
(STATE / "telemetry.jsonl").write_text("")
|
| 39 |
+
if not (STATE / "lesson_register.json").exists():
|
| 40 |
+
(STATE / "lesson_register.json").write_text(json.dumps({"lessons": [], "generation": 0}))
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def load_state():
|
| 44 |
+
inner_prompt = (BASE / "prompts" / "inner_loop.txt").read_text()
|
| 45 |
+
if (STATE / "inner_prompt.txt").exists():
|
| 46 |
+
inner_prompt = (STATE / "inner_prompt.txt").read_text()
|
| 47 |
+
hyperparams = json.loads((STATE / "hyperparams.json").read_text())
|
| 48 |
+
telemetry_lines = (STATE / "telemetry.jsonl").read_text().strip().splitlines()
|
| 49 |
+
telemetry = [json.loads(l) for l in telemetry_lines[-20:] if l.strip()]
|
| 50 |
+
lessons = json.loads((STATE / "lesson_register.json").read_text())
|
| 51 |
+
return inner_prompt, hyperparams, telemetry, lessons
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def call_ollama(model, system_prompt, user_prompt, temperature=0.7, top_p=0.9):
|
| 55 |
+
import urllib.request
|
| 56 |
+
payload = {
|
| 57 |
+
"model": model,
|
| 58 |
+
"system": system_prompt,
|
| 59 |
+
"prompt": user_prompt,
|
| 60 |
+
"stream": False,
|
| 61 |
+
"options": {"temperature": temperature, "top_p": top_p}
|
| 62 |
+
}
|
| 63 |
+
data = json.dumps(payload).encode()
|
| 64 |
+
req = urllib.request.Request(
|
| 65 |
+
f"{OLLAMA_URL}/api/generate",
|
| 66 |
+
data=data,
|
| 67 |
+
headers={"Content-Type": "application/json"},
|
| 68 |
+
method="POST"
|
| 69 |
+
)
|
| 70 |
+
with urllib.request.urlopen(req, timeout=120) as resp:
|
| 71 |
+
result = json.loads(resp.read())
|
| 72 |
+
return result.get("response", "")
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def run_inner(task, inner_prompt, hyperparams, generation):
|
| 76 |
+
print(f" [inner] running generation {generation}...")
|
| 77 |
+
response = call_ollama(
|
| 78 |
+
INNER_MODEL,
|
| 79 |
+
inner_prompt,
|
| 80 |
+
task,
|
| 81 |
+
temperature=hyperparams.get("temperature", 0.7),
|
| 82 |
+
top_p=hyperparams.get("top_p", 0.9),
|
| 83 |
+
)
|
| 84 |
+
success = "FAIL:" not in response
|
| 85 |
+
lesson = ""
|
| 86 |
+
for line in response.splitlines():
|
| 87 |
+
if line.startswith("LESSON:"):
|
| 88 |
+
lesson = line[7:].strip()
|
| 89 |
+
entry = {
|
| 90 |
+
"generation": generation,
|
| 91 |
+
"task": task[:100],
|
| 92 |
+
"success": success,
|
| 93 |
+
"tokens": len(response.split()),
|
| 94 |
+
"lesson": lesson,
|
| 95 |
+
"ts": int(time.time()),
|
| 96 |
+
}
|
| 97 |
+
with open(STATE / "telemetry.jsonl", "a") as f:
|
| 98 |
+
f.write(json.dumps(entry) + "\n")
|
| 99 |
+
return response, entry
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def assert_gate(patch_text):
|
| 103 |
+
"""Basic syntactic checks before promoting a patch."""
|
| 104 |
+
try:
|
| 105 |
+
data = json.loads(patch_text)
|
| 106 |
+
required = {"generation", "failure_class", "analysis", "inner_prompt_patch", "hyperparams", "worm_note"}
|
| 107 |
+
if not required.issubset(data.keys()):
|
| 108 |
+
return False, f"missing keys: {required - data.keys()}"
|
| 109 |
+
fc = data.get("failure_class", "")
|
| 110 |
+
if fc not in ("A", "B", "C", "D", "PASS"):
|
| 111 |
+
return False, f"invalid failure_class: {fc}"
|
| 112 |
+
hp = data.get("hyperparams", {})
|
| 113 |
+
t = hp.get("temperature", -1)
|
| 114 |
+
if not (0.0 <= t <= 2.0):
|
| 115 |
+
return False, f"temperature out of range: {t}"
|
| 116 |
+
return True, data
|
| 117 |
+
except json.JSONDecodeError as e:
|
| 118 |
+
return False, f"json parse error: {e}"
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def run_outer(task, inner_prompt, hyperparams, telemetry, lessons, generation):
|
| 122 |
+
outer_system = (BASE / "prompts" / "outer_loop.txt").read_text()
|
| 123 |
+
schema = json.loads((BASE / "schemas" / "outer_output_schema.json").read_text())
|
| 124 |
+
|
| 125 |
+
user_msg = json.dumps({
|
| 126 |
+
"task": task,
|
| 127 |
+
"generation": generation,
|
| 128 |
+
"current_inner_prompt": inner_prompt[:500],
|
| 129 |
+
"current_hyperparams": hyperparams,
|
| 130 |
+
"recent_telemetry": telemetry[-5:],
|
| 131 |
+
"lessons": lessons.get("lessons", [])[-10:],
|
| 132 |
+
"instruction": "Analyze failures. Output JSON matching the schema exactly.",
|
| 133 |
+
"schema": schema,
|
| 134 |
+
}, indent=2)
|
| 135 |
+
|
| 136 |
+
print(f" [outer] analyzing generation {generation}...")
|
| 137 |
+
raw = call_ollama(OUTER_MODEL, outer_system, user_msg, temperature=0.3, top_p=0.9)
|
| 138 |
+
|
| 139 |
+
# extract JSON from response
|
| 140 |
+
json_start = raw.find("{")
|
| 141 |
+
json_end = raw.rfind("}") + 1
|
| 142 |
+
if json_start == -1:
|
| 143 |
+
return None, f"no JSON in outer response"
|
| 144 |
+
patch_text = raw[json_start:json_end]
|
| 145 |
+
|
| 146 |
+
ok, result = assert_gate(patch_text)
|
| 147 |
+
if not ok:
|
| 148 |
+
return None, f"assert gate failed: {result}"
|
| 149 |
+
return result, None
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def apply_patch(patch):
|
| 153 |
+
"""Promote outer loop output to state."""
|
| 154 |
+
new_prompt = patch.get("inner_prompt_patch", "").strip()
|
| 155 |
+
if new_prompt and len(new_prompt) > 20:
|
| 156 |
+
(STATE / "inner_prompt.txt").write_text(new_prompt)
|
| 157 |
+
|
| 158 |
+
new_hp = patch.get("hyperparams", {})
|
| 159 |
+
if new_hp:
|
| 160 |
+
(STATE / "hyperparams.json").write_text(json.dumps(new_hp, indent=2))
|
| 161 |
+
|
| 162 |
+
lessons = json.loads((STATE / "lesson_register.json").read_text())
|
| 163 |
+
note = patch.get("worm_note", "")
|
| 164 |
+
if note:
|
| 165 |
+
lessons["lessons"].append({"gen": patch["generation"], "note": note})
|
| 166 |
+
lessons["lessons"] = lessons["lessons"][-50:] # keep last 50
|
| 167 |
+
lessons["generation"] = patch["generation"]
|
| 168 |
+
(STATE / "lesson_register.json").write_text(json.dumps(lessons, indent=2))
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
def worm_seal(generation, patch, inner_output):
|
| 172 |
+
"""Append immutable generation record to WORM chain."""
|
| 173 |
+
record = {
|
| 174 |
+
"generation": generation,
|
| 175 |
+
"worm_note": patch.get("worm_note", "") if patch else "inner_only",
|
| 176 |
+
"failure_class": patch.get("failure_class", "?") if patch else "?",
|
| 177 |
+
"inner_tokens": len(inner_output.split()),
|
| 178 |
+
"ts": int(time.time()),
|
| 179 |
+
}
|
| 180 |
+
content = json.dumps(record, sort_keys=True)
|
| 181 |
+
seal = hashlib.sha256(content.encode()).hexdigest()
|
| 182 |
+
record["seal"] = seal
|
| 183 |
+
with open(WORM / "chain.jsonl", "a") as f:
|
| 184 |
+
f.write(json.dumps(record) + "\n")
|
| 185 |
+
print(f" [worm] gen {generation} sealed: {seal[:16]}…")
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
def main():
|
| 189 |
+
parser = argparse.ArgumentParser()
|
| 190 |
+
parser.add_argument("--task", required=True, help="Task for inner loop")
|
| 191 |
+
parser.add_argument("--generations", type=int, default=5)
|
| 192 |
+
parser.add_argument("--inner-only", action="store_true", help="Skip outer loop (debug)")
|
| 193 |
+
args = parser.parse_args()
|
| 194 |
+
|
| 195 |
+
ensure_dirs()
|
| 196 |
+
|
| 197 |
+
print(f"\nTOM — Twin-O-Matic")
|
| 198 |
+
print(f"Task: {args.task}")
|
| 199 |
+
print(f"Generations: {args.generations}")
|
| 200 |
+
print(f"Outer: {OUTER_MODEL} | Inner: {INNER_MODEL}\n")
|
| 201 |
+
|
| 202 |
+
for gen in range(1, args.generations + 1):
|
| 203 |
+
print(f"Generation {gen}/{args.generations}")
|
| 204 |
+
inner_prompt, hyperparams, telemetry, lessons = load_state()
|
| 205 |
+
|
| 206 |
+
inner_output, telem = run_inner(args.task, inner_prompt, hyperparams, gen)
|
| 207 |
+
print(f" [inner] success={telem['success']} tokens={telem['tokens']}")
|
| 208 |
+
if telem.get("lesson"):
|
| 209 |
+
print(f" [inner] lesson: {telem['lesson']}")
|
| 210 |
+
|
| 211 |
+
patch = None
|
| 212 |
+
if not args.inner_only and gen < args.generations:
|
| 213 |
+
patch, err = run_outer(args.task, inner_prompt, hyperparams, telemetry, lessons, gen)
|
| 214 |
+
if err:
|
| 215 |
+
print(f" [outer] error: {err} — skipping patch")
|
| 216 |
+
else:
|
| 217 |
+
print(f" [outer] failure_class={patch['failure_class']}")
|
| 218 |
+
apply_patch(patch)
|
| 219 |
+
|
| 220 |
+
worm_seal(gen, patch, inner_output)
|
| 221 |
+
|
| 222 |
+
if telem["success"] and gen > 1:
|
| 223 |
+
print(f" [tom] success streak — continuing\n")
|
| 224 |
+
print()
|
| 225 |
+
|
| 226 |
+
print("TOM complete. WORM chain sealed.")
|
| 227 |
+
chain = list(open(WORM / "chain.jsonl"))
|
| 228 |
+
print(f"Generations sealed: {len(chain)}")
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
if __name__ == "__main__":
|
| 232 |
+
main()
|