Explorer
/proc/126/root/tmp/session_knowledge_closure.py
← Zurück ↓ Download
#!/usr/bin/env python3
"""Run the explicit Hermes VPS knowledge-closure command for one session."""
import argparse,json,os,re,sqlite3,subprocess,time
from pathlib import Path
STATE_ROOT=Path('/home/hermes/.hermes'); REVIEW=Path('/opt/struktur/session-knowledge-review/review.db')
TRIGGERS=re.compile(r'(?i)\b(wissen\s+(?:dieser\s+)?session\s+aufbereiten\s+und\s+session\s+abschließen|wissensabschluss|session\s+(?:für|fuer)\s+wissen\s+abschließen|session\s+abschließen)\b')
def parse(s):
 for i,ch in enumerate(s or ''):
  if ch=='{':
   try:
    x=json.loads(s[i:s.rfind('}')+1])
    if isinstance(x,dict):return x
   except:pass
 return None
def main():
 ap=argparse.ArgumentParser();ap.add_argument('--session-id',required=True);ap.add_argument('--profile',default='hermesvps');ap.add_argument('--pipeline',action='store_true');a=ap.parse_args()
 dbp=STATE_ROOT/'profiles'/a.profile/'state.db'; c=sqlite3.connect(dbp);c.row_factory=sqlite3.Row
 row=c.execute('select * from sessions where id=?',(a.session_id,)).fetchone()
 if not row: raise SystemExit('SESSION_NOT_FOUND')
 rc=sqlite3.connect(REVIEW);rc.execute('''create table if not exists knowledge_editor_closures (session_key text primary key, session_id text, profile text, status text, completed_at real, editor_profile text, error text, handoff_hash text)''');old=rc.execute('select status from knowledge_editor_closures where session_key=?',(a.profile+':'+a.session_id,)).fetchone()
 if old and old[0]=='COMPLETED':print(json.dumps({'status':'ALREADY_COMPLETED','session_id':a.session_id}));return 0
 msgs=c.execute("select role,content from messages where session_id=? order by id",(a.session_id,)).fetchall(); transcript='\n\n'.join(f'{r[0].upper()}: {r[1] or ""}' for r in msgs)[-120000:]
 prompt='''Erstelle ausschließlich eine strukturierte SESSION-WISSENSÜBERGABE aus dem folgenden Sessioninhalt. Keine neuen Fakten. Trenne bestätigte Erkenntnisse von Arbeitsaufträgen und Zwischenständen. Ausgabe exakt mit Überschrift SESSION-WISSENSÜBERGABE und den Kategorien Projekt, Session-ID, Dauerhaft relevante Erkenntnisse, Bestätigte Architektur-/Prozessentscheidungen, Produktive Pfade/Konfigurationen, Bestätigte Fehlerursachen/Reparaturen, Dauerhafte Rollen/Zuständigkeiten, Offene bzw. nicht bestätigte Punkte, Nicht dauerhaft relevante Zwischenstände. Leere Kategorien als „keine“ markieren.\n\nSESSION-ID: '''+a.session_id+'\n'+transcript
 cmd=['sudo','-u','hermes','env','HOME=/home/hermes','USER=hermes','LOGNAME=hermes','/home/hermes/.local/bin/hermes','-p','wissensredakteur','chat','--oneshot','-q',prompt]
 try:
  p=subprocess.run(cmd,text=True,capture_output=True,timeout=180);handoff=p.stdout[p.stdout.find('SESSION-WISSENSÜBERGABE'):].strip()
  if p.returncode!=0 or not handoff: raise RuntimeError('EDITOR_FAILED:'+p.stderr[-500:])
  h=__import__('hashlib').sha256(handoff.encode()).hexdigest(); now=time.time();c.execute("insert into messages(session_id,role,content,timestamp,display_kind) values(?,?,?,?,?)",(a.session_id,'assistant',handoff,now,'knowledge_handoff'));c.execute("update sessions set ended_at=?,end_reason=?,message_count=message_count+1,last_activity_at=? where id=?",(now,'knowledge_closure',now,a.session_id));c.commit();rc.execute('insert or replace into knowledge_editor_closures values(?,?,?,?,?,?,?,?)',(a.profile+':'+a.session_id,a.session_id,a.profile,'COMPLETED',now,'wissensredakteur',None,h));rc.commit()
  # Immediate reviewer pass for this session; existing timer remains fallback.
  rr=subprocess.run(['python3','/opt/struktur/session-knowledge-review/reviewer.py','--once','--session-id',a.session_id,'--agent-limit','25'],text=True,capture_output=True,timeout=300)
  result={'status':'COMPLETED','session_id':a.session_id,'handoff_hash':h,'reviewer_exit':rr.returncode,'reviewer_output':parse(rr.stdout) or rr.stdout[-2000:]}
  if a.pipeline:
   pi=subprocess.run(['systemctl','start','--no-block','obsidian-knowledge-pipeline.service'],text=True,capture_output=True,timeout=30);result['pipeline_start_exit']=pi.returncode;result['pipeline_status']='STARTED' if pi.returncode==0 else 'FAILED_TO_START'
  print(json.dumps(result,ensure_ascii=False));return 0
 except Exception as e:
  rc.execute('insert or replace into knowledge_editor_closures values(?,?,?,?,?,?,?,?)',(a.profile+':'+a.session_id,a.session_id,a.profile,'FAILED',None,'wissensredakteur',str(e),None));rc.commit();print(json.dumps({'status':'FAILED','error':str(e)},ensure_ascii=False));return 1
if __name__=='__main__':raise SystemExit(main())