Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/ai-brain-core / sub_brains/hypothalamus/devtools/ai_orchestrator.py |
| Date | Not specified in source |
| Repository | Janady13/ai-brain-core |
| Revision | f7275582f13ada80bfb3b1008089800ca26f4a23 |
| Branch | main |
| Path or archive member | sub_brains/hypothalamus/devtools/ai_orchestrator.py |
| Original SHA-256 | cdf212d8a796514bb0174b54bed1d278eb67c0b4827674ce77c91debf161bc4b |
| Git blob SHA | a3112d5111e5703bf84f68b1dd723b00a28b7f78 |
| Reading-copy SHA-256 | 2339c80521abb532470ce23771bf393de1c26fe92b54db93cc8445ab09d7a868 |
Every recorded occurrence
These 3 records contain identical original source bytes. Their paths and revisions remain part of the archive.
| Original record | Branch or archive | Revision / identifier | Original location |
|---|---|---|---|
| Janady13/ai-brain-core / sub_brains/hypothalamus/devtools/ai_orchestrator.py | main | f7275582f13ada80bfb3b1008089800ca26f4a23 | Open original |
| Janady13/ai-brain-core / sub_brains/hypothalamus/devtools/ai_orchestrator.py | claude/agi-architecture-diagram-01GJ7CohfKvLb77yiKpHqd6d | 365850e27004318edd582881225024026b118c2d | Open original |
| Janady13/ai-brain-core / sub_brains/hypothalamus/devtools/ai_orchestrator.py | healer-core | 0fe4cbbaa91912149f1a8e32205371ff67017268 | Open original |
Recovered source transcript
Download complete source text ↓313 lines · 14.0 KB
Credential-bearing and unrelated personal details were removed from this reading copy. The source identity and original checksum remain recorded.
#!/usr/bin/env python3
import ai_brain_env # auto-inserted by update_ai_brain_env_paths.sh
"""
AI Orchestrator for Hypothalamus Devtools
Usage:
- Called by event_handler.py with the event JSON on stdin (or as arg).
- Environment variables:
OPENAI_API_KEY (optional) - if set, orchestrator will call OpenAI ChatCompletion API.
LLM_ENDPOINT (optional) - ws/rest endpoint for a local LLM; takes precedence over OpenAI.
ALLOW_AUTO_APPLY=1 (optional) - allow automatic --apply operations (use with caution).
HUMAN_APPROVAL_FILE (optional) - path to a file to place a human-approval request; orchestrator will wait for this file content "approve" to proceed with risky actions.
Behavior:
- Request plan from LLM (or fallback heuristic).
- Execute plan actions one-by-one (dry-run by default).
- Report results back to LLM; iterate until resolved or max rounds.
- Outputs final JSON result on stdout and writes an audit file to logs/.
"""
import os, sys, json, subprocess, time, uuid, shutil
from pathlib import Path
from typing import List, Dict, Any
BASE = Path.home() / "Desktop" / "AI_Brain"
DEVTOOLS = BASE / "sub_brains" / "hypothalamus" / "devtools"
LOGS = BASE / "logs"
AUDIT_DIR = LOGS / "ai_orchestrator"
AUDIT_DIR.mkdir(parents=True, exist_ok=True)
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
LLM_ENDPOINT = os.getenv("LLM_ENDPOINT") # optional local LLM REST
ALLOW_AUTO_APPLY = os.getenv("ALLOW_AUTO_APPLY") == "1"
HUMAN_APPROVAL_FILE = os.getenv("HUMAN_APPROVAL_FILE", str(BASE / "status" / "human_approval.request"))
MAX_ITERATIONS = int(os.getenv("AI_MAX_ITER", "5"))
ACTION_TIMEOUT = int(os.getenv("AI_ACTION_TIMEOUT", "180")) # seconds per action
# Allowed actions schema (the orchestrator will only run these)
# action.type in {"fetch", "module_dry", "module_apply", "restart", "notify_human", "rollback", "noop"}
# module name must be a folder under DEVTOOLS
def log(msg):
ts = time.strftime("%Y-%m-%d %H:%M:%S")
line = f"{ts} {msg}"
print(line, file=sys.stderr)
try:
with open(LOGS / "ai_orchestrator.log", "a") as f:
f.write(line + "\n")
except Exception:
pass
def audit_write(event_id, payload):
fn = AUDIT_DIR / f"{event_id}_{int(time.time())}.json"
try:
fn.write_text(json.dumps(payload, indent=2))
except Exception:
pass
# --- LLM adapter ---------------------------------------------------------
def run_local_llm(prompt: str) -> str:
# Very small fallback: rule-based mapper. Replace with your local LLM call if available.
# This fallback should only be used for prototyping.
if "extension_crash" in prompt:
plan = {
"goal": "attempt to repair browser extension crash",
"actions": [
{"type":"fetch", "module":"devtools_healer"},
{"type":"module_dry", "module":"devtools_healer", "args":{}},
{"type":"module_apply", "module":"devtools_healer", "args":{}},
{"type":"restart", "service":"chrome"},
{"type":"noop"}
]
}
return json.dumps(plan)
# generic fallback
plan = {"goal":"investigate","actions":[{"type":"fetch","module":"devtools_healer"},{"type":"module_dry","module":"devtools_healer"},{"type":"noop"}]}
return json.dumps(plan)
def run_openai_chat(system_prompt: str, user_prompt: str) -> str:
# Use Chat Completions if openai package available and API key set
try:
import openai
openai.api_key = [credential removed]
messages = [
{"role":"system", "content": system_prompt},
{"role":"user", "content": user_prompt}
]
resp = openai.ChatCompletion.create(model="gpt-4o-mini", messages=messages, temperature=0.0, max_tokens=512)
return resp.choices[0].message.content
except Exception as e:
log(f"OpenAI call failed: {e}")
return run_local_llm(user_prompt)
def ask_llm_for_plan(event: Dict[str,Any], history: List[Dict[str,Any]]=[]) -> Dict[str,Any]:
"""
Ask LLM to propose a plan for the given event.
Expected response: JSON with keys: goal (str) and actions (list).
actions: [{type, module, args...}, ...]
"""
system = (
"You are an AI maintainer agent for a device called Hypothalamus. "
"Produce a conservative, safety-first JSON plan to investigate and fix the given event. "
"Allowed action types: fetch, module_dry, module_apply, restart, notify_human, rollback, noop. "
"Return pure JSON: {\"goal\":..., \"actions\":[...]}. "
"Each action: include type, module (if relevant), and optional args. "
"Prefer dry-run first. If an apply is recommended, include explanation in args.explain and only request apply if likely safe."
)
user = json.dumps({"event": event, "history": history}, indent=2)
if OPENAI_API_KEY:
out = run_openai_chat(system, user)
elif LLM_ENDPOINT:
# If you have a local REST LLM endpoint, post to it (this is a placeholder)
try:
import requests
r = requests.post(LLM_ENDPOINT, json={"system":system,"user":user}, timeout=30)
out = r.text
except Exception as e:
log(f"LLM endpoint call failed: {e}")
out = run_local_llm(user)
else:
out = run_local_llm(user)
# Parse JSON from output (robust parsing)
try:
# Try to find first JSON object in output
first = out.strip()
# Some LLMs return code fences; strip them
if first.startswith("```"):
first = first.split("```",2)[-1].strip()
plan = json.loads(first)
return plan
except Exception as e:
log(f"LLM output parse failed: {e}; raw output: {out}")
return {"goal":"llm_parse_error","actions":[{"type":"noop"}]}
# --- action executors ---------------------------------------------------
def safe_subprocess(cmd: List[str], timeout=ACTION_TIMEOUT) -> Dict[str,Any]:
try:
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, timeout=timeout)
return {"rc": p.returncode, "output": p.stdout[:4000]}
except subprocess.TimeoutExpired:
return {"rc":124, "output":"timeout"}
except Exception as e:
return {"rc":1, "output": f"exception: {e}"}
def action_fetch(module: str) -> Dict[str,Any]:
fetcher = DEVTOOLS / "fetcher.py"
if fetcher.exists():
p = subprocess.Popen([sys.executable, str(fetcher), "--module", module], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return {"rc":0, "info": f"fetcher started pid={p.pid}"}
# fallback: if a git-backed module has repo, try git pull in module dir
moddir = DEVTOOLS / module
if (moddir / ".git").exists():
res = safe_subprocess(["git","-C", str(moddir), "pull", "--ff"], timeout=60)
return {"rc": res["rc"], "output": res.get("output")}
return {"rc":1, "error":"no fetcher and no git repo"}
def action_module_dry(module: str, args: Dict[str,Any]) -> Dict[str,Any]:
# Prefer module's handle_event.py with --dry-run
handler = DEVTOOLS / module / "handle_event.py"
alt = DEVTOOLS / module / f"{module}.py"
if handler.exists():
cmd = [sys.executable, str(handler), "--dry-run", "--event", json.dumps(args.get("event", {}))]
res = safe_subprocess(cmd, timeout=ACTION_TIMEOUT)
return {"rc": res["rc"], "output": res.get("output")}
elif alt.exists():
cmd = [sys.executable, str(alt), "--dry-run", "--event", json.dumps(args.get("event", {}))]
res = safe_subprocess(cmd, timeout=ACTION_TIMEOUT)
return {"rc": res["rc"], "output": res.get("output")}
return {"rc":2, "error":"no handler found"}
def action_module_apply(module: str, args: Dict[str,Any]) -> Dict[str,Any]:
# Safety: require ALLOW_AUTO_APPLY or human approval
if not ALLOW_AUTO_APPLY:
# request human approval file
# write a request and return status asking for human approval
req = {"module":module, "action":"apply", "args": args, "timestamp": time.time()}
Path(HUMAN_APPROVAL_FILE).write_text(json.dumps(req, indent=2))
return {"rc":3, "error":"requires human approval; request written to HUMAN_APPROVAL_FILE", "file": HUMAN_APPROVAL_FILE}
handler = DEVTOOLS / module / "handle_event.py"
alt = DEVTOOLS / module / f"{module}.py"
if handler.exists():
cmd = [sys.executable, str(handler), "--apply", "--event", json.dumps(args.get("event", {}))]
res = safe_subprocess(cmd, timeout=ACTION_TIMEOUT)
return {"rc": res["rc"], "output": res.get("output")}
elif alt.exists():
cmd = [sys.executable, str(alt), "--apply", "--event", json.dumps(args.get("event", {}))]
res = safe_subprocess(cmd, timeout=ACTION_TIMEOUT)
return {"rc": res["rc"], "output": res.get("output")}
return {"rc":2, "error":"no handler found"}
def action_restart(service: str) -> Dict[str,Any]:
# Limited set: "chrome", "manager", "watchdog", or custom
if service == "chrome":
# best-effort: pkill chrome, then try to start (user experience may vary)
rc1 = safe_subprocess(["pkill", "-f", "Chrome"]) # may fail harmlessly
# starting Chrome headless is not desirable; we rely on user to restart. Return result.
return {"rc":0, "info":"chrome killed (if running). user may need to restart UI"}
elif service == "manager":
# use manager scripts
lm = BASE / "launch_manager.sh"
if lm.exists():
safe_subprocess([str(lm)])
return {"rc":0, "info":"manager launch invoked"}
return {"rc":1, "error":"manager launcher missing"}
elif service == "watchdog":
p = BASE / "sub_brains" / "watchdog" / "launch.sh"
if p.exists():
subprocess.Popen([str(p), "--bg"])
return {"rc":0, "info":"watchdog launcher started"}
return {"rc":1, "error":"watchdog launcher missing"}
else:
return {"rc":2, "error":"unknown service"}
def action_notify_human(payload: Dict[str,Any]) -> Dict[str,Any]:
# write a human-readable file or send via manager notify
nf = BASE / "status" / f"human_notification_{int(time.time())}.json"
nf.write_text(json.dumps(payload, indent=2))
return {"rc":0, "file": str(nf)}
# action dispatcher
def run_action(action: Dict[str,Any]) -> Dict[str,Any]:
typ = action.get("type")
module = action.get("module")
args = action.get("args", {})
# attach event into args so module handlers can read it
if "event" not in args and "event" in action:
args["event"] = action["event"]
if typ == "fetch":
return action_fetch(module)
if typ == "module_dry":
return action_module_dry(module, args)
if typ == "module_apply":
return action_module_apply(module, args)
if typ == "restart":
return action_restart(action.get("service"))
if typ == "notify_human":
return action_notify_human(action.get("payload", {}))
if typ == "rollback":
# optional: call a module's rollback handler
mdir = DEVTOOLS / module
rb = mdir / "rollback.sh"
if rb.exists():
return safe_subprocess([str(rb)], timeout=120)
return {"rc":1, "error":"no rollback handler"}
if typ == "noop":
return {"rc":0, "info":"noop"}
return {"rc":127, "error":"unknown action type"}
# --- main loop ----------------------------------------------------------
def orchestrate(event: Dict[str,Any]) -> Dict[str,Any]:
event_id = event.get("id") or str(uuid.uuid4())
audit = {"event": event, "rounds": []}
# iterative loop
history = []
for rnd in range(MAX_ITERATIONS):
log(f"[AI] requesting plan (round {rnd+1})")
plan = ask_llm_for_plan(event, history)
audit["rounds"].append({"plan":plan})
actions = plan.get("actions", []) if isinstance(plan, dict) else []
if not actions:
log("No actions proposed by LLM; exiting")
break
round_results = []
resolved = False
for act in actions:
# attach event to actions if not present
if "event" not in act:
act["event"] = event
log(f"[AI] executing action: {act}")
res = run_action(act)
round_results.append({"action":act, "result": res})
audit["rounds"][-1].setdefault("results", []).append({"action":act, "result":res})
# if any action indicates immediate success, let LLM know
if act.get("type") in ("module_apply","restart") and res.get("rc",1) == 0:
# probe to see if issue resolved by running a verification (module_dry or custom)
# ask LLM if more steps needed
pass
# simple heuristic: if module_apply returned rc==0, check for success marker
if act.get("type") == "module_apply" and res.get("rc",1) == 0:
# optimistic: consider resolved and break to re-evaluate
resolved = True
break
history.append({"plan":plan, "results":round_results})
audit_write(event_id, audit)
if resolved:
log("[AI] resolved in this round")
return {"status":"ok","event_id":event_id,"audit":audit}
# else continue loop: feed results back to LLM via history
log("[AI] max iterations reached or no resolution")
return {"status":"unresolved","event_id":event_id,"audit":audit}
def main():
# accept JSON event from stdin or arg
if not sys.stdin.isatty():
raw = sys.stdin.read()
try:
event = json.loads(raw)
except Exception:
event = {"raw": raw}
elif len(sys.argv) > 1:
try:
event = json.loads(sys.argv[1])
except Exception:
event = {"raw_arg": sys.argv[1]}
else:
print(json.dumps({"status":"error","message":"no input"}))
sys.exit(1)
log(f"AI Orchestrator invoked for event: {event.get('error_type','<unknown>')}")
result = orchestrate(event)
print(json.dumps(result))
audit_write(event.get("id", str(uuid.uuid4())), result)
if __name__ == "__main__":
main()