diff --git a/README.md b/README.md index eb61414..281d36f 100644 --- a/README.md +++ b/README.md @@ -1,332 +1,59 @@ -# Frankenbot - Multi-Agent Event-Management-System +# Agenten Orchestrierung - Flask Webanwendung -Ein Flask-basiertes Multi-Agent-System zur Orchestrierung und Verwaltung von KI-Agenten für Event-Management. Entwickelt für den **Diversity-Ball Wien 2026**. +Eine Flask-basierte Webanwendung zur Verwaltung und Orchestrierung von Agenten. -## 🎯 Überblick +## Features -Frankenbot ist ein intelligentes Event-Management-System, bei dem spezialisierte KI-Agents zusammenarbeiten, um komplexe Event-Organisationsaufgaben zu bewältigen. Ein zentraler Orchestrator koordiniert die Kommunikation zwischen den Agents und delegiert Tasks basierend auf Expertise. +- **Dashboard**: Übersicht aller verfügbaren Agenten und letzte Tasks +- **Chat**: Interaktive Kommunikation mit ausgewählten Agenten +- **Tasks**: Task-Verwaltung mit Status-Verfolgung (pending/in_progress/completed) +- **Dateien**: Datei-Upload und Verwaltung -## ✨ Haupt-Features +## Installation -### 🤖 Multi-Agent Orchestrierung -- **Orchestrator als zentraler Hub**: Alle Agent-Kommunikation läuft über den Orchestrator -- **Spezialisierte Agents**: Budget Manager, Catering Manager, Location Manager, Program Manager, etc. -- **Agent-zu-Agent Kommunikation**: Agents können Fragen stellen, Subtasks erstellen und neue Agents vorschlagen -- **Dynamische Modellauswahl**: 29+ KI-Modelle verfügbar (OpenCode, Anthropic, Ollama) +1. Installieren Sie die erforderlichen Abhängigkeiten: -### 📋 Task-Management -- **Automatische Task-Verarbeitung**: TaskBeat verarbeitet Tasks alle 10 Sekunden -- **Auto-Refresh UI**: Tasks-Seite aktualisiert sich automatisch alle 15 Sekunden -- **Task-Delegation**: Orchestrator analysiert Tasks und weist sie passenden Agents zu -- **Status-Tracking**: pending → in_progress → completed - -### 💬 Chat-System -- **Live-Streaming**: Server-Sent Events für Echtzeit-Antworten -- **Agent-Auswahl**: Chat mit spezifischen Agents oder dem Orchestrator -- **Session-basierte History**: Kontext bleibt über Konversation erhalten - -### 📧 Email-Integration -- **IMAP**: Email-Posteingang überwachen -- **SMTP**: Emails versenden -- **Email-to-Task**: Automatische Task-Erstellung aus Emails -- **Whitelist-System**: Nur autorisierte Absender - -### 📁 Datei-Management -- **Agent Work-Folders**: Jeder Agent hat eigenes Arbeitsverzeichnis -- **Email-Vorlagen**: Wiederverwendbare Email-Templates -- **Projekt-Dateien**: Zentrale Dokumentenverwaltung -- **Upload & Download**: Web-basierter Datei-Manager - -### 🧠 Memory-System -- **JSON-basierte Erinnerungen**: Strukturierte Agent-Memories -- **Kategorien**: tasks, notes, decisions, contacts -- **Agent-spezifisch**: Jeder Agent verwaltet eigene Erinnerungen -- **Memory-Summaries**: Kompakte Übersichten für Prompts - -### 📚 Wissensdatenbank -- **On-Demand Zugriff**: Agents nutzen `@READ_KNOWLEDGE` statt volle KB im Prompt -- **Performance-Optimierung**: Reduziert Prompt-Größe um ~15KB -- **Event-spezifisch**: Diversity-Ball Wien 2026 Informationen - -## 🚀 Installation - -### Voraussetzungen ```bash -# Python 3.10+ -python --version - -# OpenCode CLI (für Agent-Ausführung) -opencode --version +pip install flask ``` -### Abhängigkeiten installieren -```bash -pip install flask python-dotenv -``` +## Starten der Anwendung -### Email-Konfiguration (Optional) ```bash -cp .env.example .env -# .env editieren und Email-Credentials eintragen -``` - -## 📖 Verwendung - -### App starten -```bash -# Foreground python app.py - -# Background (empfohlen) -nohup python app.py > app_output.log 2>&1 & ``` -Die Anwendung läuft dann auf: **http://localhost:5000** +Die Anwendung ist dann unter http://localhost:5000 erreichbar. -### Agent-Kommandos +## Verfügbare Agenten -Agents können folgende Kommandos in ihren Antworten verwenden: +| Agent | Beschreibung | +|-------|---------------| +| Researcher | Recherchiert Informationen im Web | +| Location Manager | Verwaltet Veranstaltungsorte | +| Catering Manager | Organisiert Verpflegung | +| Program Manager | Koordiniert Programmabläufe | +| Document Editor | Bearbeitet Dokumente | +| Tax Advisor | Berät zu steuerlichen Fragen | +| Musik Rechte Advisor | Berät zu Musikrechten | +| Zusammenfasser | Erstellt Zusammenfassungen | -#### Frage an Orchestrator -``` -@ASK_ORCHESTRATOR -Question: Wie hoch ist das verfügbare Budget für Catering? -Context: Ich plane das Menü und brauche Budget-Info -@END -``` +## Routen -#### Subtask erstellen -``` -@CREATE_SUBTASK -Task: Location-Vertrag prüfen -Requirements: Rechtliche Prüfung der Mietbedingungen -@END -``` +- `/` - Dashboard +- `/chat` - Chat mit Agenten +- `/tasks` - Task Verwaltung +- `/files` - Datei Verwaltung -#### Wissensdatenbank durchsuchen -``` -@READ_KNOWLEDGE -Topic: Budget -@END -``` +## Technologie -#### Neuen Agent vorschlagen -``` -@SUGGEST_AGENT -Role: Security Manager -Skills: Sicherheitsplanung, Crowd Management -Reason: Für große Events mit 500+ Gästen benötigt -@END -``` +- Flask 3.x +- Bootstrap 5 +- Session-basierte Chat-Verwaltung +- Lokaler Datei-Upload -## 🗂️ Projekt-Struktur +## Hinweise -``` -frankenbot/ -├── app.py # Haupt-Flask-App (2128 Zeilen) -├── agent_config.json # Agent-Modell-Zuweisungen -├── diversityball_knowledge.md # Event-Wissensdatenbank -├── email_journal.db # SQLite-Datenbank (Emails) -│ -├── agents/ # Agent-Verzeichnisse -│ ├── orchestrator/ -│ │ ├── systemprompt.md -│ │ ├── personality.md -│ │ ├── work/ # Arbeitsverzeichnis -│ │ └── memory/ # JSON-Erinnerungen -│ ├── budget_manager/ -│ ├── catering_manager/ -│ ├── location_manager/ -│ └── ... -│ -├── templates/ # HTML-Templates (Jinja2) -│ ├── base.html -│ ├── index.html # Dashboard -│ ├── chat.html # Agent-Chat -│ ├── orchestrator.html # Orchestrator-Chat -│ ├── tasks.html # Task-Management -│ ├── agents.html # Agent-Verwaltung -│ ├── files.html # Datei-Manager -│ └── emails.html # Email-Interface -│ -├── static/ -│ └── style.css # CSS-Styling -│ -└── uploads/ # Hochgeladene Dateien -``` - -## 🤖 Verfügbare Agents - -| Agent | Rolle | Verantwortlich für | -|-------|-------|-------------------| -| **Orchestrator** | Koordinator | Task-Delegation, Agent-Kommunikation | -| **Budget Manager** | Finanzplanung | Budget-Tracking, Kostenkalkulation | -| **Catering Manager** | Verpflegung | Menüplanung, Catering-Koordination | -| **Location Manager** | Veranstaltungsort | Raumbuchung, Logistik | -| **Program Manager** | Programmablauf | Zeitplanung, Ablaufkoordination | -| **Researcher** | Recherche | Web-Recherche, Informationsbeschaffung | -| **Document Editor** | Dokumentation | Dokument-Erstellung, Bearbeitung | -| **Tax Advisor** | Steuern | Steuerliche Beratung, AKM-Meldungen | -| **Musik Rechte Advisor** | Musikrechte | GEMA/AKM-Compliance | -| **Zusammenfasser** | Synthese | Informations-Aggregation | - -## 🔧 Technologie-Stack - -- **Backend**: Flask 3.x -- **Frontend**: Bootstrap 5, Vanilla JavaScript -- **Database**: SQLite (Email-Journal) -- **AI**: OpenCode CLI (Multi-Provider Support) -- **Templates**: Jinja2 -- **Streaming**: Server-Sent Events (SSE) - -## 🎨 UI-Routen - -| Route | Beschreibung | -|-------|--------------| -| `/` | Dashboard - Agent-Übersicht & letzte Tasks | -| `/chat` | Chat mit individuellen Agents | -| `/orchestrator` | Orchestrator-Chat mit Task-Verteilung | -| `/tasks` | Task-Management mit Auto-Refresh | -| `/agents` | Agent-Verwaltung (Erstellen, Bearbeiten, Modell-Auswahl) | -| `/files` | Datei-Manager (Upload, Download, Agent Work-Folders) | -| `/emails` | Email-Interface (Senden, Empfangen, Vorlagen) | - -## ⚙️ Konfiguration - -### Agent-Modelle anpassen -Bearbeite `agent_config.json`: -```json -{ - "orchestrator": "anthropic/claude-3.7-sonnet", - "budget_manager": "opencode/qwen2.5-coder:32b", - "catering_manager": "anthropic/claude-3.5-sonnet" -} -``` - -### Email-Setup -Bearbeite `.env`: -```bash -EMAIL_ADDRESS=your@email.com -EMAIL_PASSWORD=your_app_password -EMAIL_IMAP_SERVER=imap.gmail.com -EMAIL_SMTP_SERVER=smtp.gmail.com -``` - -### Background-Threads -- **EmailPoller**: Prüft alle 2 Minuten auf neue Emails -- **TaskBeat**: Verarbeitet Tasks alle 10 Sekunden -- **TaskWorker**: Führt Agent-Tasks aus (Timeout: 10 Min) - -## 📊 Performance - -### Optimierungen -- ✅ Wissensdatenbank nicht im Prompt (on-demand via `@READ_KNOWLEDGE`) -- ✅ Model-Cache (1h TTL) -- ✅ Agent arbeiten in eigenen work-Verzeichnissen -- ✅ Timeout: 600 Sekunden (10 Min) für komplexe Tasks - -### Geschätzte Ausführungszeiten -- Einfache Tasks: 30-60 Sekunden -- Komplexe Tasks: 2-5 Minuten -- Research-Tasks: 3-8 Minuten - -## 🔒 Security - -### Implementierte Maßnahmen -- ✅ XSS-Schutz: HTML-Escaping in allen Templates -- ✅ Email-Whitelist: Nur autorisierte Absender -- ✅ Exception-Handling: Spezifische Exception-Typen mit Logging -- ✅ Request-Validierung: `.get()` mit Defaults -- ✅ Session-basierte Auth: Flask-Sessions - -### Empfehlungen für Produktion -- 🔐 HTTPS aktivieren (TLS/SSL) -- 🔐 Secrets in Umgebungsvariablen (nicht in Code) -- 🔐 CSP Headers setzen -- 🔐 Rate Limiting für API-Endpoints -- 🔐 WSGI Server verwenden (Gunicorn, uWSGI) - -## 🐛 Debugging - -### Logs prüfen -```bash -# Echtzeit-Logs -tail -f app_output.log - -# Letzte 50 Zeilen -tail -50 app_output.log - -# Nach Errors suchen -grep -i error app_output.log -``` - -### App-Status -```bash -# Läuft die App? -ps aux | grep "python3 app.py" - -# Port 5000 belegt? -lsof -i :5000 -``` - -## 📝 Entwicklung - -### Code-Quality -- ✅ 72 Funktionen, 29 Routes -- ✅ Keine unused imports -- ✅ Spezifisches Exception-Handling -- ✅ Logging für alle kritischen Operationen - -### Git-Workflow -```bash -# Status prüfen -git status - -# Änderungen committen -git add . -git commit -m "feat: neue Funktion" - -# Pushen -git push origin main -``` - -## 📚 Weitere Dokumentation - -- `CHANGES.md` - Detaillierte Feature-Implementierungen -- `FEATURES.md` - Feature-Übersicht -- `QUICKSTART.md` - Schnellstart-Anleitung -- `.env.example` - Email-Konfiguration - -## 🎓 Use Cases - -### Event-Planung -1. Orchestrator empfängt Planungs-Anfrage -2. Erstellt Subtasks für Budget, Location, Catering -3. Agents arbeiten parallel -4. Orchestrator aggregiert Ergebnisse - -### Email-basierte Tasks -1. Email kommt an (von Whitelist-Absender) -2. EmailPoller erstellt Task -3. TaskBeat weist Task zu passendem Agent -4. Agent arbeitet Task ab und antwortet per Email - -### Wissensdatenbank-Abfrage -1. Agent braucht Info (z.B. Budget) -2. Nutzt `@READ_KNOWLEDGE Topic: Budget` -3. System extrahiert relevante Sektion -4. Agent erhält nur benötigte Informationen - -## 🤝 Mitwirken - -Dieses Projekt wurde entwickelt für den **Diversity-Ball Wien 2026**. - -## 📄 Lizenz - -Dieses Projekt ist für internen Gebrauch und Event-Management entwickelt. - ---- - -**Version**: 1.0.0 -**Letztes Update**: Februar 2026 -**Status**: Production-Ready ✅ +- Dateien werden im `uploads/` Verzeichnis gespeichert +- Chat-Verlauf wird session-basiert gespeichert (max. 20 Einträge) +- Tasks werden im Speicher gehalten (nicht persistent) diff --git a/app.py b/app.py index 2f4da3d..532cea2 100644 --- a/app.py +++ b/app.py @@ -60,8 +60,7 @@ def get_agent_memory(agent_key, memory_type='tasks'): try: with open(memory_file, 'r', encoding='utf-8') as f: return json.load(f) - except (json.JSONDecodeError, IOError, OSError) as e: - logging.warning(f"Fehler beim Laden von {memory_file}: {e}") + except: pass return [] @@ -211,8 +210,7 @@ def get_agent_config(): try: with open(AGENT_CONFIG_FILE, 'r', encoding='utf-8') as f: return json.load(f) - except (json.JSONDecodeError, IOError, OSError) as e: - logging.warning(f"Fehler beim Laden von {AGENT_CONFIG_FILE}: {e}") + except: pass return {} @@ -398,53 +396,21 @@ def execute_agent_task(agent_key, user_prompt, extra_context=""): # Memory-Zusammenfassung laden memory_summary = get_agent_memory_summary(agent_key) - # Wissensdatenbank-Pfad (Agent holt sich selbst was er braucht) kb_file = os.path.join(os.path.dirname(__file__), 'diversityball_knowledge.md') + kb_content = "" + if os.path.exists(kb_file): + with open(kb_file, 'r', encoding='utf-8') as f: + kb_content = f.read() - # System-Prompt = Agent-Rolle + Memory + Kommandos (OHNE große Wissensdatenbank!) + # System-Prompt = Agent-Rolle + Wissensdatenbank + Memory full_system = f"""{system_prompt} +## Wissensdatenbank (Diversity-Ball): +{kb_content} + ## Deine Erinnerungen: {memory_summary} -## Wissensdatenbank: -Die Wissensdatenbank liegt unter: {kb_file} - -Wenn du spezifische Informationen brauchst: -@READ_KNOWLEDGE -Topic: [Thema, z.B. "Budget", "Catering", "Location"] -@END - -Falls du etwas nicht findest: -@ASK_ORCHESTRATOR -Question: [Deine Frage] -Context: [Kontext] -@END - -## Agent-Kollaboration: -Du kannst mit anderen Agents kommunizieren! Verwende folgendes Format: - -**Frage an Orchestrator stellen (er delegiert an passenden Agent):** -@ASK_ORCHESTRATOR -Question: [Deine Frage] -Context: [Warum brauchst du diese Info?] -@END - -**Sub-Task erstellen (Orchestrator delegiert automatisch):** -@CREATE_SUBTASK -Task: [Was soll gemacht werden] -Requirements: [Anforderungen/Details] -@END - -**Neuen Agent vorschlagen (wenn Fähigkeit fehlt):** -@SUGGEST_AGENT -Role: [Rolle/Beschreibung] -Skills: [Benötigte Fähigkeiten] -Reason: [Warum wird dieser Agent gebraucht?] -@END - -Der Orchestrator kümmert sich um die Zuweisung und Kommunikation! - ## Wichtig: - Du hast Zugriff auf das Internet via WebFetch-Tool - nutze es aktiv! - Du kannst Emails versenden - nutze send_email wenn beauftragt @@ -466,7 +432,7 @@ Der Orchestrator kümmert sich um die Zuweisung und Kommunikation! ['opencode', 'run', '--model', model, '--format', 'json', combined_message], capture_output=True, text=True, - timeout=600, # 10 Minuten für komplexe Tasks + timeout=300, cwd=work_dir # Agent arbeitet in seinem work-Verzeichnis ) @@ -478,14 +444,8 @@ Der Orchestrator kümmert sich um die Zuweisung und Kommunikation! data = json.loads(line) if data.get('part', {}).get('type') == 'text': response_text += data.get('part', {}).get('text', '') - except (json.JSONDecodeError, KeyError): - # Ignore invalid JSON lines in streaming output + except: pass - - # Agent-Kommandos parsen (Task-Delegation, Fragen, Agent-Erstellung) - if response_text: - parse_agent_commands(agent_key, response_text) - return response_text if response_text else "⚠️ Keine Antwort erhalten." else: return f"⚠️ Fehler: {result.stderr}" @@ -534,202 +494,6 @@ tasks = [] chat_history = [] orchestrator_chat = [] -# ── Agent Message Queue ───────────────────────────────────────────────────── -# Ermöglicht Agent-zu-Agent Kommunikation -agent_messages = [] # Liste von {id, from_agent, to_agent, message_type, content, status, created, response} - -def send_agent_message(from_agent, to_agent, message_type, content): - """Sendet eine Nachricht von einem Agent an einen anderen. - - message_type kann sein: - - 'task_request': Bitte den Ziel-Agent einen Task zu erledigen - - 'question': Stelle eine Frage - - 'info': Teile Information - - 'create_agent': Bitte um Erstellung eines neuen Agents - """ - message = { - 'id': len(agent_messages) + 1, - 'from_agent': from_agent, - 'to_agent': to_agent, - 'message_type': message_type, - 'content': content, - 'status': 'pending', - 'created': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), - 'response': None - } - agent_messages.append(message) - logger.info(f"[AgentMsg] {from_agent} → {to_agent}: {message_type}") - return message - -def get_agent_messages(agent_key, status='pending'): - """Holt alle Nachrichten für einen Agent.""" - return [m for m in agent_messages if m['to_agent'] == agent_key and m['status'] == status] - -def respond_to_message(message_id, response): - """Agent antwortet auf eine Nachricht.""" - for msg in agent_messages: - if msg['id'] == message_id: - msg['response'] = response - msg['status'] = 'answered' - logger.info(f"[AgentMsg] Message #{message_id} beantwortet") - return True - return False - -def parse_agent_commands(agent_key, response_text): - """Parst Agent-Antwort nach Orchestrator-Kommandos und führt sie aus.""" - import re - - # ASK_ORCHESTRATOR: Agent stellt Frage an Orchestrator - ask_requests = re.findall( - r'@ASK_ORCHESTRATOR\s*\nQuestion:\s*([^\n]+)\s*\nContext:\s*([^@]+)@END', - response_text, - re.DOTALL - ) - for question, context in ask_requests: - # Erstelle Task für Orchestrator um die Frage zu beantworten - new_task = { - 'id': len(tasks) + 1, - 'title': f"Frage von {agent_key}: {question.strip()[:80]}", - 'description': f"""Ein Agent braucht Hilfe! - -**Von:** {agent_key} -**Frage:** {question.strip()} -**Kontext:** {context.strip()} - -Bitte beantworte die Frage oder delegiere an den passenden Experten-Agent. -Die Antwort wird an {agent_key} zurückgegeben.""", - 'assigned_agent': 'Orchestrator', - 'agent_key': 'orchestrator', - 'status': 'pending', - 'created': datetime.now().strftime('%Y-%m-%d %H:%M'), - 'type': 'agent_question', - 'from_agent': agent_key, - 'return_to': agent_key - } - tasks.append(new_task) - logger.info(f"[AgentCmd] {agent_key} fragt Orchestrator: {question.strip()[:50]}") - - # CREATE_SUBTASK: Agent möchte Subtask erstellen - subtask_requests = re.findall( - r'@CREATE_SUBTASK\s*\nTask:\s*([^\n]+)\s*\nRequirements:\s*([^@]+)@END', - response_text, - re.DOTALL - ) - for task_desc, requirements in subtask_requests: - new_task = { - 'id': len(tasks) + 1, - 'title': task_desc.strip()[:100], - 'description': f"Von {agent_key} angefordert:\n{requirements.strip()}", - 'assigned_agent': 'Orchestrator', - 'agent_key': 'orchestrator', - 'status': 'pending', - 'created': datetime.now().strftime('%Y-%m-%d %H:%M'), - 'type': 'agent_subtask', - 'from_agent': agent_key - } - tasks.append(new_task) - logger.info(f"[AgentCmd] {agent_key} erstellt Subtask via Orchestrator") - - # SUGGEST_AGENT: Agent schlägt neuen Agent vor - suggest_requests = re.findall( - r'@SUGGEST_AGENT\s*\nRole:\s*([^\n]+)\s*\nSkills:\s*([^\n]+)\s*\nReason:\s*([^@]+)@END', - response_text, - re.DOTALL - ) - for role, skills, reason in suggest_requests: - # Agent-Key aus Role ableiten - agent_key_suggestion = role.lower().replace(' ', '_').replace('-', '_') - - # Task für Orchestrator um Agent zu erstellen - new_task = { - 'id': len(tasks) + 1, - 'title': f"Agent-Vorschlag: {role.strip()}", - 'description': f"""Agent {agent_key} schlägt vor, einen neuen Agent zu erstellen: - -**Rolle:** {role.strip()} -**Fähigkeiten:** {skills.strip()} -**Begründung:** {reason.strip()} - -Bitte entscheide ob dieser Agent erstellt werden soll.""", - 'assigned_agent': 'Orchestrator', - 'agent_key': 'orchestrator', - 'status': 'pending', - 'created': datetime.now().strftime('%Y-%m-%d %H:%M'), - 'type': 'agent_suggestion', - 'from_agent': agent_key, - 'suggested_agent': agent_key_suggestion, - 'suggested_role': role.strip(), - 'suggested_skills': skills.strip() - } - tasks.append(new_task) - logger.info(f"[AgentCmd] {agent_key} schlägt neuen Agent vor: {role.strip()}") - - # READ_KNOWLEDGE: Agent möchte Wissensdatenbank durchsuchen - read_kb_requests = re.findall( - r'@READ_KNOWLEDGE\s*\nTopic:\s*([^@]+)@END', - response_text, - re.DOTALL - ) - - # Wenn Agent Wissensdatenbank lesen will, füge relevante Sektion zur Antwort hinzu - # (wird im Response-Text nicht sichtbar, aber Agent bekommt es als Context) - if read_kb_requests: - kb_file = os.path.join(os.path.dirname(__file__), 'diversityball_knowledge.md') - if os.path.exists(kb_file): - with open(kb_file, 'r', encoding='utf-8') as f: - kb_content = f.read() - - for topic in read_kb_requests: - topic_clean = topic.strip().lower() - logger.info(f"[AgentCmd] {agent_key} liest Wissensdatenbank: {topic_clean}") - - # Einfache Suche: Gib relevante Abschnitte zurück - # TODO: Könnte später mit Vektorsuche verbessert werden - relevant_sections = [] - for line in kb_content.split('\n'): - if topic_clean in line.lower(): - relevant_sections.append(line) - - if relevant_sections: - logger.info(f"[AgentCmd] {len(relevant_sections)} relevante Zeilen gefunden") - -def create_new_agent(agent_key, role, skills): - """Erstellt dynamisch einen neuen Agenten.""" - agent_dir = os.path.join(AGENTS_BASE_DIR, agent_key) - - if os.path.exists(agent_dir): - logger.warning(f"[AgentCreate] Agent {agent_key} existiert bereits") - return False - - os.makedirs(agent_dir, exist_ok=True) - - systemprompt = f"""# {role} - -## Deine Rolle -{role} - -## Deine Fähigkeiten -{skills} - -## Aufgaben -- Erledige Tasks in deinem Fachgebiet -- Kommuniziere mit anderen Agents wenn nötig -- Dokumentiere deine Arbeit im work-Verzeichnis -""" - - with open(os.path.join(agent_dir, 'systemprompt.md'), 'w', encoding='utf-8') as f: - f.write(systemprompt) - - open(os.path.join(agent_dir, 'personality.md'), 'w').close() - with open(os.path.join(agent_dir, 'reminders.md'), 'w', encoding='utf-8') as f: - f.write(f"# Erinnerungen - {agent_key.title()}\n\n## Aktuelle Tasks\n-\n\n## Notizen\n-\n") - - global AGENTS - AGENTS = load_agents_from_directories() - - logger.info(f"[AgentCreate] Neuer Agent erstellt: {agent_key}") - return True - def load_knowledge_base(): kb_path = os.path.join(os.path.dirname(__file__), 'diversityball_knowledge.md') if os.path.exists(kb_path): @@ -857,8 +621,7 @@ def get_email_preview(msg): return part.get_payload(decode=True).decode('utf-8', errors='ignore')[:100] else: return msg.get_payload(decode=True).decode('utf-8', errors='ignore')[:100] - except (AttributeError, TypeError, UnicodeDecodeError) as e: - logging.debug(f"Email preview extraction failed: {e}") + except: return '(Vorschau nicht verfügbar)' return '' @@ -1273,7 +1036,7 @@ def process_beat_tasks(): while True: try: - pending_tasks = [t for t in tasks if t.get('status') == 'pending' and t.get('type') in ('agent_created', 'manual', 'orchestrated', 'agent_delegated')] + pending_tasks = [t for t in tasks if t.get('status') == 'pending' and t.get('type') in ('agent_created', 'manual', 'orchestrated')] for task in pending_tasks: agent_key = task.get('agent_key') or task.get('assigned_agent', '') @@ -1314,22 +1077,10 @@ Agent-Beschreibungen: if assigned not in AGENTS: assigned = available_agents[0] - # Sub-Task mit KOMPLETTEM Kontext sub_task = { 'id': len(tasks) + 1 + len(created_sub_tasks), 'title': t[:80], - 'description': f"""**Original-Aufgabe:** -{task.get('title', '')} - -{task.get('description', '')} - -**Orchestrator-Analyse:** -{response} - -**Dein spezifischer Teil:** -{t} - -Arbeite diesen Teil ab und liefere ein vollständiges Ergebnis.""", + 'description': f"Von Orchestrator zugewiesen: {response[:200]}...", 'assigned_agent': AGENTS.get(assigned, {}).get('name', assigned), 'agent_key': assigned, 'status': 'pending', @@ -1382,8 +1133,7 @@ Arbeite diesen Teil ab und liefere ein vollständiges Ergebnis.""", except Exception as e: logger.error("[TaskBeat] Fehler: %s", str(e)) - # Beat-Intervall: 10 Sekunden (statt 30) - time.sleep(10) + time.sleep(30) def start_task_beat(): diff --git a/templates/orchestrator.html b/templates/orchestrator.html index 0149a3d..aa776a9 100644 --- a/templates/orchestrator.html +++ b/templates/orchestrator.html @@ -130,7 +130,7 @@ function sendPromptWithStream() { msgDiv.className = 'chat-message'; msgDiv.innerHTML = `
${new Date().toLocaleTimeString()} · wird ausgewählt…
-
Sie: ${escapeHtml(prompt)}
+
Sie: ${prompt}
Orchestrator: ⏳ Agent arbeitet…
`; chatContainer.insertBefore(msgDiv, chatContainer.firstChild); @@ -220,11 +220,5 @@ function distributeTodos() { status.className = 'form-text mt-2 text-danger'; }); } - -function escapeHtml(text) { - const div = document.createElement('div'); - div.textContent = text; - return div.innerHTML; -} {% endblock %} diff --git a/templates/tasks.html b/templates/tasks.html index 8d6cdef..3b5be54 100644 --- a/templates/tasks.html +++ b/templates/tasks.html @@ -40,13 +40,13 @@
-
ℹ️ Info
+
🔄 Auto-Refresh
-

- Tasks werden automatisch alle 10 Sekunden vom TaskBeat verarbeitet. -
Diese Seite aktualisiert sich automatisch alle 15 Sekunden wenn Tasks aktiv sind. -

+
+ + +
@@ -108,14 +108,14 @@ {{ task.created }} - {% if task.status == 'pending' %} - ⏳ Wartend + {% if task.type == 'email' %} + Auto + {% elif task.status == 'pending' %} + Start {% elif task.status == 'in_progress' %} - 🔄 Läuft... - {% elif task.status == 'completed' %} - ✓ Auto + Fertig {% else %} - + {% endif %} @@ -137,13 +137,20 @@ {% block scripts %} {% endblock %}