feat: UX Cleanup & Critical TaskBeat Fix

UX Improvements:
- Tasks page: Remove 'Create new task' form (orchestrator handles all)
- Orchestrator: Simplified to single 'Prompt' section, removed 'Tasks verteilen'
- Orchestrator: Removed 'Klassisch senden' button (live-only responses)
- Orchestrator: Removed 'Aktive Agenten' display (redundant with dashboard)

Critical Fix:
- TaskBeat now reads pending tasks from DATABASE instead of in-memory array
- All status updates (pending→in_progress→completed) now persist to DB
- Fixes issue where tasks created via API/UI were not being processed
- Agent_key updates also synced to DB

This fixes the bug where Task #1 was stuck in pending status.
This commit is contained in:
pdyde 2026-02-21 15:04:22 +01:00
parent c949c04a5c
commit 50c1a0315b
3 changed files with 34 additions and 100 deletions

19
app.py
View file

@ -1889,12 +1889,20 @@ def process_beat_tasks():
while True: while True:
try: try:
pending_tasks = [t for t in tasks if t.get('status') == 'pending' and t.get('type') in ('agent_created', 'manual', 'orchestrated', 'agent_delegated')] # Lade pending Tasks aus Datenbank
db_tasks = get_tasks(status='pending')
# Konvertiere zu Dict-Format für Legacy-Kompatibilität
pending_tasks = []
for db_task in db_tasks:
if db_task.get('type') in ('agent_created', 'manual', 'orchestrated', 'agent_delegated', 'telegram'):
pending_tasks.append(db_task)
for task in pending_tasks: for task in pending_tasks:
agent_key = task.get('agent_key') or task.get('assigned_agent', '') agent_key = task.get('agent_key') or task.get('assigned_agent', '')
if task.get('agent_key') == 'orchestrator': if task.get('agent_key') == 'orchestrator':
# Update in DB
update_task_db(task['id'], status='in_progress')
task['status'] = 'in_progress' task['status'] = 'in_progress'
logger.info("[TaskBeat] Planungsphase für Task #%d", task['id']) logger.info("[TaskBeat] Planungsphase für Task #%d", task['id'])
@ -1953,6 +1961,8 @@ Arbeite diesen Teil ab und liefere ein vollständiges Ergebnis.""",
created_sub_tasks.append(sub_task_id) created_sub_tasks.append(sub_task_id)
logger.info("[TaskBeat] Sub-Task #%d zugewiesen an %s", sub_task_id, assigned) logger.info("[TaskBeat] Sub-Task #%d zugewiesen an %s", sub_task_id, assigned)
# Update in DB
update_task_db(task['id'], status='completed')
task['status'] = 'completed' task['status'] = 'completed'
task['sub_task_ids'] = created_sub_tasks task['sub_task_ids'] = created_sub_tasks
logger.info("[TaskBeat] Planungs-Task #%d abgeschlossen. %d Sub-Tasks erstellt.", task['id'], len(created_sub_tasks)) logger.info("[TaskBeat] Planungs-Task #%d abgeschlossen. %d Sub-Tasks erstellt.", task['id'], len(created_sub_tasks))
@ -1963,13 +1973,18 @@ Arbeite diesen Teil ab und liefere ein vollständiges Ergebnis.""",
if available_agents: if available_agents:
agent_key = available_agents[0] agent_key = available_agents[0]
task['agent_key'] = agent_key task['agent_key'] = agent_key
update_task_db(task['id'], agent_key=agent_key)
if agent_key and agent_key in AGENTS: if agent_key and agent_key in AGENTS:
# Update in DB
update_task_db(task['id'], status='in_progress')
task['status'] = 'in_progress' task['status'] = 'in_progress'
logger.info("[TaskBeat] Verarbeite Task #%d Agent: %s", task['id'], agent_key) logger.info("[TaskBeat] Verarbeite Task #%d Agent: %s", task['id'], agent_key)
response = execute_agent_task(agent_key, task.get('title', '') + '\n\n' + task.get('description', '')) response = execute_agent_task(agent_key, task.get('title', '') + '\n\n' + task.get('description', ''))
# Update in DB
update_task_db(task['id'], response=response)
task['response'] = response task['response'] = response
# Neues Memory-System: Task als strukturierte Erinnerung speichern # Neues Memory-System: Task als strukturierte Erinnerung speichern
@ -1988,6 +2003,8 @@ Arbeite diesen Teil ab und liefere ein vollständiges Ergebnis.""",
except Exception as e: except Exception as e:
logger.warning("[TaskBeat] Konnte Erinnerung nicht speichern: %s", str(e)) logger.warning("[TaskBeat] Konnte Erinnerung nicht speichern: %s", str(e))
# Update in DB
update_task_db(task['id'], status='completed')
task['status'] = 'completed' task['status'] = 'completed'
logger.info("[TaskBeat] Task #%d abgeschlossen.", task['id']) logger.info("[TaskBeat] Task #%d abgeschlossen.", task['id'])

View file

@ -16,63 +16,23 @@
<div class="row g-4"> <div class="row g-4">
<!-- Sidebar --> <!-- Sidebar -->
<div class="col-lg-4"> <div class="col-lg-4">
<!-- Task Distribution -->
<div class="card mb-3">
<div class="card-header bg-info">
<h5 class="mb-0">📋 Tasks verteilen</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label class="form-label">Aufgaben (eine pro Zeile)</label>
<textarea class="form-control" id="todoPrompt" rows="4" placeholder="Recherche Location&#10;Catering planen&#10;Pressemitteilung schreiben"></textarea>
</div>
<div class="mb-3">
<label class="form-label">Agenten auswählen</label>
<div id="agentCheckboxes">
{% for key, agent in agents.items() %}
<div class="form-check">
<input class="form-check-input agent-checkbox" type="checkbox" value="{{ key }}" id="agent_{{ key }}" checked>
<label class="form-check-label" for="agent_{{ key }}">{{ agent.name }}</label>
</div>
{% endfor %}
</div>
</div>
<button type="button" class="btn btn-info w-100" onclick="distributeTodos()">Tasks parallel ausführen</button>
<div id="todoStatus" class="form-text mt-2"></div>
</div>
</div>
<div class="card mb-3">
<div class="card-header bg-dark">
<h5 class="mb-0">Prompt eingeben</h5>
</div>
<div class="card-body">
<form id="promptForm" method="POST" action="/orchestrator">
<div class="mb-3">
<label for="prompt" class="form-label">Ihre Anfrage</label>
<textarea class="form-control" id="prompt" name="prompt" rows="5"
placeholder="Was soll erledigt werden?" required></textarea>
</div>
<button type="button" class="btn btn-primary w-100 mb-2" id="streamBtn"
onclick="sendPromptWithStream()">Live-Antwort anfordern</button>
<button type="submit" class="btn btn-secondary w-100">Klassisch senden</button>
</form>
</div>
</div>
<div class="card"> <div class="card">
<div class="card-header bg-secondary"> <div class="card-header bg-dark">
<h6 class="mb-0">Aktive Agenten</h6> <h5 class="mb-0">💬 Prompt eingeben</h5>
</div> </div>
<div class="card-body p-0"> <div class="card-body">
<ul class="list-group list-group-flush"> <div class="mb-3">
{% for key, agent in agents.items() %} <label for="prompt" class="form-label">Ihre Anfrage an den Orchestrator</label>
<li class="list-group-item d-flex justify-content-between align-items-center"> <textarea class="form-control" id="prompt" name="prompt" rows="8"
<span style="font-size:.85rem;">{{ agent.name }}</span> placeholder="Was soll erledigt werden?&#10;&#10;Beispiele:&#10;- Recherchiere Locations für den Diversity Ball&#10;- Erstelle eine Budget-Übersicht&#10;- Verteile diese Tasks an passende Agenten" required></textarea>
<span class="badge bg-success" style="font-size:.65rem;">aktiv</span> </div>
</li> <button type="button" class="btn btn-primary w-100" id="streamBtn"
{% endfor %} onclick="sendPromptWithStream()">
</ul> ▶ Live-Antwort anfordern
</button>
<p class="form-text mt-2">
Der Orchestrator analysiert deine Anfrage und delegiert automatisch an die passenden Agenten.
</p>
</div> </div>
</div> </div>
</div> </div>

View file

@ -8,50 +8,7 @@
</div> </div>
<div class="row g-4"> <div class="row g-4">
<div class="col-lg-4"> <div class="col-12">
<div class="card mb-3">
<div class="card-header bg-success">
<h5 class="mb-0">Neuen Task erstellen</h5>
</div>
<div class="card-body">
<form method="POST" action="/tasks">
<div class="mb-3">
<label for="title" class="form-label">Titel</label>
<input type="text" class="form-control" id="title" name="title" placeholder="Task-Titel" required>
</div>
<div class="mb-3">
<label for="description" class="form-label">Beschreibung</label>
<textarea class="form-control" id="description" name="description" rows="3"
placeholder="Optionale Beschreibung"></textarea>
</div>
<div class="mb-3">
<label for="assigned_agent" class="form-label">Agent (optional)</label>
<select class="form-select" id="assigned_agent" name="assigned_agent">
<option value="">— Agent wählen —</option>
{% for key, agent in agents.items() %}
<option value="{{ key }}">{{ agent.name }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-success w-100">Task erstellen</button>
</form>
</div>
</div>
<div class="card">
<div class="card-header bg-info">
<h5 class="mb-0"> Info</h5>
</div>
<div class="card-body">
<p class="mb-0" style="font-size:0.875rem;color:var(--text-muted);">
Tasks werden automatisch alle 10 Sekunden vom TaskBeat verarbeitet.
<br>Diese Seite aktualisiert sich automatisch alle 15 Sekunden wenn Tasks aktiv sind.
</p>
</div>
</div>
</div>
<div class="col-lg-8">
<div class="card"> <div class="card">
<div class="card-header bg-primary d-flex justify-content-between align-items-center"> <div class="card-header bg-primary d-flex justify-content-between align-items-center">
<h5 class="mb-0">Alle Tasks</h5> <h5 class="mb-0">Alle Tasks</h5>