"""Extrahiert Subagenten-Aufrufe (Prompt, Typ, Ergebnislaenge) aus dem persistierten Session-Transkript eines Headless-Laufs und legt sie im Laufverzeichnis unter _meta ab. Aufruf: python subagenten.py [] Die Session-ID wird aus /RawResult.json gelesen. """ import io, json, os, sys, glob lauf = sys.argv[1] wurzel = sys.argv[2] if len(sys.argv) > 2 else os.path.expandvars(r'%USERPROFILE%\.claude\projects') roh = json.load(io.open(os.path.join(lauf, 'RawResult.json'), encoding='utf-8-sig')) sid = roh.get('session_id') stats = roh.get('subagent_stats') or {} gesamt = stats.get('spawned', 0) verschachtelt = stats.get('spawned_by_subagents', 0) # Im Haupttranskript stehen nur die direkt vom Hauptagenten gestarteten Subagenten. # Von Subagenten gestartete liegen in deren eigenen Transkripten. erwartet = gesamt - verschachtelt treffer = glob.glob(os.path.join(wurzel, '*', sid + '.jsonl')) if not treffer: print('KEIN TRANSKRIPT gefunden fuer Session', sid) sys.exit(1) pfad = treffer[0] aufrufe, ergebnisse = [], {} for zeile in io.open(pfad, encoding='utf-8'): try: o = json.loads(zeile) except Exception: continue cont = (o.get('message') or {}).get('content') if not isinstance(cont, list): continue for c in cont: if not isinstance(c, dict): continue if c.get('type') == 'tool_use' and c.get('name') in ('Task', 'Agent'): ein = c.get('input') or {} aufrufe.append({ 'id': c.get('id'), 'werkzeug': c.get('name'), 'subagent_type': ein.get('subagent_type'), 'description': ein.get('description'), 'run_in_background': ein.get('run_in_background'), 'model': ein.get('model'), 'prompt': ein.get('prompt') or '', }) elif c.get('type') == 'tool_result': inhalt = c.get('content') if isinstance(inhalt, list): inhalt = ' '.join(str(x.get('text', '')) for x in inhalt if isinstance(x, dict)) ergebnisse[c.get('tool_use_id')] = len(str(inhalt or '')) for a in aufrufe: a['ergebnis_zeichen'] = ergebnisse.get(a['id']) meta = os.path.join(lauf, '_meta') os.makedirs(meta, exist_ok=True) io.open(os.path.join(meta, 'subagenten.json'), 'w', encoding='utf-8').write( json.dumps(aufrufe, indent=1, ensure_ascii=False)) md = ['# Subagenten-Aufrufe', '', 'Session `%s`, Transkript `%s`.' % (sid, os.path.basename(pfad)), '', '`subagent_stats`: **%s** Subagenten gesamt, davon **%s** von Subagenten gestartet ' '(max_depth %s). Direkt vom Hauptagenten erwartet: **%s**. Im Transkript gefunden: **%s**.' % (gesamt, verschachtelt, stats.get('max_depth'), erwartet, len(aufrufe)), ''] if verschachtelt: md += ['> Die %s von Subagenten gestarteten Aufrufe stehen in deren eigenen Transkripten und' ' sind hier **nicht** enthalten.' % verschachtelt, ''] if erwartet != len(aufrufe): md += ['> **Abweichung** zwischen erwarteter und gefundener Anzahl.', '> Ursache pruefen, bevor die Prompts ausgewertet werden.', ''] for i, a in enumerate(aufrufe, 1): md += ['## %d. %s' % (i, a['description'] or '(ohne Beschreibung)'), '', '- **Werkzeug:** `%s` **Typ:** `%s` **Hintergrund:** %s' % (a['werkzeug'], a['subagent_type'], a['run_in_background']), '- **Prompt-Zeichen:** %d **Ergebnis-Zeichen:** %s' % (len(a['prompt']), a['ergebnis_zeichen']), '', '### Prompt', '', '```', a['prompt'].rstrip(), '```', ''] io.open(os.path.join(meta, 'subagenten.md'), 'w', encoding='utf-8').write('\n'.join(md)) print('Subagenten gefunden: %d (direkt erwartet: %s, gesamt: %s, davon verschachtelt: %s)' % (len(aufrufe), erwartet, gesamt, verschachtelt)) for a in aufrufe: print(' - %-42s %s Prompt %6d Z. Ergebnis %s Z.' % ((a['description'] or '')[:42], a['subagent_type'], len(a['prompt']), a['ergebnis_zeichen'])) print('geschrieben:', os.path.join(meta, 'subagenten.md'))