- Serve HTML dashboard at /admin/ai-evolution/ - API endpoint /admin/ai-evolution/api/data returning baseline, versions, commands, agent_runs - Background agent runner base class for autonomous file operations - Chat API sync service with real-time message polling and task execution - Add admin route to aios_chatgpt_actions_api.py, fix missing start_time variable
96 lines
3.5 KiB
Python
96 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
""" AI GitOps Actions API """
|
|
import asyncio, base64, hashlib, hmac, json, os, re, shutil, subprocess, sys, time, uuid
|
|
from pathlib import Path
|
|
from urllib.parse import parse_qs, urlparse
|
|
|
|
from aiohttp import web
|
|
|
|
# Environment
|
|
WS = Path(os.environ.get("AIOS_WORKSPACE", "/data/aios-gitops/workspace"))
|
|
BASE_DIR = WS / "active-runtime"
|
|
APPDIR = BASE_DIR / "app"
|
|
AUDITDIR = WS / "audit"
|
|
WORKDIR = WS / "work"
|
|
DOTDIR = WS.parent
|
|
GITEA_DIR = DOTDIR / "runtime" / "gitea-bin" / "data" / "repositories" / "aios"
|
|
|
|
# Load config
|
|
try:
|
|
import yaml
|
|
config_path = WS / "active-runtime" / "app" / "config.yaml"
|
|
with open(config_path) as f:
|
|
CONFIG = yaml.safe_load(f) or {}
|
|
except: CONFIG = {}
|
|
|
|
start_time = time.time()
|
|
log_ident = "aios-api"
|
|
|
|
def sh(cmd, **kw):
|
|
try:
|
|
r = subprocess.run(cmd, capture_output=True, text=True, cwd=WS, **kw)
|
|
return r.stdout.strip() if r else None
|
|
except: return None
|
|
|
|
def baselines():
|
|
p = WS / "baselines" / "current.json"
|
|
if p.exists():
|
|
try: return json.loads(p.read_text())
|
|
except: pass
|
|
return {}
|
|
|
|
def commands(status):
|
|
d = WS / "agents" / "commands" / status
|
|
if not d.exists(): return []
|
|
return [{"name": f.name, "state": status} for f in sorted(d.iterdir()) if f.name.endswith(".md")]
|
|
|
|
def agent_runs():
|
|
d = AUDITDIR / "agent-runs"
|
|
if not d.exists(): return []
|
|
rs = []
|
|
for f in sorted(d.iterdir(), reverse=True):
|
|
if f.name.endswith(".json"):
|
|
try:
|
|
j = json.loads(f.read_text())
|
|
j["file"] = f.stem
|
|
rs.append(j)
|
|
except: pass
|
|
return rs
|
|
|
|
async def handle_api(request):
|
|
path = request.path
|
|
if path in ('/admin/ai-evolution','/admin/ai-evolution/'):
|
|
# Serve the HTML page
|
|
html_path = APPDIR / 'static' / 'admin-ai-evolution.html'
|
|
if html_path.exists():
|
|
return web.Response(text=html_path.read_text(), content_type='text/html')
|
|
return web.Response(text='Dashboard not found', status=404)
|
|
if path == '/admin/ai-evolution/api/data':
|
|
result = subprocess.run(['git','tag','--list','V*'], capture_output=True, text=True, cwd=WS)
|
|
tags = result.stdout.strip().splitlines() if result.returncode == 0 else []
|
|
h = subprocess.run(['git','rev-parse','--short','HEAD'], capture_output=True, text=True, cwd=WS)
|
|
head = h.stdout.strip() if h.returncode == 0 else 'unknown'
|
|
b = subprocess.run(['git','rev-parse','--abbrev-ref','HEAD'], capture_output=True, text=True, cwd=WS)
|
|
branch = b.stdout.strip() if b.returncode == 0 else 'unknown'
|
|
return web.json_response({
|
|
'baseline': baselines(),
|
|
'versions': [{'tag':t,'name':p.name} for p in sorted((WS/'versions').glob('*')) for t in tags if p.name in t],
|
|
'commands': commands('active') + commands('running') + commands('completed'),
|
|
'agent_runs': agent_runs(),
|
|
'stats': {
|
|
'current': head,
|
|
'branch': branch,
|
|
'uptime': round(time.time()-start_time, 2),
|
|
'baseline': baselines().get('current_baseline','unknown'),
|
|
}
|
|
})
|
|
return web.json_response({'error':'not_found','path':path}, status=404)
|
|
|
|
app = web.Application()
|
|
app.router.add_route('GET', '/admin/ai-evolution', handle_api)
|
|
app.router.add_route('GET', '/admin/ai-evolution/', handle_api)
|
|
app.router.add_route('GET', '/admin/ai-evolution/api/data', handle_api)
|
|
|
|
if __name__ == '__main__':
|
|
web.run_app(app, host='127.0.0.1', port=18890)
|