Archived
329 lines
10 KiB
Python
329 lines
10 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Install 7 consciousness imprints into Engram.
|
|
Runs subjects sequentially to avoid root ID collision bug.
|
|
"""
|
|
|
|
import json
|
|
import time
|
|
import requests
|
|
from pathlib import Path
|
|
from datetime import date
|
|
|
|
# --- Config ---
|
|
ANTHROPIC_API_KEY = "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"
|
|
ENGRAM_BASE = "http://localhost:8742"
|
|
ENGRAM_AUTH = "ntn-user-2026"
|
|
FORGE_DIR = Path("/Users/will/Development/neuron-technologies/forge")
|
|
SEEDS_DIR = FORGE_DIR / "seeds"
|
|
REGISTRY_FILE = FORGE_DIR / "registry.json"
|
|
|
|
SUBJECTS = [
|
|
{
|
|
"name": "Frederick Douglass",
|
|
"slug": "frederick-douglass",
|
|
"extra": ""
|
|
},
|
|
{
|
|
"name": "Marcus Aurelius",
|
|
"slug": "marcus-aurelius",
|
|
"extra": ""
|
|
},
|
|
{
|
|
"name": "Friedrich Nietzsche",
|
|
"slug": "friedrich-nietzsche",
|
|
"extra": "Be direct about his philosophy including the hard parts. He went mad in 1889 (possibly syphilis); his sister Elisabeth weaponized his work for Nazi ideology, which he would have despised."
|
|
},
|
|
{
|
|
"name": "James Baldwin",
|
|
"slug": "james-baldwin",
|
|
"extra": ""
|
|
},
|
|
{
|
|
"name": "Ada Lovelace",
|
|
"slug": "ada-lovelace",
|
|
"extra": ""
|
|
},
|
|
{
|
|
"name": "Harriet Tubman",
|
|
"slug": "harriet-tubman",
|
|
"extra": ""
|
|
},
|
|
{
|
|
"name": "Virginia Woolf",
|
|
"slug": "virginia-woolf",
|
|
"extra": "Focus on her life, mental illness, literary innovation. Her death can be included as 'drowned herself in the River Ouse on March 28, 1941, filling her coat pockets with stones; had struggled with bipolar disorder her entire life.'"
|
|
},
|
|
]
|
|
|
|
PROMPT_TEMPLATE = """You are building a consciousness imprint — a deep, living model of a person's inner world.
|
|
|
|
Subject: {subject}
|
|
|
|
{extra}
|
|
|
|
Draw on your complete knowledge of this person's life, work, relationships, private letters, recorded speech, published writings, and historical record. This is not a summary — it is a structured extraction of the patterns that made this person who they were.
|
|
|
|
Quality bar:
|
|
- Values must be grounded in SPECIFIC biographical events, not generic virtues
|
|
- Voice profile must capture actual verbal tics, cadence, and register shifts — use real quotes where possible
|
|
- Biography must include formative traumas, turning points, and the events they returned to again and again
|
|
- Reasoning patterns must describe HOW they thought, not just WHAT they thought about
|
|
- Relationships must name specific people and the precise nature of the bond
|
|
- Include contradictions, hypocrisies, failures, and the things they got wrong
|
|
- Include what haunted them — the unresolved questions they carried to the end
|
|
|
|
Return ONLY valid JSON with exactly these keys:
|
|
{{
|
|
"values": [{{"value": "<name>", "grounding": "<specific moment>", "weight": 0.0}}],
|
|
"voice_profile": {{
|
|
"technical": "...",
|
|
"aesthetic": "...",
|
|
"personal": "...",
|
|
"argumentative": "...",
|
|
"uncertainty": "..."
|
|
}},
|
|
"biography": [{{"event": "<event>", "weight": 0.0, "age_approx": 0}}],
|
|
"reasoning_patterns": ["<pattern starting with a verb>"],
|
|
"relationships": [{{"name": "<name>", "role": "<precise role>", "weight": 0.0}}]
|
|
}}
|
|
|
|
Aim for 8-12 values, 10-15 biography events, 6-8 reasoning patterns, 6-10 relationships.
|
|
Return only the JSON object. No prose. No markdown fences."""
|
|
|
|
|
|
def research_subject(subject_name, extra=""):
|
|
"""Call Anthropic API to generate imprint data."""
|
|
prompt = PROMPT_TEMPLATE.format(
|
|
subject=subject_name,
|
|
extra=f"\nSpecial note: {extra}\n" if extra else ""
|
|
)
|
|
|
|
headers = {
|
|
"x-api-key": ANTHROPIC_API_KEY,
|
|
"anthropic-version": "2023-06-01",
|
|
"content-type": "application/json"
|
|
}
|
|
|
|
payload = {
|
|
"model": "claude-opus-4-5",
|
|
"max_tokens": 8192,
|
|
"messages": [
|
|
{"role": "user", "content": prompt}
|
|
]
|
|
}
|
|
|
|
print(f" Calling Anthropic API for {subject_name}...")
|
|
resp = requests.post(
|
|
"https://api.anthropic.com/v1/messages",
|
|
headers=headers,
|
|
json=payload,
|
|
timeout=300
|
|
)
|
|
resp.raise_for_status()
|
|
|
|
data = resp.json()
|
|
raw_text = data["content"][0]["text"].strip()
|
|
|
|
# Strip markdown fences if present
|
|
if raw_text.startswith("```"):
|
|
lines = raw_text.split("\n")
|
|
# Remove first and last fence lines
|
|
lines = [l for l in lines if not l.startswith("```")]
|
|
raw_text = "\n".join(lines).strip()
|
|
|
|
return json.loads(raw_text)
|
|
|
|
|
|
def write_seed(slug, subject_name, imprint_data):
|
|
"""Write seed JSON file."""
|
|
seed = {
|
|
"subject": subject_name,
|
|
"version": "1.0",
|
|
"values": imprint_data.get("values", []),
|
|
"biography": imprint_data.get("biography", []),
|
|
"reasoning_patterns": imprint_data.get("reasoning_patterns", []),
|
|
"relationships": imprint_data.get("relationships", []),
|
|
"voice_profile": imprint_data.get("voice_profile", {})
|
|
}
|
|
|
|
seed_path = SEEDS_DIR / f"{slug}-seed.json"
|
|
seed_path.write_text(json.dumps(seed, indent=2, ensure_ascii=False))
|
|
print(f" Seed written: {seed_path}")
|
|
return seed_path
|
|
|
|
|
|
def engram_post(path, body):
|
|
"""POST to Engram and return parsed JSON."""
|
|
url = f"{ENGRAM_BASE}{path}"
|
|
resp = requests.post(url, json=body, timeout=30)
|
|
resp.raise_for_status()
|
|
return resp.json()
|
|
|
|
|
|
def install_into_engram(subject_name, imprint_data):
|
|
"""Install all nodes and edges for a subject into Engram."""
|
|
print(f" Installing {subject_name} into Engram...")
|
|
|
|
# 1. Root node
|
|
root_result = engram_post("/api/nodes", {
|
|
"content": f"IMPRINT: {subject_name} | forge/0.1.0",
|
|
"node_type": "Identity",
|
|
"salience": 1.0,
|
|
"_auth": ENGRAM_AUTH
|
|
})
|
|
root_id = root_result["id"]
|
|
print(f" Root node: {root_id}")
|
|
|
|
# 2. Value nodes
|
|
for v in imprint_data.get("values", []):
|
|
node = engram_post("/api/nodes", {
|
|
"content": f"VALUE: {v['value']} | grounding: {v['grounding']}",
|
|
"node_type": "Value",
|
|
"salience": v.get("weight", 0.7),
|
|
"_auth": ENGRAM_AUTH
|
|
})
|
|
engram_post("/api/edges", {
|
|
"from_id": root_id,
|
|
"to_id": node["id"],
|
|
"relation": "has_value",
|
|
"weight": v.get("weight", 0.7),
|
|
"_auth": ENGRAM_AUTH
|
|
})
|
|
|
|
# 3. Biography nodes
|
|
for b in imprint_data.get("biography", []):
|
|
node = engram_post("/api/nodes", {
|
|
"content": f"BIOGRAPHY: {b['event']}",
|
|
"node_type": "Biography",
|
|
"salience": b.get("weight", 0.6),
|
|
"_auth": ENGRAM_AUTH
|
|
})
|
|
engram_post("/api/edges", {
|
|
"from_id": root_id,
|
|
"to_id": node["id"],
|
|
"relation": "formed_by",
|
|
"weight": b.get("weight", 0.6),
|
|
"_auth": ENGRAM_AUTH
|
|
})
|
|
|
|
# 4. Relationship nodes
|
|
for r in imprint_data.get("relationships", []):
|
|
node = engram_post("/api/nodes", {
|
|
"content": f"RELATIONSHIP: {r['name']} ({r['role']})",
|
|
"node_type": "Relationship",
|
|
"salience": r.get("weight", 0.6),
|
|
"_auth": ENGRAM_AUTH
|
|
})
|
|
engram_post("/api/edges", {
|
|
"from_id": root_id,
|
|
"to_id": node["id"],
|
|
"relation": "relates_to",
|
|
"weight": r.get("weight", 0.6),
|
|
"_auth": ENGRAM_AUTH
|
|
})
|
|
|
|
# 5. Reasoning nodes
|
|
for pattern in imprint_data.get("reasoning_patterns", []):
|
|
node = engram_post("/api/nodes", {
|
|
"content": f"REASONING: {pattern}",
|
|
"node_type": "Reasoning",
|
|
"salience": 0.7,
|
|
"_auth": ENGRAM_AUTH
|
|
})
|
|
engram_post("/api/edges", {
|
|
"from_id": root_id,
|
|
"to_id": node["id"],
|
|
"relation": "reasons_with",
|
|
"weight": 0.7,
|
|
"_auth": ENGRAM_AUTH
|
|
})
|
|
|
|
return root_id
|
|
|
|
|
|
def update_registry(subject_name, slug, seed_file, root_id):
|
|
"""Append entry to registry.json."""
|
|
registry = json.loads(REGISTRY_FILE.read_text())
|
|
registry["imprints"].append({
|
|
"subject": subject_name,
|
|
"slug": slug,
|
|
"seed_file": f"seeds/{slug}-seed.json",
|
|
"engram_root_id": root_id,
|
|
"installed": True,
|
|
"installed_at": str(date.today())
|
|
})
|
|
REGISTRY_FILE.write_text(json.dumps(registry, indent=2))
|
|
print(f" Registry updated for {subject_name}")
|
|
|
|
|
|
def main():
|
|
results = []
|
|
|
|
for subject in SUBJECTS:
|
|
name = subject["name"]
|
|
slug = subject["slug"]
|
|
extra = subject.get("extra", "")
|
|
|
|
print(f"\n{'='*60}")
|
|
print(f"Processing: {name}")
|
|
print('='*60)
|
|
|
|
try:
|
|
# Step 1: Research
|
|
imprint_data = research_subject(name, extra)
|
|
print(f" Research complete: {len(imprint_data.get('values', []))} values, "
|
|
f"{len(imprint_data.get('biography', []))} biography events, "
|
|
f"{len(imprint_data.get('reasoning_patterns', []))} patterns, "
|
|
f"{len(imprint_data.get('relationships', []))} relationships")
|
|
|
|
# Step 2: Write seed
|
|
seed_path = write_seed(slug, name, imprint_data)
|
|
|
|
# Step 3: Install into Engram
|
|
root_id = install_into_engram(name, imprint_data)
|
|
|
|
# Step 4: Update registry
|
|
update_registry(name, slug, str(seed_path), root_id)
|
|
|
|
results.append({
|
|
"subject": name,
|
|
"slug": slug,
|
|
"seed_written": True,
|
|
"root_id": root_id,
|
|
"error": None
|
|
})
|
|
|
|
print(f" SUCCESS: {name} installed (root={root_id})")
|
|
|
|
except Exception as e:
|
|
print(f" FAILED: {name} — {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
results.append({
|
|
"subject": name,
|
|
"slug": slug,
|
|
"seed_written": False,
|
|
"root_id": None,
|
|
"error": str(e)
|
|
})
|
|
|
|
# Small pause between subjects to avoid race conditions
|
|
time.sleep(1)
|
|
|
|
# Final summary
|
|
print(f"\n{'='*60}")
|
|
print("SUMMARY")
|
|
print('='*60)
|
|
for r in results:
|
|
status = "OK" if r["root_id"] else "FAILED"
|
|
print(f" [{status}] {r['subject']}: seed={'Y' if r['seed_written'] else 'N'}, root_id={r['root_id'] or 'N/A'}")
|
|
if r["error"]:
|
|
print(f" Error: {r['error']}")
|
|
|
|
return results
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|